From c969da647374bec1548589cd47406e2a12a7800c Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Thu, 2 Dec 2010 13:25:13 +0000 Subject: [PATCH] gas/ * symbols.c (S_FORCE_RELOC): Return true for indirect functions even if !strict. * expr.c (operand): Don't convert absolute symbols to constants if S_FORCE_RELOC is true. (expr): Only reduce subtractions between different symbols if S_FORCE_RELOC is false for both of them. * write.c (fixup_segment): Don't remove symbols if S_FORCE_RELOC is true for them, regardless of their segment. gas/testsuite/ * gas/i386/ifunc-2.s, gas/i386/ifunc-2.l: New test. * gas/i386/ifunc-3.s, gas/i386/ifunc-3.d: Likeise. * gas/i386/i386.exp: Run them. --- gas/ChangeLog | 11 +++++ gas/expr.c | 13 +++-- gas/symbols.c | 2 +- gas/testsuite/ChangeLog | 6 +++ gas/testsuite/gas/i386/i386.exp | 2 + gas/testsuite/gas/i386/ifunc-2.l | 61 ++++++++++++++++++++++++ gas/testsuite/gas/i386/ifunc-2.s | 100 +++++++++++++++++++++++++++++++++++++++ gas/testsuite/gas/i386/ifunc-3.d | 57 ++++++++++++++++++++++ gas/testsuite/gas/i386/ifunc-3.s | 54 +++++++++++++++++++++ gas/write.c | 6 +++ 10 files changed, 308 insertions(+), 4 deletions(-) create mode 100644 gas/testsuite/gas/i386/ifunc-2.l create mode 100644 gas/testsuite/gas/i386/ifunc-2.s create mode 100644 gas/testsuite/gas/i386/ifunc-3.d create mode 100644 gas/testsuite/gas/i386/ifunc-3.s diff --git a/gas/ChangeLog b/gas/ChangeLog index e8e58fd..b0a1966 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,14 @@ +2010-12-02 Richard Sandiford + + * symbols.c (S_FORCE_RELOC): Return true for indirect functions + even if !strict. + * expr.c (operand): Don't convert absolute symbols to constants + if S_FORCE_RELOC is true. + (expr): Only reduce subtractions between different symbols if + S_FORCE_RELOC is false for both of them. + * write.c (fixup_segment): Don't remove symbols if S_FORCE_RELOC + is true for them, regardless of their segment. + 2010-12-01 Maciej W. Rozycki * symbols.h (dot_symbol): New declaration. diff --git a/gas/expr.c b/gas/expr.c index 215b2ba..f818ad3 100644 --- a/gas/expr.c +++ b/gas/expr.c @@ -1325,7 +1325,9 @@ operand (expressionS *expressionP, enum expr_mode mode) /* If we have an absolute symbol or a reg, then we know its value now. */ segment = S_GET_SEGMENT (symbolP); - if (mode != expr_defer && segment == absolute_section) + if (mode != expr_defer + && segment == absolute_section + && !S_FORCE_RELOC (symbolP, 0)) { expressionP->X_op = O_constant; expressionP->X_add_number = S_GET_VALUE (symbolP); @@ -1840,7 +1842,9 @@ expr (int rankarg, /* Larger # is higher rank. */ #ifdef md_allow_local_subtract && md_allow_local_subtract (resultP, & right, rightseg) #endif - && (SEG_NORMAL (rightseg) + && ((SEG_NORMAL (rightseg) + && !S_FORCE_RELOC (resultP->X_add_symbol, 0) + && !S_FORCE_RELOC (right.X_add_symbol, 0)) || right.X_add_symbol == resultP->X_add_symbol) && frag_offset_fixed_p (symbol_get_frag (resultP->X_add_symbol), symbol_get_frag (right.X_add_symbol), @@ -1954,7 +1958,10 @@ expr (int rankarg, /* Larger # is higher rank. */ else if (op_left == O_subtract) { resultP->X_add_number -= right.X_add_number; - if (retval == rightseg && SEG_NORMAL (retval)) + if (retval == rightseg + && SEG_NORMAL (retval) + && !S_FORCE_RELOC (resultP->X_add_symbol, 0) + && !S_FORCE_RELOC (right.X_add_symbol, 0)) { retval = absolute_section; rightseg = absolute_section; diff --git a/gas/symbols.c b/gas/symbols.c index 5fae547..4e4ad77 100644 --- a/gas/symbols.c +++ b/gas/symbols.c @@ -2065,9 +2065,9 @@ S_FORCE_RELOC (symbolS *s, int strict) return ((strict && ((s->bsym->flags & BSF_WEAK) != 0 - || (s->bsym->flags & BSF_GNU_INDIRECT_FUNCTION) != 0 || (EXTERN_FORCE_RELOC && (s->bsym->flags & BSF_GLOBAL) != 0))) + || (s->bsym->flags & BSF_GNU_INDIRECT_FUNCTION) != 0 || s->bsym->section == undefined_section || bfd_is_com_section (s->bsym->section)); } diff --git a/gas/testsuite/ChangeLog b/gas/testsuite/ChangeLog index 90b3bfc..10fbad8 100644 --- a/gas/testsuite/ChangeLog +++ b/gas/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2010-12-02 Richard Sandiford + + * gas/i386/ifunc-2.s, gas/i386/ifunc-2.l: New test. + * gas/i386/ifunc-3.s, gas/i386/ifunc-3.d: Likeise. + * gas/i386/i386.exp: Run them. + 2010-11-20 Richard Sandiford * lib/gas-defs.exp (regexp_diff): Delete. diff --git a/gas/testsuite/gas/i386/i386.exp b/gas/testsuite/gas/i386/i386.exp index c295be6..3a966d7 100644 --- a/gas/testsuite/gas/i386/i386.exp +++ b/gas/testsuite/gas/i386/i386.exp @@ -215,6 +215,8 @@ if [expr ([istarget "i*86-*-*"] || [istarget "x86_64-*-*"]) && [gas_32_check]] run_list_test "inval-equ-1" "-al" run_list_test "inval-equ-2" "-al" run_dump_test "ifunc" + run_list_test "ifunc-2" + run_dump_test "ifunc-3" run_list_test "l1om-inval" "-march=l1om --32" run_dump_test "localpic" run_dump_test "debug1" diff --git a/gas/testsuite/gas/i386/ifunc-2.l b/gas/testsuite/gas/i386/ifunc-2.l new file mode 100644 index 0000000..0ed314b --- /dev/null +++ b/gas/testsuite/gas/i386/ifunc-2.l @@ -0,0 +1,61 @@ +.*/ifunc-2\.s: Assembler messages: +.*/ifunc-2\.s:4: Error: can't resolve `bar1' {\.text\.1 section} - `foo1' {\.text\.1 section} +.*/ifunc-2\.s:5: Error: can't resolve `bar2' {\.text\.2 section} - `foo2' {\.text\.2 section} +.*/ifunc-2\.s:6: Error: can't resolve `bar1' {\.text\.1 section} - `bar2' {\.text\.2 section} +.*/ifunc-2\.s:7: Error: can't resolve `bar2' {\.text\.2 section} - `bar1' {\.text\.1 section} +.*/ifunc-2\.s:8: Error: can't resolve `\.text\.1' {\.text\.1 section} - `bar1' {\.text\.1 section} +.*/ifunc-2\.s:9: Error: can't resolve `\.text\.1' {\.text\.1 section} - `bar2' {\.text\.2 section} +.*/ifunc-2\.s:10: Error: can't resolve `bar1' {\.text\.1 section} - `abs1' {\*ABS\* section} +.*/ifunc-2\.s:11: Error: can't resolve `abs1' {\*ABS\* section} - `bar1' {\.text\.1 section} +.*/ifunc-2\.s:12: Error: can't resolve `\.text\.1' {\.text\.1 section} - `bar1' {\.text\.1 section} +.*/ifunc-2\.s:19: Error: can't resolve `bar1' {\.text\.1 section} - `foo1' {\.text\.1 section} +.*/ifunc-2\.s:20: Error: can't resolve `bar2' {\.text\.2 section} - `foo2' {\.text\.2 section} +.*/ifunc-2\.s:21: Error: can't resolve `bar1' {\.text\.1 section} - `bar2' {\.text\.2 section} +.*/ifunc-2\.s:22: Error: can't resolve `bar2' {\.text\.2 section} - `bar1' {\.text\.1 section} +.*/ifunc-2\.s:23: Error: can't resolve `\.text\.1' {\.text\.1 section} - `bar1' {\.text\.1 section} +.*/ifunc-2\.s:24: Error: can't resolve `\.text\.1' {\.text\.1 section} - `bar2' {\.text\.2 section} +.*/ifunc-2\.s:25: Error: can't resolve `bar1' {\.text\.1 section} - `abs1' {\*ABS\* section} +.*/ifunc-2\.s:26: Error: can't resolve `abs1' {\*ABS\* section} - `bar1' {\.text\.1 section} +.*/ifunc-2\.s:27: Error: can't resolve `\.text\.1' {\.text\.1 section} - `bar1' {\.text\.1 section} +.*/ifunc-2\.s:34: Error: can't resolve `bar1' {\.text\.1 section} - `foo1' {\.text\.1 section} +.*/ifunc-2\.s:35: Error: can't resolve `bar2' {\.text\.2 section} - `foo2' {\.text\.2 section} +.*/ifunc-2\.s:36: Error: can't resolve `bar1' {\.text\.1 section} - `bar2' {\.text\.2 section} +.*/ifunc-2\.s:37: Error: can't resolve `bar2' {\.text\.2 section} - `bar1' {\.text\.1 section} +.*/ifunc-2\.s:38: Error: can't resolve `\.text\.1' {\.text\.1 section} - `bar1' {\.text\.1 section} +.*/ifunc-2\.s:39: Error: can't resolve `\.text\.1' {\.text\.1 section} - `bar2' {\.text\.2 section} +.*/ifunc-2\.s:40: Error: can't resolve `bar1' {\.text\.1 section} - `abs1' {\*ABS\* section} +.*/ifunc-2\.s:41: Error: can't resolve `abs1' {\*ABS\* section} - `bar1' {\.text\.1 section} +.*/ifunc-2\.s:42: Error: can't resolve `\.text\.1' {\.text\.1 section} - `bar1' {\.text\.1 section} +.*/ifunc-2\.s:44: Error: can't resolve `abs1' {\*ABS\* section} - `abs2' {\*ABS\* section} +.*/ifunc-2\.s:45: Error: can't resolve `abs2' {\*ABS\* section} - `abs1' {\*ABS\* section} +.*/ifunc-2\.s:50: Error: can't resolve `abs1' {\*ABS\* section} - `abs2' {\*ABS\* section} +.*/ifunc-2\.s:51: Error: can't resolve `abs2' {\*ABS\* section} - `abs1' {\*ABS\* section} +.*/ifunc-2\.s:56: Error: can't resolve `abs1' {\*ABS\* section} - `abs2' {\*ABS\* section} +.*/ifunc-2\.s:57: Error: can't resolve `abs2' {\*ABS\* section} - `abs1' {\*ABS\* section} +.*/ifunc-2\.s:62: Error: can't resolve `bar1' {\.text\.1 section} - `foo1' {\.text\.1 section} +.*/ifunc-2\.s:63: Error: can't resolve `bar2' {\.text\.2 section} - `foo2' {\.text\.2 section} +.*/ifunc-2\.s:64: Error: can't resolve `bar1' {\.text\.1 section} - `bar2' {\.text\.2 section} +.*/ifunc-2\.s:65: Error: can't resolve `bar2' {\.text\.2 section} - `bar1' {\.text\.1 section} +.*/ifunc-2\.s:66: Error: can't resolve `\.text\.2' {\.text\.2 section} - `bar1' {\.text\.1 section} +.*/ifunc-2\.s:67: Error: can't resolve `\.text\.2' {\.text\.2 section} - `bar2' {\.text\.2 section} +.*/ifunc-2\.s:68: Error: can't resolve `bar2' {\.text\.2 section} - `abs1' {\*ABS\* section} +.*/ifunc-2\.s:69: Error: can't resolve `abs1' {\*ABS\* section} - `bar2' {\.text\.2 section} +.*/ifunc-2\.s:70: Error: can't resolve `\.text\.2' {\.text\.2 section} - `bar2' {\.text\.2 section} +.*/ifunc-2\.s:77: Error: can't resolve `bar1' {\.text\.1 section} - `foo1' {\.text\.1 section} +.*/ifunc-2\.s:78: Error: can't resolve `bar2' {\.text\.2 section} - `foo2' {\.text\.2 section} +.*/ifunc-2\.s:79: Error: can't resolve `bar1' {\.text\.1 section} - `bar2' {\.text\.2 section} +.*/ifunc-2\.s:80: Error: can't resolve `bar2' {\.text\.2 section} - `bar1' {\.text\.1 section} +.*/ifunc-2\.s:81: Error: can't resolve `\.text\.2' {\.text\.2 section} - `bar1' {\.text\.1 section} +.*/ifunc-2\.s:82: Error: can't resolve `\.text\.2' {\.text\.2 section} - `bar2' {\.text\.2 section} +.*/ifunc-2\.s:83: Error: can't resolve `bar2' {\.text\.2 section} - `abs1' {\*ABS\* section} +.*/ifunc-2\.s:84: Error: can't resolve `abs1' {\*ABS\* section} - `bar2' {\.text\.2 section} +.*/ifunc-2\.s:85: Error: can't resolve `\.text\.2' {\.text\.2 section} - `bar2' {\.text\.2 section} +.*/ifunc-2\.s:92: Error: can't resolve `bar1' {\.text\.1 section} - `foo1' {\.text\.1 section} +.*/ifunc-2\.s:93: Error: can't resolve `bar2' {\.text\.2 section} - `foo2' {\.text\.2 section} +.*/ifunc-2\.s:94: Error: can't resolve `bar1' {\.text\.1 section} - `bar2' {\.text\.2 section} +.*/ifunc-2\.s:95: Error: can't resolve `bar2' {\.text\.2 section} - `bar1' {\.text\.1 section} +.*/ifunc-2\.s:96: Error: can't resolve `\.text\.2' {\.text\.2 section} - `bar1' {\.text\.1 section} +.*/ifunc-2\.s:97: Error: can't resolve `\.text\.2' {\.text\.2 section} - `bar2' {\.text\.2 section} +.*/ifunc-2\.s:98: Error: can't resolve `bar2' {\.text\.2 section} - `abs1' {\*ABS\* section} +.*/ifunc-2\.s:99: Error: can't resolve `abs1' {\*ABS\* section} - `bar2' {\.text\.2 section} +.*/ifunc-2\.s:100: Error: can't resolve `\.text\.2' {\.text\.2 section} - `bar2' {\.text\.2 section} diff --git a/gas/testsuite/gas/i386/ifunc-2.s b/gas/testsuite/gas/i386/ifunc-2.s new file mode 100644 index 0000000..ca536d3 --- /dev/null +++ b/gas/testsuite/gas/i386/ifunc-2.s @@ -0,0 +1,100 @@ + .section .text.1,"ax",@progbits + +start1: + .long bar1-foo1 + .long bar2-foo2 + .long bar1-bar2 + .long bar2-bar1 + .long start1-bar1 + .long start1-bar2 + .long bar1-abs1 + .long abs1-bar1 + .long .-bar1 + + .type foo1,%gnu_indirect_function +foo1: + ret + .size foo1,.-foo1 + + .long bar1-foo1 + .long bar2-foo2 + .long bar1-bar2 + .long bar2-bar1 + .long start1-bar1 + .long start1-bar2 + .long bar1-abs1 + .long abs1-bar1 + .long .-bar1 + + .type bar1,%gnu_indirect_function +bar1: + ret + .size bar1,.-bar1 + + .long bar1-foo1 + .long bar2-foo2 + .long bar1-bar2 + .long bar2-bar1 + .long start1-bar1 + .long start1-bar2 + .long bar1-abs1 + .long abs1-bar1 + .long .-bar1 + + .long abs1-abs2 + .long abs2-abs1 + + .equ abs1,0x11223300 + .type abs1,%gnu_indirect_function + + .long abs1-abs2 + .long abs2-abs1 + + .equ abs2,0x11223380 + .type abs2,%gnu_indirect_function + + .long abs1-abs2 + .long abs2-abs1 + + .section .text.2,"ax",@progbits + +start2: + .long bar1-foo1 + .long bar2-foo2 + .long bar1-bar2 + .long bar2-bar1 + .long start2-bar1 + .long start2-bar2 + .long bar2-abs1 + .long abs1-bar2 + .long .-bar2 + + .type foo2,%gnu_indirect_function +foo2: + ret + .size foo2,.-foo2 + + .long bar1-foo1 + .long bar2-foo2 + .long bar1-bar2 + .long bar2-bar1 + .long start2-bar1 + .long start2-bar2 + .long bar2-abs1 + .long abs1-bar2 + .long .-bar2 + + .type bar2,%gnu_indirect_function +bar2: + ret + .size bar2,.-bar2 + + .long bar1-foo1 + .long bar2-foo2 + .long bar1-bar2 + .long bar2-bar1 + .long start2-bar1 + .long start2-bar2 + .long bar2-abs1 + .long abs1-bar2 + .long .-bar2 diff --git a/gas/testsuite/gas/i386/ifunc-3.d b/gas/testsuite/gas/i386/ifunc-3.d new file mode 100644 index 0000000..124de37 --- /dev/null +++ b/gas/testsuite/gas/i386/ifunc-3.d @@ -0,0 +1,57 @@ +#readelf: --relocs --syms -x .text.1 -x .text.2 +#name: i386 ifunc 3 + +Relocation section '\.rel\.text\.1' at offset .* contains .* entries: + Offset Info Type Sym.Value Sym. Name +00000000 ........ R_386_PC32 bar1\(\) bar1 +00000004 ........ R_386_PC32 bar2\(\) bar2 +00000008 ........ R_386_PC32 bar1\(\) bar1 +0000000c ........ R_386_PC32 bar2\(\) bar2 +00000010 ........ R_386_32 bar1\(\) bar1 +00000018 ........ R_386_PC32 bar1\(\) bar1 +0000001c ........ R_386_PC32 bar2\(\) bar2 +00000020 ........ R_386_PC32 bar1\(\) bar1 +00000024 ........ R_386_PC32 bar2\(\) bar2 +00000028 ........ R_386_32 bar1\(\) bar1 +0000002c ........ R_386_PC32 abs1\(\) abs1 +00000030 ........ R_386_PC32 abs1\(\) abs1 +00000034 ........ R_386_32 abs1\(\) abs1 +00000038 ........ R_386_PC32 abs1\(\) abs1 +0000003c ........ R_386_PC32 abs1\(\) abs1 +00000040 ........ R_386_32 abs1\(\) abs1 + +Relocation section '\.rel\.text\.2' at offset .* contains .* entries: + Offset Info Type Sym.Value Sym. Name +00000000 ........ R_386_PC32 bar1\(\) bar1 +00000004 ........ R_386_PC32 bar2\(\) bar2 +00000008 ........ R_386_PC32 bar1\(\) bar1 +0000000c ........ R_386_PC32 bar2\(\) bar2 +00000010 ........ R_386_32 bar2\(\) bar2 +00000018 ........ R_386_PC32 bar1\(\) bar1 +0000001c ........ R_386_PC32 bar2\(\) bar2 +00000020 ........ R_386_PC32 bar1\(\) bar1 +00000024 ........ R_386_PC32 bar2\(\) bar2 +00000028 ........ R_386_32 bar2\(\) bar2 + +Symbol table '.symtab' contains .* entries: + Num: Value Size Type Bind Vis Ndx Name +#... +.*: 00000014 1 IFUNC LOCAL DEFAULT .* bar1 +.*: 00000014 1 IFUNC LOCAL DEFAULT .* bar2 +#... +.*: 11223300 0 IFUNC LOCAL DEFAULT ABS abs1 +#... + +Hex dump of section '\.text\.1': + NOTE: This section has relocations against it, but these have NOT been applied to this dump\. + 0x00000000 00000000 00000000 08000000 0c000000 .* + 0x00000010 4054ffff c38d7600 00000000 00000000 .* + 0x00000020 20000000 24000000 4054ffff 00000000 .* + 0x00000030 30000000 4054ffff 00000000 3c000000 .* + 0x00000040 4054ffff .* + +Hex dump of section '\.text\.2': + NOTE: This section has relocations against it, but these have NOT been applied to this dump\. + 0x00000000 00000000 00000000 08000000 0c000000 .* + 0x00000010 4054ffff c38d7600 00000000 00000000 .* + 0x00000020 20000000 24000000 4054ffff .* diff --git a/gas/testsuite/gas/i386/ifunc-3.s b/gas/testsuite/gas/i386/ifunc-3.s new file mode 100644 index 0000000..dbcf494 --- /dev/null +++ b/gas/testsuite/gas/i386/ifunc-3.s @@ -0,0 +1,54 @@ + .section .text.1,"ax",@progbits + +start1: + .long bar1-. + .long bar2-. + .long bar1-start1 + .long bar2-start1 + .long bar1-base + + .type bar1,%gnu_indirect_function +bar1: + ret + .size bar1,.-bar1 + .align 4 + + .long bar1-. + .long bar2-. + .long bar1-start1 + .long bar2-start1 + .long bar1-base + + .long abs1-. + .long abs1-start1 + .long abs1-base + + .equ abs1,0x11223300 + .type abs1,%gnu_indirect_function + + .long abs1-. + .long abs1-start1 + .long abs1-base + + .section .text.2,"ax",@progbits + +start2: + .long bar1-. + .long bar2-. + .long bar1-start2 + .long bar2-start2 + .long bar2-base + + .type bar2,%gnu_indirect_function +bar2: + ret + .size bar2,.-bar2 + .align 4 + + .long bar1-. + .long bar2-. + .long bar1-start2 + .long bar2-start2 + .long bar2-base + + .equ base,0xabc0 diff --git a/gas/write.c b/gas/write.c index 939b80e..018800e 100644 --- a/gas/write.c +++ b/gas/write.c @@ -932,6 +932,8 @@ fixup_segment (fixS *fixP, segT this_segment) sub_symbol_segment = S_GET_SEGMENT (fixP->fx_subsy); if (fixP->fx_addsy != NULL && sub_symbol_segment == add_symbol_segment + && !S_FORCE_RELOC (fixP->fx_addsy, 0) + && !S_FORCE_RELOC (fixP->fx_subsy, 0) && !TC_FORCE_RELOCATION_SUB_SAME (fixP, add_symbol_segment)) { add_number += S_GET_VALUE (fixP->fx_addsy); @@ -945,6 +947,7 @@ fixup_segment (fixS *fixP, segT this_segment) #endif } else if (sub_symbol_segment == absolute_section + && !S_FORCE_RELOC (fixP->fx_subsy, 0) && !TC_FORCE_RELOCATION_SUB_ABS (fixP, add_symbol_segment)) { add_number -= S_GET_VALUE (fixP->fx_subsy); @@ -952,6 +955,7 @@ fixup_segment (fixS *fixP, segT this_segment) fixP->fx_subsy = NULL; } else if (sub_symbol_segment == this_segment + && !S_FORCE_RELOC (fixP->fx_subsy, 0) && !TC_FORCE_RELOCATION_SUB_LOCAL (fixP, add_symbol_segment)) { add_number -= S_GET_VALUE (fixP->fx_subsy); @@ -994,6 +998,7 @@ fixup_segment (fixS *fixP, segT this_segment) if (fixP->fx_addsy) { if (add_symbol_segment == this_segment + && !S_FORCE_RELOC (fixP->fx_addsy, 0) && !TC_FORCE_RELOCATION_LOCAL (fixP)) { /* This fixup was made when the symbol's segment was @@ -1007,6 +1012,7 @@ fixup_segment (fixS *fixP, segT this_segment) fixP->fx_pcrel = 0; } else if (add_symbol_segment == absolute_section + && !S_FORCE_RELOC (fixP->fx_addsy, 0) && !TC_FORCE_RELOCATION_ABS (fixP)) { add_number += S_GET_VALUE (fixP->fx_addsy); -- 2.7.4