x86: relax when/how @size can be used
authorJan Beulich <jbeulich@suse.com>
Thu, 29 Apr 2021 09:45:10 +0000 (11:45 +0200)
committerJan Beulich <jbeulich@suse.com>
Thu, 29 Apr 2021 09:45:10 +0000 (11:45 +0200)
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
gas/config/tc-i386.c
gas/config/tc-i386.h
gas/testsuite/gas/i386/i386.exp
gas/testsuite/gas/i386/size-5.s [new file with mode: 0644]
gas/testsuite/gas/i386/size-5a.d [new file with mode: 0644]
gas/testsuite/gas/i386/size-5b.d [new file with mode: 0644]

index e36170a2f91c5e9811493396da1e9dce8fbd5d3f..a44b880423965bd6a4f95b504d533415ab2ba1aa 100644 (file)
@@ -1,3 +1,17 @@
+2021-04-29  Jan Beulich  <jbeulich@suse.com>
+
+       * 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  <jbeulich@suse.com>
 
        * config/tc-i386.c (tc_gen_reloc): Use section size for section
index 9c544ee231de3ecd2e065f30c7aec1b523ee90ca..8bd725ab5883bfde56db2416d818691e63da4bae 100644 (file)
@@ -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.  */
 
index 39d7c27fc19738dd2dd0b36ee4da8e3a602c73b4..5516a164aa58d10d868adcb33dba8857d2606227 100644 (file)
@@ -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 *);
index 1846c980e75b5f4b8cf4d8ce28f6e8fc429d143e..ae01c8996d8e41990003ed35a8f22cceed5c56c0 100644 (file)
@@ -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 (file)
index 0000000..a870c28
--- /dev/null
@@ -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 (file)
index 0000000..56d0342
--- /dev/null
@@ -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+ <size>:
+[      ]*[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 (file)
index 0000000..8439801
--- /dev/null
@@ -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 .*