-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy patha.c
430 lines (361 loc) · 14.3 KB
/
a.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
/*
* File created 14.11.2021, last modified 07.01.2022
*
* The a.c file is part of the restored LINK.COM program
* from the Hi-Tech C compiler v3.09
*
* Not a commercial goal of this laborious work is to popularize among
* potential fans of 8-bit computers the old HI-TECH C compiler V3.09
* (HI-TECH Software) and extend its life, outside of the CP/M environment
* (Digital Research, Inc), for full operation in a Unix-like operating
* system UZI-180 without using the CP/M emulator.
*
* The HI-TECH C compiler V3.09 is provided free of charge for any use,
* private or commercial, strictly as-is. No warranty or product support
* is offered or implied including merchantability, fitness for a particular
* purpose, or non-infringement. In no event will HI-TECH Software or its
* corporate affiliates be liable for any direct or indirect damages.
*
* You may use this software for whatever you like, providing you acknowledge
* that the copyright to this software remains with HI-TECH Software and its
* corporate affiliates.
*
* All copyrights to the algorithms used, binary code, trademarks, etc.
* belong to the legal owner - Microchip Technology Inc. and its subsidiaries.
* Commercial use and distribution of recreated source codes without permission
* from the copyright holderis strictly prohibited.
*
* The solution to this problem is to recreate the object code being moved,
* replace the CP/M system functions (I/O, memory allocation, etc.) with
* similar UZI-180 calls, and compile an executable file for this operating
* system.
*
* Andrey Nikitin & Mark Ogden 07.01.2022
*/
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if CPM
#include <sys.h>
#endif
#include "link.h"
/****************************************************************
* Initialized variables
****************************************************************/
uint8_t *nonTextRecPtr = nonTextRecBuf + 3; /* 6acd */
uint8_t order32[] = { /* 6acf */
0, 1, 2, 3
};
uint8_t order16[] = { /* 6ad3 */
0, 1
};
void (*libHandlers[])() = { /* 6be7 */
libPass1, libPass2
};
char usageMsg[] = /* 6c66 */
"Usage: link [-cbase][-dsymfile][-r][-n][-s][-x][-z][-oofile][-pspec][-mmap]{-usym}[-wwidth] "
"input ...";
#ifdef CPM
FILE *moduleFp = stdin; /*6c28 */
#else
FILE *moduleFp = NULL; /* for GCC and VC stdin is actually a function call so can't be used here */
#endif
int width = 80;
char *rec_types[] = { /* 6c2c */
"", /* 0 */
"TEXT", /* 1 */
"PSECT", /* 2 */
"RELOC", /* 3 */
"SYM", /* 4 */
"START", /* 5 */
"END", /* 6 */
"IDENT", /* 7 */
"XPSECT" /* 8 */
};
/* Record handler {pass1, pass2} */
void (*recHandler[][2])() = { /* 6c3e */
{ NULL, NULL }, /* 6c3e 0 "" */
{ (void (*)())textRecPass1, textRecPass2 }, /* 6c42 1 "TEXT" */
{ psectRecPass1, skipRecData }, /* 6c46 2 "PSECT" */
{ relocRecPass1, relocRecPass2 }, /* 6c4a 3 "RELOC" */
{ symRecPass1, symRecPass2 }, /* 6c4e 4 "SYM" */
{ skipRecData, startRecPass2 }, /* 6c52 5 "START" */
{ endRecPass1, endRecPass2 }, /* 6c56 6 "END" */
{ identRecPass1, skipRecData }, /* 6c5a 7 "IDENT" */
{ xpsectRecPass1, skipRecData } /* 6c5e 8 "XPSECT" */
};
void (*finPassHandler[2])() = { finPass1, finPass2 };
psect_t *nextPsect = psectInfo; /* 6f69 */
/*
* Uninitialized variables and arrays
*/
bool haveIdent; /* 7616 */
uint8_t *textRecPtr; /* 7617 */
uint8_t nonTextRecBuf[512]; /* 7619 */
uint32_t targetAddress; /* 7819 */
int textLen; /* 781d */
uint8_t textRecBuf[512]; /* 781f */
uint8_t rectyp; /* 7a1f */
uint8_t *endAddr; /* 7a20 */
uint8_t recbuf[512]; /* 7a22 */
int alreadyWritten; /* 7c22 */
uint8_t *curAddr; /* 7c24 */
uint32_t moduleSize; /* 7c26 */
int symSize; /* 7c2a */
int num_modules; /* 7c2c */
bool moduleLoaded; /* 7c2e */
int size_symbols; /* 7c2f */
bool moduleNeeded; /* 7c31 */
int num_files; /* 7c32 */
FILE *libraryFp; /* 7c34 */
int symCnt; /* 7c36 */
uint8_t libBuf[100]; /* 7c38 */
vec_t **libTable; /* 7c9c */
bool haveEntryPt; /* 7c9e */
char *libraryName; /* 7c9f */
bool key_LM; /* 7ca1 */
bool key_C; /* 7ca2 */
FILE *symFp; /* 7ca3 */
uint8_t linker_pass; /* 7ca5 */
char *fname_sym; /* 7ca6 */
int cntUnresolved; /* 7ca8 */
char *fname_obj; /* 7caa */
bool key_R; /* 7cac */
char *fname_map; /* 7cad */
bool key_S; /* 7caf */
uint16_t curFileId; /* 7cb0 */
bool key_H; /* 7cb2 */
uint16_t length; /* 7cb3 */
char *fname_outp; /* 7cb5 */
bool key_I; /* 7cb7 */
char *psect_location; /* 7cb8 */
bool key_X; /* 7cbb */
FILE *outFp; /* 7cbc */
bool key_L; /* 7cbe */
int num_lib_files; /* 7cbf */
bool key_M; /* 7cc1 */
bool key_Z; /* 7cc2 */
int err_num; /* 7cc3 */
uint32_t offset_address; /* 7cc5 */
int numRecord; /* 7cc9 */
bool key_N; /* 7ccb */
char *fixupName; /* 7ccc */
uint32_t linkAddress; /* 7cce */
sym_t *absSym; /* 7cd2 */
psect_t psectInfo[20]; /* 7cd4 */
uint32_t saveLoadAddress; /* 7ef0 */
uint32_t maxLinkAddress; /* 7ef4 */
int newSymCnt; /* 7ef8 */
uint32_t loadAddress; /* 7efa */
sym_t **symbol_table; /* 7efe */
uint32_t textBaseAddress; /* 7f00 */
/**************************************************************************
1 err_write sub-013dh ok++ (nau)(PMO)
**************************************************************************/
void err_write() {
fatal_err("%s: Write error (out of disk space?)", fname_outp);
}
/**************************************************************************
2 identRecPass1 sub-014b ok++ (nau)(PMO)
**************************************************************************/
void identRecPass1() {
uint8_t i;
readRecData(recbuf);
if (haveIdent) {
for (i = 0; i < 4; i++)
if (recbuf[IDENT_ORDER32 + i] != order32[i])
badFormat("ident records do not match");
for (i = 0; i < 2; i++)
if (recbuf[IDENT_ORDER16 + i] != order16[i])
badFormat("ident records do not match");
return;
}
for (i = 0; i < 4; i++)
order32[i] = recbuf[IDENT_ORDER32 + i];
for (i = 0; i < 2; i++)
order16[i] = recbuf[IDENT_ORDER16 + i];
haveIdent = true;
if (key_M != 0)
printf("Machine type is %s\n\n", recbuf + IDENT_MACHINE);
if (key_C == 0)
writeRec(IDENT_RECORD, length, recbuf); /* copy the Ident record */
}
/**************************************************************************
3 readRecHdr sub_0227h ok++ (nau)(PMO)
**************************************************************************/
void readRecHdr() {
if (fread(recbuf, RECORD_HDR, 1, moduleFp) != 1)
badFormat("no end record found");
++numRecord;
length = (recbuf[1] << 8) + recbuf[0];
rectyp = recbuf[RECORD_TYPE];
if (rectyp <= 0 || rectyp >= SEGMENT_RECORD)
badFormat("unknown record type: %d", rectyp);
if (length > (512 - RECORD_HDR))
badFormat("record too uint32_t: %d+%d", 3, length);
}
/**************************************************************************
4 readRecData ok++ (nau)(PMO)
**************************************************************************/
void readRecData(uint8_t *buf) {
if (fread(buf, 1, length, moduleFp) != length)
badFormat("incomplete %s record body: length = %d", rec_types[*(recbuf + RECORD_TYPE)], length);
}
/**************************************************************************
5 writeRec ok++ (nau)(PMO)
*
* optimiser improves on calculation of address of tmp
**************************************************************************/
void writeRec(int recType, uint16_t length, uint8_t *recbuf) {
uint8_t tmp[RECORD_HDR];
tmp[RECORD_TYPE] = recType;
conv_i16tole(length, tmp);
if (fwrite(tmp, RECORD_HDR, 1, outFp) == 1 && fwrite(recbuf, 1, length, outFp) == length)
return;
err_write();
}
/**************************************************************************
6 writeText ok++ (nau)(PMO)
*
Optimiser improves on calculation of address of tmp, but misses ex (sp),hl
optimisation using pop bc, push hl instead
**************************************************************************/
void writeText() {
uint8_t tmp[RECORD_HDR];
int textHdrLen;
int writeLen;
if (curAddr < textRecPtr || endAddr <= curAddr)
return;
textHdrLen = TEXT_PNAME + (int)strlen((char *)textRecBuf + TEXT_PNAME) + 1;
writeLen = (int)(endAddr - curAddr);
conv_i16tole(textHdrLen + writeLen, tmp); /* Fillout the record header */
tmp[RECORD_TYPE] = TEXT_RECORD;
if (key_C) {
targetAddress = conv_btou32(textRecBuf); /* Pick up the text record offset */
if (targetAddress < offset_address)
fatal_err("module has code below file base of 0%" PRIx32 "h", offset_address);
if (fseek(outFp, targetAddress - offset_address, SEEK_SET) == -1)
fatal_err("%s: Seek error", fname_outp);
if (fwrite(curAddr, 1, writeLen, outFp) != writeLen)
err_write();
} else {
/* Copy the text record */
if (fwrite(tmp, RECORD_HDR, 1, outFp) != 1 ||
fwrite(textRecBuf, 1, textHdrLen, outFp) != textHdrLen ||
fwrite(curAddr, 1, writeLen, outFp) != writeLen)
err_write();
}
conv_u32tob(conv_btou32(textRecBuf) + writeLen, textRecBuf); /* Update the offset */
curAddr = endAddr; /* Advance to end */
alreadyWritten += writeLen;
}
/**************************************************************************
7 flushText ok++ (nau)
**************************************************************************/
void flushText() {
endAddr = textLen + textRecPtr;
writeText();
}
/**************************************************************************
8 wrRecord ok++ (nau)
**************************************************************************/
void wrRecord() {
int len;
len = (int)(nonTextRecPtr - nonTextRecBuf);
if (nonTextRecBuf[RECORD_TYPE] == 0 || len == RECORD_HDR)
return;
if (nonTextRecBuf[2] == RELOC_RECORD)
writeText(); /* Make sure text that was relocated is written first */
conv_i16tole(len - RECORD_HDR, nonTextRecBuf); /* Length of data item */
if (fwrite(nonTextRecBuf, 1, len, outFp) != len)
err_write();
nonTextRecBuf[RECORD_TYPE] = 0;
nonTextRecPtr = nonTextRecBuf + RECORD_HDR;
}
/**************************************************************************
9 chkAddRecordItem ok++ (nau)
**************************************************************************/
void chkAddRecordItem(uint8_t type, size_t len) {
/* Can add if same record type and it fits else flush */
if (nonTextRecBuf[RECORD_TYPE] == type && nonTextRecBuf + 512 >= nonTextRecPtr + len)
return;
wrRecord();
nonTextRecBuf[RECORD_TYPE] = type;
}
/**************************************************************************
10 conv_i16tole sub-05bfh ok++ (nau)
**************************************************************************/
void conv_i16tole(int16_t p1, uint8_t *p2) {
p2[0] = (uint8_t)p1;
p2[1] = p1 >> 8;
}
/**************************************************************************
11 conv_letoi16 sub-05e1h ok++ (PMO)
* Convert leading low string to int
*
* Optimiser eliminates the odd code of the original which did spurious
* unrequired operations
**************************************************************************/
int16_t conv_letoi16(register uint8_t *p1) {
return (p1[order16[1]] << 8) + p1[order16[0]];
}
/**************************************************************************
12 conv_u16tob sub-0616h ok++ (PMO)
* Convert int to leading low string
**************************************************************************/
void conv_u16tob(uint16_t p1, register uint8_t *p2) {
p2[order16[0]] = (uint8_t)p1;
p2[order16[1]] = p1 >> 8;
}
/**************************************************************************
13 conv_btou32 sub_0647h ok ++ (PMO)
* Calculate uint32_t value
*
* The hitech compiler generates invalid code for shift operation using
* the obvious casting.
* The double layer cast does however generate correct code and is marginally
* optimised over the original
**************************************************************************/
uint32_t conv_btou32(register uint8_t *p1) {
uint32_t l1;
char l2;
l2 = 4;
l1 = 0;
while (l2-- > 0)
l1 += ((uint32_t)(uint16_t)p1[order32[(int)l2]]) << (l2 * 8);
return l1;
}
/**************************************************************************
14 conv_u32tob ok++
**************************************************************************/
void conv_u32tob(uint32_t p1, register uint8_t *st) {
uint8_t l1;
for (l1 = 0; l1 < 4; ++l1) {
st[order32[l1]] = (uint8_t)p1;
p1 >>= 8;
}
}
/**************************************************************************
15 conv_btou24 ok ++ (PMO)
* Same issue as conv_btou32
**************************************************************************/
uint32_t conv_btou24(register uint8_t *p1) {
uint32_t l1;
char l2;
l2 = 3;
l1 = 0;
while (l2-- > 0)
l1 += ((uint32_t)(uint16_t)p1[order32[(int)l2]] << (l2 * 8));
return l1;
}
/**************************************************************************
16 conv_u24tob ok++ (nau) (PMO)
**************************************************************************/
void conv_u24tob(uint32_t p1, register uint8_t *st) {
uint8_t l1;
for (l1 = 0; l1 < 3; ++l1) {
st[order32[l1]] = (uint8_t)p1;
p1 >>= 8;
}
}