1 | /* ----------------------------------------------------------------------- * |
2 | * |
3 | * Copyright 1996-2016 The NASM Authors - All Rights Reserved |
4 | * See the file AUTHORS included with the NASM distribution for |
5 | * the specific copyright holders. |
6 | * |
7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following |
9 | * conditions are met: |
10 | * |
11 | * * Redistributions of source code must retain the above copyright |
12 | * notice, this list of conditions and the following disclaimer. |
13 | * * Redistributions in binary form must reproduce the above |
14 | * copyright notice, this list of conditions and the following |
15 | * disclaimer in the documentation and/or other materials provided |
16 | * with the distribution. |
17 | * |
18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |
19 | * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |
20 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
22 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
23 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
24 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
25 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
26 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
29 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, |
30 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
31 | * |
32 | * ----------------------------------------------------------------------- */ |
33 | |
34 | /* |
35 | * outieee.c output routines for the Netwide Assembler to produce |
36 | * IEEE-std object files |
37 | */ |
38 | |
39 | /* notes: I have tried to make this correspond to the IEEE version |
40 | * of the standard, specifically the primary ASCII version. It should |
41 | * be trivial to create the binary version given this source (which is |
42 | * one of MANY things that have to be done to make this correspond to |
43 | * the hp-microtek version of the standard). |
44 | * |
45 | * 16-bit support is assumed to use 24-bit addresses |
46 | * The linker can sort out segmentation-specific stuff |
47 | * if it keeps track of externals |
48 | * in terms of being relative to section bases |
49 | * |
50 | * A non-standard variable type, the 'Yn' variable, has been introduced. |
51 | * Basically it is a reference to extern 'n'- denoting the low limit |
52 | * (L-variable) of the section that extern 'n' is defined in. Like the |
53 | * x variable, there may be no explicit assignment to it, it is derived |
54 | * from the public definition corresponding to the extern name. This |
55 | * is required because the one thing the mufom guys forgot to do well was |
56 | * take into account segmented architectures. |
57 | * |
58 | * I use comment classes for various things and these are undefined by |
59 | * the standard. |
60 | * |
61 | * Debug info should be considered totally non-standard (local labels are |
62 | * standard but linenum records are not covered by the standard. |
63 | * Type defs have the standard format but absolute meanings for ordinal |
64 | * types are not covered by the standard.) |
65 | * |
66 | * David Lindauer, LADsoft |
67 | */ |
68 | #include "compiler.h" |
69 | |
70 | #include <stdio.h> |
71 | #include <stdlib.h> |
72 | #include <string.h> |
73 | #include <time.h> |
74 | #include <stdarg.h> /* Note: we need the ANSI version of stdarg.h */ |
75 | #include <ctype.h> |
76 | |
77 | #include "nasm.h" |
78 | #include "nasmlib.h" |
79 | #include "error.h" |
80 | #include "ver.h" |
81 | |
82 | #include "outform.h" |
83 | #include "outlib.h" |
84 | |
85 | #ifdef OF_IEEE |
86 | |
87 | #define ARRAY_BOT 0x1 |
88 | |
89 | static char ieee_infile[FILENAME_MAX]; |
90 | static int ieee_uppercase; |
91 | |
92 | static bool any_segs; |
93 | static int arrindex; |
94 | |
95 | #define HUNKSIZE 1024 /* Size of the data hunk */ |
96 | #define EXT_BLKSIZ 512 |
97 | #define LDPERLINE 32 /* bytes per line in output */ |
98 | |
99 | struct ieeeSection; |
100 | |
101 | struct LineNumber { |
102 | struct LineNumber *next; |
103 | struct ieeeSection *segment; |
104 | int32_t offset; |
105 | int32_t lineno; |
106 | }; |
107 | |
108 | static struct FileName { |
109 | struct FileName *next; |
110 | char *name; |
111 | int32_t index; |
112 | } *fnhead, **fntail; |
113 | |
114 | static struct Array { |
115 | struct Array *next; |
116 | unsigned size; |
117 | int basetype; |
118 | } *arrhead, **arrtail; |
119 | |
120 | static struct ieeePublic { |
121 | struct ieeePublic *next; |
122 | char *name; |
123 | int32_t offset; |
124 | int32_t segment; /* only if it's far-absolute */ |
125 | int32_t index; |
126 | int type; /* for debug purposes */ |
127 | } *fpubhead, **fpubtail, *last_defined; |
128 | |
129 | static struct ieeeExternal { |
130 | struct ieeeExternal *next; |
131 | char *name; |
132 | int32_t commonsize; |
133 | } *exthead, **exttail; |
134 | |
135 | static int externals; |
136 | |
137 | static struct ExtBack { |
138 | struct ExtBack *next; |
139 | int index[EXT_BLKSIZ]; |
140 | } *ebhead, **ebtail; |
141 | |
142 | /* NOTE: the first segment MUST be the lineno segment */ |
143 | static struct ieeeSection { |
144 | struct ieeeSection *next; |
145 | char *name; |
146 | struct ieeeObjData *data, *datacurr; |
147 | struct ieeeFixupp *fptr, *flptr; |
148 | int32_t index; /* the NASM segment id */ |
149 | int32_t ieee_index; /* the OBJ-file segment index */ |
150 | int32_t currentpos; |
151 | int32_t align; /* can be SEG_ABS + absolute addr */ |
152 | int32_t startpos; |
153 | int32_t use32; /* is this segment 32-bit? */ |
154 | struct ieeePublic *pubhead, **pubtail, *lochead, **loctail; |
155 | enum { |
156 | CMB_PRIVATE = 0, |
157 | CMB_PUBLIC = 2, |
158 | CMB_COMMON = 6 |
159 | } combine; |
160 | } *seghead, **segtail, *ieee_seg_needs_update; |
161 | |
162 | struct ieeeObjData { |
163 | struct ieeeObjData *next; |
164 | uint8_t data[HUNKSIZE]; |
165 | }; |
166 | |
167 | struct ieeeFixupp { |
168 | struct ieeeFixupp *next; |
169 | enum { |
170 | FT_SEG = 0, |
171 | FT_REL = 1, |
172 | FT_OFS = 2, |
173 | FT_EXT = 3, |
174 | FT_WRT = 4, |
175 | FT_EXTREL = 5, |
176 | FT_EXTWRT = 6, |
177 | FT_EXTSEG = 7 |
178 | } ftype; |
179 | int16_t size; |
180 | int32_t id1; |
181 | int32_t id2; |
182 | int32_t offset; |
183 | int32_t addend; |
184 | }; |
185 | |
186 | static int32_t ieee_entry_seg, ieee_entry_ofs; |
187 | static int checksum; |
188 | |
189 | extern const struct ofmt of_ieee; |
190 | static const struct dfmt ladsoft_debug_form; |
191 | |
192 | static void ieee_data_new(struct ieeeSection *); |
193 | static void ieee_write_fixup(int32_t, int32_t, struct ieeeSection *, |
194 | int, uint64_t, int32_t); |
195 | static void ieee_install_fixup(struct ieeeSection *, struct ieeeFixupp *); |
196 | static int32_t ieee_segment(char *, int, int *); |
197 | static void ieee_write_file(void); |
198 | static void ieee_write_byte(struct ieeeSection *, int); |
199 | static void ieee_write_word(struct ieeeSection *, int); |
200 | static void ieee_write_dword(struct ieeeSection *, int32_t); |
201 | static void ieee_putascii(char *, ...); |
202 | static void ieee_putcs(int); |
203 | static int32_t ieee_putld(int32_t, int32_t, uint8_t *); |
204 | static int32_t ieee_putlr(struct ieeeFixupp *); |
205 | static void ieee_unqualified_name(char *, char *); |
206 | |
207 | /* |
208 | * pup init |
209 | */ |
210 | static void ieee_init(void) |
211 | { |
212 | strlcpy(ieee_infile, inname, sizeof(ieee_infile)); |
213 | any_segs = false; |
214 | fpubhead = NULL; |
215 | fpubtail = &fpubhead; |
216 | exthead = NULL; |
217 | exttail = &exthead; |
218 | externals = 1; |
219 | ebhead = NULL; |
220 | ebtail = &ebhead; |
221 | seghead = ieee_seg_needs_update = NULL; |
222 | segtail = &seghead; |
223 | ieee_entry_seg = NO_SEG; |
224 | ieee_uppercase = false; |
225 | checksum = 0; |
226 | } |
227 | |
228 | /* |
229 | * Rundown |
230 | */ |
231 | static void ieee_cleanup(void) |
232 | { |
233 | ieee_write_file(); |
234 | dfmt->cleanup(); |
235 | while (seghead) { |
236 | struct ieeeSection *segtmp = seghead; |
237 | seghead = seghead->next; |
238 | while (segtmp->pubhead) { |
239 | struct ieeePublic *pubtmp = segtmp->pubhead; |
240 | segtmp->pubhead = pubtmp->next; |
241 | nasm_free(pubtmp); |
242 | } |
243 | while (segtmp->fptr) { |
244 | struct ieeeFixupp *fixtmp = segtmp->fptr; |
245 | segtmp->fptr = fixtmp->next; |
246 | nasm_free(fixtmp); |
247 | } |
248 | while (segtmp->data) { |
249 | struct ieeeObjData *dattmp = segtmp->data; |
250 | segtmp->data = dattmp->next; |
251 | nasm_free(dattmp); |
252 | } |
253 | nasm_free(segtmp); |
254 | } |
255 | while (fpubhead) { |
256 | struct ieeePublic *pubtmp = fpubhead; |
257 | fpubhead = fpubhead->next; |
258 | nasm_free(pubtmp); |
259 | } |
260 | while (exthead) { |
261 | struct ieeeExternal *exttmp = exthead; |
262 | exthead = exthead->next; |
263 | nasm_free(exttmp); |
264 | } |
265 | while (ebhead) { |
266 | struct ExtBack *ebtmp = ebhead; |
267 | ebhead = ebhead->next; |
268 | nasm_free(ebtmp); |
269 | } |
270 | } |
271 | |
272 | /* |
273 | * callback for labels |
274 | */ |
275 | static void ieee_deflabel(char *name, int32_t segment, |
276 | int64_t offset, int is_global, char *special) |
277 | { |
278 | /* |
279 | * We have three cases: |
280 | * |
281 | * (i) `segment' is a segment-base. If so, set the name field |
282 | * for the segment structure it refers to, and then |
283 | * return. |
284 | * |
285 | * (ii) `segment' is one of our segments, or a SEG_ABS segment. |
286 | * Save the label position for later output of a PUBDEF record. |
287 | * |
288 | * |
289 | * (iii) `segment' is not one of our segments. Save the label |
290 | * position for later output of an EXTDEF. |
291 | */ |
292 | struct ieeeExternal *ext; |
293 | struct ExtBack *eb; |
294 | struct ieeeSection *seg; |
295 | int i; |
296 | |
297 | if (special) { |
298 | nasm_error(ERR_NONFATAL, "unrecognised symbol type `%s'" , special); |
299 | } |
300 | /* |
301 | * First check for the double-period, signifying something |
302 | * unusual. |
303 | */ |
304 | if (name[0] == '.' && name[1] == '.' && name[2] != '@') { |
305 | if (!strcmp(name, "..start" )) { |
306 | ieee_entry_seg = segment; |
307 | ieee_entry_ofs = offset; |
308 | } |
309 | return; |
310 | } |
311 | |
312 | /* |
313 | * Case (i): |
314 | */ |
315 | if (ieee_seg_needs_update) { |
316 | ieee_seg_needs_update->name = name; |
317 | return; |
318 | } |
319 | if (segment < SEG_ABS && segment != NO_SEG && segment % 2) |
320 | return; |
321 | |
322 | /* |
323 | * case (ii) |
324 | */ |
325 | if (segment >= SEG_ABS) { |
326 | /* |
327 | * SEG_ABS subcase of (ii). |
328 | */ |
329 | if (is_global) { |
330 | struct ieeePublic *pub; |
331 | |
332 | pub = *fpubtail = nasm_malloc(sizeof(*pub)); |
333 | fpubtail = &pub->next; |
334 | pub->next = NULL; |
335 | pub->name = name; |
336 | pub->offset = offset; |
337 | pub->segment = segment & ~SEG_ABS; |
338 | } |
339 | return; |
340 | } |
341 | |
342 | for (seg = seghead; seg && is_global; seg = seg->next) |
343 | if (seg->index == segment) { |
344 | struct ieeePublic *pub; |
345 | |
346 | last_defined = pub = *seg->pubtail = nasm_malloc(sizeof(*pub)); |
347 | seg->pubtail = &pub->next; |
348 | pub->next = NULL; |
349 | pub->name = name; |
350 | pub->offset = offset; |
351 | pub->index = seg->ieee_index; |
352 | pub->segment = -1; |
353 | return; |
354 | } |
355 | |
356 | /* |
357 | * Case (iii). |
358 | */ |
359 | if (is_global) { |
360 | ext = *exttail = nasm_malloc(sizeof(*ext)); |
361 | ext->next = NULL; |
362 | exttail = &ext->next; |
363 | ext->name = name; |
364 | if (is_global == 2) |
365 | ext->commonsize = offset; |
366 | else |
367 | ext->commonsize = 0; |
368 | i = segment / 2; |
369 | eb = ebhead; |
370 | if (!eb) { |
371 | eb = *ebtail = nasm_zalloc(sizeof(*eb)); |
372 | eb->next = NULL; |
373 | ebtail = &eb->next; |
374 | } |
375 | while (i > EXT_BLKSIZ) { |
376 | if (eb && eb->next) |
377 | eb = eb->next; |
378 | else { |
379 | eb = *ebtail = nasm_zalloc(sizeof(*eb)); |
380 | eb->next = NULL; |
381 | ebtail = &eb->next; |
382 | } |
383 | i -= EXT_BLKSIZ; |
384 | } |
385 | eb->index[i] = externals++; |
386 | } |
387 | |
388 | } |
389 | |
390 | /* |
391 | * Put data out |
392 | */ |
393 | static void ieee_out(int32_t segto, const void *data, |
394 | enum out_type type, uint64_t size, |
395 | int32_t segment, int32_t wrt) |
396 | { |
397 | const uint8_t *ucdata; |
398 | int32_t ldata; |
399 | struct ieeeSection *seg; |
400 | |
401 | /* |
402 | * handle absolute-assembly (structure definitions) |
403 | */ |
404 | if (segto == NO_SEG) { |
405 | if (type != OUT_RESERVE) |
406 | nasm_error(ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]" |
407 | " space" ); |
408 | return; |
409 | } |
410 | |
411 | /* |
412 | * If `any_segs' is still false, we must define a default |
413 | * segment. |
414 | */ |
415 | if (!any_segs) { |
416 | int tempint; /* ignored */ |
417 | if (segto != ieee_segment("__NASMDEFSEG" , 2, &tempint)) |
418 | nasm_panic(0, "strange segment conditions in IEEE driver" ); |
419 | } |
420 | |
421 | /* |
422 | * Find the segment we are targetting. |
423 | */ |
424 | for (seg = seghead; seg; seg = seg->next) |
425 | if (seg->index == segto) |
426 | break; |
427 | if (!seg) |
428 | nasm_panic(0, "code directed to nonexistent segment?" ); |
429 | |
430 | if (type == OUT_RAWDATA) { |
431 | ucdata = data; |
432 | while (size--) |
433 | ieee_write_byte(seg, *ucdata++); |
434 | } else if (type == OUT_ADDRESS || type == OUT_REL2ADR || |
435 | type == OUT_REL4ADR) { |
436 | if (type == OUT_ADDRESS) |
437 | size = abs((int)size); |
438 | else if (segment == NO_SEG) |
439 | nasm_error(ERR_NONFATAL, "relative call to absolute address not" |
440 | " supported by IEEE format" ); |
441 | ldata = *(int64_t *)data; |
442 | if (type == OUT_REL2ADR) |
443 | ldata += (size - 2); |
444 | if (type == OUT_REL4ADR) |
445 | ldata += (size - 4); |
446 | ieee_write_fixup(segment, wrt, seg, size, type, ldata); |
447 | if (size == 2) |
448 | ieee_write_word(seg, ldata); |
449 | else |
450 | ieee_write_dword(seg, ldata); |
451 | } else if (type == OUT_RESERVE) { |
452 | while (size--) |
453 | ieee_write_byte(seg, 0); |
454 | } |
455 | } |
456 | |
457 | static void ieee_data_new(struct ieeeSection *segto) |
458 | { |
459 | |
460 | if (!segto->data) |
461 | segto->data = segto->datacurr = |
462 | nasm_malloc(sizeof(*(segto->datacurr))); |
463 | else |
464 | segto->datacurr = segto->datacurr->next = |
465 | nasm_malloc(sizeof(*(segto->datacurr))); |
466 | segto->datacurr->next = NULL; |
467 | } |
468 | |
469 | /* |
470 | * this routine is unalduterated bloatware. I usually don't do this |
471 | * but I might as well see what it is like on a harmless program. |
472 | * If anyone wants to optimize this is a good canditate! |
473 | */ |
474 | static void ieee_write_fixup(int32_t segment, int32_t wrt, |
475 | struct ieeeSection *segto, int size, |
476 | uint64_t realtype, int32_t offset) |
477 | { |
478 | struct ieeeSection *target; |
479 | struct ieeeFixupp s; |
480 | |
481 | /* Don't put a fixup for things NASM can calculate */ |
482 | if (wrt == NO_SEG && segment == NO_SEG) |
483 | return; |
484 | |
485 | s.ftype = -1; |
486 | /* if it is a WRT offset */ |
487 | if (wrt != NO_SEG) { |
488 | s.ftype = FT_WRT; |
489 | s.addend = offset; |
490 | if (wrt >= SEG_ABS) |
491 | s.id1 = -(wrt - SEG_ABS); |
492 | else { |
493 | if (wrt % 2 && realtype != OUT_REL2ADR |
494 | && realtype != OUT_REL4ADR) { |
495 | wrt--; |
496 | |
497 | for (target = seghead; target; target = target->next) |
498 | if (target->index == wrt) |
499 | break; |
500 | if (target) { |
501 | s.id1 = target->ieee_index; |
502 | for (target = seghead; target; target = target->next) |
503 | if (target->index == segment) |
504 | break; |
505 | |
506 | if (target) |
507 | s.id2 = target->ieee_index; |
508 | else { |
509 | /* |
510 | * Now we assume the segment field is being used |
511 | * to hold an extern index |
512 | */ |
513 | int32_t i = segment / 2; |
514 | struct ExtBack *eb = ebhead; |
515 | while (i > EXT_BLKSIZ) { |
516 | if (eb) |
517 | eb = eb->next; |
518 | else |
519 | break; |
520 | i -= EXT_BLKSIZ; |
521 | } |
522 | /* if we have an extern decide the type and make a record |
523 | */ |
524 | if (eb) { |
525 | s.ftype = FT_EXTWRT; |
526 | s.addend = 0; |
527 | s.id2 = eb->index[i]; |
528 | } else |
529 | nasm_error(ERR_NONFATAL, |
530 | "Source of WRT must be an offset" ); |
531 | } |
532 | |
533 | } else |
534 | nasm_panic(0, |
535 | "unrecognised WRT value in ieee_write_fixup" ); |
536 | } else |
537 | nasm_error(ERR_NONFATAL, "target of WRT must be a section " ); |
538 | } |
539 | s.size = size; |
540 | ieee_install_fixup(segto, &s); |
541 | return; |
542 | } |
543 | /* Pure segment fixup ? */ |
544 | if (segment != NO_SEG) { |
545 | s.ftype = FT_SEG; |
546 | s.id1 = 0; |
547 | if (segment >= SEG_ABS) { |
548 | /* absolute far segment fixup */ |
549 | s.id1 = -(segment - ~SEG_ABS); |
550 | } else if (segment % 2) { |
551 | /* fixup to named segment */ |
552 | /* look it up */ |
553 | for (target = seghead; target; target = target->next) |
554 | if (target->index == segment - 1) |
555 | break; |
556 | if (target) |
557 | s.id1 = target->ieee_index; |
558 | else { |
559 | /* |
560 | * Now we assume the segment field is being used |
561 | * to hold an extern index |
562 | */ |
563 | int32_t i = segment / 2; |
564 | struct ExtBack *eb = ebhead; |
565 | while (i > EXT_BLKSIZ) { |
566 | if (eb) |
567 | eb = eb->next; |
568 | else |
569 | break; |
570 | i -= EXT_BLKSIZ; |
571 | } |
572 | /* if we have an extern decide the type and make a record |
573 | */ |
574 | if (eb) { |
575 | if (realtype == OUT_REL2ADR || realtype == OUT_REL4ADR) { |
576 | nasm_panic(0, |
577 | "Segment of a rel not supported in ieee_write_fixup" ); |
578 | } else { |
579 | /* If we want the segment */ |
580 | s.ftype = FT_EXTSEG; |
581 | s.addend = 0; |
582 | s.id1 = eb->index[i]; |
583 | } |
584 | |
585 | } else |
586 | /* If we get here the seg value doesn't make sense */ |
587 | nasm_panic(0, |
588 | "unrecognised segment value in ieee_write_fixup" ); |
589 | } |
590 | |
591 | } else { |
592 | /* Assume we are offsetting directly from a section |
593 | * So look up the target segment |
594 | */ |
595 | for (target = seghead; target; target = target->next) |
596 | if (target->index == segment) |
597 | break; |
598 | if (target) { |
599 | if (realtype == OUT_REL2ADR || realtype == OUT_REL4ADR) { |
600 | /* PC rel to a known offset */ |
601 | s.id1 = target->ieee_index; |
602 | s.ftype = FT_REL; |
603 | s.size = size; |
604 | s.addend = offset; |
605 | } else { |
606 | /* We were offsetting from a seg */ |
607 | s.id1 = target->ieee_index; |
608 | s.ftype = FT_OFS; |
609 | s.size = size; |
610 | s.addend = offset; |
611 | } |
612 | } else { |
613 | /* |
614 | * Now we assume the segment field is being used |
615 | * to hold an extern index |
616 | */ |
617 | int32_t i = segment / 2; |
618 | struct ExtBack *eb = ebhead; |
619 | while (i > EXT_BLKSIZ) { |
620 | if (eb) |
621 | eb = eb->next; |
622 | else |
623 | break; |
624 | i -= EXT_BLKSIZ; |
625 | } |
626 | /* if we have an extern decide the type and make a record |
627 | */ |
628 | if (eb) { |
629 | if (realtype == OUT_REL2ADR || realtype == OUT_REL4ADR) { |
630 | s.ftype = FT_EXTREL; |
631 | s.addend = 0; |
632 | s.id1 = eb->index[i]; |
633 | } else { |
634 | /* else we want the external offset */ |
635 | s.ftype = FT_EXT; |
636 | s.addend = 0; |
637 | s.id1 = eb->index[i]; |
638 | } |
639 | |
640 | } else |
641 | /* If we get here the seg value doesn't make sense */ |
642 | nasm_panic(0, |
643 | "unrecognised segment value in ieee_write_fixup" ); |
644 | } |
645 | } |
646 | if (size != 2 && s.ftype == FT_SEG) |
647 | nasm_error(ERR_NONFATAL, "IEEE format can only handle 2-byte" |
648 | " segment base references" ); |
649 | s.size = size; |
650 | ieee_install_fixup(segto, &s); |
651 | return; |
652 | } |
653 | /* should never get here */ |
654 | } |
655 | static void ieee_install_fixup(struct ieeeSection *seg, |
656 | struct ieeeFixupp *fix) |
657 | { |
658 | struct ieeeFixupp *f; |
659 | f = nasm_malloc(sizeof(struct ieeeFixupp)); |
660 | memcpy(f, fix, sizeof(struct ieeeFixupp)); |
661 | f->offset = seg->currentpos; |
662 | seg->currentpos += fix->size; |
663 | f->next = NULL; |
664 | if (seg->fptr) |
665 | seg->flptr = seg->flptr->next = f; |
666 | else |
667 | seg->fptr = seg->flptr = f; |
668 | |
669 | } |
670 | |
671 | /* |
672 | * segment registry |
673 | */ |
674 | static int32_t ieee_segment(char *name, int pass, int *bits) |
675 | { |
676 | /* |
677 | * We call the label manager here to define a name for the new |
678 | * segment, and when our _own_ label-definition stub gets |
679 | * called in return, it should register the new segment name |
680 | * using the pointer it gets passed. That way we save memory, |
681 | * by sponging off the label manager. |
682 | */ |
683 | if (!name) { |
684 | *bits = 16; |
685 | if (!any_segs) |
686 | return 0; |
687 | return seghead->index; |
688 | } else { |
689 | struct ieeeSection *seg; |
690 | int ieee_idx, attrs; |
691 | bool rn_error; |
692 | char *p; |
693 | |
694 | /* |
695 | * Look for segment attributes. |
696 | */ |
697 | attrs = 0; |
698 | while (*name == '.') |
699 | name++; /* hack, but a documented one */ |
700 | p = name; |
701 | while (*p && !nasm_isspace(*p)) |
702 | p++; |
703 | if (*p) { |
704 | *p++ = '\0'; |
705 | while (*p && nasm_isspace(*p)) |
706 | *p++ = '\0'; |
707 | } |
708 | while (*p) { |
709 | while (*p && !nasm_isspace(*p)) |
710 | p++; |
711 | if (*p) { |
712 | *p++ = '\0'; |
713 | while (*p && nasm_isspace(*p)) |
714 | *p++ = '\0'; |
715 | } |
716 | |
717 | attrs++; |
718 | } |
719 | |
720 | ieee_idx = 1; |
721 | for (seg = seghead; seg; seg = seg->next) { |
722 | ieee_idx++; |
723 | if (!strcmp(seg->name, name)) { |
724 | if (attrs > 0 && pass == 1) |
725 | nasm_error(ERR_WARNING, "segment attributes specified on" |
726 | " redeclaration of segment: ignoring" ); |
727 | if (seg->use32) |
728 | *bits = 32; |
729 | else |
730 | *bits = 16; |
731 | return seg->index; |
732 | } |
733 | } |
734 | |
735 | *segtail = seg = nasm_malloc(sizeof(*seg)); |
736 | seg->next = NULL; |
737 | segtail = &seg->next; |
738 | seg->index = seg_alloc(); |
739 | seg->ieee_index = ieee_idx; |
740 | any_segs = true; |
741 | seg->name = NULL; |
742 | seg->currentpos = 0; |
743 | seg->align = 1; /* default */ |
744 | seg->use32 = *bits == 32; /* default to user spec */ |
745 | seg->combine = CMB_PUBLIC; /* default */ |
746 | seg->pubhead = NULL; |
747 | seg->pubtail = &seg->pubhead; |
748 | seg->data = NULL; |
749 | seg->fptr = NULL; |
750 | seg->lochead = NULL; |
751 | seg->loctail = &seg->lochead; |
752 | |
753 | /* |
754 | * Process the segment attributes. |
755 | */ |
756 | p = name; |
757 | while (attrs--) { |
758 | p += strlen(p); |
759 | while (!*p) |
760 | p++; |
761 | |
762 | /* |
763 | * `p' contains a segment attribute. |
764 | */ |
765 | if (!nasm_stricmp(p, "private" )) |
766 | seg->combine = CMB_PRIVATE; |
767 | else if (!nasm_stricmp(p, "public" )) |
768 | seg->combine = CMB_PUBLIC; |
769 | else if (!nasm_stricmp(p, "common" )) |
770 | seg->combine = CMB_COMMON; |
771 | else if (!nasm_stricmp(p, "use16" )) |
772 | seg->use32 = false; |
773 | else if (!nasm_stricmp(p, "use32" )) |
774 | seg->use32 = true; |
775 | else if (!nasm_strnicmp(p, "align=" , 6)) { |
776 | seg->align = readnum(p + 6, &rn_error); |
777 | if (seg->align == 0) |
778 | seg->align = 1; |
779 | if (rn_error) { |
780 | seg->align = 1; |
781 | nasm_error(ERR_NONFATAL, "segment alignment should be" |
782 | " numeric" ); |
783 | } |
784 | switch (seg->align) { |
785 | case 1: /* BYTE */ |
786 | case 2: /* WORD */ |
787 | case 4: /* DWORD */ |
788 | case 16: /* PARA */ |
789 | case 256: /* PAGE */ |
790 | case 8: |
791 | case 32: |
792 | case 64: |
793 | case 128: |
794 | break; |
795 | default: |
796 | nasm_error(ERR_NONFATAL, "invalid alignment value %d" , |
797 | seg->align); |
798 | seg->align = 1; |
799 | break; |
800 | } |
801 | } else if (!nasm_strnicmp(p, "absolute=" , 9)) { |
802 | seg->align = SEG_ABS + readnum(p + 9, &rn_error); |
803 | if (rn_error) |
804 | nasm_error(ERR_NONFATAL, "argument to `absolute' segment" |
805 | " attribute should be numeric" ); |
806 | } |
807 | } |
808 | |
809 | ieee_seg_needs_update = seg; |
810 | if (seg->align >= SEG_ABS) |
811 | define_label(name, NO_SEG, seg->align - SEG_ABS, false); |
812 | else |
813 | define_label(name, seg->index + 1, 0L, false); |
814 | ieee_seg_needs_update = NULL; |
815 | |
816 | if (seg->use32) |
817 | *bits = 32; |
818 | else |
819 | *bits = 16; |
820 | return seg->index; |
821 | } |
822 | } |
823 | |
824 | /* |
825 | * directives supported |
826 | */ |
827 | static enum directive_result |
828 | ieee_directive(enum directive directive, char *value, int pass) |
829 | { |
830 | |
831 | (void)value; |
832 | (void)pass; |
833 | |
834 | switch (directive) { |
835 | case D_UPPERCASE: |
836 | ieee_uppercase = true; |
837 | return DIRR_OK; |
838 | |
839 | default: |
840 | return DIRR_UNKNOWN; |
841 | } |
842 | } |
843 | |
844 | static void ieee_sectalign(int32_t seg, unsigned int value) |
845 | { |
846 | struct ieeeSection *s; |
847 | |
848 | list_for_each(s, seghead) { |
849 | if (s->index == seg) |
850 | break; |
851 | } |
852 | |
853 | /* |
854 | * 256 is maximum there, note it may happen |
855 | * that align is issued on "absolute" segment |
856 | * it's fine since SEG_ABS > 256 and we never |
857 | * get escape this test |
858 | */ |
859 | if (!s || !is_power2(value) || value > 256) |
860 | return; |
861 | |
862 | if ((unsigned int)s->align < value) |
863 | s->align = value; |
864 | } |
865 | |
866 | /* |
867 | * Return segment data |
868 | */ |
869 | static int32_t ieee_segbase(int32_t segment) |
870 | { |
871 | struct ieeeSection *seg; |
872 | |
873 | /* |
874 | * Find the segment in our list. |
875 | */ |
876 | for (seg = seghead; seg; seg = seg->next) |
877 | if (seg->index == segment - 1) |
878 | break; |
879 | |
880 | if (!seg) |
881 | return segment; /* not one of ours - leave it alone */ |
882 | |
883 | if (seg->align >= SEG_ABS) |
884 | return seg->align; /* absolute segment */ |
885 | |
886 | return segment; /* no special treatment */ |
887 | } |
888 | |
889 | static void ieee_write_file(void) |
890 | { |
891 | const struct tm * const thetime = &official_compile_time.local; |
892 | struct FileName *fn; |
893 | struct ieeeSection *seg; |
894 | struct ieeePublic *pub, *loc; |
895 | struct ieeeExternal *ext; |
896 | struct ieeeObjData *data; |
897 | struct ieeeFixupp *fix; |
898 | struct Array *arr; |
899 | int i; |
900 | const bool debuginfo = (dfmt == &ladsoft_debug_form); |
901 | |
902 | /* |
903 | * Write the module header |
904 | */ |
905 | ieee_putascii("MBFNASM,%02X%s.\n" , strlen(ieee_infile), ieee_infile); |
906 | |
907 | /* |
908 | * Write the NASM boast comment. |
909 | */ |
910 | ieee_putascii("CO0,%02X%s.\n" , strlen(nasm_comment), nasm_comment); |
911 | |
912 | /* |
913 | * write processor-specific information |
914 | */ |
915 | ieee_putascii("AD8,4,L.\n" ); |
916 | |
917 | /* |
918 | * date and time |
919 | */ |
920 | ieee_putascii("DT%04d%02d%02d%02d%02d%02d.\n" , |
921 | 1900 + thetime->tm_year, thetime->tm_mon + 1, |
922 | thetime->tm_mday, thetime->tm_hour, thetime->tm_min, |
923 | thetime->tm_sec); |
924 | /* |
925 | * if debugging, dump file names |
926 | */ |
927 | for (fn = fnhead; fn && debuginfo; fn = fn->next) { |
928 | ieee_putascii("C0105,%02X%s.\n" , strlen(fn->name), fn->name); |
929 | } |
930 | |
931 | ieee_putascii("CO101,07ENDHEAD.\n" ); |
932 | /* |
933 | * the standard doesn't specify when to put checksums, |
934 | * we'll just do it periodically. |
935 | */ |
936 | ieee_putcs(false); |
937 | |
938 | /* |
939 | * Write the section headers |
940 | */ |
941 | seg = seghead; |
942 | if (!debuginfo && !strcmp(seg->name, "??LINE" )) |
943 | seg = seg->next; |
944 | while (seg) { |
945 | char buf[256]; |
946 | char attrib; |
947 | switch (seg->combine) { |
948 | case CMB_PUBLIC: |
949 | default: |
950 | attrib = 'C'; |
951 | break; |
952 | case CMB_PRIVATE: |
953 | attrib = 'S'; |
954 | break; |
955 | case CMB_COMMON: |
956 | attrib = 'M'; |
957 | break; |
958 | } |
959 | ieee_unqualified_name(buf, seg->name); |
960 | if (seg->align >= SEG_ABS) { |
961 | ieee_putascii("ST%X,A,%02X%s.\n" , seg->ieee_index, |
962 | strlen(buf), buf); |
963 | ieee_putascii("ASL%X,%lX.\n" , seg->ieee_index, |
964 | (seg->align - SEG_ABS) * 16); |
965 | } else { |
966 | ieee_putascii("ST%X,%c,%02X%s.\n" , seg->ieee_index, attrib, |
967 | strlen(buf), buf); |
968 | ieee_putascii("SA%X,%lX.\n" , seg->ieee_index, seg->align); |
969 | ieee_putascii("ASS%X,%X.\n" , seg->ieee_index, |
970 | seg->currentpos); |
971 | } |
972 | seg = seg->next; |
973 | } |
974 | /* |
975 | * write the start address if there is one |
976 | */ |
977 | if (ieee_entry_seg) { |
978 | for (seg = seghead; seg; seg = seg->next) |
979 | if (seg->index == ieee_entry_seg) |
980 | break; |
981 | if (!seg) |
982 | nasm_panic(0, "Start address records are incorrect" ); |
983 | else |
984 | ieee_putascii("ASG,R%X,%lX,+.\n" , seg->ieee_index, |
985 | ieee_entry_ofs); |
986 | } |
987 | |
988 | ieee_putcs(false); |
989 | /* |
990 | * Write the publics |
991 | */ |
992 | i = 1; |
993 | for (seg = seghead; seg; seg = seg->next) { |
994 | for (pub = seg->pubhead; pub; pub = pub->next) { |
995 | char buf[256]; |
996 | ieee_unqualified_name(buf, pub->name); |
997 | ieee_putascii("NI%X,%02X%s.\n" , i, strlen(buf), buf); |
998 | if (pub->segment == -1) |
999 | ieee_putascii("ASI%X,R%X,%lX,+.\n" , i, pub->index, |
1000 | pub->offset); |
1001 | else |
1002 | ieee_putascii("ASI%X,%lX,%lX,+.\n" , i, pub->segment * 16, |
1003 | pub->offset); |
1004 | if (debuginfo) { |
1005 | if (pub->type >= 0x100) |
1006 | ieee_putascii("ATI%X,T%X.\n" , i, pub->type - 0x100); |
1007 | else |
1008 | ieee_putascii("ATI%X,%X.\n" , i, pub->type); |
1009 | } |
1010 | i++; |
1011 | } |
1012 | } |
1013 | pub = fpubhead; |
1014 | i = 1; |
1015 | while (pub) { |
1016 | char buf[256]; |
1017 | ieee_unqualified_name(buf, pub->name); |
1018 | ieee_putascii("NI%X,%02X%s.\n" , i, strlen(buf), buf); |
1019 | if (pub->segment == -1) |
1020 | ieee_putascii("ASI%X,R%X,%lX,+.\n" , i, pub->index, |
1021 | pub->offset); |
1022 | else |
1023 | ieee_putascii("ASI%X,%lX,%lX,+.\n" , i, pub->segment * 16, |
1024 | pub->offset); |
1025 | if (debuginfo) { |
1026 | if (pub->type >= 0x100) |
1027 | ieee_putascii("ATI%X,T%X.\n" , i, pub->type - 0x100); |
1028 | else |
1029 | ieee_putascii("ATI%X,%X.\n" , i, pub->type); |
1030 | } |
1031 | i++; |
1032 | pub = pub->next; |
1033 | } |
1034 | /* |
1035 | * Write the externals |
1036 | */ |
1037 | ext = exthead; |
1038 | i = 1; |
1039 | while (ext) { |
1040 | char buf[256]; |
1041 | ieee_unqualified_name(buf, ext->name); |
1042 | ieee_putascii("NX%X,%02X%s.\n" , i++, strlen(buf), buf); |
1043 | ext = ext->next; |
1044 | } |
1045 | ieee_putcs(false); |
1046 | |
1047 | /* |
1048 | * IEEE doesn't have a standard pass break record |
1049 | * so use the ladsoft variant |
1050 | */ |
1051 | ieee_putascii("CO100,06ENDSYM.\n" ); |
1052 | |
1053 | /* |
1054 | * now put types |
1055 | */ |
1056 | i = ARRAY_BOT; |
1057 | for (arr = arrhead; arr && debuginfo; arr = arr->next) { |
1058 | ieee_putascii("TY%X,20,%X,%lX.\n" , i++, arr->basetype, |
1059 | arr->size); |
1060 | } |
1061 | /* |
1062 | * now put locals |
1063 | */ |
1064 | i = 1; |
1065 | for (seg = seghead; seg && debuginfo; seg = seg->next) { |
1066 | for (loc = seg->lochead; loc; loc = loc->next) { |
1067 | char buf[256]; |
1068 | ieee_unqualified_name(buf, loc->name); |
1069 | ieee_putascii("NN%X,%02X%s.\n" , i, strlen(buf), buf); |
1070 | if (loc->segment == -1) |
1071 | ieee_putascii("ASN%X,R%X,%lX,+.\n" , i, loc->index, |
1072 | loc->offset); |
1073 | else |
1074 | ieee_putascii("ASN%X,%lX,%lX,+.\n" , i, loc->segment * 16, |
1075 | loc->offset); |
1076 | if (debuginfo) { |
1077 | if (loc->type >= 0x100) |
1078 | ieee_putascii("ATN%X,T%X.\n" , i, loc->type - 0x100); |
1079 | else |
1080 | ieee_putascii("ATN%X,%X.\n" , i, loc->type); |
1081 | } |
1082 | i++; |
1083 | } |
1084 | } |
1085 | |
1086 | /* |
1087 | * put out section data; |
1088 | */ |
1089 | seg = seghead; |
1090 | if (!debuginfo && !strcmp(seg->name, "??LINE" )) |
1091 | seg = seg->next; |
1092 | while (seg) { |
1093 | if (seg->currentpos) { |
1094 | int32_t size, org = 0; |
1095 | data = seg->data; |
1096 | ieee_putascii("SB%X.\n" , seg->ieee_index); |
1097 | fix = seg->fptr; |
1098 | while (fix) { |
1099 | size = HUNKSIZE - (org % HUNKSIZE); |
1100 | size = |
1101 | size + org > |
1102 | seg->currentpos ? seg->currentpos - org : size; |
1103 | size = fix->offset - org > size ? size : fix->offset - org; |
1104 | org = ieee_putld(org, org + size, data->data); |
1105 | if (org % HUNKSIZE == 0) |
1106 | data = data->next; |
1107 | if (org == fix->offset) { |
1108 | org += ieee_putlr(fix); |
1109 | fix = fix->next; |
1110 | } |
1111 | } |
1112 | while (org < seg->currentpos && data) { |
1113 | size = |
1114 | seg->currentpos - org > |
1115 | HUNKSIZE ? HUNKSIZE : seg->currentpos - org; |
1116 | org = ieee_putld(org, org + size, data->data); |
1117 | data = data->next; |
1118 | } |
1119 | ieee_putcs(false); |
1120 | |
1121 | } |
1122 | seg = seg->next; |
1123 | } |
1124 | /* |
1125 | * module end record |
1126 | */ |
1127 | ieee_putascii("ME.\n" ); |
1128 | } |
1129 | |
1130 | static void ieee_write_byte(struct ieeeSection *seg, int data) |
1131 | { |
1132 | int temp; |
1133 | if (!(temp = seg->currentpos++ % HUNKSIZE)) |
1134 | ieee_data_new(seg); |
1135 | seg->datacurr->data[temp] = data; |
1136 | } |
1137 | |
1138 | static void ieee_write_word(struct ieeeSection *seg, int data) |
1139 | { |
1140 | ieee_write_byte(seg, data & 0xFF); |
1141 | ieee_write_byte(seg, (data >> 8) & 0xFF); |
1142 | } |
1143 | |
1144 | static void ieee_write_dword(struct ieeeSection *seg, int32_t data) |
1145 | { |
1146 | ieee_write_byte(seg, data & 0xFF); |
1147 | ieee_write_byte(seg, (data >> 8) & 0xFF); |
1148 | ieee_write_byte(seg, (data >> 16) & 0xFF); |
1149 | ieee_write_byte(seg, (data >> 24) & 0xFF); |
1150 | } |
1151 | static void ieee_putascii(char *format, ...) |
1152 | { |
1153 | char buffer[256]; |
1154 | int i, l; |
1155 | va_list ap; |
1156 | |
1157 | va_start(ap, format); |
1158 | vsnprintf(buffer, sizeof(buffer), format, ap); |
1159 | l = strlen(buffer); |
1160 | for (i = 0; i < l; i++) |
1161 | if ((uint8_t)buffer[i] > 31) |
1162 | checksum += buffer[i]; |
1163 | va_end(ap); |
1164 | fputs(buffer, ofile); |
1165 | } |
1166 | |
1167 | /* |
1168 | * put out a checksum record */ |
1169 | static void ieee_putcs(int toclear) |
1170 | { |
1171 | if (toclear) { |
1172 | ieee_putascii("CS.\n" ); |
1173 | } else { |
1174 | checksum += 'C'; |
1175 | checksum += 'S'; |
1176 | ieee_putascii("CS%02X.\n" , checksum & 127); |
1177 | } |
1178 | checksum = 0; |
1179 | } |
1180 | |
1181 | static int32_t ieee_putld(int32_t start, int32_t end, uint8_t *buf) |
1182 | { |
1183 | int32_t val; |
1184 | if (start == end) |
1185 | return (start); |
1186 | val = start % HUNKSIZE; |
1187 | /* fill up multiple lines */ |
1188 | while (end - start >= LDPERLINE) { |
1189 | int i; |
1190 | ieee_putascii("LD" ); |
1191 | for (i = 0; i < LDPERLINE; i++) { |
1192 | ieee_putascii("%02X" , buf[val++]); |
1193 | start++; |
1194 | } |
1195 | ieee_putascii(".\n" ); |
1196 | } |
1197 | /* if no partial lines */ |
1198 | if (start == end) |
1199 | return (start); |
1200 | /* make a partial line */ |
1201 | ieee_putascii("LD" ); |
1202 | while (start < end) { |
1203 | ieee_putascii("%02X" , buf[val++]); |
1204 | start++; |
1205 | } |
1206 | ieee_putascii(".\n" ); |
1207 | return (start); |
1208 | } |
1209 | static int32_t ieee_putlr(struct ieeeFixupp *p) |
1210 | { |
1211 | /* |
1212 | * To deal with the vagaries of segmentation the LADsoft linker |
1213 | * defines two types of segments: absolute and virtual. Note that |
1214 | * 'absolute' in this context is a different thing from the IEEE |
1215 | * definition of an absolute segment type, which is also supported. If a |
1216 | * sement is linked in virtual mode the low limit (L-var) is |
1217 | * subtracted from each R,X, and P variable which appears in an |
1218 | * expression, so that we can have relative offsets. Meanwhile |
1219 | * in the ABSOLUTE mode this subtraction is not done and |
1220 | * so we can use absolute offsets from 0. In the LADsoft linker |
1221 | * this configuration is not done in the assemblker source but in |
1222 | * a source the linker reads. Generally this type of thing only |
1223 | * becomes an issue if real mode code is used. A pure 32-bit linker could |
1224 | * get away without defining the virtual mode... |
1225 | */ |
1226 | char buf[40]; |
1227 | int32_t size = p->size; |
1228 | switch (p->ftype) { |
1229 | case FT_SEG: |
1230 | if (p->id1 < 0) |
1231 | sprintf(buf, "%" PRIX32"" , -p->id1); |
1232 | else |
1233 | sprintf(buf, "L%" PRIX32",10,/" , p->id1); |
1234 | break; |
1235 | case FT_OFS: |
1236 | sprintf(buf, "R%" PRIX32",%" PRIX32",+" , p->id1, p->addend); |
1237 | break; |
1238 | case FT_REL: |
1239 | sprintf(buf, "R%" PRIX32",%" PRIX32",+,P,-,%X,-" , p->id1, p->addend, p->size); |
1240 | break; |
1241 | |
1242 | case FT_WRT: |
1243 | if (p->id2 < 0) |
1244 | sprintf(buf, "R%" PRIX32",%" PRIX32",+,L%" PRIX32",+,%" PRIX32",-" , p->id2, p->addend, |
1245 | p->id2, -p->id1 * 16); |
1246 | else |
1247 | sprintf(buf, "R%" PRIX32",%" PRIX32",+,L%" PRIX32",+,L%" PRIX32",-" , p->id2, p->addend, |
1248 | p->id2, p->id1); |
1249 | break; |
1250 | case FT_EXT: |
1251 | sprintf(buf, "X%" PRIX32"" , p->id1); |
1252 | break; |
1253 | case FT_EXTREL: |
1254 | sprintf(buf, "X%" PRIX32",P,-,%" PRIX32",-" , p->id1, size); |
1255 | break; |
1256 | case FT_EXTSEG: |
1257 | /* We needed a non-ieee hack here. |
1258 | * We introduce the Y variable, which is the low |
1259 | * limit of the native segment the extern resides in |
1260 | */ |
1261 | sprintf(buf, "Y%" PRIX32",10,/" , p->id1); |
1262 | break; |
1263 | case FT_EXTWRT: |
1264 | if (p->id2 < 0) |
1265 | sprintf(buf, "X%" PRIX32",Y%" PRIX32",+,%" PRIX32",-" , p->id2, p->id2, |
1266 | -p->id1 * 16); |
1267 | else |
1268 | sprintf(buf, "X%" PRIX32",Y%" PRIX32",+,L%" PRIX32",-" , p->id2, p->id2, p->id1); |
1269 | break; |
1270 | } |
1271 | ieee_putascii("LR(%s,%" PRIX32").\n" , buf, size); |
1272 | |
1273 | return (size); |
1274 | } |
1275 | |
1276 | /* Dump all segment data (text and fixups )*/ |
1277 | |
1278 | static void ieee_unqualified_name(char *dest, char *source) |
1279 | { |
1280 | if (ieee_uppercase) { |
1281 | while (*source) |
1282 | *dest++ = toupper(*source++); |
1283 | *dest = 0; |
1284 | } else |
1285 | strcpy(dest, source); |
1286 | } |
1287 | static void dbgls_init(void) |
1288 | { |
1289 | int tempint; |
1290 | |
1291 | fnhead = NULL; |
1292 | fntail = &fnhead; |
1293 | arrindex = ARRAY_BOT; |
1294 | arrhead = NULL; |
1295 | arrtail = &arrhead; |
1296 | ieee_segment("??LINE" , 2, &tempint); |
1297 | any_segs = false; |
1298 | } |
1299 | static void dbgls_cleanup(void) |
1300 | { |
1301 | struct ieeeSection *segtmp; |
1302 | while (fnhead) { |
1303 | struct FileName *fntemp = fnhead; |
1304 | fnhead = fnhead->next; |
1305 | nasm_free(fntemp->name); |
1306 | nasm_free(fntemp); |
1307 | } |
1308 | for (segtmp = seghead; segtmp; segtmp = segtmp->next) { |
1309 | while (segtmp->lochead) { |
1310 | struct ieeePublic *loctmp = segtmp->lochead; |
1311 | segtmp->lochead = loctmp->next; |
1312 | nasm_free(loctmp->name); |
1313 | nasm_free(loctmp); |
1314 | } |
1315 | } |
1316 | while (arrhead) { |
1317 | struct Array *arrtmp = arrhead; |
1318 | arrhead = arrhead->next; |
1319 | nasm_free(arrtmp); |
1320 | } |
1321 | } |
1322 | |
1323 | /* |
1324 | * because this routine is not bracketed in |
1325 | * the main program, this routine will be called even if there |
1326 | * is no request for debug info |
1327 | * so, we have to make sure the ??LINE segment is avaialbe |
1328 | * as the first segment when this debug format is selected |
1329 | */ |
1330 | static void dbgls_linnum(const char *lnfname, int32_t lineno, int32_t segto) |
1331 | { |
1332 | struct FileName *fn; |
1333 | struct ieeeSection *seg; |
1334 | int i = 0; |
1335 | if (segto == NO_SEG) |
1336 | return; |
1337 | |
1338 | /* |
1339 | * If `any_segs' is still false, we must define a default |
1340 | * segment. |
1341 | */ |
1342 | if (!any_segs) { |
1343 | int tempint; /* ignored */ |
1344 | if (segto != ieee_segment("__NASMDEFSEG" , 2, &tempint)) |
1345 | nasm_panic(0, "strange segment conditions in OBJ driver" ); |
1346 | } |
1347 | |
1348 | /* |
1349 | * Find the segment we are targetting. |
1350 | */ |
1351 | for (seg = seghead; seg; seg = seg->next) |
1352 | if (seg->index == segto) |
1353 | break; |
1354 | if (!seg) |
1355 | nasm_panic(0, "lineno directed to nonexistent segment?" ); |
1356 | |
1357 | for (fn = fnhead; fn; fn = fn->next) { |
1358 | if (!nasm_stricmp(lnfname, fn->name)) |
1359 | break; |
1360 | i++; |
1361 | } |
1362 | if (!fn) { |
1363 | fn = nasm_malloc(sizeof(*fn)); |
1364 | fn->name = nasm_malloc(strlen(lnfname) + 1); |
1365 | fn->index = i; |
1366 | strcpy(fn->name, lnfname); |
1367 | fn->next = NULL; |
1368 | *fntail = fn; |
1369 | fntail = &fn->next; |
1370 | } |
1371 | ieee_write_byte(seghead, fn->index); |
1372 | ieee_write_word(seghead, lineno); |
1373 | ieee_write_fixup(segto, NO_SEG, seghead, 4, OUT_ADDRESS, |
1374 | seg->currentpos); |
1375 | |
1376 | } |
1377 | static void dbgls_deflabel(char *name, int32_t segment, |
1378 | int64_t offset, int is_global, char *special) |
1379 | { |
1380 | struct ieeeSection *seg; |
1381 | |
1382 | /* Keep compiler from warning about special */ |
1383 | (void)special; |
1384 | |
1385 | /* |
1386 | * Note: ..[^@] special symbols are filtered in labels.c |
1387 | */ |
1388 | |
1389 | /* |
1390 | * If it's a special-retry from pass two, discard it. |
1391 | */ |
1392 | if (is_global == 3) |
1393 | return; |
1394 | |
1395 | /* |
1396 | * Case (i): |
1397 | */ |
1398 | if (ieee_seg_needs_update) |
1399 | return; |
1400 | if (segment < SEG_ABS && segment != NO_SEG && segment % 2) |
1401 | return; |
1402 | |
1403 | if (segment >= SEG_ABS || segment == NO_SEG) { |
1404 | return; |
1405 | } |
1406 | |
1407 | /* |
1408 | * If `any_segs' is still false, we might need to define a |
1409 | * default segment, if they're trying to declare a label in |
1410 | * `first_seg'. But the label should exist due to a prior |
1411 | * call to ieee_deflabel so we can skip that. |
1412 | */ |
1413 | |
1414 | for (seg = seghead; seg; seg = seg->next) |
1415 | if (seg->index == segment) { |
1416 | struct ieeePublic *loc; |
1417 | /* |
1418 | * Case (ii). Maybe MODPUB someday? |
1419 | */ |
1420 | if (!is_global) { |
1421 | last_defined = loc = nasm_malloc(sizeof(*loc)); |
1422 | *seg->loctail = loc; |
1423 | seg->loctail = &loc->next; |
1424 | loc->next = NULL; |
1425 | loc->name = nasm_strdup(name); |
1426 | loc->offset = offset; |
1427 | loc->segment = -1; |
1428 | loc->index = seg->ieee_index; |
1429 | } |
1430 | } |
1431 | } |
1432 | static void dbgls_typevalue(int32_t type) |
1433 | { |
1434 | int elem = TYM_ELEMENTS(type); |
1435 | type = TYM_TYPE(type); |
1436 | |
1437 | if (!last_defined) |
1438 | return; |
1439 | |
1440 | switch (type) { |
1441 | case TY_BYTE: |
1442 | last_defined->type = 1; /* uint8_t */ |
1443 | break; |
1444 | case TY_WORD: |
1445 | last_defined->type = 3; /* unsigned word */ |
1446 | break; |
1447 | case TY_DWORD: |
1448 | last_defined->type = 5; /* unsigned dword */ |
1449 | break; |
1450 | case TY_FLOAT: |
1451 | last_defined->type = 9; /* float */ |
1452 | break; |
1453 | case TY_QWORD: |
1454 | last_defined->type = 10; /* qword */ |
1455 | break; |
1456 | case TY_TBYTE: |
1457 | last_defined->type = 11; /* TBYTE */ |
1458 | break; |
1459 | default: |
1460 | last_defined->type = 0x10; /* near label */ |
1461 | break; |
1462 | } |
1463 | |
1464 | if (elem > 1) { |
1465 | struct Array *arrtmp = nasm_malloc(sizeof(*arrtmp)); |
1466 | int vtype = last_defined->type; |
1467 | arrtmp->size = elem; |
1468 | arrtmp->basetype = vtype; |
1469 | arrtmp->next = NULL; |
1470 | last_defined->type = arrindex++ + 0x100; |
1471 | *arrtail = arrtmp; |
1472 | arrtail = &(arrtmp->next); |
1473 | } |
1474 | last_defined = NULL; |
1475 | } |
1476 | static void dbgls_output(int output_type, void *param) |
1477 | { |
1478 | (void)output_type; |
1479 | (void)param; |
1480 | } |
1481 | static const struct dfmt ladsoft_debug_form = { |
1482 | "LADsoft Debug Records" , |
1483 | "ladsoft" , |
1484 | dbgls_init, |
1485 | dbgls_linnum, |
1486 | dbgls_deflabel, |
1487 | null_debug_directive, |
1488 | dbgls_typevalue, |
1489 | dbgls_output, |
1490 | dbgls_cleanup, |
1491 | NULL /* pragma list */ |
1492 | }; |
1493 | static const struct dfmt * const ladsoft_debug_arr[3] = { |
1494 | &ladsoft_debug_form, |
1495 | &null_debug_form, |
1496 | NULL |
1497 | }; |
1498 | const struct ofmt of_ieee = { |
1499 | "IEEE-695 (LADsoft variant) object file format" , |
1500 | "ieee" , |
1501 | ".o" , |
1502 | OFMT_TEXT, |
1503 | 32, |
1504 | ladsoft_debug_arr, |
1505 | &ladsoft_debug_form, |
1506 | NULL, |
1507 | ieee_init, |
1508 | null_reset, |
1509 | nasm_do_legacy_output, |
1510 | ieee_out, |
1511 | ieee_deflabel, |
1512 | ieee_segment, |
1513 | NULL, |
1514 | ieee_sectalign, |
1515 | ieee_segbase, |
1516 | ieee_directive, |
1517 | ieee_cleanup, |
1518 | NULL /* pragma list */ |
1519 | }; |
1520 | |
1521 | #endif /* OF_IEEE */ |
1522 | |