1 | /* ----------------------------------------------------------------------- * |
2 | * |
3 | * Copyright 1996-2017 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 | * outobj.c output routines for the Netwide Assembler to produce |
36 | * .OBJ object files |
37 | */ |
38 | |
39 | #include "compiler.h" |
40 | |
41 | #include <stdio.h> |
42 | #include <stdlib.h> |
43 | #include <string.h> |
44 | #include <ctype.h> |
45 | #include <limits.h> |
46 | |
47 | #include "nasm.h" |
48 | #include "nasmlib.h" |
49 | #include "error.h" |
50 | #include "stdscan.h" |
51 | #include "eval.h" |
52 | #include "ver.h" |
53 | |
54 | #include "outform.h" |
55 | #include "outlib.h" |
56 | |
57 | #ifdef OF_OBJ |
58 | |
59 | /* |
60 | * outobj.c is divided into two sections. The first section is low level |
61 | * routines for creating obj records; It has nearly zero NASM specific |
62 | * code. The second section is high level routines for processing calls and |
63 | * data structures from the rest of NASM into obj format. |
64 | * |
65 | * It should be easy (though not zero work) to lift the first section out for |
66 | * use as an obj file writer for some other assembler or compiler. |
67 | */ |
68 | |
69 | /* |
70 | * These routines are built around the ObjRecord data struture. An ObjRecord |
71 | * holds an object file record that may be under construction or complete. |
72 | * |
73 | * A major function of these routines is to support continuation of an obj |
74 | * record into the next record when the maximum record size is exceeded. The |
75 | * high level code does not need to worry about where the record breaks occur. |
76 | * It does need to do some minor extra steps to make the automatic continuation |
77 | * work. Those steps may be skipped for records where the high level knows no |
78 | * continuation could be required. |
79 | * |
80 | * 1) An ObjRecord is allocated and cleared by obj_new, or an existing ObjRecord |
81 | * is cleared by obj_clear. |
82 | * |
83 | * 2) The caller should fill in .type. |
84 | * |
85 | * 3) If the record is continuable and there is processing that must be done at |
86 | * the start of each record then the caller should fill in .ori with the |
87 | * address of the record initializer routine. |
88 | * |
89 | * 4) If the record is continuable and it should be saved (rather than emitted |
90 | * immediately) as each record is done, the caller should set .up to be a |
91 | * pointer to a location in which the caller keeps the master pointer to the |
92 | * ObjRecord. When the record is continued, the obj_bump routine will then |
93 | * allocate a new ObjRecord structure and update the master pointer. |
94 | * |
95 | * 5) If the .ori field was used then the caller should fill in the .parm with |
96 | * any data required by the initializer. |
97 | * |
98 | * 6) The caller uses the routines: obj_byte, obj_word, obj_rword, obj_dword, |
99 | * obj_x, obj_index, obj_value and obj_name to fill in the various kinds of |
100 | * data required for this record. |
101 | * |
102 | * 7) If the record is continuable, the caller should call obj_commit at each |
103 | * point where breaking the record is permitted. |
104 | * |
105 | * 8) To write out the record, the caller should call obj_emit2. If the |
106 | * caller has called obj_commit for all data written then he can get slightly |
107 | * faster code by calling obj_emit instead of obj_emit2. |
108 | * |
109 | * Most of these routines return an ObjRecord pointer. This will be the input |
110 | * pointer most of the time and will be the new location if the ObjRecord |
111 | * moved as a result of the call. The caller may ignore the return value in |
112 | * three cases: It is a "Never Reallocates" routine; or The caller knows |
113 | * continuation is not possible; or The caller uses the master pointer for the |
114 | * next operation. |
115 | */ |
116 | |
117 | #define RECORD_MAX (1024-3) /* maximal size of any record except type+reclen */ |
118 | #define OBJ_PARMS 3 /* maximum .parm used by any .ori routine */ |
119 | |
120 | #define FIX_08_LOW 0x8000 /* location type for various fixup subrecords */ |
121 | #define FIX_16_OFFSET 0x8400 |
122 | #define FIX_16_SELECTOR 0x8800 |
123 | #define FIX_32_POINTER 0x8C00 |
124 | #define FIX_08_HIGH 0x9000 |
125 | #define FIX_32_OFFSET 0xA400 |
126 | #define FIX_48_POINTER 0xAC00 |
127 | |
128 | enum RecordID { /* record ID codes */ |
129 | |
130 | THEADR = 0x80, /* module header */ |
131 | COMENT = 0x88, /* comment record */ |
132 | |
133 | LINNUM = 0x94, /* line number record */ |
134 | LNAMES = 0x96, /* list of names */ |
135 | |
136 | SEGDEF = 0x98, /* segment definition */ |
137 | GRPDEF = 0x9A, /* group definition */ |
138 | EXTDEF = 0x8C, /* external definition */ |
139 | PUBDEF = 0x90, /* public definition */ |
140 | COMDEF = 0xB0, /* common definition */ |
141 | |
142 | LEDATA = 0xA0, /* logical enumerated data */ |
143 | FIXUPP = 0x9C, /* fixups (relocations) */ |
144 | FIXU32 = 0x9D, /* 32-bit fixups (relocations) */ |
145 | |
146 | MODEND = 0x8A, /* module end */ |
147 | MODE32 = 0x8B /* module end for 32-bit objects */ |
148 | }; |
149 | |
150 | enum ComentID { /* ID codes for comment records */ |
151 | dTRANSL = 0x0000, /* translator comment */ |
152 | dOMFEXT = 0xC0A0, /* "OMF extension" */ |
153 | dEXTENDED = 0xC0A1, /* translator-specific extensions */ |
154 | dLINKPASS = 0x40A2, /* link pass 2 marker */ |
155 | dTYPEDEF = 0xC0E3, /* define a type */ |
156 | dSYM = 0xC0E6, /* symbol debug record */ |
157 | dFILNAME = 0xC0E8, /* file name record */ |
158 | dDEPFILE = 0xC0E9, /* dependency file */ |
159 | dCOMPDEF = 0xC0EA /* compiler type info */ |
160 | }; |
161 | |
162 | typedef struct ObjRecord ObjRecord; |
163 | typedef void ORI(ObjRecord * orp); |
164 | |
165 | struct ObjRecord { |
166 | ORI *ori; /* Initialization routine */ |
167 | int used; /* Current data size */ |
168 | int committed; /* Data size at last boundary */ |
169 | int x_size; /* (see obj_x) */ |
170 | unsigned int type; /* Record type */ |
171 | ObjRecord *child; /* Associated record below this one */ |
172 | ObjRecord **up; /* Master pointer to this ObjRecord */ |
173 | ObjRecord *back; /* Previous part of this record */ |
174 | uint32_t parm[OBJ_PARMS]; /* Parameters for ori routine */ |
175 | uint8_t buf[RECORD_MAX + 3]; |
176 | }; |
177 | |
178 | static void obj_fwrite(ObjRecord * orp); |
179 | static void ori_ledata(ObjRecord * orp); |
180 | static void ori_pubdef(ObjRecord * orp); |
181 | static void ori_null(ObjRecord * orp); |
182 | static ObjRecord *obj_commit(ObjRecord * orp); |
183 | |
184 | static bool obj_uppercase; /* Flag: all names in uppercase */ |
185 | static bool obj_use32; /* Flag: at least one segment is 32-bit */ |
186 | static bool obj_nodepend; /* Flag: don't emit file dependencies */ |
187 | |
188 | /* |
189 | * Clear an ObjRecord structure. (Never reallocates). |
190 | * To simplify reuse of ObjRecord's, .type, .ori and .parm are not cleared. |
191 | */ |
192 | static ObjRecord *obj_clear(ObjRecord * orp) |
193 | { |
194 | orp->used = 0; |
195 | orp->committed = 0; |
196 | orp->x_size = 0; |
197 | orp->child = NULL; |
198 | orp->up = NULL; |
199 | orp->back = NULL; |
200 | return (orp); |
201 | } |
202 | |
203 | /* |
204 | * Emit an ObjRecord structure. (Never reallocates). |
205 | * The record is written out preceeded (recursively) by its previous part (if |
206 | * any) and followed (recursively) by its child (if any). |
207 | * The previous part and the child are freed. The main ObjRecord is cleared, |
208 | * not freed. |
209 | */ |
210 | static ObjRecord *obj_emit(ObjRecord * orp) |
211 | { |
212 | if (orp->back) { |
213 | obj_emit(orp->back); |
214 | nasm_free(orp->back); |
215 | } |
216 | |
217 | if (orp->committed) |
218 | obj_fwrite(orp); |
219 | |
220 | if (orp->child) { |
221 | obj_emit(orp->child); |
222 | nasm_free(orp->child); |
223 | } |
224 | |
225 | return (obj_clear(orp)); |
226 | } |
227 | |
228 | /* |
229 | * Commit and Emit a record. (Never reallocates). |
230 | */ |
231 | static ObjRecord *obj_emit2(ObjRecord * orp) |
232 | { |
233 | obj_commit(orp); |
234 | return (obj_emit(orp)); |
235 | } |
236 | |
237 | /* |
238 | * Allocate and clear a new ObjRecord; Also sets .ori to ori_null |
239 | */ |
240 | static ObjRecord *obj_new(void) |
241 | { |
242 | ObjRecord *orp; |
243 | |
244 | orp = obj_clear(nasm_malloc(sizeof(ObjRecord))); |
245 | orp->ori = ori_null; |
246 | return (orp); |
247 | } |
248 | |
249 | /* |
250 | * Advance to the next record because the existing one is full or its x_size |
251 | * is incompatible. |
252 | * Any uncommited data is moved into the next record. |
253 | */ |
254 | static ObjRecord *obj_bump(ObjRecord * orp) |
255 | { |
256 | ObjRecord *nxt; |
257 | int used = orp->used; |
258 | int committed = orp->committed; |
259 | |
260 | if (orp->up) { |
261 | *orp->up = nxt = obj_new(); |
262 | nxt->ori = orp->ori; |
263 | nxt->type = orp->type; |
264 | nxt->up = orp->up; |
265 | nxt->back = orp; |
266 | memcpy(nxt->parm, orp->parm, sizeof(orp->parm)); |
267 | } else |
268 | nxt = obj_emit(orp); |
269 | |
270 | used -= committed; |
271 | if (used) { |
272 | nxt->committed = 1; |
273 | nxt->ori(nxt); |
274 | nxt->committed = nxt->used; |
275 | memcpy(nxt->buf + nxt->committed, orp->buf + committed, used); |
276 | nxt->used = nxt->committed + used; |
277 | } |
278 | |
279 | return (nxt); |
280 | } |
281 | |
282 | /* |
283 | * Advance to the next record if necessary to allow the next field to fit. |
284 | */ |
285 | static ObjRecord *obj_check(ObjRecord * orp, int size) |
286 | { |
287 | if (orp->used + size > RECORD_MAX) |
288 | orp = obj_bump(orp); |
289 | |
290 | if (!orp->committed) { |
291 | orp->committed = 1; |
292 | orp->ori(orp); |
293 | orp->committed = orp->used; |
294 | } |
295 | |
296 | return (orp); |
297 | } |
298 | |
299 | /* |
300 | * All data written so far is commited to the current record (won't be moved to |
301 | * the next record in case of continuation). |
302 | */ |
303 | static ObjRecord *obj_commit(ObjRecord * orp) |
304 | { |
305 | orp->committed = orp->used; |
306 | return (orp); |
307 | } |
308 | |
309 | /* |
310 | * Write a byte |
311 | */ |
312 | static ObjRecord *obj_byte(ObjRecord * orp, uint8_t val) |
313 | { |
314 | orp = obj_check(orp, 1); |
315 | orp->buf[orp->used] = val; |
316 | orp->used++; |
317 | return (orp); |
318 | } |
319 | |
320 | /* |
321 | * Write a word |
322 | */ |
323 | static ObjRecord *obj_word(ObjRecord * orp, unsigned int val) |
324 | { |
325 | orp = obj_check(orp, 2); |
326 | orp->buf[orp->used] = val; |
327 | orp->buf[orp->used + 1] = val >> 8; |
328 | orp->used += 2; |
329 | return (orp); |
330 | } |
331 | |
332 | /* |
333 | * Write a reversed word |
334 | */ |
335 | static ObjRecord *obj_rword(ObjRecord * orp, unsigned int val) |
336 | { |
337 | orp = obj_check(orp, 2); |
338 | orp->buf[orp->used] = val >> 8; |
339 | orp->buf[orp->used + 1] = val; |
340 | orp->used += 2; |
341 | return (orp); |
342 | } |
343 | |
344 | /* |
345 | * Write a dword |
346 | */ |
347 | static ObjRecord *obj_dword(ObjRecord * orp, uint32_t val) |
348 | { |
349 | orp = obj_check(orp, 4); |
350 | orp->buf[orp->used] = val; |
351 | orp->buf[orp->used + 1] = val >> 8; |
352 | orp->buf[orp->used + 2] = val >> 16; |
353 | orp->buf[orp->used + 3] = val >> 24; |
354 | orp->used += 4; |
355 | return (orp); |
356 | } |
357 | |
358 | /* |
359 | * All fields of "size x" in one obj record must be the same size (either 16 |
360 | * bits or 32 bits). There is a one bit flag in each record which specifies |
361 | * which. |
362 | * This routine is used to force the current record to have the desired |
363 | * x_size. x_size is normally automatic (using obj_x), so that this |
364 | * routine should be used outside obj_x, only to provide compatibility with |
365 | * linkers that have bugs in their processing of the size bit. |
366 | */ |
367 | |
368 | static ObjRecord *obj_force(ObjRecord * orp, int x) |
369 | { |
370 | if (orp->x_size == (x ^ 48)) |
371 | orp = obj_bump(orp); |
372 | orp->x_size = x; |
373 | return (orp); |
374 | } |
375 | |
376 | /* |
377 | * This routine writes a field of size x. The caller does not need to worry at |
378 | * all about whether 16-bits or 32-bits are required. |
379 | */ |
380 | static ObjRecord *obj_x(ObjRecord * orp, uint32_t val) |
381 | { |
382 | if (orp->type & 1) |
383 | orp->x_size = 32; |
384 | if (val > 0xFFFF) |
385 | orp = obj_force(orp, 32); |
386 | if (orp->x_size == 32) { |
387 | ObjRecord *nxt = obj_dword(orp, val); |
388 | nxt->x_size = 32; /* x_size is cleared when a record overflows */ |
389 | return nxt; |
390 | } |
391 | orp->x_size = 16; |
392 | return (obj_word(orp, val)); |
393 | } |
394 | |
395 | /* |
396 | * Writes an index |
397 | */ |
398 | static ObjRecord *obj_index(ObjRecord * orp, unsigned int val) |
399 | { |
400 | if (val < 128) |
401 | return (obj_byte(orp, val)); |
402 | return (obj_word(orp, (val >> 8) | (val << 8) | 0x80)); |
403 | } |
404 | |
405 | /* |
406 | * Writes a variable length value |
407 | */ |
408 | static ObjRecord *obj_value(ObjRecord * orp, uint32_t val) |
409 | { |
410 | if (val <= 128) |
411 | return (obj_byte(orp, val)); |
412 | if (val <= 0xFFFF) { |
413 | orp = obj_byte(orp, 129); |
414 | return (obj_word(orp, val)); |
415 | } |
416 | if (val <= 0xFFFFFF) |
417 | return (obj_dword(orp, (val << 8) + 132)); |
418 | orp = obj_byte(orp, 136); |
419 | return (obj_dword(orp, val)); |
420 | } |
421 | |
422 | /* |
423 | * Writes a counted string |
424 | */ |
425 | static ObjRecord *obj_name(ObjRecord * orp, const char *name) |
426 | { |
427 | int len = strlen(name); |
428 | uint8_t *ptr; |
429 | |
430 | orp = obj_check(orp, len + 1); |
431 | ptr = orp->buf + orp->used; |
432 | *ptr++ = len; |
433 | orp->used += len + 1; |
434 | if (obj_uppercase) |
435 | while (--len >= 0) { |
436 | *ptr++ = toupper(*name); |
437 | name++; |
438 | } else |
439 | memcpy(ptr, name, len); |
440 | return (orp); |
441 | } |
442 | |
443 | /* |
444 | * Initializer for an LEDATA record. |
445 | * parm[0] = offset |
446 | * parm[1] = segment index |
447 | * During the use of a LEDATA ObjRecord, parm[0] is constantly updated to |
448 | * represent the offset that would be required if the record were split at the |
449 | * last commit point. |
450 | * parm[2] is a copy of parm[0] as it was when the current record was initted. |
451 | */ |
452 | static void ori_ledata(ObjRecord * orp) |
453 | { |
454 | obj_index(orp, orp->parm[1]); |
455 | orp->parm[2] = orp->parm[0]; |
456 | obj_x(orp, orp->parm[0]); |
457 | } |
458 | |
459 | /* |
460 | * Initializer for a PUBDEF record. |
461 | * parm[0] = group index |
462 | * parm[1] = segment index |
463 | * parm[2] = frame (only used when both indexes are zero) |
464 | */ |
465 | static void ori_pubdef(ObjRecord * orp) |
466 | { |
467 | obj_index(orp, orp->parm[0]); |
468 | obj_index(orp, orp->parm[1]); |
469 | if (!(orp->parm[0] | orp->parm[1])) |
470 | obj_word(orp, orp->parm[2]); |
471 | } |
472 | |
473 | /* |
474 | * Initializer for a LINNUM record. |
475 | * parm[0] = group index |
476 | * parm[1] = segment index |
477 | */ |
478 | static void ori_linnum(ObjRecord * orp) |
479 | { |
480 | obj_index(orp, orp->parm[0]); |
481 | obj_index(orp, orp->parm[1]); |
482 | } |
483 | |
484 | /* |
485 | * Initializer for a local vars record. |
486 | */ |
487 | static void ori_local(ObjRecord * orp) |
488 | { |
489 | obj_rword(orp, dSYM); |
490 | } |
491 | |
492 | /* |
493 | * Null initializer for records that continue without any header info |
494 | */ |
495 | static void ori_null(ObjRecord * orp) |
496 | { |
497 | (void)orp; /* Do nothing */ |
498 | } |
499 | |
500 | /* |
501 | * This concludes the low level section of outobj.c |
502 | */ |
503 | |
504 | static char obj_infile[FILENAME_MAX]; |
505 | |
506 | static int32_t first_seg; |
507 | static bool any_segs; |
508 | static int passtwo; |
509 | static int arrindex; |
510 | |
511 | #define GROUP_MAX 256 /* we won't _realistically_ have more |
512 | * than this many segs in a group */ |
513 | #define EXT_BLKSIZ 256 /* block size for externals list */ |
514 | |
515 | struct Segment; /* need to know these structs exist */ |
516 | struct Group; |
517 | |
518 | struct LineNumber { |
519 | struct LineNumber *next; |
520 | struct Segment *segment; |
521 | int32_t offset; |
522 | int32_t lineno; |
523 | }; |
524 | |
525 | static struct FileName { |
526 | struct FileName *next; |
527 | char *name; |
528 | struct LineNumber *lnhead, **lntail; |
529 | int index; |
530 | } *fnhead, **fntail; |
531 | |
532 | static struct Array { |
533 | struct Array *next; |
534 | unsigned size; |
535 | int basetype; |
536 | } *arrhead, **arrtail; |
537 | |
538 | #define ARRAYBOT 31 /* magic number for first array index */ |
539 | |
540 | static struct Public { |
541 | struct Public *next; |
542 | char *name; |
543 | int32_t offset; |
544 | int32_t segment; /* only if it's far-absolute */ |
545 | int type; /* only for local debug syms */ |
546 | } *fpubhead, **fpubtail, *last_defined; |
547 | |
548 | static struct External { |
549 | struct External *next; |
550 | char *name; |
551 | int32_t commonsize; |
552 | int32_t commonelem; /* element size if FAR, else zero */ |
553 | int index; /* OBJ-file external index */ |
554 | enum { |
555 | DEFWRT_NONE, /* no unusual default-WRT */ |
556 | DEFWRT_STRING, /* a string we don't yet understand */ |
557 | DEFWRT_SEGMENT, /* a segment */ |
558 | DEFWRT_GROUP /* a group */ |
559 | } defwrt_type; |
560 | union { |
561 | char *string; |
562 | struct Segment *seg; |
563 | struct Group *grp; |
564 | } defwrt_ptr; |
565 | struct External *next_dws; /* next with DEFWRT_STRING */ |
566 | } *exthead, **exttail, *dws; |
567 | |
568 | static int externals; |
569 | |
570 | static struct ExtBack { |
571 | struct ExtBack *next; |
572 | struct External *exts[EXT_BLKSIZ]; |
573 | } *ebhead, **ebtail; |
574 | |
575 | static struct Segment { |
576 | struct Segment *next; |
577 | char *name; |
578 | int32_t index; /* the NASM segment id */ |
579 | int32_t obj_index; /* the OBJ-file segment index */ |
580 | struct Group *grp; /* the group it beint32_ts to */ |
581 | uint32_t currentpos; |
582 | int32_t align; /* can be SEG_ABS + absolute addr */ |
583 | struct Public *pubhead, **pubtail, *lochead, **loctail; |
584 | char *segclass, *overlay; /* `class' is a C++ keyword :-) */ |
585 | ObjRecord *orp; |
586 | enum { |
587 | CMB_PRIVATE = 0, |
588 | CMB_PUBLIC = 2, |
589 | CMB_STACK = 5, |
590 | CMB_COMMON = 6 |
591 | } combine; |
592 | bool use32; /* is this segment 32-bit? */ |
593 | } *seghead, **segtail, *obj_seg_needs_update; |
594 | |
595 | static struct Group { |
596 | struct Group *next; |
597 | char *name; |
598 | int32_t index; /* NASM segment id */ |
599 | int32_t obj_index; /* OBJ-file group index */ |
600 | int32_t nentries; /* number of elements... */ |
601 | int32_t nindices; /* ...and number of index elts... */ |
602 | union { |
603 | int32_t index; |
604 | char *name; |
605 | } segs[GROUP_MAX]; /* ...in this */ |
606 | } *grphead, **grptail, *obj_grp_needs_update; |
607 | |
608 | static struct ImpDef { |
609 | struct ImpDef *next; |
610 | char *extname; |
611 | char *libname; |
612 | unsigned int impindex; |
613 | char *impname; |
614 | } *imphead, **imptail; |
615 | |
616 | static struct ExpDef { |
617 | struct ExpDef *next; |
618 | char *intname; |
619 | char *extname; |
620 | unsigned int ordinal; |
621 | int flags; |
622 | } *exphead, **exptail; |
623 | |
624 | #define EXPDEF_FLAG_ORDINAL 0x80 |
625 | #define EXPDEF_FLAG_RESIDENT 0x40 |
626 | #define EXPDEF_FLAG_NODATA 0x20 |
627 | #define EXPDEF_MASK_PARMCNT 0x1F |
628 | |
629 | static int32_t obj_entry_seg, obj_entry_ofs; |
630 | |
631 | const struct ofmt of_obj; |
632 | static const struct dfmt borland_debug_form; |
633 | |
634 | /* The current segment */ |
635 | static struct Segment *current_seg; |
636 | |
637 | static int32_t obj_segment(char *, int, int *); |
638 | static void obj_write_file(void); |
639 | static enum directive_result obj_directive(enum directive, char *, int); |
640 | |
641 | static void obj_init(void) |
642 | { |
643 | strlcpy(obj_infile, inname, sizeof(obj_infile)); |
644 | first_seg = seg_alloc(); |
645 | any_segs = false; |
646 | fpubhead = NULL; |
647 | fpubtail = &fpubhead; |
648 | exthead = NULL; |
649 | exttail = &exthead; |
650 | imphead = NULL; |
651 | imptail = &imphead; |
652 | exphead = NULL; |
653 | exptail = &exphead; |
654 | dws = NULL; |
655 | externals = 0; |
656 | ebhead = NULL; |
657 | ebtail = &ebhead; |
658 | seghead = obj_seg_needs_update = NULL; |
659 | segtail = &seghead; |
660 | grphead = obj_grp_needs_update = NULL; |
661 | grptail = &grphead; |
662 | obj_entry_seg = NO_SEG; |
663 | obj_uppercase = false; |
664 | obj_use32 = false; |
665 | passtwo = 0; |
666 | current_seg = NULL; |
667 | } |
668 | |
669 | static void obj_cleanup(void) |
670 | { |
671 | obj_write_file(); |
672 | dfmt->cleanup(); |
673 | while (seghead) { |
674 | struct Segment *segtmp = seghead; |
675 | seghead = seghead->next; |
676 | while (segtmp->pubhead) { |
677 | struct Public *pubtmp = segtmp->pubhead; |
678 | segtmp->pubhead = pubtmp->next; |
679 | nasm_free(pubtmp->name); |
680 | nasm_free(pubtmp); |
681 | } |
682 | nasm_free(segtmp->segclass); |
683 | nasm_free(segtmp->overlay); |
684 | nasm_free(segtmp); |
685 | } |
686 | while (fpubhead) { |
687 | struct Public *pubtmp = fpubhead; |
688 | fpubhead = fpubhead->next; |
689 | nasm_free(pubtmp->name); |
690 | nasm_free(pubtmp); |
691 | } |
692 | while (exthead) { |
693 | struct External *exttmp = exthead; |
694 | exthead = exthead->next; |
695 | nasm_free(exttmp); |
696 | } |
697 | while (imphead) { |
698 | struct ImpDef *imptmp = imphead; |
699 | imphead = imphead->next; |
700 | nasm_free(imptmp->extname); |
701 | nasm_free(imptmp->libname); |
702 | nasm_free(imptmp->impname); /* nasm_free won't mind if it's NULL */ |
703 | nasm_free(imptmp); |
704 | } |
705 | while (exphead) { |
706 | struct ExpDef *exptmp = exphead; |
707 | exphead = exphead->next; |
708 | nasm_free(exptmp->extname); |
709 | nasm_free(exptmp->intname); |
710 | nasm_free(exptmp); |
711 | } |
712 | while (ebhead) { |
713 | struct ExtBack *ebtmp = ebhead; |
714 | ebhead = ebhead->next; |
715 | nasm_free(ebtmp); |
716 | } |
717 | while (grphead) { |
718 | struct Group *grptmp = grphead; |
719 | grphead = grphead->next; |
720 | nasm_free(grptmp); |
721 | } |
722 | } |
723 | |
724 | static void obj_ext_set_defwrt(struct External *ext, char *id) |
725 | { |
726 | struct Segment *seg; |
727 | struct Group *grp; |
728 | |
729 | for (seg = seghead; seg; seg = seg->next) |
730 | if (!strcmp(seg->name, id)) { |
731 | ext->defwrt_type = DEFWRT_SEGMENT; |
732 | ext->defwrt_ptr.seg = seg; |
733 | nasm_free(id); |
734 | return; |
735 | } |
736 | |
737 | for (grp = grphead; grp; grp = grp->next) |
738 | if (!strcmp(grp->name, id)) { |
739 | ext->defwrt_type = DEFWRT_GROUP; |
740 | ext->defwrt_ptr.grp = grp; |
741 | nasm_free(id); |
742 | return; |
743 | } |
744 | |
745 | ext->defwrt_type = DEFWRT_STRING; |
746 | ext->defwrt_ptr.string = id; |
747 | ext->next_dws = dws; |
748 | dws = ext; |
749 | } |
750 | |
751 | static void obj_deflabel(char *name, int32_t segment, |
752 | int64_t offset, int is_global, char *special) |
753 | { |
754 | /* |
755 | * We have three cases: |
756 | * |
757 | * (i) `segment' is a segment-base. If so, set the name field |
758 | * for the segment or group structure it refers to, and then |
759 | * return. |
760 | * |
761 | * (ii) `segment' is one of our segments, or a SEG_ABS segment. |
762 | * Save the label position for later output of a PUBDEF record. |
763 | * (Or a MODPUB, if we work out how.) |
764 | * |
765 | * (iii) `segment' is not one of our segments. Save the label |
766 | * position for later output of an EXTDEF, and also store a |
767 | * back-reference so that we can map later references to this |
768 | * segment number to the external index. |
769 | */ |
770 | struct External *ext; |
771 | struct ExtBack *eb; |
772 | struct Segment *seg; |
773 | int i; |
774 | bool used_special = false; /* have we used the special text? */ |
775 | |
776 | #if defined(DEBUG) && DEBUG>2 |
777 | nasm_error(ERR_DEBUG, |
778 | " obj_deflabel: %s, seg=%" PRIx32", off=%" PRIx64", is_global=%d, %s\n" , |
779 | name, segment, offset, is_global, special); |
780 | #endif |
781 | |
782 | /* |
783 | * If it's a special-retry from pass two, discard it. |
784 | */ |
785 | if (is_global == 3) |
786 | return; |
787 | |
788 | /* |
789 | * First check for the double-period, signifying something |
790 | * unusual. |
791 | */ |
792 | if (name[0] == '.' && name[1] == '.' && name[2] != '@') { |
793 | if (!strcmp(name, "..start" )) { |
794 | obj_entry_seg = segment; |
795 | obj_entry_ofs = offset; |
796 | return; |
797 | } |
798 | nasm_error(ERR_NONFATAL, "unrecognised special symbol `%s'" , name); |
799 | } |
800 | |
801 | /* |
802 | * Case (i): |
803 | */ |
804 | if (obj_seg_needs_update) { |
805 | obj_seg_needs_update->name = name; |
806 | return; |
807 | } else if (obj_grp_needs_update) { |
808 | obj_grp_needs_update->name = name; |
809 | return; |
810 | } |
811 | if (segment < SEG_ABS && segment != NO_SEG && segment % 2) |
812 | return; |
813 | |
814 | if (segment >= SEG_ABS || segment == NO_SEG) { |
815 | /* |
816 | * SEG_ABS subcase of (ii). |
817 | */ |
818 | if (is_global) { |
819 | struct Public *pub; |
820 | |
821 | pub = *fpubtail = nasm_malloc(sizeof(*pub)); |
822 | fpubtail = &pub->next; |
823 | pub->next = NULL; |
824 | pub->name = nasm_strdup(name); |
825 | pub->offset = offset; |
826 | pub->segment = (segment == NO_SEG ? 0 : segment & ~SEG_ABS); |
827 | } |
828 | if (special) |
829 | nasm_error(ERR_NONFATAL, "OBJ supports no special symbol features" |
830 | " for this symbol type" ); |
831 | return; |
832 | } |
833 | |
834 | /* |
835 | * If `any_segs' is still false, we might need to define a |
836 | * default segment, if they're trying to declare a label in |
837 | * `first_seg'. |
838 | */ |
839 | if (!any_segs && segment == first_seg) { |
840 | int tempint; /* ignored */ |
841 | if (segment != obj_segment("__NASMDEFSEG" , 2, &tempint)) |
842 | nasm_panic(0, "strange segment conditions in OBJ driver" ); |
843 | } |
844 | |
845 | for (seg = seghead; seg && is_global; seg = seg->next) |
846 | if (seg->index == segment) { |
847 | struct Public *loc = nasm_malloc(sizeof(*loc)); |
848 | /* |
849 | * Case (ii). Maybe MODPUB someday? |
850 | */ |
851 | *seg->pubtail = loc; |
852 | seg->pubtail = &loc->next; |
853 | loc->next = NULL; |
854 | loc->name = nasm_strdup(name); |
855 | loc->offset = offset; |
856 | |
857 | if (special) |
858 | nasm_error(ERR_NONFATAL, |
859 | "OBJ supports no special symbol features" |
860 | " for this symbol type" ); |
861 | return; |
862 | } |
863 | |
864 | /* |
865 | * Case (iii). |
866 | */ |
867 | if (is_global) { |
868 | ext = *exttail = nasm_malloc(sizeof(*ext)); |
869 | ext->next = NULL; |
870 | exttail = &ext->next; |
871 | ext->name = name; |
872 | /* Place by default all externs into the current segment */ |
873 | ext->defwrt_type = DEFWRT_NONE; |
874 | |
875 | /* 28-Apr-2002 - John Coffman |
876 | The following code was introduced on 12-Aug-2000, and breaks fixups |
877 | on code passed thru the MSC 5.1 linker (3.66) and MSC 6.00A linker |
878 | (5.10). It was introduced after FIXUP32 was added, and may be needed |
879 | for 32-bit segments. The following will get 16-bit segments working |
880 | again, and maybe someone can correct the 'if' condition which is |
881 | actually needed. |
882 | */ |
883 | #if 0 |
884 | if (current_seg) { |
885 | #else |
886 | if (current_seg && current_seg->use32) { |
887 | if (current_seg->grp) { |
888 | ext->defwrt_type = DEFWRT_GROUP; |
889 | ext->defwrt_ptr.grp = current_seg->grp; |
890 | } else { |
891 | ext->defwrt_type = DEFWRT_SEGMENT; |
892 | ext->defwrt_ptr.seg = current_seg; |
893 | } |
894 | } |
895 | #endif |
896 | |
897 | if (is_global == 2) { |
898 | ext->commonsize = offset; |
899 | ext->commonelem = 1; /* default FAR */ |
900 | } else |
901 | ext->commonsize = 0; |
902 | } else |
903 | return; |
904 | |
905 | /* |
906 | * Now process the special text, if any, to find default-WRT |
907 | * specifications and common-variable element-size and near/far |
908 | * specifications. |
909 | */ |
910 | while (special && *special) { |
911 | used_special = true; |
912 | |
913 | /* |
914 | * We might have a default-WRT specification. |
915 | */ |
916 | if (!nasm_strnicmp(special, "wrt" , 3)) { |
917 | char *p; |
918 | int len; |
919 | special += 3; |
920 | special += strspn(special, " \t" ); |
921 | p = nasm_strndup(special, len = strcspn(special, ":" )); |
922 | obj_ext_set_defwrt(ext, p); |
923 | special += len; |
924 | if (*special && *special != ':') |
925 | nasm_error(ERR_NONFATAL, "`:' expected in special symbol" |
926 | " text for `%s'" , ext->name); |
927 | else if (*special == ':') |
928 | special++; |
929 | } |
930 | |
931 | /* |
932 | * The NEAR or FAR keywords specify nearness or |
933 | * farness. FAR gives default element size 1. |
934 | */ |
935 | if (!nasm_strnicmp(special, "far" , 3)) { |
936 | if (ext->commonsize) |
937 | ext->commonelem = 1; |
938 | else |
939 | nasm_error(ERR_NONFATAL, |
940 | "`%s': `far' keyword may only be applied" |
941 | " to common variables\n" , ext->name); |
942 | special += 3; |
943 | special += strspn(special, " \t" ); |
944 | } else if (!nasm_strnicmp(special, "near" , 4)) { |
945 | if (ext->commonsize) |
946 | ext->commonelem = 0; |
947 | else |
948 | nasm_error(ERR_NONFATAL, |
949 | "`%s': `far' keyword may only be applied" |
950 | " to common variables\n" , ext->name); |
951 | special += 4; |
952 | special += strspn(special, " \t" ); |
953 | } |
954 | |
955 | /* |
956 | * If it's a common, and anything else remains on the line |
957 | * before a further colon, evaluate it as an expression and |
958 | * use that as the element size. Forward references aren't |
959 | * allowed. |
960 | */ |
961 | if (*special == ':') |
962 | special++; |
963 | else if (*special) { |
964 | if (ext->commonsize) { |
965 | expr *e; |
966 | struct tokenval tokval; |
967 | |
968 | stdscan_reset(); |
969 | stdscan_set(special); |
970 | tokval.t_type = TOKEN_INVALID; |
971 | e = evaluate(stdscan, NULL, &tokval, NULL, 1, NULL); |
972 | if (e) { |
973 | if (!is_simple(e)) |
974 | nasm_error(ERR_NONFATAL, "cannot use relocatable" |
975 | " expression as common-variable element size" ); |
976 | else |
977 | ext->commonelem = reloc_value(e); |
978 | } |
979 | special = stdscan_get(); |
980 | } else { |
981 | nasm_error(ERR_NONFATAL, |
982 | "`%s': element-size specifications only" |
983 | " apply to common variables" , ext->name); |
984 | while (*special && *special != ':') |
985 | special++; |
986 | if (*special == ':') |
987 | special++; |
988 | } |
989 | } |
990 | } |
991 | |
992 | i = segment / 2; |
993 | eb = ebhead; |
994 | if (!eb) { |
995 | eb = *ebtail = nasm_zalloc(sizeof(*eb)); |
996 | eb->next = NULL; |
997 | ebtail = &eb->next; |
998 | } |
999 | while (i >= EXT_BLKSIZ) { |
1000 | if (eb && eb->next) |
1001 | eb = eb->next; |
1002 | else { |
1003 | eb = *ebtail = nasm_zalloc(sizeof(*eb)); |
1004 | eb->next = NULL; |
1005 | ebtail = &eb->next; |
1006 | } |
1007 | i -= EXT_BLKSIZ; |
1008 | } |
1009 | eb->exts[i] = ext; |
1010 | ext->index = ++externals; |
1011 | |
1012 | if (special && !used_special) |
1013 | nasm_error(ERR_NONFATAL, "OBJ supports no special symbol features" |
1014 | " for this symbol type" ); |
1015 | } |
1016 | |
1017 | /* forward declaration */ |
1018 | static void obj_write_fixup(ObjRecord * orp, int bytes, |
1019 | int segrel, int32_t seg, int32_t wrt, |
1020 | struct Segment *segto); |
1021 | |
1022 | static void obj_out(int32_t segto, const void *data, |
1023 | enum out_type type, uint64_t size, |
1024 | int32_t segment, int32_t wrt) |
1025 | { |
1026 | const uint8_t *ucdata; |
1027 | int32_t ldata; |
1028 | struct Segment *seg; |
1029 | ObjRecord *orp; |
1030 | |
1031 | /* |
1032 | * handle absolute-assembly (structure definitions) |
1033 | */ |
1034 | if (segto == NO_SEG) { |
1035 | if (type != OUT_RESERVE) |
1036 | nasm_error(ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]" |
1037 | " space" ); |
1038 | return; |
1039 | } |
1040 | |
1041 | /* |
1042 | * If `any_segs' is still false, we must define a default |
1043 | * segment. |
1044 | */ |
1045 | if (!any_segs) { |
1046 | int tempint; /* ignored */ |
1047 | if (segto != obj_segment("__NASMDEFSEG" , 2, &tempint)) |
1048 | nasm_panic(0, "strange segment conditions in OBJ driver" ); |
1049 | } |
1050 | |
1051 | /* |
1052 | * Find the segment we are targetting. |
1053 | */ |
1054 | for (seg = seghead; seg; seg = seg->next) |
1055 | if (seg->index == segto) |
1056 | break; |
1057 | if (!seg) |
1058 | nasm_panic(0, "code directed to nonexistent segment?" ); |
1059 | |
1060 | orp = seg->orp; |
1061 | orp->parm[0] = seg->currentpos; |
1062 | |
1063 | switch (type) { |
1064 | case OUT_RAWDATA: |
1065 | ucdata = data; |
1066 | while (size > 0) { |
1067 | unsigned int len; |
1068 | orp = obj_check(seg->orp, 1); |
1069 | len = RECORD_MAX - orp->used; |
1070 | if (len > size) |
1071 | len = size; |
1072 | memcpy(orp->buf + orp->used, ucdata, len); |
1073 | orp->committed = orp->used += len; |
1074 | orp->parm[0] = seg->currentpos += len; |
1075 | ucdata += len; |
1076 | size -= len; |
1077 | } |
1078 | break; |
1079 | |
1080 | case OUT_ADDRESS: |
1081 | case OUT_REL1ADR: |
1082 | case OUT_REL2ADR: |
1083 | case OUT_REL4ADR: |
1084 | case OUT_REL8ADR: |
1085 | { |
1086 | int rsize; |
1087 | |
1088 | if (type == OUT_ADDRESS) |
1089 | size = abs((int)size); |
1090 | |
1091 | if (segment == NO_SEG && type != OUT_ADDRESS) |
1092 | nasm_error(ERR_NONFATAL, "relative call to absolute address not" |
1093 | " supported by OBJ format" ); |
1094 | if (segment >= SEG_ABS) |
1095 | nasm_error(ERR_NONFATAL, "far-absolute relocations not supported" |
1096 | " by OBJ format" ); |
1097 | |
1098 | ldata = *(int64_t *)data; |
1099 | if (type != OUT_ADDRESS) { |
1100 | /* |
1101 | * For 16-bit and 32-bit x86 code, the size and realsize() always |
1102 | * matches as only jumps, calls and loops uses PC relative |
1103 | * addressing and the address isn't followed by any other opcode |
1104 | * bytes. In 64-bit mode there is RIP relative addressing which |
1105 | * means the fixup location can be followed by an immediate value, |
1106 | * meaning that size > realsize(). |
1107 | * |
1108 | * When the CPU is calculating the effective address, it takes the |
1109 | * RIP at the end of the instruction and adds the fixed up relative |
1110 | * address value to it. |
1111 | * |
1112 | * The linker's point of reference is the end of the fixup location |
1113 | * (which is the end of the instruction for Jcc, CALL, LOOP[cc]). |
1114 | * It is calculating distance between the target symbol and the end |
1115 | * of the fixup location, and add this to the displacement value we |
1116 | * are calculating here and storing at the fixup location. |
1117 | * |
1118 | * To get the right effect, we need to _reduce_ the displacement |
1119 | * value by the number of bytes following the fixup. |
1120 | * |
1121 | * Example: |
1122 | * data at address 0x100; REL4ADR at 0x050, 4 byte immediate, |
1123 | * end of fixup at 0x054, end of instruction at 0x058. |
1124 | * => size = 8. |
1125 | * => realsize() -> 4 |
1126 | * => CPU needs a value of: 0x100 - 0x058 = 0x0a8 |
1127 | * => linker/loader will add: 0x100 - 0x054 = 0x0ac |
1128 | * => We must add an addend of -4. |
1129 | * => realsize() - size = -4. |
1130 | * |
1131 | * The code used to do size - realsize() at least since v0.90, |
1132 | * probably because it wasn't needed... |
1133 | */ |
1134 | ldata -= size; |
1135 | size = realsize(type, size); |
1136 | ldata += size; |
1137 | } |
1138 | |
1139 | switch (size) { |
1140 | default: |
1141 | nasm_error(ERR_NONFATAL, "OBJ format can only handle 16- or " |
1142 | "32-byte relocations" ); |
1143 | segment = NO_SEG; /* Don't actually generate a relocation */ |
1144 | break; |
1145 | case 2: |
1146 | orp = obj_word(orp, ldata); |
1147 | break; |
1148 | case 4: |
1149 | orp = obj_dword(orp, ldata); |
1150 | break; |
1151 | } |
1152 | |
1153 | rsize = size; |
1154 | if (segment < SEG_ABS && (segment != NO_SEG && segment % 2) && |
1155 | size == 4) { |
1156 | /* |
1157 | * This is a 4-byte segment-base relocation such as |
1158 | * `MOV EAX,SEG foo'. OBJ format can't actually handle |
1159 | * these, but if the constant term has the 16 low bits |
1160 | * zero, we can just apply a 2-byte segment-base |
1161 | * relocation to the low word instead. |
1162 | */ |
1163 | rsize = 2; |
1164 | if (ldata & 0xFFFF) |
1165 | nasm_error(ERR_NONFATAL, "OBJ format cannot handle complex" |
1166 | " dword-size segment base references" ); |
1167 | } |
1168 | if (segment != NO_SEG) |
1169 | obj_write_fixup(orp, rsize, |
1170 | (type == OUT_ADDRESS ? 0x4000 : 0), |
1171 | segment, wrt, seg); |
1172 | seg->currentpos += size; |
1173 | break; |
1174 | } |
1175 | |
1176 | default: |
1177 | nasm_error(ERR_NONFATAL, |
1178 | "Relocation type not supported by output format" ); |
1179 | /* fall through */ |
1180 | |
1181 | case OUT_RESERVE: |
1182 | if (orp->committed) |
1183 | orp = obj_bump(orp); |
1184 | seg->currentpos += size; |
1185 | break; |
1186 | } |
1187 | obj_commit(orp); |
1188 | } |
1189 | |
1190 | static void obj_write_fixup(ObjRecord * orp, int bytes, |
1191 | int segrel, int32_t seg, int32_t wrt, |
1192 | struct Segment *segto) |
1193 | { |
1194 | unsigned locat; |
1195 | int method; |
1196 | int base; |
1197 | int32_t tidx, fidx; |
1198 | struct Segment *s = NULL; |
1199 | struct Group *g = NULL; |
1200 | struct External *e = NULL; |
1201 | ObjRecord *forp; |
1202 | |
1203 | if (bytes != 2 && bytes != 4) { |
1204 | nasm_error(ERR_NONFATAL, "`obj' output driver does not support" |
1205 | " %d-bit relocations" , bytes << 3); |
1206 | return; |
1207 | } |
1208 | |
1209 | forp = orp->child; |
1210 | if (forp == NULL) { |
1211 | orp->child = forp = obj_new(); |
1212 | forp->up = &(orp->child); |
1213 | /* We should choose between FIXUPP and FIXU32 record type */ |
1214 | /* If we're targeting a 32-bit segment, use a FIXU32 record */ |
1215 | if (segto->use32) |
1216 | forp->type = FIXU32; |
1217 | else |
1218 | forp->type = FIXUPP; |
1219 | } |
1220 | |
1221 | if (seg % 2) { |
1222 | base = true; |
1223 | locat = FIX_16_SELECTOR; |
1224 | seg--; |
1225 | if (bytes != 2) |
1226 | nasm_panic(0, "OBJ: 4-byte segment base fixup got" |
1227 | " through sanity check" ); |
1228 | } else { |
1229 | base = false; |
1230 | locat = (bytes == 2) ? FIX_16_OFFSET : FIX_32_OFFSET; |
1231 | if (!segrel) |
1232 | /* |
1233 | * There is a bug in tlink that makes it process self relative |
1234 | * fixups incorrectly if the x_size doesn't match the location |
1235 | * size. |
1236 | */ |
1237 | forp = obj_force(forp, bytes << 3); |
1238 | } |
1239 | |
1240 | forp = obj_rword(forp, locat | segrel | (orp->parm[0] - orp->parm[2])); |
1241 | |
1242 | tidx = fidx = -1, method = 0; /* placate optimisers */ |
1243 | |
1244 | /* |
1245 | * See if we can find the segment ID in our segment list. If |
1246 | * so, we have a T4 (LSEG) target. |
1247 | */ |
1248 | for (s = seghead; s; s = s->next) |
1249 | if (s->index == seg) |
1250 | break; |
1251 | if (s) |
1252 | method = 4, tidx = s->obj_index; |
1253 | else { |
1254 | for (g = grphead; g; g = g->next) |
1255 | if (g->index == seg) |
1256 | break; |
1257 | if (g) |
1258 | method = 5, tidx = g->obj_index; |
1259 | else { |
1260 | int32_t i = seg / 2; |
1261 | struct ExtBack *eb = ebhead; |
1262 | while (i >= EXT_BLKSIZ) { |
1263 | if (eb) |
1264 | eb = eb->next; |
1265 | else |
1266 | break; |
1267 | i -= EXT_BLKSIZ; |
1268 | } |
1269 | if (eb) |
1270 | method = 6, e = eb->exts[i], tidx = e->index; |
1271 | else |
1272 | nasm_panic(0, |
1273 | "unrecognised segment value in obj_write_fixup" ); |
1274 | } |
1275 | } |
1276 | |
1277 | /* |
1278 | * If no WRT given, assume the natural default, which is method |
1279 | * F5 unless: |
1280 | * |
1281 | * - we are doing an OFFSET fixup for a grouped segment, in |
1282 | * which case we require F1 (group). |
1283 | * |
1284 | * - we are doing an OFFSET fixup for an external with a |
1285 | * default WRT, in which case we must honour the default WRT. |
1286 | */ |
1287 | if (wrt == NO_SEG) { |
1288 | if (!base && s && s->grp) |
1289 | method |= 0x10, fidx = s->grp->obj_index; |
1290 | else if (!base && e && e->defwrt_type != DEFWRT_NONE) { |
1291 | if (e->defwrt_type == DEFWRT_SEGMENT) |
1292 | method |= 0x00, fidx = e->defwrt_ptr.seg->obj_index; |
1293 | else if (e->defwrt_type == DEFWRT_GROUP) |
1294 | method |= 0x10, fidx = e->defwrt_ptr.grp->obj_index; |
1295 | else { |
1296 | nasm_error(ERR_NONFATAL, "default WRT specification for" |
1297 | " external `%s' unresolved" , e->name); |
1298 | method |= 0x50, fidx = -1; /* got to do _something_ */ |
1299 | } |
1300 | } else |
1301 | method |= 0x50, fidx = -1; |
1302 | } else { |
1303 | /* |
1304 | * See if we can find the WRT-segment ID in our segment |
1305 | * list. If so, we have a F0 (LSEG) frame. |
1306 | */ |
1307 | for (s = seghead; s; s = s->next) |
1308 | if (s->index == wrt - 1) |
1309 | break; |
1310 | if (s) |
1311 | method |= 0x00, fidx = s->obj_index; |
1312 | else { |
1313 | for (g = grphead; g; g = g->next) |
1314 | if (g->index == wrt - 1) |
1315 | break; |
1316 | if (g) |
1317 | method |= 0x10, fidx = g->obj_index; |
1318 | else { |
1319 | int32_t i = wrt / 2; |
1320 | struct ExtBack *eb = ebhead; |
1321 | while (i >= EXT_BLKSIZ) { |
1322 | if (eb) |
1323 | eb = eb->next; |
1324 | else |
1325 | break; |
1326 | i -= EXT_BLKSIZ; |
1327 | } |
1328 | if (eb) |
1329 | method |= 0x20, fidx = eb->exts[i]->index; |
1330 | else |
1331 | nasm_panic(0, |
1332 | "unrecognised WRT value in obj_write_fixup" ); |
1333 | } |
1334 | } |
1335 | } |
1336 | |
1337 | forp = obj_byte(forp, method); |
1338 | if (fidx != -1) |
1339 | forp = obj_index(forp, fidx); |
1340 | forp = obj_index(forp, tidx); |
1341 | obj_commit(forp); |
1342 | } |
1343 | |
1344 | static int32_t obj_segment(char *name, int pass, int *bits) |
1345 | { |
1346 | /* |
1347 | * We call the label manager here to define a name for the new |
1348 | * segment, and when our _own_ label-definition stub gets |
1349 | * called in return, it should register the new segment name |
1350 | * using the pointer it gets passed. That way we save memory, |
1351 | * by sponging off the label manager. |
1352 | */ |
1353 | #if defined(DEBUG) && DEBUG>=3 |
1354 | nasm_error(ERR_DEBUG, " obj_segment: < %s >, pass=%d, *bits=%d\n" , |
1355 | name, pass, *bits); |
1356 | #endif |
1357 | if (!name) { |
1358 | *bits = 16; |
1359 | current_seg = NULL; |
1360 | return first_seg; |
1361 | } else { |
1362 | struct Segment *seg; |
1363 | struct Group *grp; |
1364 | struct External **extp; |
1365 | int obj_idx, i, attrs; |
1366 | bool rn_error; |
1367 | char *p; |
1368 | |
1369 | /* |
1370 | * Look for segment attributes. |
1371 | */ |
1372 | attrs = 0; |
1373 | while (*name == '.') |
1374 | name++; /* hack, but a documented one */ |
1375 | p = name; |
1376 | while (*p && !nasm_isspace(*p)) |
1377 | p++; |
1378 | if (*p) { |
1379 | *p++ = '\0'; |
1380 | while (*p && nasm_isspace(*p)) |
1381 | *p++ = '\0'; |
1382 | } |
1383 | while (*p) { |
1384 | while (*p && !nasm_isspace(*p)) |
1385 | p++; |
1386 | if (*p) { |
1387 | *p++ = '\0'; |
1388 | while (*p && nasm_isspace(*p)) |
1389 | *p++ = '\0'; |
1390 | } |
1391 | |
1392 | attrs++; |
1393 | } |
1394 | |
1395 | for (seg = seghead, obj_idx = 1; ; seg = seg->next, obj_idx++) { |
1396 | if (!seg) |
1397 | break; |
1398 | |
1399 | if (!strcmp(seg->name, name)) { |
1400 | if (attrs > 0 && pass == 1) |
1401 | nasm_error(ERR_WARNING, "segment attributes specified on" |
1402 | " redeclaration of segment: ignoring" ); |
1403 | if (seg->use32) |
1404 | *bits = 32; |
1405 | else |
1406 | *bits = 16; |
1407 | current_seg = seg; |
1408 | return seg->index; |
1409 | } |
1410 | } |
1411 | |
1412 | *segtail = seg = nasm_malloc(sizeof(*seg)); |
1413 | seg->next = NULL; |
1414 | segtail = &seg->next; |
1415 | seg->index = (any_segs ? seg_alloc() : first_seg); |
1416 | seg->obj_index = obj_idx; |
1417 | seg->grp = NULL; |
1418 | any_segs = true; |
1419 | seg->name = nasm_strdup(name); |
1420 | seg->currentpos = 0; |
1421 | seg->align = 1; /* default */ |
1422 | seg->use32 = false; /* default */ |
1423 | seg->combine = CMB_PUBLIC; /* default */ |
1424 | seg->segclass = seg->overlay = NULL; |
1425 | seg->pubhead = NULL; |
1426 | seg->pubtail = &seg->pubhead; |
1427 | seg->lochead = NULL; |
1428 | seg->loctail = &seg->lochead; |
1429 | seg->orp = obj_new(); |
1430 | seg->orp->up = &(seg->orp); |
1431 | seg->orp->ori = ori_ledata; |
1432 | seg->orp->type = LEDATA; |
1433 | seg->orp->parm[1] = obj_idx; |
1434 | |
1435 | /* |
1436 | * Process the segment attributes. |
1437 | */ |
1438 | p = name; |
1439 | while (attrs--) { |
1440 | p += strlen(p); |
1441 | while (!*p) |
1442 | p++; |
1443 | |
1444 | /* |
1445 | * `p' contains a segment attribute. |
1446 | */ |
1447 | if (!nasm_stricmp(p, "private" )) |
1448 | seg->combine = CMB_PRIVATE; |
1449 | else if (!nasm_stricmp(p, "public" )) |
1450 | seg->combine = CMB_PUBLIC; |
1451 | else if (!nasm_stricmp(p, "common" )) |
1452 | seg->combine = CMB_COMMON; |
1453 | else if (!nasm_stricmp(p, "stack" )) |
1454 | seg->combine = CMB_STACK; |
1455 | else if (!nasm_stricmp(p, "use16" )) |
1456 | seg->use32 = false; |
1457 | else if (!nasm_stricmp(p, "use32" )) |
1458 | seg->use32 = true; |
1459 | else if (!nasm_stricmp(p, "flat" )) { |
1460 | /* |
1461 | * This segment is an OS/2 FLAT segment. That means |
1462 | * that its default group is group FLAT, even if |
1463 | * the group FLAT does not explicitly _contain_ the |
1464 | * segment. |
1465 | * |
1466 | * When we see this, we must create the group |
1467 | * `FLAT', containing no segments, if it does not |
1468 | * already exist; then we must set the default |
1469 | * group of this segment to be the FLAT group. |
1470 | */ |
1471 | struct Group *grp; |
1472 | for (grp = grphead; grp; grp = grp->next) |
1473 | if (!strcmp(grp->name, "FLAT" )) |
1474 | break; |
1475 | if (!grp) { |
1476 | obj_directive(D_GROUP, "FLAT" , 1); |
1477 | for (grp = grphead; grp; grp = grp->next) |
1478 | if (!strcmp(grp->name, "FLAT" )) |
1479 | break; |
1480 | if (!grp) |
1481 | nasm_panic(0, "failure to define FLAT?!" ); |
1482 | } |
1483 | seg->grp = grp; |
1484 | } else if (!nasm_strnicmp(p, "class=" , 6)) |
1485 | seg->segclass = nasm_strdup(p + 6); |
1486 | else if (!nasm_strnicmp(p, "overlay=" , 8)) |
1487 | seg->overlay = nasm_strdup(p + 8); |
1488 | else if (!nasm_strnicmp(p, "align=" , 6)) { |
1489 | seg->align = readnum(p + 6, &rn_error); |
1490 | if (rn_error) { |
1491 | seg->align = 1; |
1492 | nasm_error(ERR_NONFATAL, "segment alignment should be" |
1493 | " numeric" ); |
1494 | } |
1495 | switch (seg->align) { |
1496 | case 1: /* BYTE */ |
1497 | case 2: /* WORD */ |
1498 | case 4: /* DWORD */ |
1499 | case 16: /* PARA */ |
1500 | case 256: /* PAGE */ |
1501 | case 4096: /* PharLap extension */ |
1502 | break; |
1503 | case 8: |
1504 | nasm_error(ERR_WARNING, |
1505 | "OBJ format does not support alignment" |
1506 | " of 8: rounding up to 16" ); |
1507 | seg->align = 16; |
1508 | break; |
1509 | case 32: |
1510 | case 64: |
1511 | case 128: |
1512 | nasm_error(ERR_WARNING, |
1513 | "OBJ format does not support alignment" |
1514 | " of %d: rounding up to 256" , seg->align); |
1515 | seg->align = 256; |
1516 | break; |
1517 | case 512: |
1518 | case 1024: |
1519 | case 2048: |
1520 | nasm_error(ERR_WARNING, |
1521 | "OBJ format does not support alignment" |
1522 | " of %d: rounding up to 4096" , seg->align); |
1523 | seg->align = 4096; |
1524 | break; |
1525 | default: |
1526 | nasm_error(ERR_NONFATAL, "invalid alignment value %d" , |
1527 | seg->align); |
1528 | seg->align = 1; |
1529 | break; |
1530 | } |
1531 | } else if (!nasm_strnicmp(p, "absolute=" , 9)) { |
1532 | seg->align = SEG_ABS + readnum(p + 9, &rn_error); |
1533 | if (rn_error) |
1534 | nasm_error(ERR_NONFATAL, "argument to `absolute' segment" |
1535 | " attribute should be numeric" ); |
1536 | } |
1537 | } |
1538 | |
1539 | /* We need to know whenever we have at least one 32-bit segment */ |
1540 | obj_use32 |= seg->use32; |
1541 | |
1542 | obj_seg_needs_update = seg; |
1543 | if (seg->align >= SEG_ABS) |
1544 | define_label(name, NO_SEG, seg->align - SEG_ABS, false); |
1545 | else |
1546 | define_label(name, seg->index + 1, 0L, false); |
1547 | obj_seg_needs_update = NULL; |
1548 | |
1549 | /* |
1550 | * See if this segment is defined in any groups. |
1551 | */ |
1552 | for (grp = grphead; grp; grp = grp->next) { |
1553 | for (i = grp->nindices; i < grp->nentries; i++) { |
1554 | if (!strcmp(grp->segs[i].name, seg->name)) { |
1555 | nasm_free(grp->segs[i].name); |
1556 | grp->segs[i] = grp->segs[grp->nindices]; |
1557 | grp->segs[grp->nindices++].index = seg->obj_index; |
1558 | if (seg->grp) |
1559 | nasm_error(ERR_WARNING, |
1560 | "segment `%s' is already part of" |
1561 | " a group: first one takes precedence" , |
1562 | seg->name); |
1563 | else |
1564 | seg->grp = grp; |
1565 | } |
1566 | } |
1567 | } |
1568 | |
1569 | /* |
1570 | * Walk through the list of externals with unresolved |
1571 | * default-WRT clauses, and resolve any that point at this |
1572 | * segment. |
1573 | */ |
1574 | extp = &dws; |
1575 | while (*extp) { |
1576 | if ((*extp)->defwrt_type == DEFWRT_STRING && |
1577 | !strcmp((*extp)->defwrt_ptr.string, seg->name)) { |
1578 | nasm_free((*extp)->defwrt_ptr.string); |
1579 | (*extp)->defwrt_type = DEFWRT_SEGMENT; |
1580 | (*extp)->defwrt_ptr.seg = seg; |
1581 | *extp = (*extp)->next_dws; |
1582 | } else |
1583 | extp = &(*extp)->next_dws; |
1584 | } |
1585 | |
1586 | if (seg->use32) |
1587 | *bits = 32; |
1588 | else |
1589 | *bits = 16; |
1590 | current_seg = seg; |
1591 | return seg->index; |
1592 | } |
1593 | } |
1594 | |
1595 | static enum directive_result |
1596 | obj_directive(enum directive directive, char *value, int pass) |
1597 | { |
1598 | switch (directive) { |
1599 | case D_GROUP: |
1600 | { |
1601 | char *p, *q, *v; |
1602 | if (pass == 1) { |
1603 | struct Group *grp; |
1604 | struct Segment *seg; |
1605 | struct External **extp; |
1606 | int obj_idx; |
1607 | |
1608 | q = value; |
1609 | while (*q == '.') |
1610 | q++; /* hack, but a documented one */ |
1611 | v = q; |
1612 | while (*q && !nasm_isspace(*q)) |
1613 | q++; |
1614 | if (nasm_isspace(*q)) { |
1615 | *q++ = '\0'; |
1616 | while (*q && nasm_isspace(*q)) |
1617 | q++; |
1618 | } |
1619 | /* |
1620 | * Here we used to sanity-check the group directive to |
1621 | * ensure nobody tried to declare a group containing no |
1622 | * segments. However, OS/2 does this as standard |
1623 | * practice, so the sanity check has been removed. |
1624 | * |
1625 | * if (!*q) { |
1626 | * nasm_error(ERR_NONFATAL,"GROUP directive contains no segments"); |
1627 | * return DIRR_ERROR; |
1628 | * } |
1629 | */ |
1630 | |
1631 | obj_idx = 1; |
1632 | for (grp = grphead; grp; grp = grp->next) { |
1633 | obj_idx++; |
1634 | if (!strcmp(grp->name, v)) { |
1635 | nasm_error(ERR_NONFATAL, "group `%s' defined twice" , v); |
1636 | return DIRR_ERROR; |
1637 | } |
1638 | } |
1639 | |
1640 | *grptail = grp = nasm_malloc(sizeof(*grp)); |
1641 | grp->next = NULL; |
1642 | grptail = &grp->next; |
1643 | grp->index = seg_alloc(); |
1644 | grp->obj_index = obj_idx; |
1645 | grp->nindices = grp->nentries = 0; |
1646 | grp->name = NULL; |
1647 | |
1648 | obj_grp_needs_update = grp; |
1649 | backend_label(v, grp->index + 1, 0L); |
1650 | obj_grp_needs_update = NULL; |
1651 | |
1652 | while (*q) { |
1653 | p = q; |
1654 | while (*q && !nasm_isspace(*q)) |
1655 | q++; |
1656 | if (nasm_isspace(*q)) { |
1657 | *q++ = '\0'; |
1658 | while (*q && nasm_isspace(*q)) |
1659 | q++; |
1660 | } |
1661 | /* |
1662 | * Now p contains a segment name. Find it. |
1663 | */ |
1664 | for (seg = seghead; seg; seg = seg->next) |
1665 | if (!strcmp(seg->name, p)) |
1666 | break; |
1667 | if (seg) { |
1668 | /* |
1669 | * We have a segment index. Shift a name entry |
1670 | * to the end of the array to make room. |
1671 | */ |
1672 | grp->segs[grp->nentries++] = grp->segs[grp->nindices]; |
1673 | grp->segs[grp->nindices++].index = seg->obj_index; |
1674 | if (seg->grp) |
1675 | nasm_error(ERR_WARNING, |
1676 | "segment `%s' is already part of" |
1677 | " a group: first one takes precedence" , |
1678 | seg->name); |
1679 | else |
1680 | seg->grp = grp; |
1681 | } else { |
1682 | /* |
1683 | * We have an as-yet undefined segment. |
1684 | * Remember its name, for later. |
1685 | */ |
1686 | grp->segs[grp->nentries++].name = nasm_strdup(p); |
1687 | } |
1688 | } |
1689 | |
1690 | /* |
1691 | * Walk through the list of externals with unresolved |
1692 | * default-WRT clauses, and resolve any that point at |
1693 | * this group. |
1694 | */ |
1695 | extp = &dws; |
1696 | while (*extp) { |
1697 | if ((*extp)->defwrt_type == DEFWRT_STRING && |
1698 | !strcmp((*extp)->defwrt_ptr.string, grp->name)) { |
1699 | nasm_free((*extp)->defwrt_ptr.string); |
1700 | (*extp)->defwrt_type = DEFWRT_GROUP; |
1701 | (*extp)->defwrt_ptr.grp = grp; |
1702 | *extp = (*extp)->next_dws; |
1703 | } else |
1704 | extp = &(*extp)->next_dws; |
1705 | } |
1706 | } |
1707 | return DIRR_OK; |
1708 | } |
1709 | case D_UPPERCASE: |
1710 | obj_uppercase = true; |
1711 | return DIRR_OK; |
1712 | |
1713 | case D_IMPORT: |
1714 | { |
1715 | char *q, *extname, *libname, *impname; |
1716 | |
1717 | if (pass == 2) |
1718 | return 1; /* ignore in pass two */ |
1719 | extname = q = value; |
1720 | while (*q && !nasm_isspace(*q)) |
1721 | q++; |
1722 | if (nasm_isspace(*q)) { |
1723 | *q++ = '\0'; |
1724 | while (*q && nasm_isspace(*q)) |
1725 | q++; |
1726 | } |
1727 | |
1728 | libname = q; |
1729 | while (*q && !nasm_isspace(*q)) |
1730 | q++; |
1731 | if (nasm_isspace(*q)) { |
1732 | *q++ = '\0'; |
1733 | while (*q && nasm_isspace(*q)) |
1734 | q++; |
1735 | } |
1736 | |
1737 | impname = q; |
1738 | |
1739 | if (!*extname || !*libname) |
1740 | nasm_error(ERR_NONFATAL, "`import' directive requires symbol name" |
1741 | " and library name" ); |
1742 | else { |
1743 | struct ImpDef *imp; |
1744 | bool err = false; |
1745 | |
1746 | imp = *imptail = nasm_malloc(sizeof(struct ImpDef)); |
1747 | imptail = &imp->next; |
1748 | imp->next = NULL; |
1749 | imp->extname = nasm_strdup(extname); |
1750 | imp->libname = nasm_strdup(libname); |
1751 | imp->impindex = readnum(impname, &err); |
1752 | if (!*impname || err) |
1753 | imp->impname = nasm_strdup(impname); |
1754 | else |
1755 | imp->impname = NULL; |
1756 | } |
1757 | |
1758 | return DIRR_OK; |
1759 | } |
1760 | case D_EXPORT: |
1761 | { |
1762 | char *q, *extname, *intname, *v; |
1763 | struct ExpDef *export; |
1764 | int flags = 0; |
1765 | unsigned int ordinal = 0; |
1766 | |
1767 | if (pass == 2) |
1768 | return DIRR_OK; /* ignore in pass two */ |
1769 | intname = q = value; |
1770 | while (*q && !nasm_isspace(*q)) |
1771 | q++; |
1772 | if (nasm_isspace(*q)) { |
1773 | *q++ = '\0'; |
1774 | while (*q && nasm_isspace(*q)) |
1775 | q++; |
1776 | } |
1777 | |
1778 | extname = q; |
1779 | while (*q && !nasm_isspace(*q)) |
1780 | q++; |
1781 | if (nasm_isspace(*q)) { |
1782 | *q++ = '\0'; |
1783 | while (*q && nasm_isspace(*q)) |
1784 | q++; |
1785 | } |
1786 | |
1787 | if (!*intname) { |
1788 | nasm_error(ERR_NONFATAL, "`export' directive requires export name" ); |
1789 | return DIRR_OK; |
1790 | } |
1791 | if (!*extname) { |
1792 | extname = intname; |
1793 | intname = "" ; |
1794 | } |
1795 | while (*q) { |
1796 | v = q; |
1797 | while (*q && !nasm_isspace(*q)) |
1798 | q++; |
1799 | if (nasm_isspace(*q)) { |
1800 | *q++ = '\0'; |
1801 | while (*q && nasm_isspace(*q)) |
1802 | q++; |
1803 | } |
1804 | if (!nasm_stricmp(v, "resident" )) |
1805 | flags |= EXPDEF_FLAG_RESIDENT; |
1806 | else if (!nasm_stricmp(v, "nodata" )) |
1807 | flags |= EXPDEF_FLAG_NODATA; |
1808 | else if (!nasm_strnicmp(v, "parm=" , 5)) { |
1809 | bool err = false; |
1810 | flags |= EXPDEF_MASK_PARMCNT & readnum(v + 5, &err); |
1811 | if (err) { |
1812 | nasm_error(ERR_NONFATAL, |
1813 | "value `%s' for `parm' is non-numeric" , v + 5); |
1814 | return DIRR_ERROR; |
1815 | } |
1816 | } else { |
1817 | bool err = false; |
1818 | ordinal = readnum(v, &err); |
1819 | if (err) { |
1820 | nasm_error(ERR_NONFATAL, |
1821 | "unrecognised export qualifier `%s'" , v); |
1822 | return DIRR_ERROR; |
1823 | } |
1824 | flags |= EXPDEF_FLAG_ORDINAL; |
1825 | } |
1826 | } |
1827 | |
1828 | export = *exptail = nasm_malloc(sizeof(struct ExpDef)); |
1829 | exptail = &export->next; |
1830 | export->next = NULL; |
1831 | export->extname = nasm_strdup(extname); |
1832 | export->intname = nasm_strdup(intname); |
1833 | export->ordinal = ordinal; |
1834 | export->flags = flags; |
1835 | |
1836 | return DIRR_OK; |
1837 | } |
1838 | default: |
1839 | return DIRR_UNKNOWN; |
1840 | } |
1841 | } |
1842 | |
1843 | static void obj_sectalign(int32_t seg, unsigned int value) |
1844 | { |
1845 | struct Segment *s; |
1846 | |
1847 | list_for_each(s, seghead) { |
1848 | if (s->index == seg) |
1849 | break; |
1850 | } |
1851 | |
1852 | /* |
1853 | * it should not be too big value |
1854 | * and applied on non-absolute sections |
1855 | */ |
1856 | if (!s || !is_power2(value) || |
1857 | value > 4096 || s->align >= SEG_ABS) |
1858 | return; |
1859 | |
1860 | /* |
1861 | * FIXME: No code duplication please |
1862 | * consider making helper for this |
1863 | * mapping since section handler has |
1864 | * to do the same |
1865 | */ |
1866 | switch (value) { |
1867 | case 8: |
1868 | value = 16; |
1869 | break; |
1870 | case 32: |
1871 | case 64: |
1872 | case 128: |
1873 | value = 256; |
1874 | break; |
1875 | case 512: |
1876 | case 1024: |
1877 | case 2048: |
1878 | value = 4096; |
1879 | break; |
1880 | } |
1881 | |
1882 | if (s->align < (int)value) |
1883 | s->align = value; |
1884 | } |
1885 | |
1886 | static int32_t obj_segbase(int32_t segment) |
1887 | { |
1888 | struct Segment *seg; |
1889 | |
1890 | /* |
1891 | * Find the segment in our list. |
1892 | */ |
1893 | for (seg = seghead; seg; seg = seg->next) |
1894 | if (seg->index == segment - 1) |
1895 | break; |
1896 | |
1897 | if (!seg) { |
1898 | /* |
1899 | * Might be an external with a default WRT. |
1900 | */ |
1901 | int32_t i = segment / 2; |
1902 | struct ExtBack *eb = ebhead; |
1903 | struct External *e; |
1904 | |
1905 | while (i >= EXT_BLKSIZ) { |
1906 | if (eb) |
1907 | eb = eb->next; |
1908 | else |
1909 | break; |
1910 | i -= EXT_BLKSIZ; |
1911 | } |
1912 | if (eb) { |
1913 | e = eb->exts[i]; |
1914 | if (!e) { |
1915 | /* Not available yet, probably a forward reference */ |
1916 | nasm_assert(pass0 < 2); /* Convergence failure */ |
1917 | return NO_SEG; |
1918 | } |
1919 | |
1920 | switch (e->defwrt_type) { |
1921 | case DEFWRT_NONE: |
1922 | return segment; /* fine */ |
1923 | case DEFWRT_SEGMENT: |
1924 | return e->defwrt_ptr.seg->index + 1; |
1925 | case DEFWRT_GROUP: |
1926 | return e->defwrt_ptr.grp->index + 1; |
1927 | default: |
1928 | return NO_SEG; /* can't tell what it is */ |
1929 | } |
1930 | } |
1931 | |
1932 | return segment; /* not one of ours - leave it alone */ |
1933 | } |
1934 | |
1935 | if (seg->align >= SEG_ABS) |
1936 | return seg->align; /* absolute segment */ |
1937 | if (seg->grp) |
1938 | return seg->grp->index + 1; /* grouped segment */ |
1939 | |
1940 | return segment; /* no special treatment */ |
1941 | } |
1942 | |
1943 | /* Get a file timestamp in MS-DOS format */ |
1944 | static uint32_t obj_file_timestamp(const char *pathname) |
1945 | { |
1946 | time_t t; |
1947 | const struct tm *lt; |
1948 | |
1949 | if (!nasm_file_time(&t, pathname)) |
1950 | return 0; |
1951 | |
1952 | lt = localtime(&t); |
1953 | if (!lt) |
1954 | return 0; |
1955 | |
1956 | if (lt->tm_year < 80 || lt->tm_year > 207) |
1957 | return 0; /* Only years 1980-2107 representable */ |
1958 | |
1959 | return |
1960 | ((uint32_t)lt->tm_sec >> 1) + |
1961 | ((uint32_t)lt->tm_min << 5) + |
1962 | ((uint32_t)lt->tm_hour << 11) + |
1963 | ((uint32_t)lt->tm_mday << 16) + |
1964 | (((uint32_t)lt->tm_mon + 1) << 21) + |
1965 | (((uint32_t)lt->tm_year - 80) << 25); |
1966 | } |
1967 | |
1968 | static void obj_write_file(void) |
1969 | { |
1970 | struct Segment *seg, *entry_seg_ptr = 0; |
1971 | struct FileName *fn; |
1972 | struct LineNumber *ln; |
1973 | struct Group *grp; |
1974 | struct Public *pub, *loc; |
1975 | struct External *ext; |
1976 | struct ImpDef *imp; |
1977 | struct ExpDef *export; |
1978 | int lname_idx; |
1979 | ObjRecord *orp; |
1980 | const StrList *depfile; |
1981 | const bool debuginfo = (dfmt == &borland_debug_form); |
1982 | |
1983 | /* |
1984 | * Write the THEADR module header. |
1985 | */ |
1986 | orp = obj_new(); |
1987 | orp->type = THEADR; |
1988 | obj_name(orp, obj_infile); |
1989 | obj_emit2(orp); |
1990 | |
1991 | /* |
1992 | * Write the NASM boast comment. |
1993 | */ |
1994 | orp->type = COMENT; |
1995 | obj_rword(orp, dTRANSL); |
1996 | obj_name(orp, nasm_comment); |
1997 | obj_emit2(orp); |
1998 | |
1999 | /* |
2000 | * Output file dependency information |
2001 | */ |
2002 | if (!obj_nodepend) { |
2003 | list_for_each(depfile, depend_list) { |
2004 | uint32_t ts; |
2005 | |
2006 | ts = obj_file_timestamp(depfile->str); |
2007 | if (ts) { |
2008 | orp->type = COMENT; |
2009 | obj_rword(orp, dDEPFILE); |
2010 | obj_dword(orp, ts); |
2011 | obj_name(orp, depfile->str); |
2012 | obj_emit2(orp); |
2013 | } |
2014 | } |
2015 | } |
2016 | |
2017 | orp->type = COMENT; |
2018 | /* |
2019 | * Write the IMPDEF records, if any. |
2020 | */ |
2021 | for (imp = imphead; imp; imp = imp->next) { |
2022 | obj_rword(orp, dOMFEXT); |
2023 | obj_byte(orp, 1); /* subfunction 1: IMPDEF */ |
2024 | if (imp->impname) |
2025 | obj_byte(orp, 0); /* import by name */ |
2026 | else |
2027 | obj_byte(orp, 1); /* import by ordinal */ |
2028 | obj_name(orp, imp->extname); |
2029 | obj_name(orp, imp->libname); |
2030 | if (imp->impname) |
2031 | obj_name(orp, imp->impname); |
2032 | else |
2033 | obj_word(orp, imp->impindex); |
2034 | obj_emit2(orp); |
2035 | } |
2036 | |
2037 | /* |
2038 | * Write the EXPDEF records, if any. |
2039 | */ |
2040 | for (export = exphead; export; export = export->next) { |
2041 | obj_rword(orp, dOMFEXT); |
2042 | obj_byte(orp, 2); /* subfunction 2: EXPDEF */ |
2043 | obj_byte(orp, export->flags); |
2044 | obj_name(orp, export->extname); |
2045 | obj_name(orp, export->intname); |
2046 | if (export->flags & EXPDEF_FLAG_ORDINAL) |
2047 | obj_word(orp, export->ordinal); |
2048 | obj_emit2(orp); |
2049 | } |
2050 | |
2051 | /* we're using extended OMF if we put in debug info */ |
2052 | if (debuginfo) { |
2053 | orp->type = COMENT; |
2054 | obj_rword(orp, dEXTENDED); |
2055 | obj_emit2(orp); |
2056 | } |
2057 | |
2058 | /* |
2059 | * Write the first LNAMES record, containing LNAME one, which |
2060 | * is null. Also initialize the LNAME counter. |
2061 | */ |
2062 | orp->type = LNAMES; |
2063 | obj_byte(orp, 0); |
2064 | lname_idx = 1; |
2065 | /* |
2066 | * Write some LNAMES for the segment names |
2067 | */ |
2068 | for (seg = seghead; seg; seg = seg->next) { |
2069 | orp = obj_name(orp, seg->name); |
2070 | if (seg->segclass) |
2071 | orp = obj_name(orp, seg->segclass); |
2072 | if (seg->overlay) |
2073 | orp = obj_name(orp, seg->overlay); |
2074 | obj_commit(orp); |
2075 | } |
2076 | /* |
2077 | * Write some LNAMES for the group names |
2078 | */ |
2079 | for (grp = grphead; grp; grp = grp->next) { |
2080 | orp = obj_name(orp, grp->name); |
2081 | obj_commit(orp); |
2082 | } |
2083 | obj_emit(orp); |
2084 | |
2085 | /* |
2086 | * Write the SEGDEF records. |
2087 | */ |
2088 | orp->type = SEGDEF; |
2089 | for (seg = seghead; seg; seg = seg->next) { |
2090 | int acbp; |
2091 | uint32_t seglen = seg->currentpos; |
2092 | |
2093 | acbp = (seg->combine << 2); /* C field */ |
2094 | |
2095 | if (seg->use32) |
2096 | acbp |= 0x01; /* P bit is Use32 flag */ |
2097 | else if (seglen == 0x10000L) { |
2098 | seglen = 0; /* This special case may be needed for old linkers */ |
2099 | acbp |= 0x02; /* B bit */ |
2100 | } |
2101 | |
2102 | /* A field */ |
2103 | if (seg->align >= SEG_ABS) |
2104 | /* acbp |= 0x00 */ ; |
2105 | else if (seg->align >= 4096) { |
2106 | if (seg->align > 4096) |
2107 | nasm_error(ERR_NONFATAL, "segment `%s' requires more alignment" |
2108 | " than OBJ format supports" , seg->name); |
2109 | acbp |= 0xC0; /* PharLap extension */ |
2110 | } else if (seg->align >= 256) { |
2111 | acbp |= 0x80; |
2112 | } else if (seg->align >= 16) { |
2113 | acbp |= 0x60; |
2114 | } else if (seg->align >= 4) { |
2115 | acbp |= 0xA0; |
2116 | } else if (seg->align >= 2) { |
2117 | acbp |= 0x40; |
2118 | } else |
2119 | acbp |= 0x20; |
2120 | |
2121 | obj_byte(orp, acbp); |
2122 | if (seg->align & SEG_ABS) { |
2123 | obj_x(orp, seg->align - SEG_ABS); /* Frame */ |
2124 | obj_byte(orp, 0); /* Offset */ |
2125 | } |
2126 | obj_x(orp, seglen); |
2127 | obj_index(orp, ++lname_idx); |
2128 | obj_index(orp, seg->segclass ? ++lname_idx : 1); |
2129 | obj_index(orp, seg->overlay ? ++lname_idx : 1); |
2130 | obj_emit2(orp); |
2131 | } |
2132 | |
2133 | /* |
2134 | * Write the GRPDEF records. |
2135 | */ |
2136 | orp->type = GRPDEF; |
2137 | for (grp = grphead; grp; grp = grp->next) { |
2138 | int i; |
2139 | |
2140 | if (grp->nindices != grp->nentries) { |
2141 | for (i = grp->nindices; i < grp->nentries; i++) { |
2142 | nasm_error(ERR_NONFATAL, "group `%s' contains undefined segment" |
2143 | " `%s'" , grp->name, grp->segs[i].name); |
2144 | nasm_free(grp->segs[i].name); |
2145 | grp->segs[i].name = NULL; |
2146 | } |
2147 | } |
2148 | obj_index(orp, ++lname_idx); |
2149 | for (i = 0; i < grp->nindices; i++) { |
2150 | obj_byte(orp, 0xFF); |
2151 | obj_index(orp, grp->segs[i].index); |
2152 | } |
2153 | obj_emit2(orp); |
2154 | } |
2155 | |
2156 | /* |
2157 | * Write the PUBDEF records: first the ones in the segments, |
2158 | * then the far-absolutes. |
2159 | */ |
2160 | orp->type = PUBDEF; |
2161 | orp->ori = ori_pubdef; |
2162 | for (seg = seghead; seg; seg = seg->next) { |
2163 | orp->parm[0] = seg->grp ? seg->grp->obj_index : 0; |
2164 | orp->parm[1] = seg->obj_index; |
2165 | for (pub = seg->pubhead; pub; pub = pub->next) { |
2166 | orp = obj_name(orp, pub->name); |
2167 | orp = obj_x(orp, pub->offset); |
2168 | orp = obj_byte(orp, 0); /* type index */ |
2169 | obj_commit(orp); |
2170 | } |
2171 | obj_emit(orp); |
2172 | } |
2173 | orp->parm[0] = 0; |
2174 | orp->parm[1] = 0; |
2175 | for (pub = fpubhead; pub; pub = pub->next) { /* pub-crawl :-) */ |
2176 | if (orp->parm[2] != (uint32_t)pub->segment) { |
2177 | obj_emit(orp); |
2178 | orp->parm[2] = pub->segment; |
2179 | } |
2180 | orp = obj_name(orp, pub->name); |
2181 | orp = obj_x(orp, pub->offset); |
2182 | orp = obj_byte(orp, 0); /* type index */ |
2183 | obj_commit(orp); |
2184 | } |
2185 | obj_emit(orp); |
2186 | |
2187 | /* |
2188 | * Write the EXTDEF and COMDEF records, in order. |
2189 | */ |
2190 | orp->ori = ori_null; |
2191 | for (ext = exthead; ext; ext = ext->next) { |
2192 | if (ext->commonsize == 0) { |
2193 | if (orp->type != EXTDEF) { |
2194 | obj_emit(orp); |
2195 | orp->type = EXTDEF; |
2196 | } |
2197 | orp = obj_name(orp, ext->name); |
2198 | orp = obj_index(orp, 0); |
2199 | } else { |
2200 | if (orp->type != COMDEF) { |
2201 | obj_emit(orp); |
2202 | orp->type = COMDEF; |
2203 | } |
2204 | orp = obj_name(orp, ext->name); |
2205 | orp = obj_index(orp, 0); |
2206 | if (ext->commonelem) { |
2207 | orp = obj_byte(orp, 0x61); /* far communal */ |
2208 | orp = obj_value(orp, (ext->commonsize / ext->commonelem)); |
2209 | orp = obj_value(orp, ext->commonelem); |
2210 | } else { |
2211 | orp = obj_byte(orp, 0x62); /* near communal */ |
2212 | orp = obj_value(orp, ext->commonsize); |
2213 | } |
2214 | } |
2215 | obj_commit(orp); |
2216 | } |
2217 | obj_emit(orp); |
2218 | |
2219 | /* |
2220 | * Write a COMENT record stating that the linker's first pass |
2221 | * may stop processing at this point. Exception is if our |
2222 | * MODEND record specifies a start point, in which case, |
2223 | * according to some variants of the documentation, this COMENT |
2224 | * should be omitted. So we'll omit it just in case. |
2225 | * But, TASM puts it in all the time so if we are using |
2226 | * TASM debug stuff we are putting it in |
2227 | */ |
2228 | if (debuginfo || obj_entry_seg == NO_SEG) { |
2229 | orp->type = COMENT; |
2230 | obj_rword(orp, dLINKPASS); |
2231 | obj_byte(orp, 1); |
2232 | obj_emit2(orp); |
2233 | } |
2234 | |
2235 | /* |
2236 | * 1) put out the compiler type |
2237 | * 2) Put out the type info. The only type we are using is near label #19 |
2238 | */ |
2239 | if (debuginfo) { |
2240 | int i; |
2241 | struct Array *arrtmp = arrhead; |
2242 | orp->type = COMENT; |
2243 | obj_rword(orp, dCOMPDEF); |
2244 | obj_byte(orp, 4); |
2245 | obj_byte(orp, 0); |
2246 | obj_emit2(orp); |
2247 | |
2248 | obj_rword(orp, dTYPEDEF); |
2249 | obj_word(orp, 0x18); /* type # for linking */ |
2250 | obj_word(orp, 6); /* size of type */ |
2251 | obj_byte(orp, 0x2a); /* absolute type for debugging */ |
2252 | obj_emit2(orp); |
2253 | obj_rword(orp, dTYPEDEF); |
2254 | obj_word(orp, 0x19); /* type # for linking */ |
2255 | obj_word(orp, 0); /* size of type */ |
2256 | obj_byte(orp, 0x24); /* absolute type for debugging */ |
2257 | obj_byte(orp, 0); /* near/far specifier */ |
2258 | obj_emit2(orp); |
2259 | obj_rword(orp, dTYPEDEF); |
2260 | obj_word(orp, 0x1A); /* type # for linking */ |
2261 | obj_word(orp, 0); /* size of type */ |
2262 | obj_byte(orp, 0x24); /* absolute type for debugging */ |
2263 | obj_byte(orp, 1); /* near/far specifier */ |
2264 | obj_emit2(orp); |
2265 | obj_rword(orp, dTYPEDEF); |
2266 | obj_word(orp, 0x1b); /* type # for linking */ |
2267 | obj_word(orp, 0); /* size of type */ |
2268 | obj_byte(orp, 0x23); /* absolute type for debugging */ |
2269 | obj_byte(orp, 0); |
2270 | obj_byte(orp, 0); |
2271 | obj_byte(orp, 0); |
2272 | obj_emit2(orp); |
2273 | obj_rword(orp, dTYPEDEF); |
2274 | obj_word(orp, 0x1c); /* type # for linking */ |
2275 | obj_word(orp, 0); /* size of type */ |
2276 | obj_byte(orp, 0x23); /* absolute type for debugging */ |
2277 | obj_byte(orp, 0); |
2278 | obj_byte(orp, 4); |
2279 | obj_byte(orp, 0); |
2280 | obj_emit2(orp); |
2281 | obj_rword(orp, dTYPEDEF); |
2282 | obj_word(orp, 0x1d); /* type # for linking */ |
2283 | obj_word(orp, 0); /* size of type */ |
2284 | obj_byte(orp, 0x23); /* absolute type for debugging */ |
2285 | obj_byte(orp, 0); |
2286 | obj_byte(orp, 1); |
2287 | obj_byte(orp, 0); |
2288 | obj_emit2(orp); |
2289 | obj_rword(orp, dTYPEDEF); |
2290 | obj_word(orp, 0x1e); /* type # for linking */ |
2291 | obj_word(orp, 0); /* size of type */ |
2292 | obj_byte(orp, 0x23); /* absolute type for debugging */ |
2293 | obj_byte(orp, 0); |
2294 | obj_byte(orp, 5); |
2295 | obj_byte(orp, 0); |
2296 | obj_emit2(orp); |
2297 | |
2298 | /* put out the array types */ |
2299 | for (i = ARRAYBOT; i < arrindex; i++) { |
2300 | obj_rword(orp, dTYPEDEF); |
2301 | obj_word(orp, i); /* type # for linking */ |
2302 | obj_word(orp, arrtmp->size); /* size of type */ |
2303 | obj_byte(orp, 0x1A); /* absolute type for debugging (array) */ |
2304 | obj_byte(orp, arrtmp->basetype); /* base type */ |
2305 | obj_emit2(orp); |
2306 | arrtmp = arrtmp->next; |
2307 | } |
2308 | } |
2309 | /* |
2310 | * write out line number info with a LINNUM record |
2311 | * switch records when we switch segments, and output the |
2312 | * file in a pseudo-TASM fashion. The record switch is naive; that |
2313 | * is that one file may have many records for the same segment |
2314 | * if there are lots of segment switches |
2315 | */ |
2316 | if (fnhead && debuginfo) { |
2317 | seg = fnhead->lnhead->segment; |
2318 | |
2319 | for (fn = fnhead; fn; fn = fn->next) { |
2320 | /* write out current file name */ |
2321 | orp->type = COMENT; |
2322 | orp->ori = ori_null; |
2323 | obj_rword(orp, dFILNAME); |
2324 | obj_byte(orp, 0); |
2325 | obj_name(orp, fn->name); |
2326 | obj_dword(orp, 0); |
2327 | obj_emit2(orp); |
2328 | |
2329 | /* write out line numbers this file */ |
2330 | |
2331 | orp->type = LINNUM; |
2332 | orp->ori = ori_linnum; |
2333 | for (ln = fn->lnhead; ln; ln = ln->next) { |
2334 | if (seg != ln->segment) { |
2335 | /* if we get here have to flush the buffer and start |
2336 | * a new record for a new segment |
2337 | */ |
2338 | seg = ln->segment; |
2339 | obj_emit(orp); |
2340 | } |
2341 | orp->parm[0] = seg->grp ? seg->grp->obj_index : 0; |
2342 | orp->parm[1] = seg->obj_index; |
2343 | orp = obj_word(orp, ln->lineno); |
2344 | orp = obj_x(orp, ln->offset); |
2345 | obj_commit(orp); |
2346 | } |
2347 | obj_emit(orp); |
2348 | } |
2349 | } |
2350 | /* |
2351 | * we are going to locate the entry point segment now |
2352 | * rather than wait until the MODEND record, because, |
2353 | * then we can output a special symbol to tell where the |
2354 | * entry point is. |
2355 | * |
2356 | */ |
2357 | if (obj_entry_seg != NO_SEG) { |
2358 | for (seg = seghead; seg; seg = seg->next) { |
2359 | if (seg->index == obj_entry_seg) { |
2360 | entry_seg_ptr = seg; |
2361 | break; |
2362 | } |
2363 | } |
2364 | if (!seg) |
2365 | nasm_error(ERR_NONFATAL, "entry point is not in this module" ); |
2366 | } |
2367 | |
2368 | /* |
2369 | * get ready to put out symbol records |
2370 | */ |
2371 | orp->type = COMENT; |
2372 | orp->ori = ori_local; |
2373 | |
2374 | /* |
2375 | * put out a symbol for the entry point |
2376 | * no dots in this symbol, because, borland does |
2377 | * not (officially) support dots in label names |
2378 | * and I don't know what various versions of TLINK will do |
2379 | */ |
2380 | if (debuginfo && obj_entry_seg != NO_SEG) { |
2381 | orp = obj_name(orp, "start_of_program" ); |
2382 | orp = obj_word(orp, 0x19); /* type: near label */ |
2383 | orp = obj_index(orp, seg->grp ? seg->grp->obj_index : 0); |
2384 | orp = obj_index(orp, seg->obj_index); |
2385 | orp = obj_x(orp, obj_entry_ofs); |
2386 | obj_commit(orp); |
2387 | } |
2388 | |
2389 | /* |
2390 | * put out the local labels |
2391 | */ |
2392 | for (seg = seghead; seg && debuginfo; seg = seg->next) { |
2393 | /* labels this seg */ |
2394 | for (loc = seg->lochead; loc; loc = loc->next) { |
2395 | orp = obj_name(orp, loc->name); |
2396 | orp = obj_word(orp, loc->type); |
2397 | orp = obj_index(orp, seg->grp ? seg->grp->obj_index : 0); |
2398 | orp = obj_index(orp, seg->obj_index); |
2399 | orp = obj_x(orp, loc->offset); |
2400 | obj_commit(orp); |
2401 | } |
2402 | } |
2403 | if (orp->used) |
2404 | obj_emit(orp); |
2405 | |
2406 | /* |
2407 | * Write the LEDATA/FIXUPP pairs. |
2408 | */ |
2409 | for (seg = seghead; seg; seg = seg->next) { |
2410 | obj_emit(seg->orp); |
2411 | nasm_free(seg->orp); |
2412 | } |
2413 | |
2414 | /* |
2415 | * Write the MODEND module end marker. |
2416 | */ |
2417 | orp->type = obj_use32 ? MODE32 : MODEND; |
2418 | orp->ori = ori_null; |
2419 | if (entry_seg_ptr) { |
2420 | orp->type = entry_seg_ptr->use32 ? MODE32 : MODEND; |
2421 | obj_byte(orp, 0xC1); |
2422 | seg = entry_seg_ptr; |
2423 | if (seg->grp) { |
2424 | obj_byte(orp, 0x10); |
2425 | obj_index(orp, seg->grp->obj_index); |
2426 | } else { |
2427 | /* |
2428 | * the below changed to prevent TLINK crashing. |
2429 | * Previous more efficient version read: |
2430 | * |
2431 | * obj_byte (orp, 0x50); |
2432 | */ |
2433 | obj_byte(orp, 0x00); |
2434 | obj_index(orp, seg->obj_index); |
2435 | } |
2436 | obj_index(orp, seg->obj_index); |
2437 | obj_x(orp, obj_entry_ofs); |
2438 | } else |
2439 | obj_byte(orp, 0); |
2440 | obj_emit2(orp); |
2441 | nasm_free(orp); |
2442 | } |
2443 | |
2444 | static void obj_fwrite(ObjRecord * orp) |
2445 | { |
2446 | unsigned int cksum, len; |
2447 | uint8_t *ptr; |
2448 | |
2449 | cksum = orp->type; |
2450 | if (orp->x_size == 32) |
2451 | cksum |= 1; |
2452 | fputc(cksum, ofile); |
2453 | len = orp->committed + 1; |
2454 | cksum += (len & 0xFF) + ((len >> 8) & 0xFF); |
2455 | fwriteint16_t(len, ofile); |
2456 | nasm_write(orp->buf, len-1, ofile); |
2457 | for (ptr = orp->buf; --len; ptr++) |
2458 | cksum += *ptr; |
2459 | fputc((-cksum) & 0xFF, ofile); |
2460 | } |
2461 | |
2462 | static enum directive_result |
2463 | obj_pragma(const struct pragma *pragma) |
2464 | { |
2465 | switch (pragma->opcode) { |
2466 | case D_NODEPEND: |
2467 | obj_nodepend = true; |
2468 | break; |
2469 | |
2470 | default: |
2471 | break; |
2472 | } |
2473 | |
2474 | return DIRR_OK; |
2475 | } |
2476 | |
2477 | extern macros_t obj_stdmac[]; |
2478 | |
2479 | static void dbgbi_init(void) |
2480 | { |
2481 | fnhead = NULL; |
2482 | fntail = &fnhead; |
2483 | arrindex = ARRAYBOT; |
2484 | arrhead = NULL; |
2485 | arrtail = &arrhead; |
2486 | } |
2487 | static void dbgbi_cleanup(void) |
2488 | { |
2489 | struct Segment *segtmp; |
2490 | while (fnhead) { |
2491 | struct FileName *fntemp = fnhead; |
2492 | while (fnhead->lnhead) { |
2493 | struct LineNumber *lntemp = fnhead->lnhead; |
2494 | fnhead->lnhead = lntemp->next; |
2495 | nasm_free(lntemp); |
2496 | } |
2497 | fnhead = fnhead->next; |
2498 | nasm_free(fntemp->name); |
2499 | nasm_free(fntemp); |
2500 | } |
2501 | for (segtmp = seghead; segtmp; segtmp = segtmp->next) { |
2502 | while (segtmp->lochead) { |
2503 | struct Public *loctmp = segtmp->lochead; |
2504 | segtmp->lochead = loctmp->next; |
2505 | nasm_free(loctmp->name); |
2506 | nasm_free(loctmp); |
2507 | } |
2508 | } |
2509 | while (arrhead) { |
2510 | struct Array *arrtmp = arrhead; |
2511 | arrhead = arrhead->next; |
2512 | nasm_free(arrtmp); |
2513 | } |
2514 | } |
2515 | |
2516 | static void dbgbi_linnum(const char *lnfname, int32_t lineno, int32_t segto) |
2517 | { |
2518 | struct FileName *fn; |
2519 | struct LineNumber *ln; |
2520 | struct Segment *seg; |
2521 | |
2522 | if (segto == NO_SEG) |
2523 | return; |
2524 | |
2525 | /* |
2526 | * If `any_segs' is still false, we must define a default |
2527 | * segment. |
2528 | */ |
2529 | if (!any_segs) { |
2530 | int tempint; /* ignored */ |
2531 | if (segto != obj_segment("__NASMDEFSEG" , 2, &tempint)) |
2532 | nasm_panic(0, "strange segment conditions in OBJ driver" ); |
2533 | } |
2534 | |
2535 | /* |
2536 | * Find the segment we are targetting. |
2537 | */ |
2538 | for (seg = seghead; seg; seg = seg->next) |
2539 | if (seg->index == segto) |
2540 | break; |
2541 | if (!seg) |
2542 | nasm_panic(0, "lineno directed to nonexistent segment?" ); |
2543 | |
2544 | /* for (fn = fnhead; fn; fn = fnhead->next) */ |
2545 | for (fn = fnhead; fn; fn = fn->next) /* fbk - Austin Lunnen - John Fine */ |
2546 | if (!nasm_stricmp(lnfname, fn->name)) |
2547 | break; |
2548 | if (!fn) { |
2549 | fn = nasm_malloc(sizeof(*fn)); |
2550 | fn->name = nasm_malloc(strlen(lnfname) + 1); |
2551 | strcpy(fn->name, lnfname); |
2552 | fn->lnhead = NULL; |
2553 | fn->lntail = &fn->lnhead; |
2554 | fn->next = NULL; |
2555 | *fntail = fn; |
2556 | fntail = &fn->next; |
2557 | } |
2558 | ln = nasm_malloc(sizeof(*ln)); |
2559 | ln->segment = seg; |
2560 | ln->offset = seg->currentpos; |
2561 | ln->lineno = lineno; |
2562 | ln->next = NULL; |
2563 | *fn->lntail = ln; |
2564 | fn->lntail = &ln->next; |
2565 | |
2566 | } |
2567 | static void dbgbi_deflabel(char *name, int32_t segment, |
2568 | int64_t offset, int is_global, char *special) |
2569 | { |
2570 | struct Segment *seg; |
2571 | |
2572 | (void)special; |
2573 | |
2574 | /* |
2575 | * Note: ..[^@] special symbols are filtered in labels.c |
2576 | */ |
2577 | |
2578 | /* |
2579 | * If it's a special-retry from pass two, discard it. |
2580 | */ |
2581 | if (is_global == 3) |
2582 | return; |
2583 | |
2584 | /* |
2585 | * Case (i): |
2586 | */ |
2587 | if (obj_seg_needs_update) { |
2588 | return; |
2589 | } else if (obj_grp_needs_update) { |
2590 | return; |
2591 | } |
2592 | if (segment < SEG_ABS && segment != NO_SEG && segment % 2) |
2593 | return; |
2594 | |
2595 | if (segment >= SEG_ABS || segment == NO_SEG) { |
2596 | return; |
2597 | } |
2598 | |
2599 | /* |
2600 | * If `any_segs' is still false, we might need to define a |
2601 | * default segment, if they're trying to declare a label in |
2602 | * `first_seg'. But the label should exist due to a prior |
2603 | * call to obj_deflabel so we can skip that. |
2604 | */ |
2605 | |
2606 | for (seg = seghead; seg; seg = seg->next) |
2607 | if (seg->index == segment) { |
2608 | struct Public *loc = nasm_malloc(sizeof(*loc)); |
2609 | /* |
2610 | * Case (ii). Maybe MODPUB someday? |
2611 | */ |
2612 | last_defined = *seg->loctail = loc; |
2613 | seg->loctail = &loc->next; |
2614 | loc->next = NULL; |
2615 | loc->name = nasm_strdup(name); |
2616 | loc->offset = offset; |
2617 | } |
2618 | } |
2619 | static void dbgbi_typevalue(int32_t type) |
2620 | { |
2621 | int vsize; |
2622 | int elem = TYM_ELEMENTS(type); |
2623 | type = TYM_TYPE(type); |
2624 | |
2625 | if (!last_defined) |
2626 | return; |
2627 | |
2628 | switch (type) { |
2629 | case TY_BYTE: |
2630 | last_defined->type = 8; /* uint8_t */ |
2631 | vsize = 1; |
2632 | break; |
2633 | case TY_WORD: |
2634 | last_defined->type = 10; /* unsigned word */ |
2635 | vsize = 2; |
2636 | break; |
2637 | case TY_DWORD: |
2638 | last_defined->type = 12; /* unsigned dword */ |
2639 | vsize = 4; |
2640 | break; |
2641 | case TY_FLOAT: |
2642 | last_defined->type = 14; /* float */ |
2643 | vsize = 4; |
2644 | break; |
2645 | case TY_QWORD: |
2646 | last_defined->type = 15; /* qword */ |
2647 | vsize = 8; |
2648 | break; |
2649 | case TY_TBYTE: |
2650 | last_defined->type = 16; /* TBYTE */ |
2651 | vsize = 10; |
2652 | break; |
2653 | default: |
2654 | last_defined->type = 0x19; /* label */ |
2655 | vsize = 0; |
2656 | break; |
2657 | } |
2658 | |
2659 | if (elem > 1) { |
2660 | struct Array *arrtmp = nasm_malloc(sizeof(*arrtmp)); |
2661 | int vtype = last_defined->type; |
2662 | arrtmp->size = vsize * elem; |
2663 | arrtmp->basetype = vtype; |
2664 | arrtmp->next = NULL; |
2665 | last_defined->type = arrindex++; |
2666 | *arrtail = arrtmp; |
2667 | arrtail = &(arrtmp->next); |
2668 | } |
2669 | last_defined = NULL; |
2670 | } |
2671 | static void dbgbi_output(int output_type, void *param) |
2672 | { |
2673 | (void)output_type; |
2674 | (void)param; |
2675 | } |
2676 | static const struct dfmt borland_debug_form = { |
2677 | "Borland Debug Records" , |
2678 | "borland" , |
2679 | dbgbi_init, |
2680 | dbgbi_linnum, |
2681 | dbgbi_deflabel, |
2682 | null_debug_directive, |
2683 | dbgbi_typevalue, |
2684 | dbgbi_output, |
2685 | dbgbi_cleanup, |
2686 | NULL /* pragma list */ |
2687 | }; |
2688 | |
2689 | static const struct dfmt * const borland_debug_arr[3] = { |
2690 | &borland_debug_form, |
2691 | &null_debug_form, |
2692 | NULL |
2693 | }; |
2694 | |
2695 | static const struct pragma_facility obj_pragma_list[] = { |
2696 | { NULL, obj_pragma } |
2697 | }; |
2698 | |
2699 | const struct ofmt of_obj = { |
2700 | "MS-DOS 16-bit/32-bit OMF object files" , |
2701 | "obj" , |
2702 | ".obj" , |
2703 | 0, |
2704 | 32, |
2705 | borland_debug_arr, |
2706 | &borland_debug_form, |
2707 | obj_stdmac, |
2708 | obj_init, |
2709 | null_reset, |
2710 | nasm_do_legacy_output, |
2711 | obj_out, |
2712 | obj_deflabel, |
2713 | obj_segment, |
2714 | NULL, |
2715 | obj_sectalign, |
2716 | obj_segbase, |
2717 | obj_directive, |
2718 | obj_cleanup, |
2719 | obj_pragma_list |
2720 | }; |
2721 | #endif /* OF_OBJ */ |
2722 | |