1 /* ----------------------------------------------------------------------- *
2  *
3  *   Copyright 1996-2020 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  * outcoff.c    output routines for the Netwide Assembler to produce
36  *              COFF object files (for DJGPP and Win32)
37  */
38 
39 #include "compiler.h"
40 
41 #include "nctype.h"
42 #include <time.h>
43 
44 #include "nasm.h"
45 #include "nasmlib.h"
46 #include "ilog2.h"
47 #include "error.h"
48 #include "saa.h"
49 #include "raa.h"
50 #include "eval.h"
51 #include "outform.h"
52 #include "outlib.h"
53 #include "pecoff.h"
54 
55 #if defined(OF_COFF) || defined(OF_WIN32) || defined(OF_WIN64)
56 
57 /*
58  * Notes on COFF:
59  *
60  * (0) When I say `standard COFF' below, I mean `COFF as output and
61  * used by DJGPP'. I assume DJGPP gets it right.
62  *
63  * (1) Win32 appears to interpret the term `relative relocation'
64  * differently from standard COFF. Standard COFF understands a
65  * relative relocation to mean that during relocation you add the
66  * address of the symbol you're referencing, and subtract the base
67  * address of the section you're in. Win32 COFF, by contrast, seems
68  * to add the address of the symbol and then subtract the address
69  * of THE BYTE AFTER THE RELOCATED DWORD. Hence the two formats are
70  * subtly incompatible.
71  *
72  * (2) Win32 doesn't bother putting any flags in the header flags
73  * field (at offset 0x12 into the file).
74  *
75  * (3) Win32/64 uses some extra flags into the section header table:
76  * it defines flags 0x80000000 (writable), 0x40000000 (readable)
77  * and 0x20000000 (executable), and uses them in the expected
78  * combinations. It also defines 0x00100000 through 0x00f00000 for
79  * section alignments of 1 through 8192 bytes.
80  *
81  * (4) Both standard COFF and Win32 COFF seem to use the DWORD
82  * field directly after the section name in the section header
83  * table for something strange: they store what the address of the
84  * section start point _would_ be, if you laid all the sections end
85  * to end starting at zero. Dunno why. Microsoft's documentation
86  * lists this field as "Virtual Size of Section", which doesn't
87  * seem to fit at all. In fact, Win32 even includes non-linked
88  * sections such as .drectve in this calculation.
89  *
90  * Newer versions of MASM seem to have changed this to be zero, and
91  * that apparently matches the COFF spec, so go with that.
92  *
93  * (5) Standard COFF does something very strange to common
94  * variables: the relocation point for a common variable is as far
95  * _before_ the variable as its size stretches out _after_ it. So
96  * we must fix up common variable references. Win32 seems to be
97  * sensible on this one.
98  */
99 
100 /* Flag which version of COFF we are currently outputting. */
101 bool win32, win64;
102 
103 static int32_t imagebase_sect;
104 #define WRT_IMAGEBASE "..imagebase"
105 
106 /*
107  * Some common section flags by default
108  */
109 #define TEXT_FLAGS_WIN                                  \
110         (IMAGE_SCN_CNT_CODE                     |       \
111          IMAGE_SCN_ALIGN_16BYTES                |       \
112          IMAGE_SCN_MEM_EXECUTE                  |       \
113          IMAGE_SCN_MEM_READ)
114 #define TEXT_FLAGS_DOS                                  \
115         (IMAGE_SCN_CNT_CODE)
116 
117 #define DATA_FLAGS_WIN                                  \
118         (IMAGE_SCN_CNT_INITIALIZED_DATA         |       \
119          IMAGE_SCN_ALIGN_4BYTES                 |       \
120          IMAGE_SCN_MEM_READ                     |       \
121          IMAGE_SCN_MEM_WRITE)
122 #define DATA_FLAGS_DOS                                  \
123         (IMAGE_SCN_CNT_INITIALIZED_DATA)
124 
125 #define BSS_FLAGS_WIN                                   \
126         (IMAGE_SCN_CNT_UNINITIALIZED_DATA       |       \
127          IMAGE_SCN_ALIGN_4BYTES                 |       \
128          IMAGE_SCN_MEM_READ                     |       \
129          IMAGE_SCN_MEM_WRITE)
130 #define BSS_FLAGS_DOS                                   \
131         (IMAGE_SCN_CNT_UNINITIALIZED_DATA)
132 
133 #define RDATA_FLAGS_WIN                                 \
134         (IMAGE_SCN_CNT_INITIALIZED_DATA         |       \
135          IMAGE_SCN_ALIGN_8BYTES                 |       \
136          IMAGE_SCN_MEM_READ)
137 
138 #define RDATA_FLAGS_DOS                                 \
139         (IMAGE_SCN_CNT_INITIALIZED_DATA)
140 
141 #define PDATA_FLAGS                                     \
142         (IMAGE_SCN_CNT_INITIALIZED_DATA         |       \
143          IMAGE_SCN_ALIGN_4BYTES                 |       \
144          IMAGE_SCN_MEM_READ)
145 
146 #define XDATA_FLAGS                                     \
147         (IMAGE_SCN_CNT_INITIALIZED_DATA         |       \
148          IMAGE_SCN_ALIGN_8BYTES                 |       \
149          IMAGE_SCN_MEM_READ)
150 
151 #define INFO_FLAGS                                      \
152         (IMAGE_SCN_ALIGN_1BYTES                 |       \
153          IMAGE_SCN_LNK_INFO                     |       \
154          IMAGE_SCN_LNK_REMOVE)
155 
156 #define TEXT_FLAGS      ((win32 | win64) ? TEXT_FLAGS_WIN  : TEXT_FLAGS_DOS)
157 #define DATA_FLAGS      ((win32 | win64) ? DATA_FLAGS_WIN  : DATA_FLAGS_DOS)
158 #define BSS_FLAGS       ((win32 | win64) ? BSS_FLAGS_WIN   : BSS_FLAGS_DOS)
159 #define RDATA_FLAGS     ((win32 | win64) ? RDATA_FLAGS_WIN : RDATA_FLAGS_DOS)
160 
161 #define COFF_MAX_ALIGNMENT 8192
162 
163 #define SECT_DELTA 32
164 struct coff_Section **coff_sects;
165 static int sectlen;
166 int coff_nsects;
167 
168 struct SAA *coff_syms;
169 uint32_t coff_nsyms;
170 
171 static int32_t def_seg;
172 
173 static int initsym;
174 
175 static struct RAA *bsym, *symval;
176 
177 struct SAA *coff_strs;
178 static uint32_t strslen;
179 
180 static void coff_gen_init(void);
181 static void coff_sect_write(struct coff_Section *, const uint8_t *, uint32_t);
182 static void coff_write(void);
183 static void coff_section_header(char *, int32_t, int32_t, int32_t, int32_t, int32_t, int, int32_t);
184 static void coff_write_relocs(struct coff_Section *);
185 static void coff_write_symbols(void);
186 
coff_win32_init(void)187 static void coff_win32_init(void)
188 {
189     win32 = true;
190     win64 = false;
191     coff_gen_init();
192 }
193 
coff_win64_init(void)194 static void coff_win64_init(void)
195 {
196     win32 = false;
197     win64 = true;
198     coff_gen_init();
199     imagebase_sect = seg_alloc()+1;
200     backend_label(WRT_IMAGEBASE, imagebase_sect, 0);
201 }
202 
coff_std_init(void)203 static void coff_std_init(void)
204 {
205     win32 = win64 = false;
206     coff_gen_init();
207 }
208 
coff_gen_init(void)209 static void coff_gen_init(void)
210 {
211 
212     coff_sects = NULL;
213     coff_nsects = sectlen = 0;
214     coff_syms = saa_init(sizeof(struct coff_Symbol));
215     coff_nsyms = 0;
216     bsym = raa_init();
217     symval = raa_init();
218     coff_strs = saa_init(1);
219     strslen = 0;
220     def_seg = seg_alloc();
221 }
222 
coff_cleanup(void)223 static void coff_cleanup(void)
224 {
225     struct coff_Reloc *r;
226     int i;
227 
228     dfmt->cleanup();
229 
230     coff_write();
231     for (i = 0; i < coff_nsects; i++) {
232         if (coff_sects[i]->data)
233             saa_free(coff_sects[i]->data);
234         while (coff_sects[i]->head) {
235             r = coff_sects[i]->head;
236             coff_sects[i]->head = coff_sects[i]->head->next;
237             nasm_free(r);
238         }
239         nasm_free(coff_sects[i]->name);
240         nasm_free(coff_sects[i]);
241     }
242     nasm_free(coff_sects);
243     saa_free(coff_syms);
244     raa_free(bsym);
245     raa_free(symval);
246     saa_free(coff_strs);
247 }
248 
coff_make_section(char * name,uint32_t flags)249 int coff_make_section(char *name, uint32_t flags)
250 {
251     struct coff_Section *s;
252     size_t namelen;
253 
254     s = nasm_zalloc(sizeof(*s));
255 
256     if (flags != BSS_FLAGS)
257         s->data = saa_init(1);
258     s->tail = &s->head;
259     if (!strcmp(name, ".text"))
260         s->index = def_seg;
261     else
262         s->index = seg_alloc();
263     s->namepos = -1;
264     namelen = strlen(name);
265     if (namelen > 8) {
266         if (win32 || win64) {
267             s->namepos = strslen + 4;
268             saa_wbytes(coff_strs, name, namelen + 1);
269             strslen += namelen + 1;
270         } else {
271             namelen = 8;
272         }
273     }
274     s->name = nasm_malloc(namelen + 1);
275     strncpy(s->name, name, namelen);
276     s->name[namelen] = '\0';
277     s->flags = flags;
278 
279     if (coff_nsects >= sectlen) {
280         sectlen += SECT_DELTA;
281         coff_sects = nasm_realloc(coff_sects, sectlen * sizeof(*coff_sects));
282     }
283     coff_sects[coff_nsects++] = s;
284 
285     return coff_nsects - 1;
286 }
287 
288 /*
289  * Convert an alignment value to the corresponding flags.
290  * An alignment value of 0 means no flags should be set.
291  */
coff_sectalign_flags(unsigned int align)292 static inline uint32_t coff_sectalign_flags(unsigned int align)
293 {
294     return (alignlog2_32(align) + 1) << 20;
295 }
296 
297 /*
298  * Get the alignment value from a flags field.
299  * Returns 0 if no alignment defined.
300  */
coff_alignment(uint32_t flags)301 static inline unsigned int coff_alignment(uint32_t flags)
302 {
303     return (1U << ((flags & IMAGE_SCN_ALIGN_MASK) >> 20)) >> 1;
304 }
305 
coff_section_names(char * name,int * bits)306 static int32_t coff_section_names(char *name, int *bits)
307 {
308     char *p;
309     uint32_t flags, align_flags;
310     int i;
311 
312     /*
313      * Set default bits.
314      */
315     if (!name) {
316         if(win64)
317             *bits = 64;
318         else
319             *bits = 32;
320 
321         return def_seg;
322     }
323 
324     p = name;
325     while (*p && !nasm_isspace(*p))
326         p++;
327     if (*p)
328         *p++ = '\0';
329     if (strlen(name) > 8) {
330         if (!win32 && !win64) {
331             nasm_warn(WARN_OTHER, "COFF section names limited to 8 characters:  truncating");
332             name[8] = '\0';
333         }
334     }
335     flags = align_flags = 0;
336 
337     while (*p && nasm_isspace(*p))
338         p++;
339     while (*p) {
340         char *q = p;
341         while (*p && !nasm_isspace(*p))
342             p++;
343         if (*p)
344             *p++ = '\0';
345         while (*p && nasm_isspace(*p))
346             p++;
347 
348         if (!nasm_stricmp(q, "code") || !nasm_stricmp(q, "text")) {
349             flags = TEXT_FLAGS;
350         } else if (!nasm_stricmp(q, "data")) {
351             flags = DATA_FLAGS;
352         } else if (!nasm_stricmp(q, "rdata")) {
353             if (win32 | win64)
354                 flags = RDATA_FLAGS;
355             else {
356                 flags = DATA_FLAGS;     /* gotta do something */
357                 nasm_nonfatal("standard COFF does not support"
358                               " read-only data sections");
359             }
360         } else if (!nasm_stricmp(q, "bss")) {
361             flags = BSS_FLAGS;
362         } else if (!nasm_stricmp(q, "info")) {
363             if (win32 | win64)
364                 flags = INFO_FLAGS;
365             else {
366                 flags = DATA_FLAGS;     /* gotta do something */
367                 nasm_nonfatal("standard COFF does not support"
368                               " informational sections");
369             }
370         } else if (!nasm_strnicmp(q, "align=", 6)) {
371             if (q[6 + strspn(q + 6, "0123456789")])
372                 nasm_nonfatal("argument to `align' is not numeric");
373             else {
374                 unsigned int align = atoi(q + 6);
375                 /* Allow align=0 meaning use default */
376                 if (!align) {
377                     align_flags = 0;
378                 } else if (!is_power2(align)) {
379                     nasm_nonfatal("argument to `align' is not a"
380                                   " power of two");
381                 } else if (align > COFF_MAX_ALIGNMENT) {
382                     nasm_nonfatal("maximum alignment in COFF is %d bytes",
383                                   COFF_MAX_ALIGNMENT);
384                 } else {
385                     align_flags = coff_sectalign_flags(align);
386                 }
387             }
388         }
389     }
390 
391     for (i = 0; i < coff_nsects; i++)
392         if (!strcmp(name, coff_sects[i]->name))
393             break;
394     if (i == coff_nsects) {
395         if (!flags) {
396             flags = TEXT_FLAGS;
397 
398             if (!strcmp(name, ".data")) {
399                 flags = DATA_FLAGS;
400             } else if (!strcmp(name, ".rdata")) {
401                 flags = RDATA_FLAGS;
402             } else if (!strcmp(name, ".bss")) {
403                 flags = BSS_FLAGS;
404             } else if (win64) {
405                 if (!strcmp(name, ".pdata"))
406                     flags = PDATA_FLAGS;
407                 else if (!strcmp(name, ".xdata"))
408                     flags = XDATA_FLAGS;
409             }
410         }
411         i = coff_make_section(name, flags);
412         coff_sects[i]->align_flags = align_flags;
413     } else {
414         if (flags) {
415             /* Warn if non-alignment flags differ */
416             if (((flags ^ coff_sects[i]->flags) & ~IMAGE_SCN_ALIGN_MASK) &&
417                 coff_sects[i]->pass_last_seen == pass_count()) {
418                 nasm_warn(WARN_OTHER, "section attributes changed on"
419                           " redeclaration of section `%s'", name);
420             }
421         }
422 
423         /* Check if alignment might be needed */
424         if (align_flags) {
425             uint32_t sect_align_flags = coff_sects[i]->align_flags;
426 
427             /* Compute the actual alignment */
428             unsigned int align = coff_alignment(align_flags);
429 
430             /* Update section header as needed */
431             if (align_flags > sect_align_flags) {
432                 coff_sects[i]->align_flags = align_flags;
433             }
434 
435             /* Check if not already aligned */
436             /* XXX: other formats don't do this... */
437             if (coff_sects[i]->len % align) {
438                 unsigned int padding = (align - coff_sects[i]->len) % align;
439                 /* We need to write at most 8095 bytes */
440                 char         buffer[8095];
441 
442                 nasm_assert(padding <= sizeof buffer);
443 
444                 if (coff_sects[i]->flags & IMAGE_SCN_CNT_CODE) {
445                     /* Fill with INT 3 instructions */
446                     memset(buffer, 0xCC, padding);
447                 } else {
448                     memset(buffer, 0x00, padding);
449                 }
450                 saa_wbytes(coff_sects[i]->data, buffer, padding);
451                 coff_sects[i]->len += padding;
452             }
453         }
454     }
455 
456     coff_sects[i]->pass_last_seen = pass_count();
457     return coff_sects[i]->index;
458 }
459 
coff_deflabel(char * name,int32_t segment,int64_t offset,int is_global,char * special)460 static void coff_deflabel(char *name, int32_t segment, int64_t offset,
461                           int is_global, char *special)
462 {
463     int pos = strslen + 4;
464     struct coff_Symbol *sym;
465 
466     if (special)
467         nasm_nonfatal("COFF format does not support any"
468                       " special symbol types");
469 
470     if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
471         if (strcmp(name,WRT_IMAGEBASE))
472             nasm_nonfatal("unrecognized special symbol `%s'", name);
473         return;
474     }
475 
476     if (strlen(name) > 8) {
477         size_t nlen = strlen(name)+1;
478         saa_wbytes(coff_strs, name, nlen);
479         strslen += nlen;
480     } else
481         pos = -1;
482 
483     sym = saa_wstruct(coff_syms);
484 
485     sym->strpos = pos;
486     sym->namlen = strlen(name);
487     if (pos == -1)
488         strcpy(sym->name, name);
489     sym->is_global = !!is_global;
490     sym->type = 0;              /* Default to T_NULL (no type) */
491     if (segment == NO_SEG)
492         sym->section = -1;      /* absolute symbol */
493     else {
494         int i;
495         sym->section = 0;
496         for (i = 0; i < coff_nsects; i++)
497             if (segment == coff_sects[i]->index) {
498                 sym->section = i + 1;
499                 break;
500             }
501         if (!sym->section)
502             sym->is_global = true;
503     }
504     if (is_global == 2)
505         sym->value = offset;
506     else
507         sym->value = (sym->section == 0 ? 0 : offset);
508 
509     /*
510      * define the references from external-symbol segment numbers
511      * to these symbol records.
512      */
513     if (sym->section == 0)
514         bsym = raa_write(bsym, segment, coff_nsyms);
515 
516     if (segment != NO_SEG)
517         symval = raa_write(symval, segment, sym->section ? 0 : sym->value);
518 
519     coff_nsyms++;
520 }
521 
coff_add_reloc(struct coff_Section * sect,int32_t segment,int16_t type)522 static int32_t coff_add_reloc(struct coff_Section *sect, int32_t segment,
523                               int16_t type)
524 {
525     struct coff_Reloc *r;
526 
527     r = *sect->tail = nasm_malloc(sizeof(struct coff_Reloc));
528     sect->tail = &r->next;
529     r->next = NULL;
530 
531     r->address = sect->len;
532     if (segment == NO_SEG) {
533         r->symbol = 0, r->symbase = ABS_SYMBOL;
534     } else {
535         int i;
536         r->symbase = REAL_SYMBOLS;
537         for (i = 0; i < coff_nsects; i++) {
538             if (segment == coff_sects[i]->index) {
539                 r->symbol = i * 2;
540                 r->symbase = SECT_SYMBOLS;
541                 break;
542             }
543         }
544         if (r->symbase == REAL_SYMBOLS)
545             r->symbol = raa_read(bsym, segment);
546     }
547     r->type = type;
548 
549     sect->nrelocs++;
550 
551     /*
552      * Return the fixup for standard COFF common variables.
553      */
554     if (r->symbase == REAL_SYMBOLS && !(win32 | win64))
555         return raa_read(symval, segment);
556 
557     return 0;
558 }
559 
coff_out(int32_t segto,const void * data,enum out_type type,uint64_t size,int32_t segment,int32_t wrt)560 static void coff_out(int32_t segto, const void *data,
561                      enum out_type type, uint64_t size,
562                      int32_t segment, int32_t wrt)
563 {
564     struct coff_Section *s;
565     uint8_t mydata[8], *p;
566     int i;
567 
568     if (wrt != NO_SEG && !win64) {
569         wrt = NO_SEG;           /* continue to do _something_ */
570         nasm_nonfatal("WRT not supported by COFF output formats");
571     }
572 
573     s = NULL;
574     for (i = 0; i < coff_nsects; i++) {
575         if (segto == coff_sects[i]->index) {
576             s = coff_sects[i];
577             break;
578         }
579     }
580     if (!s) {
581         int tempint;            /* ignored */
582         if (segto != coff_section_names(".text", &tempint))
583             nasm_panic("strange segment conditions in COFF driver");
584         else
585             s = coff_sects[coff_nsects - 1];
586     }
587 
588     /* magically default to 'wrt ..imagebase' in .pdata and .xdata */
589     if (win64 && wrt == NO_SEG) {
590         if (!strcmp(s->name,".pdata") || !strcmp(s->name,".xdata"))
591             wrt = imagebase_sect;
592     }
593 
594     if (!s->data && type != OUT_RESERVE) {
595         nasm_warn(WARN_OTHER, "attempt to initialize memory in"
596                   " BSS section `%s': ignored", s->name);
597         s->len += realsize(type, size);
598         return;
599     }
600 
601     memset(mydata, 0, sizeof(mydata));
602 
603     if (dfmt && dfmt->debug_output) {
604         struct coff_DebugInfo dinfo;
605         dinfo.segto = segto;
606         dinfo.seg = segment;
607         dinfo.section = s;
608 
609         if (type == OUT_ADDRESS)
610             dinfo.size = abs((int)size);
611         else
612             dinfo.size = realsize(type, size);
613 
614         dfmt->debug_output(type, &dinfo);
615     }
616 
617     if (type == OUT_RESERVE) {
618         if (s->data) {
619             nasm_warn(WARN_ZEROING, "uninitialised space declared in"
620                       " non-BSS section `%s': zeroing", s->name);
621             coff_sect_write(s, NULL, size);
622         } else
623             s->len += size;
624     } else if (type == OUT_RAWDATA) {
625         coff_sect_write(s, data, size);
626     } else if (type == OUT_ADDRESS) {
627         int asize = abs((int)size);
628         if (!win64) {
629             if (asize != 4 && (segment != NO_SEG || wrt != NO_SEG)) {
630                 nasm_nonfatal("COFF format does not support non-32-bit"
631                               " relocations");
632             } else {
633                 int32_t fix = 0;
634                 if (segment != NO_SEG || wrt != NO_SEG) {
635                     if (wrt != NO_SEG) {
636                         nasm_nonfatal("COFF format does not support WRT types");
637                     } else if (segment % 2) {
638                         nasm_nonfatal("COFF format does not support"
639                                       " segment base references");
640                     } else
641                         fix = coff_add_reloc(s, segment, IMAGE_REL_I386_DIR32);
642                 }
643                 p = mydata;
644                 WRITELONG(p, *(int64_t *)data + fix);
645                 coff_sect_write(s, mydata, asize);
646             }
647         } else {
648             int32_t fix = 0;
649             p = mydata;
650             if (asize == 8) {
651                 if (wrt == imagebase_sect) {
652                     nasm_nonfatal("operand size mismatch: 'wrt "
653                                   WRT_IMAGEBASE "' is a 32-bit operand");
654                 }
655                 fix = coff_add_reloc(s, segment, IMAGE_REL_AMD64_ADDR64);
656                 WRITEDLONG(p, *(int64_t *)data + fix);
657                 coff_sect_write(s, mydata, asize);
658             } else {
659                 fix = coff_add_reloc(s, segment,
660                         wrt == imagebase_sect ?	IMAGE_REL_AMD64_ADDR32NB:
661                                                 IMAGE_REL_AMD64_ADDR32);
662                 WRITELONG(p, *(int64_t *)data + fix);
663                 coff_sect_write(s, mydata, asize);
664             }
665         }
666     } else if (type == OUT_REL2ADR) {
667         nasm_nonfatal("COFF format does not support 16-bit relocations");
668     } else if (type == OUT_REL4ADR) {
669         if (segment == segto && !(win64))  /* Acceptable for RIP-relative */
670             nasm_panic("intra-segment OUT_REL4ADR");
671         else if (segment == NO_SEG && win32)
672             nasm_nonfatal("Win32 COFF does not correctly support"
673                           " relative references to absolute addresses");
674         else {
675             int32_t fix = 0;
676             if (segment != NO_SEG && segment % 2) {
677                 nasm_nonfatal("COFF format does not support"
678                               " segment base references");
679             } else
680                 fix = coff_add_reloc(s, segment,
681                         win64 ? IMAGE_REL_AMD64_REL32 : IMAGE_REL_I386_REL32);
682             p = mydata;
683             if (win32 | win64) {
684                 WRITELONG(p, *(int64_t *)data + 4 - size + fix);
685             } else {
686                 WRITELONG(p, *(int64_t *)data - (size + s->len) + fix);
687             }
688             coff_sect_write(s, mydata, 4L);
689         }
690 
691     }
692 }
693 
coff_sect_write(struct coff_Section * sect,const uint8_t * data,uint32_t len)694 static void coff_sect_write(struct coff_Section *sect,
695                             const uint8_t *data, uint32_t len)
696 {
697     saa_wbytes(sect->data, data, len);
698     sect->len += len;
699 }
700 
701 typedef struct tagString {
702     struct tagString *next;
703     int len;
704     char *String;
705 } STRING;
706 
707 #define EXPORT_SECTION_NAME ".drectve"
708 #define EXPORT_SECTION_FLAGS INFO_FLAGS
709 /*
710  * #define EXPORT_SECTION_NAME ".text"
711  * #define EXPORT_SECTION_FLAGS TEXT_FLAGS
712  */
713 
714 static STRING *Exports = NULL;
715 static struct coff_Section *directive_sec;
AddExport(char * name)716 static void AddExport(char *name)
717 {
718     STRING *rvp = Exports, *newS;
719 
720     newS = (STRING *) nasm_malloc(sizeof(STRING));
721     newS->len = strlen(name);
722     newS->next = NULL;
723     newS->String = (char *)nasm_malloc(newS->len + 1);
724     strcpy(newS->String, name);
725     if (rvp == NULL) {
726         int i;
727 
728         for (i = 0; i < coff_nsects; i++) {
729             if (!strcmp(EXPORT_SECTION_NAME, coff_sects[i]->name))
730                 break;
731         }
732 
733         if (i == coff_nsects)
734             i = coff_make_section(EXPORT_SECTION_NAME, EXPORT_SECTION_FLAGS);
735 
736         directive_sec = coff_sects[i];
737         Exports = newS;
738     } else {
739         while (rvp->next) {
740             if (!strcmp(rvp->String, name))
741                 return;
742             rvp = rvp->next;
743         }
744         rvp->next = newS;
745     }
746 }
747 
BuildExportTable(STRING ** rvp)748 static void BuildExportTable(STRING **rvp)
749 {
750     STRING *p, *t;
751 
752     if (!rvp || !*rvp)
753         return;
754 
755     list_for_each_safe(p, t, *rvp) {
756         coff_sect_write(directive_sec, (uint8_t *)"-export:", 8);
757         coff_sect_write(directive_sec, (uint8_t *)p->String, p->len);
758         coff_sect_write(directive_sec, (uint8_t *)" ", 1);
759         nasm_free(p->String);
760         nasm_free(p);
761     }
762 
763     *rvp = NULL;
764 }
765 
766 static enum directive_result
coff_directives(enum directive directive,char * value)767 coff_directives(enum directive directive, char *value)
768 {
769     switch (directive) {
770     case D_EXPORT:
771     {
772         char *q, *name;
773 
774         /*
775          * XXX: pass_first() is really wrong here, but AddExport()
776          * needs to be modified to handle duplicate calls for the
777          * same value in order to change that. The right thing to do
778          * is probably to mark a label as an export in the label
779          * structure, in case the label doesn't actually exist.
780          */
781         if (!pass_first())
782             return DIRR_OK;           /* ignore in pass two */
783         name = q = value;
784         while (*q && !nasm_isspace(*q))
785             q++;
786         if (nasm_isspace(*q)) {
787             *q++ = '\0';
788             while (*q && nasm_isspace(*q))
789                 q++;
790         }
791 
792         if (!*name) {
793             nasm_nonfatal("`export' directive requires export name");
794             return DIRR_ERROR;
795         }
796         if (*q) {
797             nasm_nonfatal("unrecognized export qualifier `%s'", q);
798             return DIRR_ERROR;
799         }
800         AddExport(name);
801         return DIRR_OK;
802     }
803     case D_SAFESEH:
804     {
805         static int sxseg=-1;
806         int i;
807 
808         if (!win32) /* Only applicable for -f win32 */
809             return 0;
810 
811         if (sxseg == -1) {
812             for (i = 0; i < coff_nsects; i++)
813                 if (!strcmp(".sxdata",coff_sects[i]->name))
814                     break;
815             if (i == coff_nsects)
816                 sxseg = coff_make_section(".sxdata", IMAGE_SCN_LNK_INFO);
817             else
818                 sxseg = i;
819         }
820         /*
821          * pass_final() is the only time when the full set of symbols are
822          * guaranteed to be present as it is the final output pass.
823          */
824         if (pass_final()) {
825             uint32_t n;
826             saa_rewind(coff_syms);
827             for (n = 0; n < coff_nsyms; n++) {
828                 struct coff_Symbol *sym = saa_rstruct(coff_syms);
829                 bool equals;
830 
831                 /*
832                  * sym->strpos is biased by 4, because symbol
833                  * table is prefixed with table length
834                  */
835                 if (sym->strpos >=4) {
836                     char *name = nasm_malloc(sym->namlen+1);
837                     saa_fread(coff_strs, sym->strpos-4, name, sym->namlen);
838                     name[sym->namlen] = '\0';
839                     equals = !strcmp(value,name);
840                     nasm_free(name);
841                 } else {
842                     equals = !strcmp(value,sym->name);
843                 }
844 
845                 if (equals) {
846                     /*
847                      * this value arithmetics effectively reflects
848                      * initsym in coff_write(): 2 for file, 1 for
849                      * .absolute and two per each section
850                      */
851                     unsigned char value[4],*p=value;
852                     WRITELONG(p,n + 2 + 1 + coff_nsects*2);
853                     coff_sect_write(coff_sects[sxseg],value,4);
854                     sym->type = 0x20;
855                     break;
856                 }
857             }
858             if (n == coff_nsyms) {
859                 nasm_nonfatal("`safeseh' directive requires valid symbol");
860                 return DIRR_ERROR;
861             }
862         }
863         return DIRR_OK;
864     }
865     default:
866         return DIRR_UNKNOWN;
867     }
868 }
869 
870 /* handle relocations storm, valid for win32/64 only */
coff_adjust_relocs(struct coff_Section * s)871 static inline void coff_adjust_relocs(struct coff_Section *s)
872 {
873     if (s->nrelocs < IMAGE_SCN_MAX_RELOC)
874         return;
875 #ifdef OF_COFF
876     else
877     {
878         if (ofmt == &of_coff)
879             nasm_fatal("Too many relocations (%d) for section `%s'",
880                        s->nrelocs, s->name);
881     }
882 #endif
883 
884     s->flags |= IMAGE_SCN_LNK_NRELOC_OVFL;
885     s->nrelocs++;
886 }
887 
888 /*
889  * Make sure we satisfy all section alignment requirements and put the
890  * resulting alignment flags into the flags value in the header.  If
891  * no user-specified alignment is given, use the default for the
892  * section type; then either way round up to alignment specified by
893  * sectalign directives.
894  */
coff_adjust_alignment(struct coff_Section * s)895 static inline void coff_adjust_alignment(struct coff_Section *s)
896 {
897     uint32_t align_flags = s->align_flags;
898 
899     if (!align_flags) {
900         /* No user-specified alignment, use default for partition type */
901         align_flags = s->flags & IMAGE_SCN_ALIGN_MASK;
902     }
903 
904     if (align_flags < s->sectalign_flags)
905         align_flags = s->sectalign_flags;
906 
907     s->flags = (s->flags & ~IMAGE_SCN_ALIGN_MASK) | align_flags;
908 }
909 
coff_write(void)910 static void coff_write(void)
911 {
912     int32_t pos, sympos, vsize;
913     int i;
914 
915     /* fill in the .drectve section with -export's */
916     BuildExportTable(&Exports);
917 
918     if (win32) {
919         /* add default value for @feat.00, this allows to 'link /safeseh' */
920         uint32_t n;
921 
922         saa_rewind(coff_syms);
923         for (n = 0; n < coff_nsyms; n++) {
924             struct coff_Symbol *sym = saa_rstruct(coff_syms);
925             if (sym->strpos == -1 && !strcmp("@feat.00",sym->name))
926                 break;
927         }
928         if (n == coff_nsyms)
929             coff_deflabel("@feat.00", NO_SEG, 1, 0, NULL);
930     }
931 
932     /*
933      * Work out how big the file will get.
934      * Calculate the start of the `real' symbols at the same time.
935      * Check for massive relocations.
936      */
937     pos = 0x14 + 0x28 * coff_nsects;
938     initsym = 3;                /* two for the file, one absolute */
939     for (i = 0; i < coff_nsects; i++) {
940         coff_adjust_alignment(coff_sects[i]);
941         if (coff_sects[i]->data) {
942             coff_adjust_relocs(coff_sects[i]);
943             coff_sects[i]->pos = pos;
944             pos += coff_sects[i]->len;
945             coff_sects[i]->relpos = pos;
946             pos += 10 * coff_sects[i]->nrelocs;
947         } else
948             coff_sects[i]->pos = coff_sects[i]->relpos = 0L;
949         initsym += 2;           /* two for each section */
950     }
951     sympos = pos;
952 
953     /*
954      * Output the COFF header.
955      */
956     if (win64)
957         i = IMAGE_FILE_MACHINE_AMD64;
958     else
959         i = IMAGE_FILE_MACHINE_I386;
960     fwriteint16_t(i,                    ofile); /* machine type */
961     fwriteint16_t(coff_nsects,               ofile); /* number of sections */
962     // Chromium patch: Builds should be deterministic and not embed timestamps.
963     fwriteint32_t(0,                    ofile); /* time stamp */
964     fwriteint32_t(sympos,               ofile);
965     fwriteint32_t(coff_nsyms + initsym,      ofile);
966     fwriteint16_t(0,                    ofile); /* no optional header */
967     /* Flags: 32-bit, no line numbers. Win32 doesn't even bother with them. */
968     fwriteint16_t((win32 | win64) ? 0 : 0x104, ofile);
969 
970     /*
971      * Output the section headers.
972      */
973     vsize = 0L;
974     for (i = 0; i < coff_nsects; i++) {
975         coff_section_header(coff_sects[i]->name, coff_sects[i]->namepos, vsize, coff_sects[i]->len,
976                             coff_sects[i]->pos, coff_sects[i]->relpos,
977                             coff_sects[i]->nrelocs, coff_sects[i]->flags);
978         vsize += coff_sects[i]->len;
979     }
980 
981     /*
982      * Output the sections and their relocations.
983      */
984     for (i = 0; i < coff_nsects; i++)
985         if (coff_sects[i]->data) {
986             saa_fpwrite(coff_sects[i]->data, ofile);
987             coff_write_relocs(coff_sects[i]);
988         }
989 
990     /*
991      * Output the symbol and string tables.
992      */
993     coff_write_symbols();
994     fwriteint32_t(strslen + 4, ofile);     /* length includes length count */
995     saa_fpwrite(coff_strs, ofile);
996 }
997 
coff_section_header(char * name,int32_t namepos,int32_t vsize,int32_t datalen,int32_t datapos,int32_t relpos,int nrelocs,int32_t flags)998 static void coff_section_header(char *name, int32_t namepos, int32_t vsize,
999                                 int32_t datalen, int32_t datapos,
1000                                 int32_t relpos, int nrelocs, int32_t flags)
1001 {
1002     char padname[8];
1003 
1004     (void)vsize;
1005 
1006     if (namepos == -1) {
1007         strncpy(padname, name, 8);
1008         nasm_write(padname, 8, ofile);
1009     } else {
1010         /*
1011          * If name is longer than 8 bytes, write '/' followed
1012          * by offset into the strings table represented as
1013          * decimal number.
1014          */
1015         namepos = namepos % 100000000;
1016         padname[0] = '/';
1017         padname[1] = '0' + (namepos / 1000000);
1018         namepos = namepos % 1000000;
1019         padname[2] = '0' + (namepos / 100000);
1020         namepos = namepos % 100000;
1021         padname[3] = '0' + (namepos / 10000);
1022         namepos = namepos % 10000;
1023         padname[4] = '0' + (namepos / 1000);
1024         namepos = namepos % 1000;
1025         padname[5] = '0' + (namepos / 100);
1026         namepos = namepos % 100;
1027         padname[6] = '0' + (namepos / 10);
1028         namepos = namepos % 10;
1029         padname[7] = '0' + (namepos);
1030         nasm_write(padname, 8, ofile);
1031     }
1032 
1033     fwriteint32_t(0,            ofile); /* Virtual size field - set to 0 or vsize */
1034     fwriteint32_t(0L,           ofile); /* RVA/offset - we ignore */
1035     fwriteint32_t(datalen,      ofile);
1036     fwriteint32_t(datapos,      ofile);
1037     fwriteint32_t(relpos,       ofile);
1038     fwriteint32_t(0L,           ofile); /* no line numbers - we don't do 'em */
1039 
1040     /*
1041      * a special case -- if there are too many relocs
1042      * we have to put IMAGE_SCN_MAX_RELOC here and write
1043      * the real relocs number into VirtualAddress of first
1044      * relocation
1045      */
1046     if (flags & IMAGE_SCN_LNK_NRELOC_OVFL)
1047         fwriteint16_t(IMAGE_SCN_MAX_RELOC, ofile);
1048     else
1049         fwriteint16_t(nrelocs,  ofile);
1050 
1051     fwriteint16_t(0,            ofile); /* again, no line numbers */
1052     fwriteint32_t(flags,        ofile);
1053 }
1054 
coff_write_relocs(struct coff_Section * s)1055 static void coff_write_relocs(struct coff_Section *s)
1056 {
1057     struct coff_Reloc *r;
1058 
1059     /* a real number of relocations if needed */
1060     if (s->flags & IMAGE_SCN_LNK_NRELOC_OVFL) {
1061         fwriteint32_t(s->nrelocs, ofile);
1062         fwriteint32_t(0, ofile);
1063         fwriteint16_t(0, ofile);
1064     }
1065 
1066     for (r = s->head; r; r = r->next) {
1067         fwriteint32_t(r->address, ofile);
1068         fwriteint32_t(r->symbol + (r->symbase == REAL_SYMBOLS ? initsym :
1069                                    r->symbase == ABS_SYMBOL   ? initsym - 1 :
1070                                    r->symbase == SECT_SYMBOLS ? 2 : 0),
1071                       ofile);
1072         fwriteint16_t(r->type, ofile);
1073     }
1074 }
1075 
coff_symbol(char * name,int32_t strpos,int32_t value,int section,int type,int storageclass,int aux)1076 static void coff_symbol(char *name, int32_t strpos, int32_t value,
1077                         int section, int type, int storageclass, int aux)
1078 {
1079     char padname[8];
1080 
1081     if (name) {
1082         strncpy(padname, name, 8);
1083         nasm_write(padname, 8, ofile);
1084     } else {
1085         fwriteint32_t(0, ofile);
1086         fwriteint32_t(strpos, ofile);
1087     }
1088 
1089     fwriteint32_t(value,        ofile);
1090     fwriteint16_t(section,      ofile);
1091     fwriteint16_t(type,         ofile);
1092 
1093     fputc(storageclass, ofile);
1094     fputc(aux, ofile);
1095 }
1096 
coff_write_symbols(void)1097 static void coff_write_symbols(void)
1098 {
1099     char filename[18];
1100     uint32_t i;
1101 
1102     /*
1103      * The `.file' record, and the file name auxiliary record.
1104      */
1105     coff_symbol(".file", 0L, 0L, -2, 0, 0x67, 1);
1106     strncpy(filename, inname, 18);
1107     nasm_write(filename, 18, ofile);
1108 
1109     /*
1110      * The section records, with their auxiliaries.
1111      */
1112     memset(filename, 0, 18);    /* useful zeroed buffer */
1113 
1114     for (i = 0; i < (uint32_t) coff_nsects; i++) {
1115         coff_symbol(coff_sects[i]->name, 0L, 0L, i + 1, 0, 3, 1);
1116         fwriteint32_t(coff_sects[i]->len,    ofile);
1117         fwriteint16_t(coff_sects[i]->nrelocs,ofile);
1118         nasm_write(filename, 12, ofile);
1119     }
1120 
1121     /*
1122      * The absolute symbol, for relative-to-absolute relocations.
1123      */
1124     coff_symbol(".absolut", 0L, 0L, -1, 0, 3, 0);
1125 
1126     /*
1127      * The real symbols.
1128      */
1129     saa_rewind(coff_syms);
1130     for (i = 0; i < coff_nsyms; i++) {
1131         struct coff_Symbol *sym = saa_rstruct(coff_syms);
1132         coff_symbol(sym->strpos == -1 ? sym->name : NULL,
1133                     sym->strpos, sym->value, sym->section,
1134                     sym->type, sym->is_global ? 2 : 3, 0);
1135     }
1136 }
1137 
coff_sectalign(int32_t seg,unsigned int value)1138 static void coff_sectalign(int32_t seg, unsigned int value)
1139 {
1140     struct coff_Section *s = NULL;
1141     uint32_t flags;
1142     int i;
1143 
1144     for (i = 0; i < coff_nsects; i++) {
1145         if (coff_sects[i]->index == seg) {
1146             s = coff_sects[i];
1147             break;
1148         }
1149     }
1150 
1151     if (!s || !is_power2(value))
1152         return;
1153 
1154     if (value > COFF_MAX_ALIGNMENT)
1155         value = COFF_MAX_ALIGNMENT; /* Do our best... */
1156 
1157     flags = coff_sectalign_flags(value);
1158     if (flags > s->sectalign_flags)
1159         s->sectalign_flags = flags;
1160 }
1161 
1162 extern macros_t coff_stdmac[];
1163 
1164 #endif /* defined(OF_COFF) || defined(OF_WIN32) */
1165 
1166 #ifdef OF_COFF
1167 
1168 static const struct pragma_facility coff_pragma_list[] = {
1169     { "coff", NULL },
1170     { NULL,   NULL }
1171 };
1172 
1173 const struct ofmt of_coff = {
1174     "COFF (i386) (DJGPP, some Unix variants)",
1175     "coff",
1176     ".o",
1177     0,
1178     32,
1179     null_debug_arr,
1180     &null_debug_form,
1181     coff_stdmac,
1182     coff_std_init,
1183     null_reset,
1184     nasm_do_legacy_output,
1185     coff_out,
1186     coff_deflabel,
1187     coff_section_names,
1188     NULL,
1189     coff_sectalign,
1190     null_segbase,
1191     coff_directives,
1192     coff_cleanup,
1193     coff_pragma_list
1194 };
1195 
1196 #endif
1197 
1198 
1199 #ifdef OF_WIN32
1200 
1201 static const struct pragma_facility coff_win_pragma_list[] = {
1202     { "win",  NULL },
1203     { "coff", NULL },
1204     { NULL,   NULL }
1205 };
1206 
1207 extern const struct dfmt df_cv8;
1208 static const struct dfmt * const win32_debug_arr[2] = { &df_cv8, NULL };
1209 
1210 const struct ofmt of_win32 = {
1211     "Microsoft extended COFF for Win32 (i386)",
1212     "win32",
1213     ".obj",
1214     0,
1215     32,
1216     win32_debug_arr,
1217     &df_cv8,
1218     coff_stdmac,
1219     coff_win32_init,
1220     null_reset,
1221     nasm_do_legacy_output,
1222     coff_out,
1223     coff_deflabel,
1224     coff_section_names,
1225     NULL,
1226     coff_sectalign,
1227     null_segbase,
1228     coff_directives,
1229     coff_cleanup,
1230     coff_win_pragma_list
1231 };
1232 
1233 #endif
1234 
1235 #ifdef OF_WIN64
1236 
1237 static const struct dfmt * const win64_debug_arr[2] = { &df_cv8, NULL };
1238 
1239 const struct ofmt of_win64 = {
1240     "Microsoft extended COFF for Win64 (x86-64)",
1241     "win64",
1242     ".obj",
1243     0,
1244     64,
1245     win64_debug_arr,
1246     &df_cv8,
1247     coff_stdmac,
1248     coff_win64_init,
1249     null_reset,
1250     nasm_do_legacy_output,
1251     coff_out,
1252     coff_deflabel,
1253     coff_section_names,
1254     NULL,
1255     coff_sectalign,
1256     null_segbase,
1257     coff_directives,
1258     coff_cleanup,
1259     coff_win_pragma_list
1260 };
1261 
1262 #endif
1263