]> granicus.if.org Git - yasm/commitdiff
Fix ELF64 relocations for common, global, and common+global symbols to match
authorPeter Johnson <peter@tortall.net>
Sun, 6 Nov 2005 20:07:15 +0000 (20:07 -0000)
committerPeter Johnson <peter@tortall.net>
Sun, 6 Nov 2005 20:07:15 +0000 (20:07 -0000)
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

12 files changed:
libyasm/expr.c
libyasm/expr.h
modules/dbgfmts/stabs/tests/stabs-elf.hex
modules/objfmts/coff/coff-objfmt.c
modules/objfmts/elf/elf-objfmt.c
modules/objfmts/elf/tests/Makefile.inc
modules/objfmts/elf/tests/elftest.hex
modules/objfmts/elf/tests/gas64/Makefile.inc [new file with mode: 0644]
modules/objfmts/elf/tests/gas64/elf_gas64_reloc.asm [new file with mode: 0644]
modules/objfmts/elf/tests/gas64/elf_gas64_reloc.errwarn [new file with mode: 0644]
modules/objfmts/elf/tests/gas64/elf_gas64_test.sh [new file with mode: 0755]
modules/objfmts/xdf/xdf-objfmt.c

index 984c1c8db6c57175a50a725acdc2e9130a8ee647..164d05896904d69fa615e7e78f44cfc8e66ec6f8 100644 (file)
@@ -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)
index 47e34550c0e9f12712b1ef8b8dae30f6287b5a2d..87268d5108e084988c03967da3970dd9e4cf08ce 100644 (file)
@@ -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.
index efc6ea27cb8944782438fd1730dfdb73eef82150..46c003c49577ecbbb98b59e619bdb5241fe2c033 100644 (file)
@@ -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 
index 30210331e9467fd8a5392ee4176ee64c99e2944b..49b8578d31043b370dc8de31eeb14f712581e2fa 100644 (file)
@@ -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;
index 8bacc6e1a4c6266b1c6b566344d7afc9c38ba023..29542cf261506008e74e32cf1503b64d694f426f 100644 (file)
@@ -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)) {
index a20402bb2e6d91311986e9c88634e1e968f6f6fe..e9642e7abd6426f3e26c1b78bf7dbe399eba0815 100644 (file)
@@ -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
index f680a0de338b41facf49a8fd1545f6124ebdaa9c..45775269a7b03bfd57ceb60c9ced8c5bd055636f 100644 (file)
@@ -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 (file)
index 0000000..78267fc
--- /dev/null
@@ -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 (file)
index 0000000..e015ce4
--- /dev/null
@@ -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 (file)
index 0000000..e69de29
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 (executable)
index 0000000..de90bc1
--- /dev/null
@@ -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 $?
index 317f08ebeecf33db28ff0990f8c8e5d7bdd35557..d7ff9b77459207863b2324b9216f1e367fb6da5f 100644 (file)
@@ -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"));