From 3abbafc2aacc6706fea3e3e326e2f08d107c3672 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Thu, 29 Apr 2021 11:45:10 +0200 Subject: [PATCH] x86: relax when/how @size can be used Allow a few more expression forms when the entire expression can be resolved at assembly time. For this, i386_validate_fix() needs to arrange for all processing of the relocation to be deferred to tc_gen_reloc(). --- gas/ChangeLog | 14 +++++++++ gas/config/tc-i386.c | 50 +++++++++++++++++++++++++++----- gas/config/tc-i386.h | 6 ++-- gas/testsuite/gas/i386/i386.exp | 2 ++ gas/testsuite/gas/i386/size-5.s | 32 ++++++++++++++++++++ gas/testsuite/gas/i386/size-5a.d | 28 ++++++++++++++++++ gas/testsuite/gas/i386/size-5b.d | 15 ++++++++++ 7 files changed, 138 insertions(+), 9 deletions(-) create mode 100644 gas/testsuite/gas/i386/size-5.s create mode 100644 gas/testsuite/gas/i386/size-5a.d create mode 100644 gas/testsuite/gas/i386/size-5b.d diff --git a/gas/ChangeLog b/gas/ChangeLog index e36170a2f91..a44b8804239 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,17 @@ +2021-04-29 Jan Beulich + + * config/tc-i386.c (i386_validate_fix): Change return type to + int. Short-circuit BFD_RELOC_SIZE* handling. + (tc_gen_reloc): New local variable sym. Extend logic when + processing BFD_RELOC_SIZE*. + * config/tc-i386.f (i386_validate_fix): Change return type to + int. + (TC_VALIDATE_FIX): Proceed to SKIP when i386_validate_fix() + returns zero. + * testsuite/gas/i386/size-5.s, testsuite/gas/i386/size-5a.d, + testsuite/gas/i386/size-5b.d: New. + * testsuite/gas/i386/i386.exp: Run new tests. + 2021-04-29 Jan Beulich * config/tc-i386.c (tc_gen_reloc): Use section size for section diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c index 9c544ee231d..8bd725ab588 100644 --- a/gas/config/tc-i386.c +++ b/gas/config/tc-i386.c @@ -14173,9 +14173,17 @@ i386_cons_align (int ignore ATTRIBUTE_UNUSED) } } -void +int i386_validate_fix (fixS *fixp) { +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) + if (fixp->fx_r_type == BFD_RELOC_SIZE32 + || fixp->fx_r_type == BFD_RELOC_SIZE64) + return IS_ELF && fixp->fx_addsy + && (!S_IS_DEFINED (fixp->fx_addsy) + || S_IS_EXTERNAL (fixp->fx_addsy)); +#endif + if (fixp->fx_subsy) { if (fixp->fx_subsy == GOT_symbol) @@ -14222,6 +14230,8 @@ i386_validate_fix (fixS *fixp) } } #endif + + return 1; } arelent * @@ -14233,18 +14243,38 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp) switch (fixp->fx_r_type) { #if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) + symbolS *sym; + case BFD_RELOC_SIZE32: case BFD_RELOC_SIZE64: - if (IS_ELF - && S_IS_DEFINED (fixp->fx_addsy) - && !S_IS_EXTERNAL (fixp->fx_addsy)) + if (fixp->fx_addsy + && !bfd_is_abs_section (S_GET_SEGMENT (fixp->fx_addsy)) + && (!fixp->fx_subsy + || bfd_is_abs_section (S_GET_SEGMENT (fixp->fx_subsy)))) + sym = fixp->fx_addsy; + else if (fixp->fx_subsy + && !bfd_is_abs_section (S_GET_SEGMENT (fixp->fx_subsy)) + && (!fixp->fx_addsy + || bfd_is_abs_section (S_GET_SEGMENT (fixp->fx_addsy)))) + sym = fixp->fx_subsy; + else + sym = NULL; + if (IS_ELF && sym && S_IS_DEFINED (sym) && !S_IS_EXTERNAL (sym)) { /* Resolve size relocation against local symbol to size of the symbol plus addend. */ - valueT value = S_GET_SIZE (fixp->fx_addsy); + valueT value = S_GET_SIZE (sym); - if (symbol_get_bfdsym (fixp->fx_addsy)->flags & BSF_SECTION_SYM) - value = bfd_section_size (S_GET_SEGMENT (fixp->fx_addsy)); + if (symbol_get_bfdsym (sym)->flags & BSF_SECTION_SYM) + value = bfd_section_size (S_GET_SEGMENT (sym)); + if (sym == fixp->fx_subsy) + { + value = -value; + if (fixp->fx_addsy) + value += S_GET_VALUE (fixp->fx_addsy); + } + else if (fixp->fx_subsy) + value -= S_GET_VALUE (fixp->fx_subsy); value += fixp->fx_offset; if (fixp->fx_r_type == BFD_RELOC_SIZE32 && object_64bit @@ -14256,6 +14286,12 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp) md_apply_fix (fixp, (valueT *) &value, NULL); return NULL; } + if (!fixp->fx_addsy || fixp->fx_subsy) + { + as_bad_where (fixp->fx_file, fixp->fx_line, + "unsupported expression involving @size"); + return NULL; + } #endif /* Fall through. */ diff --git a/gas/config/tc-i386.h b/gas/config/tc-i386.h index 39d7c27fc19..5516a164aa5 100644 --- a/gas/config/tc-i386.h +++ b/gas/config/tc-i386.h @@ -143,8 +143,10 @@ extern int x86_address_bytes (void); #define NO_RELOC BFD_RELOC_NONE -void i386_validate_fix (struct fix *); -#define TC_VALIDATE_FIX(FIX,SEGTYPE,SKIP) i386_validate_fix(FIX) +int i386_validate_fix (struct fix *); +#define TC_VALIDATE_FIX(FIX,SEGTYPE,SKIP) do { \ + if (!i386_validate_fix(FIX)) goto SKIP; \ + } while (0) #define tc_fix_adjustable(X) tc_i386_fix_adjustable(X) extern int tc_i386_fix_adjustable (struct fix *); diff --git a/gas/testsuite/gas/i386/i386.exp b/gas/testsuite/gas/i386/i386.exp index 1846c980e75..ae01c8996d8 100644 --- a/gas/testsuite/gas/i386/i386.exp +++ b/gas/testsuite/gas/i386/i386.exp @@ -637,6 +637,8 @@ if [gas_32_check] then { run_dump_test "size-2" run_dump_test "size-3" run_dump_test "size-4" + run_dump_test "size-5a" + run_dump_test "size-5b" run_dump_test "note" diff --git a/gas/testsuite/gas/i386/size-5.s b/gas/testsuite/gas/i386/size-5.s new file mode 100644 index 00000000000..a870c286b85 --- /dev/null +++ b/gas/testsuite/gas/i386/size-5.s @@ -0,0 +1,32 @@ + .text +size: + mov $size@size, %eax + mov $size@size + val, %eax + mov $-size@size, %ecx + mov $0 - size@size, %ecx + mov $0x100 - size@size, %edx + mov $val - size@size, %edx + + lea size@size, %eax + lea size@size + val, %eax + lea -size@size, %ecx + lea 0 - size@size, %ecx + lea 0x100 - size@size, %edx + lea val - size@size, %edx + + ret + .size size, . - size + + .data + .p2align 2 + .long size@size + .long size@size + val + .long -size@size + .long 0 - size@size + .long 0x100 - size@size + .long val - size@size + + .long ext@size + .long ext@size + val + + .equ val, 0x1000 diff --git a/gas/testsuite/gas/i386/size-5a.d b/gas/testsuite/gas/i386/size-5a.d new file mode 100644 index 00000000000..56d034225c2 --- /dev/null +++ b/gas/testsuite/gas/i386/size-5a.d @@ -0,0 +1,28 @@ +#name: i386 size 5 (text) +#source: size-5.s +#objdump: -dtwr + +.*: +file format .* + +SYMBOL TABLE: +0*0 l +\.text 0*43 size +0*1000 l +\*ABS\* 0*0 val +0*0 +\*UND\* 0*0 ext + +Disassembly of section .text: + +0+ : +[ ]*[a-f0-9]+: b8 43 00 00 00 mov \$0x43,%eax +[ ]*[a-f0-9]+: b8 43 10 00 00 mov \$0x1043,%eax +[ ]*[a-f0-9]+: b9 bd ff ff ff mov \$0xffffffbd,%ecx +[ ]*[a-f0-9]+: b9 bd ff ff ff mov \$0xffffffbd,%ecx +[ ]*[a-f0-9]+: ba bd 00 00 00 mov \$0xbd,%edx +[ ]*[a-f0-9]+: ba bd 0f 00 00 mov \$0xfbd,%edx +[ ]*[a-f0-9]+: 8d 05 43 00 00 00 lea 0x43,%eax +[ ]*[a-f0-9]+: 8d 05 43 10 00 00 lea 0x1043,%eax +[ ]*[a-f0-9]+: 8d 0d bd ff ff ff lea 0xffffffbd,%ecx +[ ]*[a-f0-9]+: 8d 0d bd ff ff ff lea 0xffffffbd,%ecx +[ ]*[a-f0-9]+: 8d 15 bd 00 00 00 lea 0xbd,%edx +[ ]*[a-f0-9]+: 8d 15 bd 0f 00 00 lea 0xfbd,%edx +[ ]*[a-f0-9]+: c3 ret * +#pass diff --git a/gas/testsuite/gas/i386/size-5b.d b/gas/testsuite/gas/i386/size-5b.d new file mode 100644 index 00000000000..8439801daaa --- /dev/null +++ b/gas/testsuite/gas/i386/size-5b.d @@ -0,0 +1,15 @@ +#name: i386 size 5 (data) +#source: size-5.s +#objdump: -rsj .data + +.*: +file format .* + +RELOCATION RECORDS FOR \[\.data\]: + +OFFSET +TYPE +VALUE * +0*18 R_386_SIZE32 *ext +0*1c R_386_SIZE32 *ext + +Contents of section .data: + 0+00 43 ?00 ?00 ?00 43 ?10 ?00 ?00 bd ?ff ?ff ?ff bd ?ff ?ff ?ff .* + 0+10 bd ?00 ?00 ?00 bd ?0f ?00 ?00 00 ?00 ?00 ?00 00 ?10 ?00 ?00 .* -- 2.30.2