diff --git a/libyasm/expr.c b/libyasm/expr.c index 984c1c8d..164d0589 100644 --- a/libyasm/expr.c +++ b/libyasm/expr.c @@ -990,7 +990,8 @@ yasm_expr__traverse_leaves_in(yasm_expr *e, void *d, } yasm_symrec * -yasm_expr_extract_symrec(yasm_expr **ep, int relocate, +yasm_expr_extract_symrec(yasm_expr **ep, + yasm_symrec_relocate_action relocate_action, yasm_calc_bc_dist_func calc_bc_dist) { yasm_symrec *sym = NULL; @@ -1001,7 +1002,7 @@ yasm_expr_extract_symrec(yasm_expr **ep, int relocate, /* 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); + relocate_action, calc_bc_dist); /* Replace sym with 0 value, return sym */ if ((*ep)->terms[0].type == YASM_EXPR_SYM) { sym = (*ep)->terms[0].data.sym; @@ -1025,7 +1026,10 @@ yasm_expr_extract_symrec(yasm_expr **ep, int relocate, /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc; /*@null@*/ yasm_intnum *intn; - if (relocate && yasm_symrec_get_label(sym, &precbc)) { + if (yasm_symrec_get_label(sym, &precbc) + && (relocate_action == YASM_SYMREC_REPLACE_VALUE || + (relocate_action == YASM_SYMREC_REPLACE_VALUE_IF_LOCAL + && yasm_symrec_get_visibility(sym) == YASM_SYM_LOCAL))) { intn = calc_bc_dist(yasm_section_bcs_first( yasm_bc_get_section(precbc)), precbc); if (!intn) diff --git a/libyasm/expr.h b/libyasm/expr.h index 47e34550..87268d51 100644 --- a/libyasm/expr.h +++ b/libyasm/expr.h @@ -169,16 +169,29 @@ SLIST_HEAD(yasm__exprhead, yasm__exprentry); #define yasm_expr_simplify(e, cbd) \ yasm_expr__level_tree(e, 1, 1, cbd, NULL, NULL, NULL) +/** Relocation actions for yasm_expr_extract_symrec(). */ +typedef enum yasm_symrec_relocate_action { + YASM_SYMREC_REPLACE_ZERO = 0, /**< Replace the symbol with 0 */ + YASM_SYMREC_REPLACE_VALUE, /**< Replace with symbol's value (offset) + * if symbol is a label. + */ + YASM_SYMREC_REPLACE_VALUE_IF_LOCAL /**< Replace with symbol's value only + * if symbol is label and declared + * local. + */ +} yasm_symrec_relocate_action; + /** Extract a single symbol out of an expression. Replaces it with 0, or * optionally the symbol's value (if it's a label). - * \param ep expression (pointer to) - * \param relocate replace symbol with value (if label) if nonzero - * \param calc_bc_dist bytecode distance-calculation function + * \param ep expression (pointer to) + * \param relocate_action replacement action to take on symbol in expr + * \param calc_bc_dist bytecode distance-calculation function * \return NULL if unable to extract a symbol (too complex of expr, none * present, etc); otherwise returns the extracted symbol. */ /*@dependent@*/ /*@null@*/ yasm_symrec *yasm_expr_extract_symrec - (yasm_expr **ep, int relocate, yasm_calc_bc_dist_func calc_bc_dist); + (yasm_expr **ep, yasm_symrec_relocate_action relocate_action, + yasm_calc_bc_dist_func calc_bc_dist); /** Remove the SEG unary operator if present, leaving the lower level * expression. diff --git a/modules/dbgfmts/stabs/tests/stabs-elf.hex b/modules/dbgfmts/stabs/tests/stabs-elf.hex index efc6ea27..46c003c4 100644 --- a/modules/dbgfmts/stabs/tests/stabs-elf.hex +++ b/modules/dbgfmts/stabs/tests/stabs-elf.hex @@ -131,7 +131,7 @@ c3 00 00 01 -03 +0f 00 00 18 @@ -163,7 +163,7 @@ c3 00 00 01 -03 +0f 00 00 30 @@ -238,11 +238,11 @@ c3 00 00 00 -11 00 00 00 -3c +00 +00 00 00 00 @@ -259,7 +259,7 @@ c3 00 00 01 -09 +0b 00 00 3c @@ -267,7 +267,7 @@ c3 00 00 01 -04 +0e 00 00 01 diff --git a/modules/objfmts/coff/coff-objfmt.c b/modules/objfmts/coff/coff-objfmt.c index 30210331..49b8578d 100644 --- a/modules/objfmts/coff/coff-objfmt.c +++ b/modules/objfmts/coff/coff-objfmt.c @@ -392,8 +392,13 @@ coff_objfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize, } /* Handle integer expressions, with relocation if necessary */ - sym = yasm_expr_extract_symrec(ep, !objfmt_coff->win64, - yasm_common_calc_bc_dist); + if (objfmt_coff->win64) + sym = yasm_expr_extract_symrec(ep, YASM_SYMREC_REPLACE_ZERO, + yasm_common_calc_bc_dist); + else + sym = yasm_expr_extract_symrec(ep, YASM_SYMREC_REPLACE_VALUE, + yasm_common_calc_bc_dist); + if (sym) { unsigned long addr; coff_reloc *reloc; diff --git a/modules/objfmts/elf/elf-objfmt.c b/modules/objfmts/elf/elf-objfmt.c index 8bacc6e1..29542cf2 100644 --- a/modules/objfmts/elf/elf-objfmt.c +++ b/modules/objfmts/elf/elf-objfmt.c @@ -317,7 +317,7 @@ elf_objfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize, /* Check for a WRT relocation */ wrt_expr = yasm_expr_extract_wrt(ep); if (wrt_expr) { - wrt = yasm_expr_extract_symrec(&wrt_expr, 0, + wrt = yasm_expr_extract_symrec(&wrt_expr, YASM_SYMREC_REPLACE_ZERO, yasm_common_calc_bc_dist); yasm_expr_destroy(wrt_expr); if (!wrt) { @@ -327,10 +327,14 @@ elf_objfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize, } /* Handle integer expressions, with relocation if necessary */ - sym = yasm_expr_extract_symrec(ep, - !(wrt == info->objfmt_elf->dotdotsym || - (wrt && elf_is_wrt_sym_relative(wrt))), - yasm_common_calc_bc_dist); + if (wrt == info->objfmt_elf->dotdotsym + || (wrt && elf_is_wrt_sym_relative(wrt))) + sym = yasm_expr_extract_symrec(ep, YASM_SYMREC_REPLACE_ZERO, + yasm_common_calc_bc_dist); + else + sym = yasm_expr_extract_symrec(ep, YASM_SYMREC_REPLACE_VALUE_IF_LOCAL, + yasm_common_calc_bc_dist); + if (sym) { yasm_sym_vis vis; @@ -339,8 +343,7 @@ elf_objfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize, wrt = NULL; else if (wrt && elf_is_wrt_sym_relative(wrt)) ; - else if (!(vis & (YASM_SYM_COMMON|YASM_SYM_EXTERN))) - { + else if (vis == YASM_SYM_LOCAL) { yasm_bytecode *label_precbc; /* Local symbols need relocation to their section's start */ if (yasm_symrec_get_label(sym, &label_precbc)) { diff --git a/modules/objfmts/elf/tests/Makefile.inc b/modules/objfmts/elf/tests/Makefile.inc index a20402bb..e9642e7a 100644 --- a/modules/objfmts/elf/tests/Makefile.inc +++ b/modules/objfmts/elf/tests/Makefile.inc @@ -45,5 +45,7 @@ EXTRA_DIST += modules/objfmts/elf/tests/elfvisibility.errwarn EXTRA_DIST += modules/objfmts/elf/tests/elfvisibility.hex EXTRA_DIST += modules/objfmts/elf/tests/amd64/Makefile.inc +EXTRA_DIST += modules/objfmts/elf/tests/gas64/Makefile.inc include modules/objfmts/elf/tests/amd64/Makefile.inc +include modules/objfmts/elf/tests/gas64/Makefile.inc diff --git a/modules/objfmts/elf/tests/elftest.hex b/modules/objfmts/elf/tests/elftest.hex index f680a0de..45775269 100644 --- a/modules/objfmts/elf/tests/elftest.hex +++ b/modules/objfmts/elf/tests/elftest.hex @@ -131,7 +131,7 @@ c3 00 00 01 -02 +0e 00 00 18 @@ -163,7 +163,7 @@ c3 00 00 01 -02 +0e 00 00 30 @@ -238,11 +238,11 @@ c3 00 00 00 -11 00 00 00 -3c +00 +00 00 00 00 @@ -259,7 +259,7 @@ c3 00 00 01 -08 +0a 00 00 3c @@ -267,7 +267,7 @@ c3 00 00 01 -03 +0d 00 00 00 diff --git a/modules/objfmts/elf/tests/gas64/Makefile.inc b/modules/objfmts/elf/tests/gas64/Makefile.inc new file mode 100644 index 00000000..78267fc2 --- /dev/null +++ b/modules/objfmts/elf/tests/gas64/Makefile.inc @@ -0,0 +1,8 @@ +# $Id: Makefile.inc 1168 2004-10-31 01:07:52Z peter $ + +TESTS += modules/objfmts/elf/tests/gas64/elf_gas64_test.sh + +EXTRA_DIST += modules/objfmts/elf/tests/gas64/elf_gas64_test.sh +EXTRA_DIST += modules/objfmts/elf/tests/amd64/elf_gas64_reloc.asm +EXTRA_DIST += modules/objfmts/elf/tests/amd64/elf_gas64_reloc.hex +EXTRA_DIST += modules/objfmts/elf/tests/amd64/elf_gas64_reloc.errwarn diff --git a/modules/objfmts/elf/tests/gas64/elf_gas64_reloc.asm b/modules/objfmts/elf/tests/gas64/elf_gas64_reloc.asm new file mode 100644 index 00000000..e015ce4b --- /dev/null +++ b/modules/objfmts/elf/tests/gas64/elf_gas64_reloc.asm @@ -0,0 +1,37 @@ +.comm _ZEROVAR, 32, 16 +.comm _VAR, 16, 16 +.data +.org 0 +_ZEROVAR: +.org 0xa0 +.globl _VAR +.type _VAR, @object +.size _VAR, 16 +_VAR: +.4byte 0 +.4byte 0 +.4byte 0 +.4byte 0 +.org 0xc0 +_VAR2: +.org 0xe0 +.globl _VAR3 +_VAR3: + +.text +movq $0, %rax +movq _VAR, %rax +movq %rax, _VAR(%rip) +movq _VAR+8(%rip), %rcx +movlpd _VAR(%rip), %xmm1 + +movq _VAR2, %rax +movq %rax, _VAR2(%rip) +movq _VAR2+8(%rip), %rcx +movlpd _VAR2(%rip), %xmm1 + +movq _VAR3, %rax +movq %rax, _VAR3(%rip) +movq _VAR3+8(%rip), %rcx +movlpd _VAR3(%rip), %xmm1 + diff --git a/modules/objfmts/elf/tests/gas64/elf_gas64_reloc.errwarn b/modules/objfmts/elf/tests/gas64/elf_gas64_reloc.errwarn new file mode 100644 index 00000000..e69de29b diff --git a/modules/objfmts/elf/tests/gas64/elf_gas64_test.sh b/modules/objfmts/elf/tests/gas64/elf_gas64_test.sh new file mode 100755 index 00000000..de90bc13 --- /dev/null +++ b/modules/objfmts/elf/tests/gas64/elf_gas64_test.sh @@ -0,0 +1,4 @@ +#! /bin/sh +# $Id: elf_amd64_test.sh 1137 2004-09-04 01:24:57Z peter $ +${srcdir}/out_test.sh elf_gas64_test modules/objfmts/elf/tests/gas64 "GAS elf-amd64 objfmt" "-f elf64 -p gas" ".o" +exit $? diff --git a/modules/objfmts/xdf/xdf-objfmt.c b/modules/objfmts/xdf/xdf-objfmt.c index 317f08eb..d7ff9b77 100644 --- a/modules/objfmts/xdf/xdf-objfmt.c +++ b/modules/objfmts/xdf/xdf-objfmt.c @@ -208,7 +208,8 @@ xdf_objfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize, wrt_expr = yasm_expr_extract_wrt(ep); /* Handle integer expressions, with relocation if necessary */ - sym = yasm_expr_extract_symrec(ep, 0, yasm_common_calc_bc_dist); + sym = yasm_expr_extract_symrec(ep, YASM_SYMREC_REPLACE_ZERO, + yasm_common_calc_bc_dist); if (sym) { xdf_reloc *reloc; @@ -222,7 +223,8 @@ xdf_objfmt_output_expr(yasm_expr **ep, unsigned char *buf, size_t destsize, if (seg) reloc->type = XDF_RELOC_SEG; else if (wrt_expr) { - reloc->base = yasm_expr_extract_symrec(&wrt_expr, 0, + reloc->base = yasm_expr_extract_symrec(&wrt_expr, + YASM_SYMREC_REPLACE_ZERO, yasm_common_calc_bc_dist); if (!reloc->base) { yasm__error(bc->line, N_("WRT expression too complex"));