/* ----------------------------------------------------------------------- * * * Copyright 1996-2020 The NASM Authors - All Rights Reserved * See the file AUTHORS included with the NASM distribution for * the specific copyright holders. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following * conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * ----------------------------------------------------------------------- */ /* * outcoff.c output routines for the Netwide Assembler to produce * COFF object files (for DJGPP and Win32) */ #include "compiler.h" #include "nctype.h" #include <time.h> #include "nasm.h" #include "nasmlib.h" #include "ilog2.h" #include "error.h" #include "saa.h" #include "raa.h" #include "eval.h" #include "outform.h" #include "outlib.h" #include "pecoff.h" #if defined(OF_COFF) || defined(OF_WIN32) || defined(OF_WIN64) /* * Notes on COFF: * * (0) When I say `standard COFF' below, I mean `COFF as output and * used by DJGPP'. I assume DJGPP gets it right. * * (1) Win32 appears to interpret the term `relative relocation' * differently from standard COFF. Standard COFF understands a * relative relocation to mean that during relocation you add the * address of the symbol you're referencing, and subtract the base * address of the section you're in. Win32 COFF, by contrast, seems * to add the address of the symbol and then subtract the address * of THE BYTE AFTER THE RELOCATED DWORD. Hence the two formats are * subtly incompatible. * * (2) Win32 doesn't bother putting any flags in the header flags * field (at offset 0x12 into the file). * * (3) Win32/64 uses some extra flags into the section header table: * it defines flags 0x80000000 (writable), 0x40000000 (readable) * and 0x20000000 (executable), and uses them in the expected * combinations. It also defines 0x00100000 through 0x00f00000 for * section alignments of 1 through 8192 bytes. * * (4) Both standard COFF and Win32 COFF seem to use the DWORD * field directly after the section name in the section header * table for something strange: they store what the address of the * section start point _would_ be, if you laid all the sections end * to end starting at zero. Dunno why. Microsoft's documentation * lists this field as "Virtual Size of Section", which doesn't * seem to fit at all. In fact, Win32 even includes non-linked * sections such as .drectve in this calculation. * * Newer versions of MASM seem to have changed this to be zero, and * that apparently matches the COFF spec, so go with that. * * (5) Standard COFF does something very strange to common * variables: the relocation point for a common variable is as far * _before_ the variable as its size stretches out _after_ it. So * we must fix up common variable references. Win32 seems to be * sensible on this one. */ /* Flag which version of COFF we are currently outputting. */ bool win32, win64; static int32_t imagebase_sect; #define WRT_IMAGEBASE … /* * Some common section flags by default */ #define TEXT_FLAGS_WIN … #define TEXT_FLAGS_DOS … #define DATA_FLAGS_WIN … #define DATA_FLAGS_DOS … #define BSS_FLAGS_WIN … #define BSS_FLAGS_DOS … #define RDATA_FLAGS_WIN … #define RDATA_FLAGS_DOS … #define PDATA_FLAGS … #define XDATA_FLAGS … #define INFO_FLAGS … #define TEXT_FLAGS … #define DATA_FLAGS … #define BSS_FLAGS … #define RDATA_FLAGS … #define COFF_MAX_ALIGNMENT … #define SECT_DELTA … struct coff_Section **coff_sects; static int sectlen; int coff_nsects; struct SAA *coff_syms; uint32_t coff_nsyms; static int32_t def_seg; static int initsym; static struct RAA *bsym, *symval; struct SAA *coff_strs; static uint32_t strslen; static void coff_gen_init(void); static void coff_sect_write(struct coff_Section *, const uint8_t *, uint32_t); static void coff_write(void); static void coff_section_header(char *, int32_t, int32_t, int32_t, int32_t, int32_t, int, int32_t); static void coff_write_relocs(struct coff_Section *); static void coff_write_symbols(void); static void coff_win32_init(void) { … } static void coff_win64_init(void) { … } static void coff_std_init(void) { … } static void coff_gen_init(void) { … } static void coff_cleanup(void) { … } int coff_make_section(char *name, uint32_t flags) { … } /* * Convert an alignment value to the corresponding flags. * An alignment value of 0 means no flags should be set. */ static inline uint32_t coff_sectalign_flags(unsigned int align) { … } /* * Get the alignment value from a flags field. * Returns 0 if no alignment defined. */ static inline unsigned int coff_alignment(uint32_t flags) { … } static int32_t coff_section_names(char *name, int *bits) { … } static void coff_deflabel(char *name, int32_t segment, int64_t offset, int is_global, char *special) { … } static int32_t coff_add_reloc(struct coff_Section *sect, int32_t segment, int16_t type) { … } static void coff_out(int32_t segto, const void *data, enum out_type type, uint64_t size, int32_t segment, int32_t wrt) { … } static void coff_sect_write(struct coff_Section *sect, const uint8_t *data, uint32_t len) { … } STRING; #define EXPORT_SECTION_NAME … #define EXPORT_SECTION_FLAGS … /* * #define EXPORT_SECTION_NAME ".text" * #define EXPORT_SECTION_FLAGS TEXT_FLAGS */ static STRING *Exports = …; static struct coff_Section *directive_sec; static void AddExport(char *name) { … } static void BuildExportTable(STRING **rvp) { … } static enum directive_result coff_directives(enum directive directive, char *value) { … } /* handle relocations storm, valid for win32/64 only */ static inline void coff_adjust_relocs(struct coff_Section *s) { … } /* * Make sure we satisfy all section alignment requirements and put the * resulting alignment flags into the flags value in the header. If * no user-specified alignment is given, use the default for the * section type; then either way round up to alignment specified by * sectalign directives. */ static inline void coff_adjust_alignment(struct coff_Section *s) { … } static void coff_write(void) { … } static void 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) { … } static void coff_write_relocs(struct coff_Section *s) { … } static void coff_symbol(char *name, int32_t strpos, int32_t value, int section, int type, int storageclass, int aux) { … } static void coff_write_symbols(void) { … } static void coff_sectalign(int32_t seg, unsigned int value) { … } extern macros_t coff_stdmac[]; #endif /* defined(OF_COFF) || defined(OF_WIN32) */ #ifdef OF_COFF static const struct pragma_facility coff_pragma_list[] = …; const struct ofmt of_coff = …; #endif #ifdef OF_WIN32 static const struct pragma_facility coff_win_pragma_list[] = …; extern const struct dfmt df_cv8; static const struct dfmt * const win32_debug_arr[2] = …; const struct ofmt of_win32 = …; #endif #ifdef OF_WIN64 static const struct dfmt * const win64_debug_arr[2] = …; const struct ofmt of_win64 = …; #endif