From 23e53d41ce27f8a03901d9cb2b63b0c7f36f8a75 Mon Sep 17 00:00:00 2001 From: Peter Johnson Date: Sun, 31 Oct 2004 01:07:52 +0000 Subject: [PATCH] Fix #44 by adding support for WRT special symbols (e.g. [sym WRT ..plt] and similar) to ELF. They are used identically to NASM's ELF shared object support. Due to limited WRT support throughout libyasm, this caused a lot of rippling changes. A major cleanup needs to be performed later to clear some of this hackiness up. * elf-machine.h (func_accepts_size_t): Rename to func_accepts_reloc(). (func_map_reloc_info_to_type): Add parameter ssyms for array of special syms. (elf_machine_ssym): New; for defining machine-specific special syms. (elf_machine_handler): Change accepts_reloc_size to accepts_reloc. Add new ssyms and num_ssyms members. * elf-x86-x86.c (ssym_index): New; this allows nice indexing of ssym arrays. (elf_x86_x86_accepts_reloc): Rename of elf_x86_x86_accepts_reloc_size. Add support for various WRT ssyms. (elf_x86_x86_map_reloc_info_to_type): Add support for various WRT ssyms. (elf_x86_x86_ssyms): New array of supported special symbols. (elf_machine_handler_x86_x86): Update for above changes/additions. * elf-x86-amd64.c (ssym_index, elf_x86_amd64_accepts_reloc) (elf_x86_amd64_map_reloc_info_to_type, elf_x86_amd64_ssyms) (elf_machine_handler_x86_amd64): Likewise. * elf.h (elf_reloc_entry): Add wrt member. (elf_set_arch): Add symtab parameter. (elf_is_wrt_sym_relative): New. (elf_reloc_entry_create): Add wrt parameter. * elf.c (elf_set_arch): Allocate special syms from machine level. (elf_is_wrt_sym_relative): New; search special syms, and report whether a WRT ssym should be symbol-relative or section-relative. (elf_reloc_entry_create): Pass WRT and ssyms info down to machine level. * elf-objfmt.c (yasm_objfmt_elf): Add dotdotsym (..sym) symrec member. (elf_objfmt_create): Pass symtab to elf_set_arch(). Allocate ..sym symbol. (elf_objfmt_output_reloc): Update for elf_reloc_entry_create() change. (elf_objfmt_output_expr): Handle WRT ssym. Make relocation symbol-relative rather than section-relative if either WRT ..sym or WRT ssym that machine level desires to be symbol-relative. * symrec.c (yasm_symrec_get_label): Check for NULL sym->value.precbc; this is now possible due to the user-accessible special symbols that ELF et al create, which all have NULL precbc's. * expr.c (yasm_expr_extract_symrec): Recurse into IDENT's to make more exprs acceptable. * coretype.h (yasm_output_reloc_func): Remove rel parameter as it shouldn't be needed and complexifies writing of the reloc functions. * stabs-dbgfmt.c (stabs_bc_stab_tobytes): Update output_reloc() call. * elf-objfmt.c (elf_objfmt_output_reloc): Update to match. * arch.h (yasm_arch_module): Add intnum_fixup_rel() function, change intnum_tobytes() to not take rel parameter. The rel functionality is being separated because sometimes it's desirable not to put the data into the written intnum (e.g. ELF RELA relocations). (YASM_ARCH_VERSION): Bump due to above change. (yasm_arch_intnum_fixup_rel): New wrapper. (yasm_arch_intnum_tobytes): Update wrapper (removing rel). * lc3bbc.c (yasm_lc3b__intnum_fixup_rel): New, with code from: (yasm_lc3b__intnum_tobytes): Remove rel code. * lc3barch.h (yasm_lc3b__intnum_fixup_rel): New. (yasm_lc3b__intnum_tobytes): Update. * lc3barch.c (yasm_lc3b_LTX_arch): Reference yasm_lc3b__intnum_fixup_rel(). * x86bc.c (yasm_x86__intnum_fixup_rel): New, with code from: (yasm_x86__intnum_tobytes): Remove rel code. * x86arch.h (yasm_x86__intnum_fixup_rel): New. (yasm_x86__intnum_tobytes): Update. * x86arch.c (yasm_x86_LTX_arch): Reference yasm_x86__intnum_fixup_rel(). * xdf-objfmt.c (xdf_objfmt_output_expr): Update to use intnum_fixup_rel() / new intnum_tobytes(). * bin-objfmt.c (bin_objfmt_output_expr): Likewise. * coff-objfmt.c (coff_objfmt_output_expr): Likewise. * elf-objfmt.c (elf_objfmt_output_expr: Likewise. * nasm-listfmt.c (nasm_listfmt_output_expr): Likewise. * nasm-bison.y: Change precedence of WRT and : operators: instead of being the strongest binders they are now the weakest. This is needed to correctly parse and be able to split WRT expressions. WRT handling is still somewhat of a hack throughout yasm; we'll fix this later. * x86expr.c (x86_expr_checkea_distcheck_reg): Don't check for WRT here. (x86_expr_checkea_getregusage): Add new wrt parameter. Use it to handle "WRT rip" separately from other operators. Recurse if there's a WRT below the WRT rip; this is to handle cases like ELF-AMD64's elfso64.asm. (yasm_x86__expr_checkea): Split off top-level WRT's and feed through separately to x86_expr_checkea_getregusage(). * x86bc.c (x86_bc_insn_tobytes): Ensure the SUB operation for PC-relative displacements goes BELOW any WRT expression. (x86_bc_jmp_tobytes): Likewise. * elfso.asm, elfso.hex, elfso.errwarn: New 32-bit ELF shared object tests. * modules/objfmts/elf/tests/Makefile.inc: Include in distribution. * elfso64.asm, elfso64.hex, elfso64.errwarn: New 64-bit ELF shared object tests. This is not a good example, as the assembled code doesn't work, but it at least tests the special symbols. * modules/objfmts/elf/tests/amd64/Makefile.inc: Include in distribution. svn path=/trunk/yasm/; revision=1168 --- libyasm/arch.h | 34 +- libyasm/coretype.h | 3 +- libyasm/expr.c | 4 + libyasm/symrec.c | 2 +- modules/arch/lc3b/lc3barch.c | 1 + modules/arch/lc3b/lc3barch.h | 6 +- modules/arch/lc3b/lc3bbc.c | 39 +- modules/arch/x86/x86arch.c | 1 + modules/arch/x86/x86arch.h | 5 +- modules/arch/x86/x86bc.c | 54 +- modules/arch/x86/x86expr.c | 96 +- modules/dbgfmts/stabs/stabs-dbgfmt.c | 2 +- modules/listfmts/nasm/nasm-listfmt.c | 7 +- modules/objfmts/bin/bin-objfmt.c | 16 +- modules/objfmts/coff/coff-objfmt.c | 14 +- modules/objfmts/elf/elf-machine.h | 16 +- modules/objfmts/elf/elf-objfmt.c | 67 +- modules/objfmts/elf/elf-x86-amd64.c | 44 +- modules/objfmts/elf/elf-x86-x86.c | 49 +- modules/objfmts/elf/elf.c | 37 +- modules/objfmts/elf/elf.h | 5 +- modules/objfmts/elf/tests/Makefile.inc | 3 + modules/objfmts/elf/tests/amd64/Makefile.inc | 3 + modules/objfmts/elf/tests/amd64/elf-rip.hex | 48 +- modules/objfmts/elf/tests/amd64/elfso64.asm | 90 + .../objfmts/elf/tests/amd64/elfso64.errwarn | 0 modules/objfmts/elf/tests/amd64/elfso64.hex | 1680 +++++++++++++++++ modules/objfmts/elf/tests/elfso.asm | 97 + modules/objfmts/elf/tests/elfso.errwarn | 0 modules/objfmts/elf/tests/elfso.hex | 1144 +++++++++++ modules/objfmts/xdf/xdf-objfmt.c | 14 +- modules/parsers/nasm/nasm-bison.y | 5 +- 32 files changed, 3423 insertions(+), 163 deletions(-) create mode 100644 modules/objfmts/elf/tests/amd64/elfso64.asm create mode 100644 modules/objfmts/elf/tests/amd64/elfso64.errwarn create mode 100644 modules/objfmts/elf/tests/amd64/elfso64.hex create mode 100644 modules/objfmts/elf/tests/elfso.asm create mode 100644 modules/objfmts/elf/tests/elfso.errwarn create mode 100644 modules/objfmts/elf/tests/elfso.hex diff --git a/libyasm/arch.h b/libyasm/arch.h index e522db9d..79a23139 100644 --- a/libyasm/arch.h +++ b/libyasm/arch.h @@ -104,7 +104,7 @@ typedef struct yasm_arch_machine { * module loader's function definitions. The version number must never be * decreased. */ -#define YASM_ARCH_VERSION 2 +#define YASM_ARCH_VERSION 3 /** YASM architecture module interface. * \note All "data" in parser-related functions (yasm_arch_parse_*) needs to @@ -208,12 +208,19 @@ typedef struct yasm_arch_module { size_t valsize, size_t shift, int warn, unsigned long line); + /** Module-level implementation of yasm_arch_intnum_fixup_rel(). + * Call yasm_arch_intnum_fixup_rel() instead of calling this function. + */ + int (*intnum_fixup_rel) (yasm_arch *arch, yasm_intnum *intn, + size_t valsize, const yasm_bytecode *bc, + unsigned long line); + /** Module-level implementation of yasm_arch_intnum_tobytes(). * Call yasm_arch_intnum_tobytes() instead of calling this function. */ int (*intnum_tobytes) (yasm_arch *arch, const yasm_intnum *intn, unsigned char *buf, size_t destsize, size_t valsize, - int shift, const yasm_bytecode *bc, int rel, + int shift, const yasm_bytecode *bc, int warn, unsigned long line); /** Module-level implementation of yasm_arch_get_reg_size(). @@ -446,6 +453,19 @@ int yasm_arch_floatnum_tobytes(yasm_arch *arch, const yasm_floatnum *flt, size_t valsize, size_t shift, int warn, unsigned long line); +/** Adjust #yasm_intnum for relative displacement from bc. Displacement + * is modified in-place. + * \param arch architecture + * \param intn integer value + * \param valsize size (in bits) + * \param bc bytecode being output ("parent" of value) + * \param line virtual line; may be 0 if warn is 0 + * \return Nonzero on error. + */ +int yasm_arch_intnum_fixup_rel(yasm_arch *arch, yasm_intnum *intn, + size_t valsize, const yasm_bytecode *bc, + unsigned long line); + /** Output #yasm_intnum to buffer. Puts the value into the least * significant bits of the destination, or may be shifted into more * significant bits by the shift parameter. The destination bits are @@ -458,7 +478,6 @@ int yasm_arch_floatnum_tobytes(yasm_arch *arch, const yasm_floatnum *flt, * \param shift left shift (in bits); may be negative to specify right * shift (standard warnings include truncation to boundary) * \param bc bytecode being output ("parent" of value) - * \param rel value is a relative displacement from bc * \param warn enables standard warnings (value doesn't fit into * valsize bits) * \param line virtual line; may be 0 if warn is 0 @@ -467,7 +486,7 @@ int yasm_arch_floatnum_tobytes(yasm_arch *arch, const yasm_floatnum *flt, int yasm_arch_intnum_tobytes(yasm_arch *arch, const yasm_intnum *intn, unsigned char *buf, size_t destsize, size_t valsize, int shift, - const yasm_bytecode *bc, int rel, int warn, + const yasm_bytecode *bc, int warn, unsigned long line); /** Get the equivalent byte size of a register. @@ -541,10 +560,13 @@ yasm_effaddr *yasm_arch_ea_create(yasm_arch *arch, /*@keep@*/ yasm_expr *e); warn, line) \ ((yasm_arch_base *)arch)->module->floatnum_tobytes \ (arch, flt, buf, destsize, valsize, shift, warn, line) +#define yasm_arch_intnum_fixup_rel(arch, intn, valsize, bc, line) \ + ((yasm_arch_base *)arch)->module->intnum_fixup_rel \ + (arch, intn, valsize, bc, line) #define yasm_arch_intnum_tobytes(arch, intn, buf, destsize, valsize, shift, \ - bc, rel, warn, line) \ + bc, warn, line) \ ((yasm_arch_base *)arch)->module->intnum_tobytes \ - (arch, intn, buf, destsize, valsize, shift, bc, rel, warn, line) + (arch, intn, buf, destsize, valsize, shift, bc, warn, line) #define yasm_arch_get_reg_size(arch, reg) \ ((yasm_arch_base *)arch)->module->get_reg_size(arch, reg) #define yasm_arch_reg_print(arch, reg, f) \ diff --git a/libyasm/coretype.h b/libyasm/coretype.h index a1a39e1f..83fd0b70 100644 --- a/libyasm/coretype.h +++ b/libyasm/coretype.h @@ -201,7 +201,6 @@ typedef int (*yasm_output_expr_func) * \param buf buffer for byte representation * \param destsize destination size (in bytes) * \param valsize size (in bits) - * \param rel if nonzero, expr should be treated as PC/IP-relative * \param warn enables standard warnings: zero for none; * nonzero for overflow/underflow floating point warnings; * negative for signed integer warnings, @@ -212,7 +211,7 @@ typedef int (*yasm_output_expr_func) */ typedef int (*yasm_output_reloc_func) (yasm_symrec *sym, yasm_bytecode *bc, unsigned char *buf, size_t destsize, - size_t valsize, int rel, int warn, void *d); + size_t valsize, int warn, void *d); /** Sort an array using merge sort algorithm. * \internal diff --git a/libyasm/expr.c b/libyasm/expr.c index 12120b4c..cd53c6b6 100644 --- a/libyasm/expr.c +++ b/libyasm/expr.c @@ -993,6 +993,10 @@ yasm_expr_extract_symrec(yasm_expr **ep, int relocate, switch ((*ep)->op) { case YASM_EXPR_IDENT: + /* Be kind, recurse */ + if ((*ep)->terms[0].type == YASM_EXPR_EXPR) + return yasm_expr_extract_symrec(&((*ep)->terms[0].data.expn), + relocate, calc_bc_dist); /* Replace sym with 0 value, return sym */ if ((*ep)->terms[0].type == YASM_EXPR_SYM) { sym = (*ep)->terms[0].data.sym; diff --git a/libyasm/symrec.c b/libyasm/symrec.c index 10741a23..ca5f6057 100644 --- a/libyasm/symrec.c +++ b/libyasm/symrec.c @@ -356,7 +356,7 @@ int yasm_symrec_get_label(const yasm_symrec *sym, yasm_symrec_get_label_bytecodep *precbc) { - if (sym->type != SYM_LABEL) { + if (sym->type != SYM_LABEL || !sym->value.precbc) { *precbc = (yasm_symrec_get_label_bytecodep)0xDEADBEEF; return 0; } diff --git a/modules/arch/lc3b/lc3barch.c b/modules/arch/lc3b/lc3barch.c index de0c8771..4a6b10b5 100644 --- a/modules/arch/lc3b/lc3barch.c +++ b/modules/arch/lc3b/lc3barch.c @@ -130,6 +130,7 @@ yasm_arch_module yasm_lc3b_LTX_arch = { NULL, /*yasm_lc3b__parse_seg_prefix*/ NULL, /*yasm_lc3b__parse_seg_override*/ lc3b_floatnum_tobytes, + yasm_lc3b__intnum_fixup_rel, yasm_lc3b__intnum_tobytes, lc3b_get_reg_size, lc3b_reg_print, diff --git a/modules/arch/lc3b/lc3barch.h b/modules/arch/lc3b/lc3barch.h index 9390fe10..4b8c860e 100644 --- a/modules/arch/lc3b/lc3barch.h +++ b/modules/arch/lc3b/lc3barch.h @@ -65,8 +65,12 @@ yasm_arch_check_id_retval yasm_lc3b__parse_check_id /*@null@*/ yasm_insn_operands *operands, yasm_bytecode *prev_bc, unsigned long line); +int yasm_lc3b__intnum_fixup_rel + (yasm_arch *arch, yasm_intnum *intn, size_t valsize, + const yasm_bytecode *bc, unsigned long line); + int yasm_lc3b__intnum_tobytes (yasm_arch *arch, const yasm_intnum *intn, unsigned char *buf, size_t destsize, size_t valsize, int shift, const yasm_bytecode *bc, - int rel, int warn, unsigned long line); + int warn, unsigned long line); #endif diff --git a/modules/arch/lc3b/lc3bbc.c b/modules/arch/lc3b/lc3bbc.c index be754200..87fdf279 100644 --- a/modules/arch/lc3b/lc3bbc.c +++ b/modules/arch/lc3b/lc3bbc.c @@ -240,28 +240,29 @@ lc3b_bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d, return 0; } +int +yasm_lc3b__intnum_fixup_rel(yasm_arch *arch, yasm_intnum *intn, + size_t valsize, const yasm_bytecode *bc, + unsigned long line) +{ + yasm_intnum *delta; + if (valsize != 9) + yasm_internal_error( + N_("tried to do PC-relative offset from invalid sized value")); + delta = yasm_intnum_create_uint(bc->len); + yasm_intnum_calc(intn, YASM_EXPR_SUB, delta, line); + yasm_intnum_destroy(delta); + return 0; +} + int yasm_lc3b__intnum_tobytes(yasm_arch *arch, const yasm_intnum *intn, unsigned char *buf, size_t destsize, size_t valsize, - int shift, const yasm_bytecode *bc, int rel, - int warn, unsigned long line) + int shift, const yasm_bytecode *bc, int warn, + unsigned long line) { - if (rel) { - yasm_intnum *relnum, *delta; - if (valsize != 9) - yasm_internal_error( - N_("tried to do PC-relative offset from invalid sized value")); - relnum = yasm_intnum_copy(intn); - delta = yasm_intnum_create_uint(bc->len); - yasm_intnum_calc(relnum, YASM_EXPR_SUB, delta, line); - yasm_intnum_destroy(delta); - yasm_intnum_get_sized(relnum, buf, destsize, valsize, shift, 0, warn, - line); - yasm_intnum_destroy(relnum); - } else { - /* Write value out. */ - yasm_intnum_get_sized(intn, buf, destsize, valsize, shift, 0, warn, - line); - } + /* Write value out. */ + yasm_intnum_get_sized(intn, buf, destsize, valsize, shift, 0, warn, + line); return 0; } diff --git a/modules/arch/x86/x86arch.c b/modules/arch/x86/x86arch.c index d22f6e1f..ca662584 100644 --- a/modules/arch/x86/x86arch.c +++ b/modules/arch/x86/x86arch.c @@ -263,6 +263,7 @@ yasm_arch_module yasm_x86_LTX_arch = { x86_parse_seg_prefix, x86_parse_seg_override, yasm_x86__floatnum_tobytes, + yasm_x86__intnum_fixup_rel, yasm_x86__intnum_tobytes, yasm_x86__get_reg_size, x86_reg_print, diff --git a/modules/arch/x86/x86arch.h b/modules/arch/x86/x86arch.h index f6668b70..c7fb9df4 100644 --- a/modules/arch/x86/x86arch.h +++ b/modules/arch/x86/x86arch.h @@ -218,10 +218,13 @@ int yasm_x86__floatnum_tobytes (yasm_arch *arch, const yasm_floatnum *flt, unsigned char *buf, size_t destsize, size_t valsize, size_t shift, int warn, unsigned long line); +int yasm_x86__intnum_fixup_rel + (yasm_arch *arch, yasm_intnum *intn, size_t valsize, + const yasm_bytecode *bc, unsigned long line); int yasm_x86__intnum_tobytes (yasm_arch *arch, const yasm_intnum *intn, unsigned char *buf, size_t destsize, size_t valsize, int shift, const yasm_bytecode *bc, - int rel, int warn, unsigned long line); + int warn, unsigned long line); unsigned int yasm_x86__get_reg_size(yasm_arch *arch, unsigned long reg); #endif diff --git a/modules/arch/x86/x86bc.c b/modules/arch/x86/x86bc.c index 02439fc7..a959d261 100644 --- a/modules/arch/x86/x86bc.c +++ b/modules/arch/x86/x86bc.c @@ -1026,10 +1026,17 @@ x86_bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d, if (ea->disp) { if (eat.pcrel) { + /*@null@*/ yasm_expr *wrt = yasm_expr_extract_wrt(&ea->disp); ea->disp = yasm_expr_create(YASM_EXPR_SUB, yasm_expr_expr(ea->disp), yasm_expr_sym(eat.origin), bc->line); + if (wrt) { + ea->disp = + yasm_expr_create(YASM_EXPR_WRT, + yasm_expr_expr(ea->disp), + yasm_expr_expr(wrt), bc->line); + } if (output_expr(&ea->disp, *bufp, ea->len, (size_t)(ea->len*8), 0, (unsigned long)(*bufp-bufp_orig), bc, 1, 1, @@ -1074,6 +1081,7 @@ x86_bc_jmp_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d, unsigned int i; unsigned char *bufp_orig = *bufp; /*@null@*/ yasm_expr *targetseg; + /*@null@*/ yasm_expr *wrt; yasm_expr *dup; /* Prefixes */ @@ -1101,9 +1109,14 @@ x86_bc_jmp_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d, YASM_WRITE_8(*bufp, jmp->shortop.opcode[i]); /* Relative displacement */ + wrt = yasm_expr_extract_wrt(&jmp->target); jmp->target = yasm_expr_create(YASM_EXPR_SUB, yasm_expr_expr(jmp->target), yasm_expr_sym(jmp->origin), bc->line); + if (wrt) + jmp->target = yasm_expr_create_tree(jmp->target, + YASM_EXPR_WRT, wrt, + bc->line); if (output_expr(&jmp->target, *bufp, 1, 8, 0, (unsigned long)(*bufp-bufp_orig), bc, 1, 1, d)) return 1; @@ -1122,9 +1135,14 @@ x86_bc_jmp_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d, YASM_WRITE_8(*bufp, jmp->nearop.opcode[i]); /* Relative displacement */ + wrt = yasm_expr_extract_wrt(&jmp->target); jmp->target = yasm_expr_create(YASM_EXPR_SUB, yasm_expr_expr(jmp->target), yasm_expr_sym(jmp->origin), bc->line); + if (wrt) + jmp->target = yasm_expr_create_tree(jmp->target, + YASM_EXPR_WRT, wrt, + bc->line); i = (opersize == 16) ? 2 : 4; if (output_expr(&jmp->target, *bufp, i, i*8, 0, (unsigned long)(*bufp-bufp_orig), bc, 1, 1, d)) @@ -1168,28 +1186,28 @@ x86_bc_jmp_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d, return 0; } +int +yasm_x86__intnum_fixup_rel(yasm_arch *arch, yasm_intnum *intn, size_t valsize, + const yasm_bytecode *bc, unsigned long line) +{ + yasm_intnum *delta; + if (valsize != 8 && valsize != 16 && valsize != 32) + yasm_internal_error( + N_("tried to do PC-relative offset from invalid sized value")); + delta = yasm_intnum_create_uint(bc->len); + yasm_intnum_calc(intn, YASM_EXPR_SUB, delta, line); + yasm_intnum_destroy(delta); + return 0; +} + int yasm_x86__intnum_tobytes(yasm_arch *arch, const yasm_intnum *intn, unsigned char *buf, size_t destsize, size_t valsize, - int shift, const yasm_bytecode *bc, int rel, int warn, + int shift, const yasm_bytecode *bc, int warn, unsigned long line) { - if (rel) { - yasm_intnum *relnum, *delta; - if (valsize != 8 && valsize != 16 && valsize != 32) - yasm_internal_error( - N_("tried to do PC-relative offset from invalid sized value")); - relnum = yasm_intnum_copy(intn); - delta = yasm_intnum_create_uint(bc->len); - yasm_intnum_calc(relnum, YASM_EXPR_SUB, delta, line); - yasm_intnum_destroy(delta); - yasm_intnum_get_sized(relnum, buf, destsize, valsize, shift, 0, warn, - line); - yasm_intnum_destroy(relnum); - } else { - /* Write value out. */ - yasm_intnum_get_sized(intn, buf, destsize, valsize, shift, 0, warn, - line); - } + /* Write value out. */ + yasm_intnum_get_sized(intn, buf, destsize, valsize, shift, 0, warn, + line); return 0; } diff --git a/modules/arch/x86/x86expr.c b/modules/arch/x86/x86expr.c index 4bea638b..4d1f1a85 100644 --- a/modules/arch/x86/x86expr.c +++ b/modules/arch/x86/x86expr.c @@ -157,11 +157,6 @@ x86_expr_checkea_distcheck_reg(yasm_expr **ep, unsigned int bits) case YASM_EXPR_ADD: case YASM_EXPR_IDENT: break; - case YASM_EXPR_WRT: - /* Allow expr WRT rip in 64-bit mode. */ - if (bits != 64 || i != 1) - return 0; - break; default: return 0; } @@ -252,9 +247,9 @@ x86_expr_checkea_distcheck_reg(yasm_expr **ep, unsigned int bits) * and 0 if all values successfully determined and saved in data. */ static int -x86_expr_checkea_getregusage(yasm_expr **ep, /*@null@*/ int *indexreg, - unsigned char *pcrel, unsigned int bits, void *data, - int *(*get_reg)(yasm_expr__item *ei, int *regnum, void *d), +x86_expr_checkea_getregusage(yasm_expr **ep, /*@null@*/ yasm_expr **wrt, + /*@null@*/ int *indexreg, unsigned char *pcrel, unsigned int bits, + void *data, int *(*get_reg)(yasm_expr__item *ei, int *regnum, void *d), yasm_calc_bc_dist_func calc_bc_dist) { int i; @@ -267,6 +262,9 @@ x86_expr_checkea_getregusage(yasm_expr **ep, /*@null@*/ int *indexreg, /*@-unqualifiedtrans@*/ *ep = yasm_expr__level_tree(*ep, 1, indexreg == 0, calc_bc_dist, NULL, NULL, NULL); + if (*wrt) + *wrt = yasm_expr__level_tree(*wrt, 1, indexreg == 0, calc_bc_dist, + NULL, NULL, NULL); /*@=unqualifiedtrans@*/ assert(*ep != NULL); e = *ep; @@ -283,27 +281,31 @@ x86_expr_checkea_getregusage(yasm_expr **ep, /*@null@*/ int *indexreg, break; } - switch (e->op) { - case YASM_EXPR_WRT: - /* Handle xx WRT rip. */ - if (e->terms[1].type == YASM_EXPR_REG) { - if (bits != 64) /* only valid in 64-bit mode */ - return 1; - reg = get_reg(&e->terms[1], ®num, data); - if (!reg || regnum != 16) /* only accept rip */ - return 1; - (*reg)++; + if (*wrt && (*wrt)->op == YASM_EXPR_IDENT && + (*wrt)->terms[0].type == YASM_EXPR_REG) { + /* Handle xx WRT rip. */ + if (bits != 64) /* only valid in 64-bit mode */ + return 1; + reg = get_reg(&(*wrt)->terms[0], ®num, data); + if (!reg || regnum != 16) /* only accept rip */ + return 1; + (*reg)++; - /* Simplify WRT to ident. Set pcrel to 1 to indicate to x86 - * bytecode code to do PC-relative displacement transform. - */ - *pcrel = 1; - e->op = YASM_EXPR_IDENT; - e->numterms = 1; - /* Delete the intnum created by get_reg(). */ - yasm_intnum_destroy(e->terms[1].data.intn); - } - break; + /* Delete WRT. Set pcrel to 1 to indicate to x86 + * bytecode code to do PC-relative displacement transform. + */ + *pcrel = 1; + yasm_expr_destroy(*wrt); + + /* Drill down to next WRT and recurse if there was one. */ + *wrt = yasm_expr_extract_wrt(ep); + if (*wrt) + return x86_expr_checkea_getregusage(ep, wrt, indexreg, pcrel, + bits, data, get_reg, + calc_bc_dist); + } + + switch (e->op) { case YASM_EXPR_ADD: /* Prescan for non-int multipliers against a reg. * This is because if any of the terms is a more complex @@ -563,7 +565,12 @@ yasm_x86__expr_checkea(yasm_expr **ep, unsigned char *addrsize, unsigned char *rex, yasm_calc_bc_dist_func calc_bc_dist) { - yasm_expr *e = *ep; + yasm_expr *e, *wrt; + int retval; + + /* First split off any top-level WRT. We'll add it back in at the end */ + wrt = yasm_expr_extract_wrt(ep); + e = *ep; if (*addrsize == 0) { /* we need to figure out the address size from what we know about: @@ -651,7 +658,7 @@ yasm_x86__expr_checkea(yasm_expr **ep, unsigned char *addrsize, reg3264_data.regs = reg3264mult; reg3264_data.bits = bits; reg3264_data.addrsize = *addrsize; - switch (x86_expr_checkea_getregusage(ep, &indexreg, pcrel, bits, + switch (x86_expr_checkea_getregusage(ep, &wrt, &indexreg, pcrel, bits, ®3264_data, x86_expr_checkea_get_reg3264, calc_bc_dist)) { @@ -660,6 +667,9 @@ yasm_x86__expr_checkea(yasm_expr **ep, unsigned char *addrsize, yasm__error(e->line, N_("invalid effective address")); return 1; case 2: + if (wrt) + *ep = yasm_expr_create_tree(*ep, YASM_EXPR_WRT, wrt, + (*ep)->line); return 2; default: e = *ep; @@ -782,6 +792,9 @@ yasm_x86__expr_checkea(yasm_expr **ep, unsigned char *addrsize, /* RIP always requires a 32-bit displacement */ *v_modrm = 1; *displen = 4; + if (wrt) + *ep = yasm_expr_create_tree(*ep, YASM_EXPR_WRT, wrt, + (*ep)->line); return 0; } else if (indexreg == REG3264_NONE) { /* basereg only */ @@ -860,9 +873,12 @@ yasm_x86__expr_checkea(yasm_expr **ep, unsigned char *addrsize, } /* Calculate displacement length (if possible) */ - return x86_checkea_calc_displen(ep, 4, basereg == REG3264_NONE, + retval = x86_checkea_calc_displen(ep, 4, basereg == REG3264_NONE, basereg == REG3264_EBP || basereg == REG64_R13, displen, modrm, v_modrm); + if (wrt) + *ep = yasm_expr_create_tree(*ep, YASM_EXPR_WRT, wrt, (*ep)->line); + return retval; } else if (*addrsize == 16 && *n_modrm && !*v_modrm) { static const unsigned char modrm16[16] = { 0006 /* disp16 */, 0007 /* [BX] */, 0004 /* [SI] */, @@ -893,8 +909,8 @@ yasm_x86__expr_checkea(yasm_expr **ep, unsigned char *addrsize, *v_sib = 0; *n_sib = 0; - switch (x86_expr_checkea_getregusage(ep, (int *)NULL, pcrel, bits, - ®16mult, + switch (x86_expr_checkea_getregusage(ep, &wrt, (int *)NULL, pcrel, + bits, ®16mult, x86_expr_checkea_get_reg16, calc_bc_dist)) { case 1: @@ -902,6 +918,9 @@ yasm_x86__expr_checkea(yasm_expr **ep, unsigned char *addrsize, yasm__error(e->line, N_("invalid effective address")); return 1; case 2: + if (wrt) + *ep = yasm_expr_create_tree(*ep, YASM_EXPR_WRT, wrt, + (*ep)->line); return 2; default: e = *ep; @@ -935,9 +954,12 @@ yasm_x86__expr_checkea(yasm_expr **ep, unsigned char *addrsize, *modrm |= modrm16[havereg]; /* Calculate displacement length (if possible) */ - return x86_checkea_calc_displen(ep, 2, havereg == HAVE_NONE, - havereg == HAVE_BP, displen, modrm, - v_modrm); + retval = x86_checkea_calc_displen(ep, 2, havereg == HAVE_NONE, + havereg == HAVE_BP, displen, modrm, + v_modrm); + if (wrt) + *ep = yasm_expr_create_tree(*ep, YASM_EXPR_WRT, wrt, (*ep)->line); + return retval; } else if (!*n_modrm && !*n_sib) { /* Special case for MOV MemOffs opcode: displacement but no modrm. */ switch (*addrsize) { @@ -963,6 +985,8 @@ yasm_x86__expr_checkea(yasm_expr **ep, unsigned char *addrsize, break; } } + if (wrt) + *ep = yasm_expr_create_tree(*ep, YASM_EXPR_WRT, wrt, (*ep)->line); return 0; } diff --git a/modules/dbgfmts/stabs/stabs-dbgfmt.c b/modules/dbgfmts/stabs/stabs-dbgfmt.c index cd2bc025..9cdead87 100644 --- a/modules/dbgfmts/stabs/stabs-dbgfmt.c +++ b/modules/dbgfmts/stabs/stabs-dbgfmt.c @@ -443,7 +443,7 @@ stabs_bc_stab_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d, if (stab->symvalue != NULL) { bc->offset += 8; - output_reloc(stab->symvalue, bc, buf, 4, 32, 0, 0, d); + output_reloc(stab->symvalue, bc, buf, 4, 32, 0, d); bc->offset -= 8; buf += 4; } diff --git a/modules/listfmts/nasm/nasm-listfmt.c b/modules/listfmts/nasm/nasm-listfmt.c index a8046d78..9dcd8063 100644 --- a/modules/listfmts/nasm/nasm-listfmt.c +++ b/modules/listfmts/nasm/nasm-listfmt.c @@ -87,7 +87,7 @@ nasm_listfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize, /*@null@*/ void *d) { /*@null@*/ nasm_listfmt_output_info *info = (nasm_listfmt_output_info *)d; - /*@dependent@*/ /*@null@*/ const yasm_intnum *intn; + /*@dependent@*/ /*@null@*/ yasm_intnum *intn; /*@dependent@*/ /*@null@*/ const yasm_floatnum *flt; assert(info != NULL); @@ -115,15 +115,14 @@ nasm_listfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize, if (shift < 0) yasm_internal_error(N_("attempting to negative shift a float")); return yasm_arch_floatnum_tobytes(info->arch, flt, buf, destsize, - valsize, (unsigned int)shift, warn, + valsize, (unsigned int)shift, 0, bc->line); } intn = yasm_expr_get_intnum(ep, NULL); if (intn) return yasm_arch_intnum_tobytes(info->arch, intn, buf, destsize, - valsize, shift, bc, rel, warn, - bc->line); + valsize, shift, bc, 0, bc->line); return 0; } diff --git a/modules/objfmts/bin/bin-objfmt.c b/modules/objfmts/bin/bin-objfmt.c index 3995bcc2..f2ee7e61 100644 --- a/modules/objfmts/bin/bin-objfmt.c +++ b/modules/objfmts/bin/bin-objfmt.c @@ -155,7 +155,7 @@ bin_objfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize, int rel, int warn, /*@null@*/ void *d) { /*@null@*/ bin_objfmt_output_info *info = (bin_objfmt_output_info *)d; - /*@dependent@*/ /*@null@*/ const yasm_intnum *intn; + /*@dependent@*/ /*@null@*/ yasm_intnum *intn; /*@dependent@*/ /*@null@*/ const yasm_floatnum *flt; assert(info != NULL); @@ -180,10 +180,18 @@ bin_objfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize, /* Handle integer expressions */ intn = yasm_expr_get_intnum(ep, NULL); - if (intn) + if (intn) { + if (rel) { + int retval = yasm_arch_intnum_fixup_rel(info->objfmt_bin->arch, + intn, valsize, bc, + bc->line); + if (retval) + return retval; + } return yasm_arch_intnum_tobytes(info->objfmt_bin->arch, intn, buf, - destsize, valsize, shift, bc, rel, - warn, bc->line); + destsize, valsize, shift, bc, warn, + bc->line); + } /* Check for complex float expressions */ if (yasm_expr__contains(*ep, YASM_EXPR_FLOAT)) { diff --git a/modules/objfmts/coff/coff-objfmt.c b/modules/objfmts/coff/coff-objfmt.c index 5616e4f3..ff919681 100644 --- a/modules/objfmts/coff/coff-objfmt.c +++ b/modules/objfmts/coff/coff-objfmt.c @@ -361,7 +361,7 @@ coff_objfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize, { /*@null@*/ coff_objfmt_output_info *info = (coff_objfmt_output_info *)d; yasm_objfmt_coff *objfmt_coff; - /*@dependent@*/ /*@null@*/ const yasm_intnum *intn; + /*@dependent@*/ /*@null@*/ yasm_intnum *intn; /*@dependent@*/ /*@null@*/ const yasm_floatnum *flt; /*@dependent@*/ /*@null@*/ yasm_symrec *sym; /*@dependent@*/ yasm_section *label_sect; @@ -464,10 +464,16 @@ coff_objfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize, yasm_section_add_reloc(info->sect, (yasm_reloc *)reloc, yasm_xfree); } intn = yasm_expr_get_intnum(ep, NULL); - if (intn) + if (intn) { + if (rel) { + int retval = yasm_arch_intnum_fixup_rel(objfmt_coff->arch, intn, + valsize, bc, bc->line); + if (retval) + return retval; + } return yasm_arch_intnum_tobytes(objfmt_coff->arch, intn, buf, destsize, - valsize, shift, bc, rel, warn, - bc->line); + valsize, shift, bc, warn, bc->line); + } /* Check for complex float expressions */ if (yasm_expr__contains(*ep, YASM_EXPR_FLOAT)) { diff --git a/modules/objfmts/elf/elf-machine.h b/modules/objfmts/elf/elf-machine.h index edc3f10f..2a375971 100644 --- a/modules/objfmts/elf/elf-machine.h +++ b/modules/objfmts/elf/elf-machine.h @@ -44,7 +44,8 @@ #define YASM_WRITE_64Z_L(p, i) YASM_WRITE_64C_L(p, 0, i) -typedef int(*func_accepts_size_t)(size_t); +typedef int(*func_accepts_reloc)(size_t val, yasm_symrec *wrt, + yasm_symrec **ssyms); typedef void(*func_write_symtab_entry)(unsigned char *bufp, elf_symtab_entry *entry, yasm_intnum *value_intn, @@ -57,7 +58,8 @@ typedef void(*func_write_secthead_rel)(unsigned char *bufp, typedef void(*func_handle_reloc_addend)(yasm_intnum *intn, elf_reloc_entry *reloc); -typedef unsigned int(*func_map_reloc_info_to_type)(elf_reloc_entry *reloc); +typedef unsigned int(*func_map_reloc_info_to_type)(elf_reloc_entry *reloc, + yasm_symrec **ssyms); typedef void(*func_write_reloc)(unsigned char *bufp, elf_reloc_entry *reloc, unsigned int r_type, @@ -67,6 +69,11 @@ typedef void (*func_write_proghead)(unsigned char **bufpp, unsigned long secthead_count, elf_section_index shstrtab_index); +typedef struct { + const char *name; /* should be something like ..name */ + const int sym_rel; /* symbol or section-relative? */ +} elf_machine_ssym; + typedef struct { const char *arch; const char *machine; @@ -76,7 +83,7 @@ typedef struct { const unsigned long reloc_entry_size; const unsigned long secthead_size; const unsigned long proghead_size; - func_accepts_size_t accepts_reloc_size; + func_accepts_reloc accepts_reloc; func_write_symtab_entry write_symtab_entry; func_write_secthead write_secthead; func_write_secthead_rel write_secthead_rel; @@ -84,6 +91,9 @@ typedef struct { func_map_reloc_info_to_type map_reloc_info_to_type; func_write_reloc write_reloc; func_write_proghead write_proghead; + + const elf_machine_ssym *ssyms; /* array of "special" syms */ + const size_t num_ssyms; /* size of array */ } elf_machine_handler; #endif /* ELF_MACHINE_H_INCLUDED */ diff --git a/modules/objfmts/elf/elf-objfmt.c b/modules/objfmts/elf/elf-objfmt.c index 78861b61..9172b64d 100644 --- a/modules/objfmts/elf/elf-objfmt.c +++ b/modules/objfmts/elf/elf-objfmt.c @@ -62,6 +62,8 @@ typedef struct yasm_objfmt_elf { yasm_object *object; yasm_symtab *symtab; /*@dependent@*/ yasm_arch *arch; + + yasm_symrec *dotdotsym; /* ..sym symbol */ } yasm_objfmt_elf; typedef struct { @@ -154,7 +156,7 @@ elf_objfmt_create(const char *in_filename, yasm_object *object, yasm_arch *a) objfmt_elf->object = object; objfmt_elf->symtab = yasm_object_get_symtab(object); objfmt_elf->arch = a; - if (!elf_set_arch(a)) { + if (!elf_set_arch(a, objfmt_elf->symtab)) { yasm_xfree(objfmt_elf); return NULL; } @@ -166,14 +168,18 @@ elf_objfmt_create(const char *in_filename, yasm_object *object, yasm_arch *a) objfmt_elf->elf_symtab = elf_symtab_create(); /* FIXME: misuse of NULL bytecode here; it works, but only barely. */ - filesym = yasm_symtab_define_label(yasm_object_get_symtab(object), ".file", - NULL, 0, 0); + filesym = yasm_symtab_define_label(objfmt_elf->symtab, ".file", NULL, 0, + 0); entry = elf_symtab_entry_create( elf_strtab_append_str(objfmt_elf->strtab, in_filename), filesym); yasm_symrec_add_data(filesym, &elf_symrec_data, entry); elf_symtab_set_nonzero(entry, NULL, SHN_ABS, STB_LOCAL, STT_FILE, NULL, 0); elf_symtab_append_entry(objfmt_elf->elf_symtab, entry); + /* FIXME: misuse of NULL bytecode */ + objfmt_elf->dotdotsym = yasm_symtab_define_label(objfmt_elf->symtab, + "..sym", NULL, 1, 0); + return (yasm_objfmt *)objfmt_elf; } @@ -204,15 +210,15 @@ elf_objfmt_output_align(FILE *f, unsigned int align) static int elf_objfmt_output_reloc(yasm_symrec *sym, yasm_bytecode *bc, unsigned char *buf, size_t destsize, size_t valsize, - int rel, int warn, void *d) + int warn, void *d) { elf_reloc_entry *reloc; elf_objfmt_output_info *info = d; yasm_intnum *zero; int retval; - reloc = elf_reloc_entry_create(sym, - yasm_intnum_create_uint(bc->offset), rel, valsize); + reloc = elf_reloc_entry_create(sym, NULL, + yasm_intnum_create_uint(bc->offset), 0, valsize); if (reloc == NULL) { yasm__error(bc->line, N_("elf: invalid relocation size")); return 1; @@ -224,7 +230,7 @@ elf_objfmt_output_reloc(yasm_symrec *sym, yasm_bytecode *bc, zero = yasm_intnum_create_uint(0); elf_handle_reloc_addend(zero, reloc); retval = yasm_arch_intnum_tobytes(info->objfmt_elf->arch, zero, buf, - destsize, valsize, 0, bc, rel, warn, + destsize, valsize, 0, bc, warn, bc->line); yasm_intnum_destroy(zero); return retval; @@ -241,6 +247,8 @@ elf_objfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize, /*@dependent@*/ /*@null@*/ const yasm_floatnum *flt; /*@dependent@*/ /*@null@*/ yasm_symrec *sym; /*@null@*/ elf_reloc_entry *reloc = NULL; + /*@null@*/ yasm_expr *wrt_expr; + /*@dependent@*/ /*@null@*/ yasm_symrec *wrt = NULL; if (info == NULL) yasm_internal_error("null info struct"); @@ -257,13 +265,32 @@ elf_objfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize, (unsigned int)shift, warn, bc->line); } + /* Check for a WRT relocation */ + wrt_expr = yasm_expr_extract_wrt(ep); + if (wrt_expr) { + wrt = yasm_expr_extract_symrec(&wrt_expr, 0, + yasm_common_calc_bc_dist); + yasm_expr_destroy(wrt_expr); + if (!wrt) { + yasm__error(bc->line, N_("WRT expression too complex")); + return 1; + } + } + /* Handle integer expressions, with relocation if necessary */ - sym = yasm_expr_extract_symrec(ep, 1, yasm_common_calc_bc_dist); + sym = yasm_expr_extract_symrec(ep, + !(wrt == info->objfmt_elf->dotdotsym || + (wrt && elf_is_wrt_sym_relative(wrt))), + yasm_common_calc_bc_dist); if (sym) { yasm_sym_vis vis; vis = yasm_symrec_get_visibility(sym); - if (!(vis & (YASM_SYM_COMMON|YASM_SYM_EXTERN))) + if (wrt == info->objfmt_elf->dotdotsym) + wrt = NULL; + else if (wrt && elf_is_wrt_sym_relative(wrt)) + ; + else if (!(vis & (YASM_SYM_COMMON|YASM_SYM_EXTERN))) { yasm_bytecode *label_precbc; /* Local symbols need relocation to their section's start */ @@ -290,10 +317,10 @@ elf_objfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize, *ep = yasm_expr_simplify(*ep, yasm_common_calc_bc_dist); } - reloc = elf_reloc_entry_create(sym, + reloc = elf_reloc_entry_create(sym, wrt, yasm_intnum_create_uint(bc->offset + offset), rel, valsize); if (reloc == NULL) { - yasm__error(bc->line, N_("elf: invalid relocation size")); + yasm__error(bc->line, N_("elf: invalid relocation (WRT or size)")); return 1; } /* allocate .rel[a] sections on a need-basis */ @@ -302,12 +329,20 @@ elf_objfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize, } intn = yasm_expr_get_intnum(ep, NULL); - if (intn && reloc) - elf_handle_reloc_addend(intn, reloc); - if (intn) + if (intn) { + if (rel) { + int retval = yasm_arch_intnum_fixup_rel(info->objfmt_elf->arch, + intn, valsize, bc, + bc->line); + if (retval) + return retval; + } + if (reloc) + elf_handle_reloc_addend(intn, reloc); return yasm_arch_intnum_tobytes(info->objfmt_elf->arch, intn, buf, - destsize, valsize, shift, bc, rel, - warn, bc->line); + destsize, valsize, shift, bc, warn, + bc->line); + } /* Check for complex float expressions */ if (yasm_expr__contains(*ep, YASM_EXPR_FLOAT)) { diff --git a/modules/objfmts/elf/elf-x86-amd64.c b/modules/objfmts/elf/elf-x86-amd64.c index 56121ba6..29542f92 100644 --- a/modules/objfmts/elf/elf-x86-amd64.c +++ b/modules/objfmts/elf/elf-x86-amd64.c @@ -26,7 +26,7 @@ */ #include -/*@unused@*/ RCSID("$Id:$"); +/*@unused@*/ RCSID("$Id$"); #define YASM_LIB_INTERNAL #define YASM_EXPR_INTERNAL @@ -35,9 +35,23 @@ #include "elf.h" #include "elf-machine.h" +enum ssym_index { + SSYM_GOTPCREL = 0, + SSYM_GOT, + SSYM_PLT +}; + static int -elf_x86_amd64_accepts_reloc_size(size_t val) +elf_x86_amd64_accepts_reloc(size_t val, yasm_symrec *wrt, yasm_symrec **ssyms) { + if (wrt) { + if ((wrt == ssyms[SSYM_GOTPCREL] && val == 32) + || (wrt == ssyms[SSYM_GOT] && val == 32) + || (wrt == ssyms[SSYM_PLT] && val == 32)) + return 1; + else + return 0; + } return (val&(val-1)) ? 0 : ((val & (8|16|32|64)) != 0); } @@ -126,9 +140,19 @@ elf_x86_amd64_handle_reloc_addend(yasm_intnum *intn, elf_reloc_entry *reloc) } static unsigned int -elf_x86_amd64_map_reloc_info_to_type(elf_reloc_entry *reloc) +elf_x86_amd64_map_reloc_info_to_type(elf_reloc_entry *reloc, + yasm_symrec **ssyms) { - if (reloc->rtype_rel) { + if (reloc->wrt) { + if (reloc->wrt == ssyms[SSYM_GOTPCREL] && reloc->valsize == 32) + return (unsigned char) R_X86_64_GOTPCREL; + else if (reloc->wrt == ssyms[SSYM_GOT] && reloc->valsize == 32) + return (unsigned char) R_X86_64_GOT32; + else if (reloc->wrt == ssyms[SSYM_PLT] && reloc->valsize == 32) + return (unsigned char) R_X86_64_PLT32; + else + yasm_internal_error(N_("Unsupported WRT")); + } else if (reloc->rtype_rel) { switch (reloc->valsize) { case 8: return (unsigned char) R_X86_64_PC8; case 16: return (unsigned char) R_X86_64_PC16; @@ -190,16 +214,24 @@ elf_x86_amd64_write_proghead(unsigned char **bufpp, *bufpp = bufp; } +static elf_machine_ssym elf_x86_amd64_ssyms[] = { + {"..gotpcrel", 1}, + {"..got", 1}, + {"..plt", 0} +}; + const elf_machine_handler elf_machine_handler_x86_amd64 = { "x86", "amd64", ".rela", SYMTAB64_SIZE, SYMTAB64_ALIGN, RELOC64A_SIZE, SHDR64_SIZE, EHDR64_SIZE, - elf_x86_amd64_accepts_reloc_size, + elf_x86_amd64_accepts_reloc, elf_x86_amd64_write_symtab_entry, elf_x86_amd64_write_secthead, elf_x86_amd64_write_secthead_rel, elf_x86_amd64_handle_reloc_addend, elf_x86_amd64_map_reloc_info_to_type, elf_x86_amd64_write_reloc, - elf_x86_amd64_write_proghead + elf_x86_amd64_write_proghead, + elf_x86_amd64_ssyms, + sizeof(elf_x86_amd64_ssyms)/sizeof(elf_x86_amd64_ssyms[0]) }; diff --git a/modules/objfmts/elf/elf-x86-x86.c b/modules/objfmts/elf/elf-x86-x86.c index 689622e1..e20150ea 100644 --- a/modules/objfmts/elf/elf-x86-x86.c +++ b/modules/objfmts/elf/elf-x86-x86.c @@ -26,7 +26,7 @@ */ #include -/*@unused@*/ RCSID("$Id:$"); +/*@unused@*/ RCSID("$Id$"); #define YASM_LIB_INTERNAL #define YASM_EXPR_INTERNAL @@ -35,9 +35,25 @@ #include "elf.h" #include "elf-machine.h" +enum ssym_index { + SSYM_GOTPC = 0, + SSYM_GOTOFF, + SSYM_GOT, + SSYM_PLT +}; + static int -elf_x86_x86_accepts_reloc_size(size_t val) +elf_x86_x86_accepts_reloc(size_t val, yasm_symrec *wrt, yasm_symrec **ssyms) { + if (wrt) { + if ((wrt == ssyms[SSYM_GOTPC] && val == 32) + || (wrt == ssyms[SSYM_GOTOFF] && val == 32) + || (wrt == ssyms[SSYM_GOT] && val == 32) + || (wrt == ssyms[SSYM_PLT] && val == 32)) + return 1; + else + return 0; + } return (val&(val-1)) ? 0 : ((val & (8|16|32)) != 0); } @@ -117,9 +133,21 @@ elf_x86_x86_handle_reloc_addend(yasm_intnum *intn, elf_reloc_entry *reloc) } static unsigned int -elf_x86_x86_map_reloc_info_to_type(elf_reloc_entry *reloc) +elf_x86_x86_map_reloc_info_to_type(elf_reloc_entry *reloc, + yasm_symrec **ssyms) { - if (reloc->rtype_rel) { + if (reloc->wrt) { + if (reloc->wrt == ssyms[SSYM_GOTPC] && reloc->valsize == 32) + return (unsigned char) R_386_GOTPC; + else if (reloc->wrt == ssyms[SSYM_GOTOFF] && reloc->valsize == 32) + return (unsigned char) R_386_GOTOFF; + else if (reloc->wrt == ssyms[SSYM_GOT] && reloc->valsize == 32) + return (unsigned char) R_386_GOT32; + else if (reloc->wrt == ssyms[SSYM_PLT] && reloc->valsize == 32) + return (unsigned char) R_386_PLT32; + else + yasm_internal_error(N_("Unsupported WRT")); + } else if (reloc->rtype_rel) { switch (reloc->valsize) { case 8: return (unsigned char) R_386_PC8; case 16: return (unsigned char) R_386_PC16; @@ -175,16 +203,25 @@ elf_x86_x86_write_proghead(unsigned char **bufpp, *bufpp = bufp; } +static elf_machine_ssym elf_x86_x86_ssyms[] = { + {"..gotpc", 0}, + {"..gotoff", 0}, + {"..got", 1}, + {"..plt", 0} +}; + const elf_machine_handler elf_machine_handler_x86_x86 = { "x86", "x86", ".rel", SYMTAB32_SIZE, SYMTAB32_ALIGN, RELOC32_SIZE, SHDR32_SIZE, EHDR32_SIZE, - elf_x86_x86_accepts_reloc_size, + elf_x86_x86_accepts_reloc, elf_x86_x86_write_symtab_entry, elf_x86_x86_write_secthead, elf_x86_x86_write_secthead_rel, elf_x86_x86_handle_reloc_addend, elf_x86_x86_map_reloc_info_to_type, elf_x86_x86_write_reloc, - elf_x86_x86_write_proghead + elf_x86_x86_write_proghead, + elf_x86_x86_ssyms, + sizeof(elf_x86_x86_ssyms)/sizeof(elf_x86_x86_ssyms[0]) }; diff --git a/modules/objfmts/elf/elf.c b/modules/objfmts/elf/elf.c index 7d63be49..513ed161 100644 --- a/modules/objfmts/elf/elf.c +++ b/modules/objfmts/elf/elf.c @@ -63,9 +63,10 @@ static const elf_machine_handler *elf_machine_handlers[] = }; static const elf_machine_handler elf_null_machine = {0}; static elf_machine_handler const *elf_march = &elf_null_machine; +static yasm_symrec **elf_ssyms; int -elf_set_arch(yasm_arch *arch) +elf_set_arch(yasm_arch *arch, yasm_symtab *symtab) { const char *machine = yasm_arch_get_machine(arch); int i; @@ -78,23 +79,50 @@ elf_set_arch(yasm_arch *arch) if (yasm__strcasecmp(machine, elf_march->machine)==0) break; } + + if (elf_march && elf_march->num_ssyms > 0) + { + /* Allocate "special" syms */ + elf_ssyms = + yasm_xmalloc(elf_march->num_ssyms * sizeof(yasm_symrec *)); + for (i=0; (unsigned int)inum_ssyms; i++) + { + /* FIXME: misuse of NULL bytecode */ + elf_ssyms[i] = yasm_symtab_define_label(symtab, + elf_march->ssyms[i].name, + NULL, 1, 0); + } + } + return elf_march != NULL; } /* reloc functions */ +int +elf_is_wrt_sym_relative(yasm_symrec *wrt) +{ + int i; + for (i=0; (unsigned int)inum_ssyms; i++) { + if (elf_ssyms[i] == wrt) + return elf_march->ssyms[i].sym_rel; + } + return 0; +} + /* takes ownership of addr */ elf_reloc_entry * elf_reloc_entry_create(yasm_symrec *sym, + yasm_symrec *wrt, yasm_intnum *addr, int rel, size_t valsize) { elf_reloc_entry *entry; - if (!elf_march->accepts_reloc_size) + if (!elf_march->accepts_reloc) yasm_internal_error(N_("Unsupported machine for ELF output")); - if (!elf_march->accepts_reloc_size(valsize)) + if (!elf_march->accepts_reloc(valsize, wrt, elf_ssyms)) { if (addr) yasm_intnum_destroy(addr); @@ -110,6 +138,7 @@ elf_reloc_entry_create(yasm_symrec *sym, entry->rtype_rel = rel; entry->valsize = valsize; entry->addend = NULL; + entry->wrt = wrt; return entry; } @@ -670,7 +699,7 @@ elf_secthead_write_relocs_to_file(FILE *f, yasm_section *sect, vis = yasm_symrec_get_visibility(reloc->reloc.sym); if (!elf_march->map_reloc_info_to_type) yasm_internal_error(N_("Unsupported arch/machine for elf output")); - r_type = elf_march->map_reloc_info_to_type(reloc); + r_type = elf_march->map_reloc_info_to_type(reloc, elf_ssyms); bufp = buf; if (!elf_march->write_reloc || !elf_march->reloc_entry_size) diff --git a/modules/objfmts/elf/elf.h b/modules/objfmts/elf/elf.h index edf62f7c..10208c5c 100644 --- a/modules/objfmts/elf/elf.h +++ b/modules/objfmts/elf/elf.h @@ -354,6 +354,7 @@ struct elf_reloc_entry { int rtype_rel; size_t valsize; yasm_intnum *addend; + /*@null@*/ yasm_symrec *wrt; }; STAILQ_HEAD(elf_strtab_head, elf_strtab_entry); @@ -384,10 +385,12 @@ extern const yasm_assoc_data_callback elf_section_data; extern const yasm_assoc_data_callback elf_symrec_data; -int elf_set_arch(struct yasm_arch *arch); +int elf_set_arch(struct yasm_arch *arch, yasm_symtab *symtab); /* reloc functions */ +int elf_is_wrt_sym_relative(yasm_symrec *wrt); elf_reloc_entry *elf_reloc_entry_create(yasm_symrec *sym, + /*@null@*/ yasm_symrec *wrt, yasm_intnum *addr, int rel, size_t valsize); diff --git a/modules/objfmts/elf/tests/Makefile.inc b/modules/objfmts/elf/tests/Makefile.inc index 100cca0d..dee1cb8a 100644 --- a/modules/objfmts/elf/tests/Makefile.inc +++ b/modules/objfmts/elf/tests/Makefile.inc @@ -6,6 +6,9 @@ EXTRA_DIST += modules/objfmts/elf/tests/elf_test.sh EXTRA_DIST += modules/objfmts/elf/tests/elfsectalign.asm EXTRA_DIST += modules/objfmts/elf/tests/elfsectalign.hex EXTRA_DIST += modules/objfmts/elf/tests/elfsectalign.errwarn +EXTRA_DIST += modules/objfmts/elf/tests/elfso.asm +EXTRA_DIST += modules/objfmts/elf/tests/elfso.hex +EXTRA_DIST += modules/objfmts/elf/tests/elfso.errwarn EXTRA_DIST += modules/objfmts/elf/tests/elftest.c EXTRA_DIST += modules/objfmts/elf/tests/elftest.asm EXTRA_DIST += modules/objfmts/elf/tests/elftest.hex diff --git a/modules/objfmts/elf/tests/amd64/Makefile.inc b/modules/objfmts/elf/tests/amd64/Makefile.inc index 5fdfe3c2..28dec568 100644 --- a/modules/objfmts/elf/tests/amd64/Makefile.inc +++ b/modules/objfmts/elf/tests/amd64/Makefile.inc @@ -6,3 +6,6 @@ EXTRA_DIST += modules/objfmts/elf/tests/amd64/elf_amd64_test.sh EXTRA_DIST += modules/objfmts/elf/tests/amd64/elf-rip.asm EXTRA_DIST += modules/objfmts/elf/tests/amd64/elf-rip.hex EXTRA_DIST += modules/objfmts/elf/tests/amd64/elf-rip.errwarn +EXTRA_DIST += modules/objfmts/elf/tests/amd64/elfso64.asm +EXTRA_DIST += modules/objfmts/elf/tests/amd64/elfso64.hex +EXTRA_DIST += modules/objfmts/elf/tests/amd64/elfso64.errwarn diff --git a/modules/objfmts/elf/tests/amd64/elf-rip.hex b/modules/objfmts/elf/tests/amd64/elf-rip.hex index 9e68a15d..42947421 100644 --- a/modules/objfmts/elf/tests/amd64/elf-rip.hex +++ b/modules/objfmts/elf/tests/amd64/elf-rip.hex @@ -82,43 +82,35 @@ 00 8b 05 -fa -ff -ff -ff -e8 -fb -ff -ff -ff 00 00 00 -0e 00 +e8 00 00 00 00 00 00 -0a +00 +0e 00 00 00 -03 00 00 00 00 +0a 00 00 00 +03 00 00 00 00 -14 00 00 00 @@ -126,22 +118,30 @@ ff 00 00 00 -02 +14 00 00 00 -03 00 00 00 -02 00 +02 00 00 00 +03 00 00 00 +fc +ff +ff +ff +ff +ff +ff +ff 19 00 00 @@ -158,14 +158,14 @@ ff 00 00 00 -01 -00 -00 -00 -00 -00 -00 -00 +fc +ff +ff +ff +ff +ff +ff +ff 00 2e 74 diff --git a/modules/objfmts/elf/tests/amd64/elfso64.asm b/modules/objfmts/elf/tests/amd64/elfso64.asm new file mode 100644 index 00000000..39dbf2ea --- /dev/null +++ b/modules/objfmts/elf/tests/amd64/elfso64.asm @@ -0,0 +1,90 @@ +; This code is UNTESTED, and almost certainly DOES NOT WORK! +; Do NOT use this as an example of how to write AMD64 shared libraries! +; This code is simply to test the AMD64 ELF WRT relocations. + +; This file should test the following: +; [1] Define and export a global text-section symbol +; [2] Define and export a global data-section symbol +; [3] Define and export a global BSS-section symbol +; [4] Define a non-global text-section symbol +; [5] Define a non-global data-section symbol +; [6] Define a non-global BSS-section symbol +; [7] Define a COMMON symbol +; [8] Define a NASM local label +; [9] Reference a NASM local label +; [10] Import an external symbol +; [11] Make a PC-relative call to an external symbol +; [12] Reference a text-section symbol in the text section +; [13] Reference a data-section symbol in the text section +; [14] Reference a BSS-section symbol in the text section +; [15] Reference a text-section symbol in the data section +; [16] Reference a data-section symbol in the data section +; [17] Reference a BSS-section symbol in the data section + + BITS 64 + GLOBAL lrotate:function ; [1] + GLOBAL greet:function ; [1] + GLOBAL asmstr:data asmstr.end-asmstr ; [2] + GLOBAL textptr:data 4 ; [2] + GLOBAL selfptr:data 4 ; [2] + GLOBAL integer:data 4 ; [3] + EXTERN printf ; [10] + COMMON commvar 4:4 ; [7] + EXTERN _GLOBAL_OFFSET_TABLE_ + + SECTION .text + +; prototype: long lrotate(long x, int num); +lrotate: ; [1] + push rbp + mov rbp,rsp + mov rax,[rbp+8] + mov rcx,[rbp+12] +.label rol rax,1 ; [4] [8] + loop .label ; [9] [12] + mov rsp,rbp + pop rbp + ret + +; prototype: void greet(void); +greet push rbx ; we'll use RBX for GOT, so save it + mov rbx,[integer wrt ..gotpcrel wrt rip] + mov rax,[rbx] ; [14] + inc rax + mov rbx,[_GLOBAL_OFFSET_TABLE_ wrt ..gotpcrel wrt rip] + mov [rbx+localint wrt ..got],eax ; [14] + mov rax,[rbx+commvar wrt ..got] + push qword [rax] + mov rax,[rbx+localptr wrt ..got] ; [13] + push qword [rax] + mov rax,[rbx+integer wrt ..got] ; [1] [14] + push qword [rax] + lea rax,[rbx+printfstr wrt ..got] + push rax ; [13] + call printf wrt ..plt ; [11] + add rsp,16 + pop rbx + ret + + SECTION .data + +; a string +asmstr db 'hello, world', 0 ; [2] +.end + +; a string for Printf +printfstr db "integer==%d, localint==%d, commvar=%d" + db 10, 0 + +; some pointers +localptr dd localint ; [5] [17] +textptr dd greet wrt ..sym ; [15] +selfptr dd selfptr wrt ..sym ; [16] + + SECTION .bss + +; an integer +integer resd 1 ; [3] + +; a local integer +localint resd 1 ; [6] diff --git a/modules/objfmts/elf/tests/amd64/elfso64.errwarn b/modules/objfmts/elf/tests/amd64/elfso64.errwarn new file mode 100644 index 00000000..e69de29b diff --git a/modules/objfmts/elf/tests/amd64/elfso64.hex b/modules/objfmts/elf/tests/amd64/elfso64.hex new file mode 100644 index 00000000..f6bc60f4 --- /dev/null +++ b/modules/objfmts/elf/tests/amd64/elfso64.hex @@ -0,0 +1,1680 @@ +7f +45 +4c +46 +02 +01 +01 +00 +00 +00 +00 +00 +00 +00 +00 +00 +01 +00 +3e +00 +01 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +50 +04 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +40 +00 +00 +00 +00 +00 +40 +00 +09 +00 +01 +00 +55 +48 +89 +e5 +48 +8b +45 +08 +48 +8b +4d +0c +48 +d1 +c0 +e2 +fb +48 +89 +ec +5d +c3 +53 +48 +8b +1d +00 +00 +00 +00 +48 +8b +03 +48 +ff +c0 +48 +8b +1d +00 +00 +00 +00 +89 +83 +00 +00 +00 +00 +48 +8b +83 +00 +00 +00 +00 +ff +30 +48 +8b +83 +00 +00 +00 +00 +ff +30 +48 +8b +83 +00 +00 +00 +00 +ff +30 +48 +8d +83 +00 +00 +00 +00 +50 +e8 +00 +00 +00 +00 +48 +81 +c4 +10 +00 +00 +00 +5b +c3 +00 +00 +1a +00 +00 +00 +00 +00 +00 +00 +09 +00 +00 +00 +0f +00 +00 +00 +fc +ff +ff +ff +ff +ff +ff +ff +27 +00 +00 +00 +00 +00 +00 +00 +09 +00 +00 +00 +12 +00 +00 +00 +fc +ff +ff +ff +ff +ff +ff +ff +2d +00 +00 +00 +00 +00 +00 +00 +03 +00 +00 +00 +05 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +34 +00 +00 +00 +00 +00 +00 +00 +03 +00 +00 +00 +11 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +3d +00 +00 +00 +00 +00 +00 +00 +03 +00 +00 +00 +06 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +46 +00 +00 +00 +00 +00 +00 +00 +03 +00 +00 +00 +0f +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +4f +00 +00 +00 +00 +00 +00 +00 +03 +00 +00 +00 +07 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +55 +00 +00 +00 +00 +00 +00 +00 +04 +00 +00 +00 +10 +00 +00 +00 +fc +ff +ff +ff +ff +ff +ff +ff +68 +65 +6c +6c +6f +2c +20 +77 +6f +72 +6c +64 +00 +69 +6e +74 +65 +67 +65 +72 +3d +3d +25 +64 +2c +20 +6c +6f +63 +61 +6c +69 +6e +74 +3d +3d +25 +64 +2c +20 +63 +6f +6d +6d +76 +61 +72 +3d +25 +64 +0a +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +34 +00 +00 +00 +00 +00 +00 +00 +0a +00 +00 +00 +09 +00 +00 +00 +04 +00 +00 +00 +00 +00 +00 +00 +38 +00 +00 +00 +00 +00 +00 +00 +0a +00 +00 +00 +0b +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +3c +00 +00 +00 +00 +00 +00 +00 +0a +00 +00 +00 +0e +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +2e +74 +65 +78 +74 +00 +2e +64 +61 +74 +61 +00 +2e +62 +73 +73 +00 +2e +72 +65 +6c +61 +2e +74 +65 +78 +74 +00 +2e +72 +65 +6c +61 +2e +64 +61 +74 +61 +00 +2e +73 +74 +72 +74 +61 +62 +00 +2e +73 +79 +6d +74 +61 +62 +00 +2e +73 +68 +73 +74 +72 +74 +61 +62 +00 +00 +00 +00 +2d +00 +6c +72 +6f +74 +61 +74 +65 +00 +67 +72 +65 +65 +74 +00 +61 +73 +6d +73 +74 +72 +00 +74 +65 +78 +74 +70 +74 +72 +00 +73 +65 +6c +66 +70 +74 +72 +00 +69 +6e +74 +65 +67 +65 +72 +00 +70 +72 +69 +6e +74 +66 +00 +63 +6f +6d +6d +76 +61 +72 +00 +5f +47 +4c +4f +42 +41 +4c +5f +4f +46 +46 +53 +45 +54 +5f +54 +41 +42 +4c +45 +5f +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +01 +00 +00 +00 +04 +00 +f1 +ff +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +03 +00 +04 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +06 +00 +0d +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +04 +00 +0c +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +08 +00 +04 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +06 +00 +34 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +06 +00 +0d +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +03 +00 +06 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +03 +00 +08 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +03 +00 +00 +00 +12 +00 +04 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +0b +00 +00 +00 +12 +00 +04 +00 +16 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +11 +00 +00 +00 +11 +00 +06 +00 +00 +00 +00 +00 +00 +00 +00 +00 +0d +00 +00 +00 +00 +00 +00 +00 +18 +00 +00 +00 +11 +00 +06 +00 +38 +00 +00 +00 +00 +00 +00 +00 +04 +00 +00 +00 +00 +00 +00 +00 +20 +00 +00 +00 +11 +00 +06 +00 +3c +00 +00 +00 +00 +00 +00 +00 +04 +00 +00 +00 +00 +00 +00 +00 +28 +00 +00 +00 +11 +00 +08 +00 +00 +00 +00 +00 +00 +00 +00 +00 +04 +00 +00 +00 +00 +00 +00 +00 +30 +00 +00 +00 +10 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +37 +00 +00 +00 +10 +00 +f2 +ff +04 +00 +00 +00 +00 +00 +00 +00 +04 +00 +00 +00 +00 +00 +00 +00 +3f +00 +00 +00 +10 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +38 +00 +00 +00 +03 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +ec +01 +00 +00 +00 +00 +00 +00 +42 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +28 +00 +00 +00 +03 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +30 +02 +00 +00 +00 +00 +00 +00 +55 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +30 +00 +00 +00 +02 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +88 +02 +00 +00 +00 +00 +00 +00 +c8 +01 +00 +00 +00 +00 +00 +00 +02 +00 +00 +00 +0a +00 +00 +00 +08 +00 +00 +00 +00 +00 +00 +00 +18 +00 +00 +00 +00 +00 +00 +00 +01 +00 +00 +00 +01 +00 +00 +00 +06 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +40 +00 +00 +00 +00 +00 +00 +00 +62 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +10 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +12 +00 +00 +00 +04 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +a4 +00 +00 +00 +00 +00 +00 +00 +c0 +00 +00 +00 +00 +00 +00 +00 +03 +00 +00 +00 +04 +00 +00 +00 +08 +00 +00 +00 +00 +00 +00 +00 +18 +00 +00 +00 +00 +00 +00 +00 +07 +00 +00 +00 +01 +00 +00 +00 +03 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +64 +01 +00 +00 +00 +00 +00 +00 +40 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +04 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +1d +00 +00 +00 +04 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +a4 +01 +00 +00 +00 +00 +00 +00 +48 +00 +00 +00 +00 +00 +00 +00 +03 +00 +00 +00 +06 +00 +00 +00 +08 +00 +00 +00 +00 +00 +00 +00 +18 +00 +00 +00 +00 +00 +00 +00 +0d +00 +00 +00 +08 +00 +00 +00 +03 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +08 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +04 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 diff --git a/modules/objfmts/elf/tests/elfso.asm b/modules/objfmts/elf/tests/elfso.asm new file mode 100644 index 00000000..5adb6339 --- /dev/null +++ b/modules/objfmts/elf/tests/elfso.asm @@ -0,0 +1,97 @@ +; test source file for assembling to ELF shared library +; build with: +; nasm -f elf elfso.asm +; ld -shared -o elfso.so elfso.o +; test with: +; gcc -o elfso elftest.c ./elfso.so +; ./elfso +; (assuming your gcc is ELF, and you're running bash) + +; This file should test the following: +; [1] Define and export a global text-section symbol +; [2] Define and export a global data-section symbol +; [3] Define and export a global BSS-section symbol +; [4] Define a non-global text-section symbol +; [5] Define a non-global data-section symbol +; [6] Define a non-global BSS-section symbol +; [7] Define a COMMON symbol +; [8] Define a NASM local label +; [9] Reference a NASM local label +; [10] Import an external symbol +; [11] Make a PC-relative call to an external symbol +; [12] Reference a text-section symbol in the text section +; [13] Reference a data-section symbol in the text section +; [14] Reference a BSS-section symbol in the text section +; [15] Reference a text-section symbol in the data section +; [16] Reference a data-section symbol in the data section +; [17] Reference a BSS-section symbol in the data section + + BITS 32 + GLOBAL lrotate:function ; [1] + GLOBAL greet:function ; [1] + GLOBAL asmstr:data asmstr.end-asmstr ; [2] + GLOBAL textptr:data 4 ; [2] + GLOBAL selfptr:data 4 ; [2] + GLOBAL integer:data 4 ; [3] + EXTERN printf ; [10] + COMMON commvar 4:4 ; [7] + EXTERN _GLOBAL_OFFSET_TABLE_ + + SECTION .text + +; prototype: long lrotate(long x, int num); +lrotate: ; [1] + push ebp + mov ebp,esp + mov eax,[ebp+8] + mov ecx,[ebp+12] +.label rol eax,1 ; [4] [8] + loop .label ; [9] [12] + mov esp,ebp + pop ebp + ret + +; prototype: void greet(void); +greet push ebx ; we'll use EBX for GOT, so save it + call .getgot +.getgot: pop ebx + add ebx,_GLOBAL_OFFSET_TABLE_ + $$ - .getgot wrt ..gotpc + mov eax,[ebx+integer wrt ..got] ; [14] + mov eax,[eax] + inc eax + mov [ebx+localint wrt ..gotoff],eax ; [14] + mov eax,[ebx+commvar wrt ..got] + push dword [eax] + mov eax,[ebx+localptr wrt ..gotoff] ; [13] + push dword [eax] + mov eax,[ebx+integer wrt ..got] ; [1] [14] + push dword [eax] + lea eax,[ebx+printfstr wrt ..gotoff] + push eax ; [13] + call printf wrt ..plt ; [11] + add esp,16 + pop ebx + ret + + SECTION .data + +; a string +asmstr db 'hello, world', 0 ; [2] +.end + +; a string for Printf +printfstr db "integer==%d, localint==%d, commvar=%d" + db 10, 0 + +; some pointers +localptr dd localint ; [5] [17] +textptr dd greet wrt ..sym ; [15] +selfptr dd selfptr wrt ..sym ; [16] + + SECTION .bss + +; an integer +integer resd 1 ; [3] + +; a local integer +localint resd 1 ; [6] diff --git a/modules/objfmts/elf/tests/elfso.errwarn b/modules/objfmts/elf/tests/elfso.errwarn new file mode 100644 index 00000000..e69de29b diff --git a/modules/objfmts/elf/tests/elfso.hex b/modules/objfmts/elf/tests/elfso.hex new file mode 100644 index 00000000..b23ed991 --- /dev/null +++ b/modules/objfmts/elf/tests/elfso.hex @@ -0,0 +1,1144 @@ +7f +45 +4c +46 +01 +01 +01 +00 +00 +00 +00 +00 +00 +00 +00 +00 +01 +00 +03 +00 +01 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +10 +03 +00 +00 +00 +00 +00 +00 +34 +00 +00 +00 +00 +00 +28 +00 +09 +00 +01 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +55 +89 +e5 +8b +45 +08 +8b +4d +0c +d1 +c0 +e2 +fc +89 +ec +5d +c3 +53 +e8 +00 +00 +00 +00 +5b +81 +c3 +e9 +ff +ff +ff +8b +83 +00 +00 +00 +00 +8b +00 +40 +89 +83 +04 +00 +00 +00 +8b +83 +00 +00 +00 +00 +ff +30 +8b +83 +34 +00 +00 +00 +ff +30 +8b +83 +00 +00 +00 +00 +ff +30 +8d +83 +0d +00 +00 +00 +50 +e8 +fc +ff +ff +ff +81 +c4 +10 +00 +00 +00 +5b +c3 +00 +00 +00 +1a +00 +00 +00 +0a +13 +00 +00 +20 +00 +00 +00 +03 +10 +00 +00 +29 +00 +00 +00 +09 +0a +00 +00 +2f +00 +00 +00 +03 +12 +00 +00 +37 +00 +00 +00 +09 +09 +00 +00 +3f +00 +00 +00 +03 +10 +00 +00 +47 +00 +00 +00 +09 +09 +00 +00 +4d +00 +00 +00 +04 +11 +00 +00 +68 +65 +6c +6c +6f +2c +20 +77 +6f +72 +6c +64 +00 +69 +6e +74 +65 +67 +65 +72 +3d +3d +25 +64 +2c +20 +6c +6f +63 +61 +6c +69 +6e +74 +3d +3d +25 +64 +2c +20 +63 +6f +6d +6d +76 +61 +72 +3d +25 +64 +0a +00 +04 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +34 +00 +00 +00 +01 +0a +00 +00 +38 +00 +00 +00 +01 +0c +00 +00 +3c +00 +00 +00 +01 +0f +00 +00 +00 +2e +74 +65 +78 +74 +00 +2e +64 +61 +74 +61 +00 +2e +62 +73 +73 +00 +2e +72 +65 +6c +2e +74 +65 +78 +74 +00 +2e +72 +65 +6c +2e +64 +61 +74 +61 +00 +2e +73 +74 +72 +74 +61 +62 +00 +2e +73 +79 +6d +74 +61 +62 +00 +2e +73 +68 +73 +74 +72 +74 +61 +62 +00 +00 +2d +00 +6c +72 +6f +74 +61 +74 +65 +00 +67 +72 +65 +65 +74 +00 +61 +73 +6d +73 +74 +72 +00 +74 +65 +78 +74 +70 +74 +72 +00 +73 +65 +6c +66 +70 +74 +72 +00 +69 +6e +74 +65 +67 +65 +72 +00 +70 +72 +69 +6e +74 +66 +00 +63 +6f +6d +6d +76 +61 +72 +00 +5f +47 +4c +4f +42 +41 +4c +5f +4f +46 +46 +53 +45 +54 +5f +54 +41 +42 +4c +45 +5f +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +01 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +04 +00 +f1 +ff +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +03 +00 +04 +00 +00 +00 +00 +00 +0d +00 +00 +00 +00 +00 +00 +00 +00 +00 +06 +00 +00 +00 +00 +00 +09 +00 +00 +00 +00 +00 +00 +00 +00 +00 +04 +00 +00 +00 +00 +00 +17 +00 +00 +00 +00 +00 +00 +00 +00 +00 +04 +00 +00 +00 +00 +00 +04 +00 +00 +00 +00 +00 +00 +00 +00 +00 +08 +00 +00 +00 +00 +00 +34 +00 +00 +00 +00 +00 +00 +00 +00 +00 +06 +00 +00 +00 +00 +00 +0d +00 +00 +00 +00 +00 +00 +00 +00 +00 +06 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +03 +00 +06 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +03 +00 +08 +00 +03 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +12 +00 +04 +00 +0b +00 +00 +00 +11 +00 +00 +00 +00 +00 +00 +00 +12 +00 +04 +00 +11 +00 +00 +00 +00 +00 +00 +00 +0d +00 +00 +00 +11 +00 +06 +00 +18 +00 +00 +00 +38 +00 +00 +00 +04 +00 +00 +00 +11 +00 +06 +00 +20 +00 +00 +00 +3c +00 +00 +00 +04 +00 +00 +00 +11 +00 +06 +00 +28 +00 +00 +00 +00 +00 +00 +00 +04 +00 +00 +00 +11 +00 +08 +00 +30 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +10 +00 +00 +00 +37 +00 +00 +00 +04 +00 +00 +00 +04 +00 +00 +00 +10 +00 +f2 +ff +3f +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +10 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +36 +00 +00 +00 +03 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +34 +01 +00 +00 +40 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +26 +00 +00 +00 +03 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +74 +01 +00 +00 +55 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +2e +00 +00 +00 +02 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +cc +01 +00 +00 +40 +01 +00 +00 +02 +00 +00 +00 +0b +00 +00 +00 +04 +00 +00 +00 +10 +00 +00 +00 +01 +00 +00 +00 +01 +00 +00 +00 +06 +00 +00 +00 +00 +00 +00 +00 +40 +00 +00 +00 +59 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +10 +00 +00 +00 +00 +00 +00 +00 +12 +00 +00 +00 +09 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +9c +00 +00 +00 +40 +00 +00 +00 +03 +00 +00 +00 +04 +00 +00 +00 +04 +00 +00 +00 +08 +00 +00 +00 +07 +00 +00 +00 +01 +00 +00 +00 +03 +00 +00 +00 +00 +00 +00 +00 +dc +00 +00 +00 +40 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +04 +00 +00 +00 +00 +00 +00 +00 +1c +00 +00 +00 +09 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +1c +01 +00 +00 +18 +00 +00 +00 +03 +00 +00 +00 +06 +00 +00 +00 +04 +00 +00 +00 +08 +00 +00 +00 +0d +00 +00 +00 +08 +00 +00 +00 +03 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +08 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +00 +04 +00 +00 +00 +00 +00 +00 +00 diff --git a/modules/objfmts/xdf/xdf-objfmt.c b/modules/objfmts/xdf/xdf-objfmt.c index 1384c461..b4434035 100644 --- a/modules/objfmts/xdf/xdf-objfmt.c +++ b/modules/objfmts/xdf/xdf-objfmt.c @@ -206,7 +206,7 @@ xdf_objfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize, { /*@null@*/ xdf_objfmt_output_info *info = (xdf_objfmt_output_info *)d; yasm_objfmt_xdf *objfmt_xdf; - /*@dependent@*/ /*@null@*/ const yasm_intnum *intn; + /*@dependent@*/ /*@null@*/ yasm_intnum *intn; /*@dependent@*/ /*@null@*/ const yasm_floatnum *flt; /*@dependent@*/ /*@null@*/ yasm_symrec *sym; yasm_expr *shr_expr; @@ -284,10 +284,16 @@ xdf_objfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize, yasm_section_add_reloc(info->sect, (yasm_reloc *)reloc, yasm_xfree); } intn = yasm_expr_get_intnum(ep, NULL); - if (intn) + if (intn) { + if (rel) { + int retval = yasm_arch_intnum_fixup_rel(objfmt_xdf->arch, intn, + valsize, bc, bc->line); + if (retval) + return retval; + } return yasm_arch_intnum_tobytes(objfmt_xdf->arch, intn, buf, destsize, - valsize, shift, bc, rel, warn, - bc->line); + valsize, shift, bc, warn, bc->line); + } /* Check for complex float expressions */ if (yasm_expr__contains(*ep, YASM_EXPR_FLOAT)) { diff --git a/modules/parsers/nasm/nasm-bison.y b/modules/parsers/nasm/nasm-bison.y index 80c5bd80..aa23cda2 100644 --- a/modules/parsers/nasm/nasm-bison.y +++ b/modules/parsers/nasm/nasm-bison.y @@ -110,6 +110,8 @@ static void define_label(yasm_parser_nasm *parser_nasm, /*@only@*/ char *name, %type operands %type operand +%left ':' +%left WRT %left '|' %left '^' %left '&' @@ -117,8 +119,7 @@ static void define_label(yasm_parser_nasm *parser_nasm, /*@only@*/ char *name, %left '-' '+' %left '*' '/' SIGNDIV '%' SIGNMOD %nonassoc UNARYOP -%nonassoc SEG WRT -%left ':' +%nonassoc SEG %% input: /* empty */ -- 2.40.0