Fix ELF64 relocations for common, global, and common+global symbols to match

GAS output.  The way we were generating relocations before would make
common+global symbol usage generate a relocation against the symbol but
figure in the symbol's value into the relocation addend.

* expr.h (yasm_symrec_relocate_action): New enum, so that:
(yasm_expr_extract_symrec): can conditionalize replacing the symbol with its
value based on whether the symbol is only local (e.g. not declared global,
etc).
* expr.c (yasm_expr_extract_symrec): Update implementation.

* xdf-objfmt.c, coff-objfmt.c: Update to use new enum constants.

* elf-objfmt.c (elf_objfmt_output_expr): Only relocate against section if
symbol is only local, and change call to yasm_expr_extract_symrec to only
add in symbol value if symbol is only local.

* stabs-elf.hex, elftest.hex: Update for changes.

* elf_gas64_reloc.asm: New test.

svn path=/trunk/yasm/; revision=1311
0.5.0rc2
Peter Johnson 19 years ago
parent b4d6598630
commit 36ff44b3ac
  1. 10
      libyasm/expr.c
  2. 21
      libyasm/expr.h
  3. 12
      modules/dbgfmts/stabs/tests/stabs-elf.hex
  4. 9
      modules/objfmts/coff/coff-objfmt.c
  5. 17
      modules/objfmts/elf/elf-objfmt.c
  6. 2
      modules/objfmts/elf/tests/Makefile.inc
  7. 12
      modules/objfmts/elf/tests/elftest.hex
  8. 8
      modules/objfmts/elf/tests/gas64/Makefile.inc
  9. 37
      modules/objfmts/elf/tests/gas64/elf_gas64_reloc.asm
  10. 0
      modules/objfmts/elf/tests/gas64/elf_gas64_reloc.errwarn
  11. 4
      modules/objfmts/elf/tests/gas64/elf_gas64_test.sh
  12. 6
      modules/objfmts/xdf/xdf-objfmt.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)

@ -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.

@ -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

@ -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;

@ -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)) {

@ -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

@ -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

@ -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

@ -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

@ -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 $?

@ -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"));

Loading…
Cancel
Save