mirror of
https://github.com/netwide-assembler/nasm
synced 2026-08-26 16:23:04 -04:00
outcoff.c: dd symbol wrt ..symtab
Added a special symbol ..symtab for emitting the COFF symbol table index of a symbol rather than some kind of address. For use with ehcont metadata and possible other stuff. Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
This commit is contained in:
parent
f216d5b65d
commit
f1e4e6fe16
5 changed files with 183 additions and 4 deletions
|
|
@ -992,6 +992,7 @@ NASM has the capacity to define other special symbols beginning with
|
|||
a double period: for example, \c{..start} is used to specify the
|
||||
entry point in the \c{obj} output format (see \k{dotdotstart}),
|
||||
\c{..imagebase} is used to find out the offset from a base address
|
||||
of the current image in the \c{win64} output format (see \k{win64pic}).
|
||||
of the current image in the \c{win64} output format (see \k{win64pic}),
|
||||
\c{..symtab} is used to emit the COFF symbol table index (see \k{win32wrt}).
|
||||
So just keep in mind that symbols beginning with a double period are
|
||||
special.
|
||||
|
|
|
|||
|
|
@ -759,6 +759,16 @@ data for "safe exception handler table" causes no backward
|
|||
incompatibilities and "safeseh" modules generated by NASM 2.03 and
|
||||
later can still be linked by earlier versions or non-Microsoft linkers.
|
||||
|
||||
\S{win32wrt} \c{win32}: Special Symbol and WRT
|
||||
|
||||
The Microsoft linker may require symbol table indexes instead of absolute or
|
||||
image relative addresses in some more modern structures, like those used for
|
||||
exception handler control flow guard metadata (ehcont). This can be
|
||||
accomplished by getting the symbol address with respect to the special
|
||||
\c{..symtab} symbol. For instance:
|
||||
|
||||
\c __guard_ehcont_main: dd main.cont wrt ..symtab
|
||||
|
||||
\S{codeview} Debugging formats for Windows
|
||||
\I{Windows debugging formats}
|
||||
|
||||
|
|
|
|||
|
|
@ -74,6 +74,9 @@ bool win32, win64;
|
|||
static int32_t imagebase_sect;
|
||||
#define WRT_IMAGEBASE "..imagebase"
|
||||
|
||||
static int32_t symtab_sect;
|
||||
#define WRT_SYMTAB "..symtab"
|
||||
|
||||
/*
|
||||
* Some common section flags by default
|
||||
*/
|
||||
|
|
@ -192,6 +195,8 @@ static void coff_gen_init(void)
|
|||
coff_strs = saa_init(1);
|
||||
strslen = 0;
|
||||
def_seg = seg_alloc();
|
||||
symtab_sect = seg_alloc()+1;
|
||||
backend_label(WRT_SYMTAB, symtab_sect, 0);
|
||||
}
|
||||
|
||||
static void coff_cleanup(void)
|
||||
|
|
@ -210,6 +215,11 @@ static void coff_cleanup(void)
|
|||
coff_sects[i]->head = coff_sects[i]->head->next;
|
||||
nasm_free(r);
|
||||
}
|
||||
while (coff_sects[i]->symidx_reloc_head) {
|
||||
struct coff_SymIdxReloc * const ir = coff_sects[i]->symidx_reloc_head;
|
||||
coff_sects[i]->symidx_reloc_head = ir->next;
|
||||
nasm_free(ir);
|
||||
}
|
||||
nasm_free(coff_sects[i]->name);
|
||||
nasm_free(coff_sects[i]->comdat_name);
|
||||
nasm_free(coff_sects[i]);
|
||||
|
|
@ -544,7 +554,7 @@ static void coff_deflabel(char *name, int32_t segment, int64_t offset,
|
|||
" special symbol types");
|
||||
|
||||
if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
|
||||
if (strcmp(name,WRT_IMAGEBASE))
|
||||
if (strcmp(name,WRT_IMAGEBASE) && strcmp(name, WRT_SYMTAB))
|
||||
nasm_nonfatal("unrecognized special symbol `%s'", name);
|
||||
return;
|
||||
}
|
||||
|
|
@ -649,6 +659,50 @@ static int32_t coff_add_reloc(struct coff_Section *sect, int32_t segment,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Helper for coff_out handling wrt ..symtab addressing. */
|
||||
static uint32_t coff_out_get_symbol_idx(int32_t tsegment, int64_t offset)
|
||||
{
|
||||
/* No better way of doing this? */
|
||||
int section;
|
||||
if (tsegment == NO_SEG) {
|
||||
section = -1;
|
||||
} else {
|
||||
for (section = 0; section < coff_nsects; section++)
|
||||
if (tsegment == coff_sects[section]->index)
|
||||
break;
|
||||
section++;
|
||||
}
|
||||
|
||||
/* Do symbol table lookup (unless it is external). */
|
||||
if (section <= coff_nsects) {
|
||||
uint32_t symidx = UINT32_MAX;
|
||||
int n;
|
||||
saa_rewind(coff_syms);
|
||||
for (n = 0; n < coff_nsyms; n++) {
|
||||
struct coff_Symbol *sym = saa_rstruct(coff_syms);
|
||||
nasm_try_static_assert(sizeof(sym->value) == sizeof(int32_t));
|
||||
if (sym->section == section && sym->value == (int32_t)offset) {
|
||||
if (sym->type & 0x30) /* N_TMASK */
|
||||
return n; /* Prefer symbol with non-NULL type. */
|
||||
if (symidx == UINT32_MAX)
|
||||
symidx = n;
|
||||
}
|
||||
}
|
||||
if (symidx == UINT32_MAX)
|
||||
nasm_nonfatal("wrt ..symtab: Unable to find symbol for %s:%#" PRIx64,
|
||||
section > 0 ? coff_sects[section - 1]->name : "ABS", offset);
|
||||
return symidx;
|
||||
}
|
||||
|
||||
/* External symbols. */
|
||||
if (tsegment != NO_SEG)
|
||||
return raa_read(bsym, tsegment);
|
||||
|
||||
nasm_nonfatal("wrt ..symtab: Unable to find symbol for %#"PRIx32":%#" PRIx64,
|
||||
tsegment, offset);
|
||||
return UINT32_MAX;
|
||||
}
|
||||
|
||||
static void coff_out(const struct out_data *out)
|
||||
{
|
||||
OUT_LEGACY(out,segto,data,type,size,segment,wrt);
|
||||
|
|
@ -656,7 +710,7 @@ static void coff_out(const struct out_data *out)
|
|||
uint8_t mydata[8], *p;
|
||||
int i;
|
||||
|
||||
if (wrt != NO_SEG && !win64) {
|
||||
if (wrt != NO_SEG && wrt != symtab_sect && !win64) {
|
||||
wrt = NO_SEG; /* continue to do _something_ */
|
||||
nasm_nonfatal("WRT not supported by COFF output formats");
|
||||
}
|
||||
|
|
@ -716,7 +770,25 @@ static void coff_out(const struct out_data *out)
|
|||
coff_sect_write(s, data, size);
|
||||
} else if (type == OUT_ADDRESS) {
|
||||
int asize = abs((int)size);
|
||||
if (!win64) {
|
||||
if (wrt == symtab_sect) {
|
||||
/* Emit internal fixup since the table starts with sections and
|
||||
stuff that can be added to after this statement. */
|
||||
struct coff_SymIdxReloc *ir;
|
||||
nasm_new(ir);
|
||||
ir->offset = s->len;
|
||||
ir->size = (uint8_t)asize;
|
||||
ir->symbol = coff_out_get_symbol_idx(segment, out->toffset);
|
||||
ir->next = s->symidx_reloc_head;
|
||||
s->symidx_reloc_head = ir;
|
||||
nasm_assert(asize <= sizeof(mydata));
|
||||
coff_sect_write(s, mydata, asize);
|
||||
if (asize > 4)
|
||||
nasm_warn(WARN_OTHER, "zero extending 'wrt "WRT_SYMTAB
|
||||
"' (32-bit) to %u-bit", asize * 8);
|
||||
else if (asize < 4)
|
||||
nasm_warn(WARN_OTHER, "truncating 'wrt "WRT_SYMTAB
|
||||
"' (32-bit) to %u-bit", asize * 8);
|
||||
} else if (!win64) {
|
||||
if (asize != 4 && (segment != NO_SEG || wrt != NO_SEG)) {
|
||||
nasm_nonfatal("COFF format does not support non-32-bit"
|
||||
" relocations");
|
||||
|
|
@ -1102,6 +1174,15 @@ static void coff_write(void)
|
|||
*/
|
||||
for (i = 0; i < coff_nsects; i++)
|
||||
if (coff_sects[i]->data) {
|
||||
/* Apply symbol table index fixups before writing */
|
||||
struct coff_SymIdxReloc *ir;
|
||||
for (ir = coff_sects[i]->symidx_reloc_head; ir; ir = ir->next) {
|
||||
uint8_t mydata[4];
|
||||
setu32(mydata, ir->symbol + initsym);
|
||||
saa_fwrite(coff_sects[i]->data, ir->offset,
|
||||
mydata, ir->size >= 4 ? 4 : ir->size);
|
||||
}
|
||||
|
||||
saa_fpwrite(coff_sects[i]->data, ofile);
|
||||
coff_write_relocs(coff_sects[i]);
|
||||
|
||||
|
|
|
|||
|
|
@ -457,6 +457,7 @@ struct coff_Section {
|
|||
int32_t namepos; /* Offset of name into the strings table */
|
||||
int32_t pos, relpos;
|
||||
int64_t pass_last_seen;
|
||||
struct coff_SymIdxReloc *symidx_reloc_head;
|
||||
|
||||
/* comdat-related members */
|
||||
char *comdat_name;
|
||||
|
|
@ -478,6 +479,13 @@ struct coff_Reloc {
|
|||
int16_t type;
|
||||
};
|
||||
|
||||
struct coff_SymIdxReloc {
|
||||
struct coff_SymIdxReloc *next;
|
||||
uint32_t symbol; /* symbol number */
|
||||
uint32_t offset; /* byte offset into the secetion. */
|
||||
uint32_t size; /* the size of the area to fix up */
|
||||
};
|
||||
|
||||
struct coff_Symbol {
|
||||
char name[9];
|
||||
int32_t strpos; /* string table position of name */
|
||||
|
|
|
|||
79
test/wrtsymtab.asm
Normal file
79
test/wrtsymtab.asm
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
;Testname=win32; Arguments=-fwin32 -owrtsymtab.o -Ox; Files=stdout stderr wrtsymtab.o
|
||||
;Testname=win64; Arguments=-fwin64 -owrtsymtab.o -Ox; Files=stdout stderr wrtsymtab.o
|
||||
|
||||
; Just some symbols & code to work with.
|
||||
abs_sym1 equ 0x12345678
|
||||
|
||||
section .text
|
||||
extern extrn_sym_unused
|
||||
required extrn_sym1
|
||||
mysymbol1:
|
||||
ret
|
||||
int3
|
||||
int3
|
||||
mysymbol2:
|
||||
ret
|
||||
int3
|
||||
mysymbol3_private:
|
||||
.start_of_prolog:
|
||||
mysymbol3:
|
||||
global mysymbol3:function
|
||||
ret
|
||||
|
||||
oddsym1:
|
||||
ret
|
||||
|
||||
required extrn_sym2
|
||||
required extrn_sym3
|
||||
extern extrn_sym4
|
||||
|
||||
section .data
|
||||
abs_sym2 equ 0x91929394
|
||||
|
||||
section .rodata rdata
|
||||
; Various uses with DD
|
||||
db ' mysymbol1:'
|
||||
dd mysymbol1 wrt ..symtab
|
||||
db ' extrn_sym1:'
|
||||
dd extrn_sym1 wrt ..symtab
|
||||
db ' abs_sym1:'
|
||||
dd abs_sym1 wrt ..symtab
|
||||
|
||||
db ' mysymbol2:'
|
||||
dd mysymbol2 wrt ..symtab
|
||||
db ' extrn_sym2:'
|
||||
dd extrn_sym2 wrt ..symtab
|
||||
db ' abs_sym2:'
|
||||
dd abs_sym2 wrt ..symtab
|
||||
|
||||
db ' extrn_sym3:'
|
||||
dd extrn_sym3 wrt ..symtab
|
||||
db ' mysymbol3:'
|
||||
dd mysymbol3 wrt ..symtab
|
||||
db ' extrn_sym4:'
|
||||
dd extrn_sym4 wrt ..symtab
|
||||
|
||||
; Uses with DB, DW, DD and DQ. Will generate warnings.
|
||||
db ' db oddsym1:'
|
||||
db oddsym1 wrt ..symtab
|
||||
db ' dw oddsym1:'
|
||||
dw oddsym1 wrt ..symtab
|
||||
db ' dd oddsym1:'
|
||||
dd oddsym1 wrt ..symtab ; ok, no warning
|
||||
db 'dq same:'
|
||||
dq oddsym1 wrt ..symtab
|
||||
|
||||
; a little closer to real life use.
|
||||
section gehcont$y align=4 rdata
|
||||
__guard_ehcont_main: dd main.cont wrt ..symtab
|
||||
|
||||
section .text
|
||||
global main:function
|
||||
main:
|
||||
call mysymbol3
|
||||
xor eax, eax
|
||||
ret
|
||||
.cont:
|
||||
mov eax, -1
|
||||
ret
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue