1 /* ----------------------------------------------------------------------- *
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.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following
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.
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.
32 * ----------------------------------------------------------------------- */
35 * outcoff.c output routines for the Netwide Assembler to produce
36 * COFF object files (for DJGPP and Win32)
55 #if defined(OF_COFF) || defined(OF_WIN32) || defined(OF_WIN64)
60 * (0) When I say `standard COFF' below, I mean `COFF as output and
61 * used by DJGPP'. I assume DJGPP gets it right.
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.
72 * (2) Win32 doesn't bother putting any flags in the header flags
73 * field (at offset 0x12 into the file).
75 * (3) Win32 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 0x00700000 for
79 * section alignments of 1 through 64 bytes.
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.
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.
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.
100 /* Flag which version of COFF we are currently outputting. */
103 static int32_t imagebase_sect
;
104 #define WRT_IMAGEBASE "..imagebase"
107 * Some common section flags by default
109 #define TEXT_FLAGS_WIN \
110 (IMAGE_SCN_CNT_CODE | \
111 IMAGE_SCN_ALIGN_16BYTES | \
112 IMAGE_SCN_MEM_EXECUTE | \
114 #define TEXT_FLAGS_DOS \
117 #define DATA_FLAGS_WIN \
118 (IMAGE_SCN_CNT_INITIALIZED_DATA | \
119 IMAGE_SCN_ALIGN_4BYTES | \
120 IMAGE_SCN_MEM_READ | \
122 #define DATA_FLAGS_DOS \
123 (IMAGE_SCN_CNT_INITIALIZED_DATA)
125 #define BSS_FLAGS_WIN \
126 (IMAGE_SCN_CNT_UNINITIALIZED_DATA | \
127 IMAGE_SCN_ALIGN_4BYTES | \
128 IMAGE_SCN_MEM_READ | \
130 #define BSS_FLAGS_DOS \
131 (IMAGE_SCN_CNT_UNINITIALIZED_DATA)
133 #define RDATA_FLAGS_WIN \
134 (IMAGE_SCN_CNT_INITIALIZED_DATA | \
135 IMAGE_SCN_ALIGN_8BYTES | \
138 #define RDATA_FLAGS_DOS \
139 (IMAGE_SCN_CNT_INITIALIZED_DATA)
141 #define PDATA_FLAGS \
142 (IMAGE_SCN_CNT_INITIALIZED_DATA | \
143 IMAGE_SCN_ALIGN_4BYTES | \
146 #define XDATA_FLAGS \
147 (IMAGE_SCN_CNT_INITIALIZED_DATA | \
148 IMAGE_SCN_ALIGN_8BYTES | \
152 (IMAGE_SCN_ALIGN_1BYTES | \
153 IMAGE_SCN_LNK_INFO | \
154 IMAGE_SCN_LNK_REMOVE)
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)
161 #define SECT_DELTA 32
162 struct coff_Section
**coff_sects
;
166 struct SAA
*coff_syms
;
169 static int32_t def_seg
;
173 static struct RAA
*bsym
, *symval
;
175 struct SAA
*coff_strs
;
176 static uint32_t strslen
;
178 static void coff_gen_init(void);
179 static void coff_sect_write(struct coff_Section
*, const uint8_t *, uint32_t);
180 static void coff_write(void);
181 static void coff_section_header(char *, int32_t, int32_t, int32_t, int32_t, int32_t, int, int32_t);
182 static void coff_write_relocs(struct coff_Section
*);
183 static void coff_write_symbols(void);
185 static void coff_win32_init(void)
192 static void coff_win64_init(void)
197 imagebase_sect
= seg_alloc()+1;
198 backend_label(WRT_IMAGEBASE
, imagebase_sect
, 0);
201 static void coff_std_init(void)
203 win32
= win64
= false;
207 static void coff_gen_init(void)
211 coff_nsects
= sectlen
= 0;
212 coff_syms
= saa_init(sizeof(struct coff_Symbol
));
216 coff_strs
= saa_init(1);
218 def_seg
= seg_alloc();
221 static void coff_cleanup(void)
223 struct coff_Reloc
*r
;
229 for (i
= 0; i
< coff_nsects
; i
++) {
230 if (coff_sects
[i
]->data
)
231 saa_free(coff_sects
[i
]->data
);
232 while (coff_sects
[i
]->head
) {
233 r
= coff_sects
[i
]->head
;
234 coff_sects
[i
]->head
= coff_sects
[i
]->head
->next
;
237 nasm_free(coff_sects
[i
]->name
);
238 nasm_free(coff_sects
[i
]);
240 nasm_free(coff_sects
);
247 int coff_make_section(char *name
, uint32_t flags
)
249 struct coff_Section
*s
;
252 s
= nasm_zalloc(sizeof(*s
));
254 if (flags
!= BSS_FLAGS
)
255 s
->data
= saa_init(1);
257 if (!strcmp(name
, ".text"))
260 s
->index
= seg_alloc();
262 namelen
= strlen(name
);
264 if (win32
|| win64
) {
265 s
->namepos
= strslen
+ 4;
266 saa_wbytes(coff_strs
, name
, namelen
+ 1);
267 strslen
+= namelen
+ 1;
272 s
->name
= nasm_malloc(namelen
+ 1);
273 strncpy(s
->name
, name
, namelen
);
274 s
->name
[namelen
] = '\0';
277 if (coff_nsects
>= sectlen
) {
278 sectlen
+= SECT_DELTA
;
279 coff_sects
= nasm_realloc(coff_sects
, sectlen
* sizeof(*coff_sects
));
281 coff_sects
[coff_nsects
++] = s
;
283 return coff_nsects
- 1;
286 static inline int32_t coff_sectalign_flags(unsigned int align
)
288 return (ilog2_32(align
) + 1) << 20;
291 static int32_t coff_section_names(char *name
, int *bits
)
294 uint32_t flags
, align_and
= ~0L, align_or
= 0L;
310 while (*p
&& !nasm_isspace(*p
))
314 if (strlen(name
) > 8) {
315 if (!win32
&& !win64
) {
316 nasm_warn(WARN_OTHER
, "COFF section names limited to 8 characters: truncating");
322 while (*p
&& nasm_isspace(*p
))
326 while (*p
&& !nasm_isspace(*p
))
330 while (*p
&& nasm_isspace(*p
))
333 if (!nasm_stricmp(q
, "code") || !nasm_stricmp(q
, "text")) {
335 } else if (!nasm_stricmp(q
, "data")) {
337 } else if (!nasm_stricmp(q
, "rdata")) {
341 flags
= DATA_FLAGS
; /* gotta do something */
342 nasm_nonfatal("standard COFF does not support"
343 " read-only data sections");
345 } else if (!nasm_stricmp(q
, "bss")) {
347 } else if (!nasm_stricmp(q
, "info")) {
351 flags
= DATA_FLAGS
; /* gotta do something */
352 nasm_nonfatal("standard COFF does not support"
353 " informational sections");
355 } else if (!nasm_strnicmp(q
, "align=", 6)) {
356 if (!(win32
| win64
))
357 nasm_nonfatal("standard COFF does not support"
358 " section alignment specification");
360 if (q
[6 + strspn(q
+ 6, "0123456789")])
361 nasm_nonfatal("argument to `align' is not numeric");
363 unsigned int align
= atoi(q
+ 6);
364 if (!align
|| ((align
- 1) & align
))
365 nasm_nonfatal("argument to `align' is not a"
368 nasm_nonfatal("Win32 cannot align sections"
369 " to better than 64-byte boundaries");
371 align_and
= ~0x00F00000L
;
372 align_or
= coff_sectalign_flags(align
);
379 for (i
= 0; i
< coff_nsects
; i
++)
380 if (!strcmp(name
, coff_sects
[i
]->name
))
382 if (i
== coff_nsects
) {
384 if (!strcmp(name
, ".data"))
386 else if (!strcmp(name
, ".rdata"))
388 else if (!strcmp(name
, ".bss"))
390 else if (win64
&& !strcmp(name
, ".pdata"))
392 else if (win64
&& !strcmp(name
, ".xdata"))
397 i
= coff_make_section(name
, flags
);
399 coff_sects
[i
]->flags
= flags
;
400 coff_sects
[i
]->flags
&= align_and
;
401 coff_sects
[i
]->flags
|= align_or
;
403 /* Check if any flags are respecified */
404 unsigned int align_flags
= flags
& IMAGE_SCN_ALIGN_MASK
;
406 /* Warn if non-alignment flags differ */
407 if ((flags
^ coff_sects
[i
]->flags
) & ~IMAGE_SCN_ALIGN_MASK
&&
408 coff_sects
[i
]->pass_last_seen
== pass_count()) {
409 nasm_warn(WARN_OTHER
, "section attributes changed on"
410 " redeclaration of section `%s'", name
);
412 /* Check if alignment might be needed */
413 if (align_flags
> IMAGE_SCN_ALIGN_1BYTES
) {
414 unsigned int sect_align_flags
= coff_sects
[i
]->flags
& IMAGE_SCN_ALIGN_MASK
;
416 /* Compute the actual alignment */
417 unsigned int align
= 1u << ((align_flags
- IMAGE_SCN_ALIGN_1BYTES
) >> 20);
419 /* Update section header as needed */
420 if (align_flags
> sect_align_flags
) {
421 coff_sects
[i
]->flags
= (coff_sects
[i
]->flags
& ~IMAGE_SCN_ALIGN_MASK
) | align_flags
;
423 /* Check if not already aligned */
424 if (coff_sects
[i
]->len
% align
) {
425 unsigned int padding
= (align
- coff_sects
[i
]->len
) % align
;
426 /* We need to write at most 8095 bytes */
429 nasm_assert(padding
<= sizeof buffer
);
432 nasm_nonfatal("section alignment changed during code generation");
434 if (coff_sects
[i
]->flags
& IMAGE_SCN_CNT_CODE
) {
435 /* Fill with INT 3 instructions */
436 memset(buffer
, 0xCC, padding
);
438 memset(buffer
, 0x00, padding
);
440 saa_wbytes(coff_sects
[i
]->data
, buffer
, padding
);
441 coff_sects
[i
]->len
+= padding
;
446 coff_sects
[i
]->pass_last_seen
= pass_count();
447 return coff_sects
[i
]->index
;
450 static void coff_deflabel(char *name
, int32_t segment
, int64_t offset
,
451 int is_global
, char *special
)
453 int pos
= strslen
+ 4;
454 struct coff_Symbol
*sym
;
457 nasm_nonfatal("COFF format does not support any"
458 " special symbol types");
460 if (name
[0] == '.' && name
[1] == '.' && name
[2] != '@') {
461 if (strcmp(name
,WRT_IMAGEBASE
))
462 nasm_nonfatal("unrecognized special symbol `%s'", name
);
466 if (strlen(name
) > 8) {
467 size_t nlen
= strlen(name
)+1;
468 saa_wbytes(coff_strs
, name
, nlen
);
473 sym
= saa_wstruct(coff_syms
);
476 sym
->namlen
= strlen(name
);
478 strcpy(sym
->name
, name
);
479 sym
->is_global
= !!is_global
;
480 sym
->type
= 0; /* Default to T_NULL (no type) */
481 if (segment
== NO_SEG
)
482 sym
->section
= -1; /* absolute symbol */
486 for (i
= 0; i
< coff_nsects
; i
++)
487 if (segment
== coff_sects
[i
]->index
) {
488 sym
->section
= i
+ 1;
492 sym
->is_global
= true;
497 sym
->value
= (sym
->section
== 0 ? 0 : offset
);
500 * define the references from external-symbol segment numbers
501 * to these symbol records.
503 if (sym
->section
== 0)
504 bsym
= raa_write(bsym
, segment
, coff_nsyms
);
506 if (segment
!= NO_SEG
)
507 symval
= raa_write(symval
, segment
, sym
->section
? 0 : sym
->value
);
512 static int32_t coff_add_reloc(struct coff_Section
*sect
, int32_t segment
,
515 struct coff_Reloc
*r
;
517 r
= *sect
->tail
= nasm_malloc(sizeof(struct coff_Reloc
));
518 sect
->tail
= &r
->next
;
521 r
->address
= sect
->len
;
522 if (segment
== NO_SEG
) {
523 r
->symbol
= 0, r
->symbase
= ABS_SYMBOL
;
526 r
->symbase
= REAL_SYMBOLS
;
527 for (i
= 0; i
< coff_nsects
; i
++) {
528 if (segment
== coff_sects
[i
]->index
) {
530 r
->symbase
= SECT_SYMBOLS
;
534 if (r
->symbase
== REAL_SYMBOLS
)
535 r
->symbol
= raa_read(bsym
, segment
);
542 * Return the fixup for standard COFF common variables.
544 if (r
->symbase
== REAL_SYMBOLS
&& !(win32
| win64
))
545 return raa_read(symval
, segment
);
550 static void coff_out(int32_t segto
, const void *data
,
551 enum out_type type
, uint64_t size
,
552 int32_t segment
, int32_t wrt
)
554 struct coff_Section
*s
;
555 uint8_t mydata
[8], *p
;
558 if (wrt
!= NO_SEG
&& !win64
) {
559 wrt
= NO_SEG
; /* continue to do _something_ */
560 nasm_nonfatal("WRT not supported by COFF output formats");
564 for (i
= 0; i
< coff_nsects
; i
++) {
565 if (segto
== coff_sects
[i
]->index
) {
571 int tempint
; /* ignored */
572 if (segto
!= coff_section_names(".text", &tempint
))
573 nasm_panic("strange segment conditions in COFF driver");
575 s
= coff_sects
[coff_nsects
- 1];
578 /* magically default to 'wrt ..imagebase' in .pdata and .xdata */
579 if (win64
&& wrt
== NO_SEG
) {
580 if (!strcmp(s
->name
,".pdata") || !strcmp(s
->name
,".xdata"))
581 wrt
= imagebase_sect
;
584 if (!s
->data
&& type
!= OUT_RESERVE
) {
585 nasm_warn(WARN_OTHER
, "attempt to initialize memory in"
586 " BSS section `%s': ignored", s
->name
);
587 s
->len
+= realsize(type
, size
);
591 memset(mydata
, 0, sizeof(mydata
));
593 if (dfmt
&& dfmt
->debug_output
) {
594 struct coff_DebugInfo dinfo
;
599 if (type
== OUT_ADDRESS
)
600 dinfo
.size
= abs((int)size
);
602 dinfo
.size
= realsize(type
, size
);
604 dfmt
->debug_output(type
, &dinfo
);
607 if (type
== OUT_RESERVE
) {
609 nasm_warn(WARN_ZEROING
, "uninitialised space declared in"
610 " non-BSS section `%s': zeroing", s
->name
);
611 coff_sect_write(s
, NULL
, size
);
614 } else if (type
== OUT_RAWDATA
) {
615 coff_sect_write(s
, data
, size
);
616 } else if (type
== OUT_ADDRESS
) {
617 int asize
= abs((int)size
);
619 if (asize
!= 4 && (segment
!= NO_SEG
|| wrt
!= NO_SEG
)) {
620 nasm_nonfatal("COFF format does not support non-32-bit"
624 if (segment
!= NO_SEG
|| wrt
!= NO_SEG
) {
626 nasm_nonfatal("COFF format does not support WRT types");
627 } else if (segment
% 2) {
628 nasm_nonfatal("COFF format does not support"
629 " segment base references");
631 fix
= coff_add_reloc(s
, segment
, IMAGE_REL_I386_DIR32
);
634 WRITELONG(p
, *(int64_t *)data
+ fix
);
635 coff_sect_write(s
, mydata
, asize
);
641 if (wrt
== imagebase_sect
) {
642 nasm_nonfatal("operand size mismatch: 'wrt "
643 WRT_IMAGEBASE
"' is a 32-bit operand");
645 fix
= coff_add_reloc(s
, segment
, IMAGE_REL_AMD64_ADDR64
);
646 WRITEDLONG(p
, *(int64_t *)data
+ fix
);
647 coff_sect_write(s
, mydata
, asize
);
649 fix
= coff_add_reloc(s
, segment
,
650 wrt
== imagebase_sect
? IMAGE_REL_AMD64_ADDR32NB
:
651 IMAGE_REL_AMD64_ADDR32
);
652 WRITELONG(p
, *(int64_t *)data
+ fix
);
653 coff_sect_write(s
, mydata
, asize
);
656 } else if (type
== OUT_REL2ADR
) {
657 nasm_nonfatal("COFF format does not support 16-bit relocations");
658 } else if (type
== OUT_REL4ADR
) {
659 if (segment
== segto
&& !(win64
)) /* Acceptable for RIP-relative */
660 nasm_panic("intra-segment OUT_REL4ADR");
661 else if (segment
== NO_SEG
&& win32
)
662 nasm_nonfatal("Win32 COFF does not correctly support"
663 " relative references to absolute addresses");
666 if (segment
!= NO_SEG
&& segment
% 2) {
667 nasm_nonfatal("COFF format does not support"
668 " segment base references");
670 fix
= coff_add_reloc(s
, segment
,
671 win64
? IMAGE_REL_AMD64_REL32
: IMAGE_REL_I386_REL32
);
674 WRITELONG(p
, *(int64_t *)data
+ 4 - size
+ fix
);
676 WRITELONG(p
, *(int64_t *)data
- (size
+ s
->len
) + fix
);
678 coff_sect_write(s
, mydata
, 4L);
684 static void coff_sect_write(struct coff_Section
*sect
,
685 const uint8_t *data
, uint32_t len
)
687 saa_wbytes(sect
->data
, data
, len
);
691 typedef struct tagString
{
692 struct tagString
*next
;
697 #define EXPORT_SECTION_NAME ".drectve"
698 #define EXPORT_SECTION_FLAGS INFO_FLAGS
700 * #define EXPORT_SECTION_NAME ".text"
701 * #define EXPORT_SECTION_FLAGS TEXT_FLAGS
704 static STRING
*Exports
= NULL
;
705 static struct coff_Section
*directive_sec
;
706 static void AddExport(char *name
)
708 STRING
*rvp
= Exports
, *newS
;
710 newS
= (STRING
*) nasm_malloc(sizeof(STRING
));
711 newS
->len
= strlen(name
);
713 newS
->String
= (char *)nasm_malloc(newS
->len
+ 1);
714 strcpy(newS
->String
, name
);
718 for (i
= 0; i
< coff_nsects
; i
++) {
719 if (!strcmp(EXPORT_SECTION_NAME
, coff_sects
[i
]->name
))
723 if (i
== coff_nsects
)
724 i
= coff_make_section(EXPORT_SECTION_NAME
, EXPORT_SECTION_FLAGS
);
726 directive_sec
= coff_sects
[i
];
730 if (!strcmp(rvp
->String
, name
))
738 static void BuildExportTable(STRING
**rvp
)
745 list_for_each_safe(p
, t
, *rvp
) {
746 coff_sect_write(directive_sec
, (uint8_t *)"-export:", 8);
747 coff_sect_write(directive_sec
, (uint8_t *)p
->String
, p
->len
);
748 coff_sect_write(directive_sec
, (uint8_t *)" ", 1);
749 nasm_free(p
->String
);
756 static enum directive_result
757 coff_directives(enum directive directive
, char *value
)
765 * XXX: pass_first() is really wrong here, but AddExport()
766 * needs to be modified to handle duplicate calls for the
767 * same value in order to change that. The right thing to do
768 * is probably to mark a label as an export in the label
769 * structure, in case the label doesn't actually exist.
772 return DIRR_OK
; /* ignore in pass two */
774 while (*q
&& !nasm_isspace(*q
))
776 if (nasm_isspace(*q
)) {
778 while (*q
&& nasm_isspace(*q
))
783 nasm_nonfatal("`export' directive requires export name");
787 nasm_nonfatal("unrecognized export qualifier `%s'", q
);
798 if (!win32
) /* Only applicable for -f win32 */
802 for (i
= 0; i
< coff_nsects
; i
++)
803 if (!strcmp(".sxdata",coff_sects
[i
]->name
))
805 if (i
== coff_nsects
)
806 sxseg
= coff_make_section(".sxdata", IMAGE_SCN_LNK_INFO
);
811 * pass_final() is the only time when the full set of symbols are
812 * guaranteed to be present as it is the final output pass.
816 saa_rewind(coff_syms
);
817 for (n
= 0; n
< coff_nsyms
; n
++) {
818 struct coff_Symbol
*sym
= saa_rstruct(coff_syms
);
822 * sym->strpos is biased by 4, because symbol
823 * table is prefixed with table length
825 if (sym
->strpos
>=4) {
826 char *name
= nasm_malloc(sym
->namlen
+1);
827 saa_fread(coff_strs
, sym
->strpos
-4, name
, sym
->namlen
);
828 name
[sym
->namlen
] = '\0';
829 equals
= !strcmp(value
,name
);
832 equals
= !strcmp(value
,sym
->name
);
837 * this value arithmetics effectively reflects
838 * initsym in coff_write(): 2 for file, 1 for
839 * .absolute and two per each section
841 unsigned char value
[4],*p
=value
;
842 WRITELONG(p
,n
+ 2 + 1 + coff_nsects
*2);
843 coff_sect_write(coff_sects
[sxseg
],value
,4);
848 if (n
== coff_nsyms
) {
849 nasm_nonfatal("`safeseh' directive requires valid symbol");
860 /* handle relocations storm, valid for win32/64 only */
861 static inline void coff_adjust_relocs(struct coff_Section
*s
)
863 if (s
->nrelocs
< IMAGE_SCN_MAX_RELOC
)
868 if (ofmt
== &of_coff
)
869 nasm_fatal("Too many relocations (%d) for section `%s'",
870 s
->nrelocs
, s
->name
);
874 s
->flags
|= IMAGE_SCN_LNK_NRELOC_OVFL
;
878 static void coff_write(void)
880 int32_t pos
, sympos
, vsize
;
883 /* fill in the .drectve section with -export's */
884 BuildExportTable(&Exports
);
887 /* add default value for @feat.00, this allows to 'link /safeseh' */
890 saa_rewind(coff_syms
);
891 for (n
= 0; n
< coff_nsyms
; n
++) {
892 struct coff_Symbol
*sym
= saa_rstruct(coff_syms
);
893 if (sym
->strpos
== -1 && !strcmp("@feat.00",sym
->name
))
897 coff_deflabel("@feat.00", NO_SEG
, 1, 0, NULL
);
901 * Work out how big the file will get.
902 * Calculate the start of the `real' symbols at the same time.
903 * Check for massive relocations.
905 pos
= 0x14 + 0x28 * coff_nsects
;
906 initsym
= 3; /* two for the file, one absolute */
907 for (i
= 0; i
< coff_nsects
; i
++) {
908 if (coff_sects
[i
]->data
) {
909 coff_adjust_relocs(coff_sects
[i
]);
910 coff_sects
[i
]->pos
= pos
;
911 pos
+= coff_sects
[i
]->len
;
912 coff_sects
[i
]->relpos
= pos
;
913 pos
+= 10 * coff_sects
[i
]->nrelocs
;
915 coff_sects
[i
]->pos
= coff_sects
[i
]->relpos
= 0L;
916 initsym
+= 2; /* two for each section */
921 * Output the COFF header.
924 i
= IMAGE_FILE_MACHINE_AMD64
;
926 i
= IMAGE_FILE_MACHINE_I386
;
927 fwriteint16_t(i
, ofile
); /* machine type */
928 fwriteint16_t(coff_nsects
, ofile
); /* number of sections */
929 fwriteint32_t(time(NULL
), ofile
); /* time stamp */
930 fwriteint32_t(sympos
, ofile
);
931 fwriteint32_t(coff_nsyms
+ initsym
, ofile
);
932 fwriteint16_t(0, ofile
); /* no optional header */
933 /* Flags: 32-bit, no line numbers. Win32 doesn't even bother with them. */
934 fwriteint16_t((win32
| win64
) ? 0 : 0x104, ofile
);
937 * Output the section headers.
940 for (i
= 0; i
< coff_nsects
; i
++) {
941 coff_section_header(coff_sects
[i
]->name
, coff_sects
[i
]->namepos
, vsize
, coff_sects
[i
]->len
,
942 coff_sects
[i
]->pos
, coff_sects
[i
]->relpos
,
943 coff_sects
[i
]->nrelocs
, coff_sects
[i
]->flags
);
944 vsize
+= coff_sects
[i
]->len
;
948 * Output the sections and their relocations.
950 for (i
= 0; i
< coff_nsects
; i
++)
951 if (coff_sects
[i
]->data
) {
952 saa_fpwrite(coff_sects
[i
]->data
, ofile
);
953 coff_write_relocs(coff_sects
[i
]);
957 * Output the symbol and string tables.
959 coff_write_symbols();
960 fwriteint32_t(strslen
+ 4, ofile
); /* length includes length count */
961 saa_fpwrite(coff_strs
, ofile
);
964 static void coff_section_header(char *name
, int32_t namepos
, int32_t vsize
,
965 int32_t datalen
, int32_t datapos
,
966 int32_t relpos
, int nrelocs
, int32_t flags
)
973 strncpy(padname
, name
, 8);
974 nasm_write(padname
, 8, ofile
);
977 * If name is longer than 8 bytes, write '/' followed
978 * by offset into the strings table represented as
981 namepos
= namepos
% 100000000;
983 padname
[1] = '0' + (namepos
/ 1000000);
984 namepos
= namepos
% 1000000;
985 padname
[2] = '0' + (namepos
/ 100000);
986 namepos
= namepos
% 100000;
987 padname
[3] = '0' + (namepos
/ 10000);
988 namepos
= namepos
% 10000;
989 padname
[4] = '0' + (namepos
/ 1000);
990 namepos
= namepos
% 1000;
991 padname
[5] = '0' + (namepos
/ 100);
992 namepos
= namepos
% 100;
993 padname
[6] = '0' + (namepos
/ 10);
994 namepos
= namepos
% 10;
995 padname
[7] = '0' + (namepos
);
996 nasm_write(padname
, 8, ofile
);
999 fwriteint32_t(0, ofile
); /* Virtual size field - set to 0 or vsize */
1000 fwriteint32_t(0L, ofile
); /* RVA/offset - we ignore */
1001 fwriteint32_t(datalen
, ofile
);
1002 fwriteint32_t(datapos
, ofile
);
1003 fwriteint32_t(relpos
, ofile
);
1004 fwriteint32_t(0L, ofile
); /* no line numbers - we don't do 'em */
1007 * a special case -- if there are too many relocs
1008 * we have to put IMAGE_SCN_MAX_RELOC here and write
1009 * the real relocs number into VirtualAddress of first
1012 if (flags
& IMAGE_SCN_LNK_NRELOC_OVFL
)
1013 fwriteint16_t(IMAGE_SCN_MAX_RELOC
, ofile
);
1015 fwriteint16_t(nrelocs
, ofile
);
1017 fwriteint16_t(0, ofile
); /* again, no line numbers */
1018 fwriteint32_t(flags
, ofile
);
1021 static void coff_write_relocs(struct coff_Section
*s
)
1023 struct coff_Reloc
*r
;
1025 /* a real number of relocations if needed */
1026 if (s
->flags
& IMAGE_SCN_LNK_NRELOC_OVFL
) {
1027 fwriteint32_t(s
->nrelocs
, ofile
);
1028 fwriteint32_t(0, ofile
);
1029 fwriteint16_t(0, ofile
);
1032 for (r
= s
->head
; r
; r
= r
->next
) {
1033 fwriteint32_t(r
->address
, ofile
);
1034 fwriteint32_t(r
->symbol
+ (r
->symbase
== REAL_SYMBOLS
? initsym
:
1035 r
->symbase
== ABS_SYMBOL
? initsym
- 1 :
1036 r
->symbase
== SECT_SYMBOLS
? 2 : 0),
1038 fwriteint16_t(r
->type
, ofile
);
1042 static void coff_symbol(char *name
, int32_t strpos
, int32_t value
,
1043 int section
, int type
, int storageclass
, int aux
)
1048 strncpy(padname
, name
, 8);
1049 nasm_write(padname
, 8, ofile
);
1051 fwriteint32_t(0, ofile
);
1052 fwriteint32_t(strpos
, ofile
);
1055 fwriteint32_t(value
, ofile
);
1056 fwriteint16_t(section
, ofile
);
1057 fwriteint16_t(type
, ofile
);
1059 fputc(storageclass
, ofile
);
1063 static void coff_write_symbols(void)
1069 * The `.file' record, and the file name auxiliary record.
1071 coff_symbol(".file", 0L, 0L, -2, 0, 0x67, 1);
1072 strncpy(filename
, inname
, 18);
1073 nasm_write(filename
, 18, ofile
);
1076 * The section records, with their auxiliaries.
1078 memset(filename
, 0, 18); /* useful zeroed buffer */
1080 for (i
= 0; i
< (uint32_t) coff_nsects
; i
++) {
1081 coff_symbol(coff_sects
[i
]->name
, 0L, 0L, i
+ 1, 0, 3, 1);
1082 fwriteint32_t(coff_sects
[i
]->len
, ofile
);
1083 fwriteint16_t(coff_sects
[i
]->nrelocs
,ofile
);
1084 nasm_write(filename
, 12, ofile
);
1088 * The absolute symbol, for relative-to-absolute relocations.
1090 coff_symbol(".absolut", 0L, 0L, -1, 0, 3, 0);
1095 saa_rewind(coff_syms
);
1096 for (i
= 0; i
< coff_nsyms
; i
++) {
1097 struct coff_Symbol
*sym
= saa_rstruct(coff_syms
);
1098 coff_symbol(sym
->strpos
== -1 ? sym
->name
: NULL
,
1099 sym
->strpos
, sym
->value
, sym
->section
,
1100 sym
->type
, sym
->is_global
? 2 : 3, 0);
1104 static void coff_sectalign(int32_t seg
, unsigned int value
)
1106 struct coff_Section
*s
= NULL
;
1110 for (i
= 0; i
< coff_nsects
; i
++) {
1111 if (coff_sects
[i
]->index
== seg
) {
1117 if (!s
|| !is_power2(value
))
1120 /* DOS has limitation on 64 bytes */
1121 if (!(win32
| win64
) && value
> 64)
1124 align
= (s
->flags
& IMAGE_SCN_ALIGN_MASK
);
1125 value
= coff_sectalign_flags(value
);
1127 s
->flags
= (s
->flags
& ~IMAGE_SCN_ALIGN_MASK
) | value
;
1130 extern macros_t coff_stdmac
[];
1132 #endif /* defined(OF_COFF) || defined(OF_WIN32) */
1136 static const struct pragma_facility coff_pragma_list
[] = {
1141 const struct ofmt of_coff
= {
1142 "COFF (i386) (DJGPP, some Unix variants)",
1152 nasm_do_legacy_output
,
1169 static const struct pragma_facility coff_win_pragma_list
[] = {
1175 extern const struct dfmt df_cv8
;
1176 static const struct dfmt
* const win32_debug_arr
[2] = { &df_cv8
, NULL
};
1178 const struct ofmt of_win32
= {
1179 "Microsoft extended COFF for Win32 (i386)",
1189 nasm_do_legacy_output
,
1198 coff_win_pragma_list
1205 static const struct dfmt
* const win64_debug_arr
[2] = { &df_cv8
, NULL
};
1207 const struct ofmt of_win64
= {
1208 "Microsoft extended COFF for Win64 (x86-64)",
1218 nasm_do_legacy_output
,
1227 coff_win_pragma_list