]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
macho section symbol handling
authorAlan Modra <amodra@gmail.com>
Mon, 1 Jun 2026 08:58:11 +0000 (18:28 +0930)
committerAlan Modra <amodra@gmail.com>
Mon, 1 Jun 2026 08:58:11 +0000 (18:28 +0930)
The macho gas support starts a new frag at non-local labels,
identifying the frag with the label symbol as a "subsection".  Relocs
are needed when referencing labels in a different subsection, to
support relaxation.  There is a problem when reloc symbols are reduced
to a section symbol plus offset (see write.c:adjust_reloc_syms), as
this loses the subsection.  Not reducing symbols like this is not a
good option as it results in a large number of symbols, some with
weird internal gas names.  So instead this patch finds the original
frag for any fx_addsy reduced to a section symbol.

Test results are:
+FAIL: .org test 1
-FAIL: i386 opcodes
-FAIL: i386 opcodes (Intel disassembly)
-FAIL: i386 opcodes (w/ suffix)
-FAIL: i386 intel (AT&T disassembly)
-FAIL: i386 intel
-FAIL: Check -madd-bnd-prefix
-FAIL: x86-64 RTM insns
-FAIL: x86-64 RTM insns (Intel disassembly)
-FAIL: Check -madd-bnd-prefix (x86-64)

The reason ".org test 1" fails is the -gdwarf2 .debug_aranges
generates two temp symbols and uses them for the start and size of
each range, the size being calculated by "end" - "beg" (see
out_debug_aranges).  For the test, "beg" is before any source symbol
is emitted so has subsection NULL.  "end" has a subsection but lost
that when the fixup was converted to a section symbol plus offset.
So prior to this change obj_mach_o_in_different_subsection returned
false.  Now that the lost subsection is recovered for "end" it returns
true, and results in "Error: can't resolve .text - L0^A$".

* config/obj-macho.c (obj_mach_o_in_different_subsection):
Add parameters.  Get frag containing section sym plus offset.
(obj_mach_o_force_reloc_sub_same): Adjust to suit
obj_mach_o_in_different_subsection change.
(obj_mach_o_force_reloc_sub_local): Likewise.
(obj_mach_o_force_reloc): Likewise.
* testsuite/gas/i386/insn-32.d: Don't xfail darwin.
* write.c (get_frag_for_address): New function, extracted from..
(get_frag_for_reloc): ..here.
* write.h (get_frag_for_address): Declare.

gas/config/obj-macho.c
gas/testsuite/gas/i386/insn-32.d
gas/write.c
gas/write.h

index 6de2410e1a70aa4faf3de075e2883f4772927463..bf6f2758bc7f95a7fa2812f2a0d79f6ad9c7b60e 100644 (file)
@@ -1864,7 +1864,8 @@ obj_mach_o_allow_local_subtract (expressionS * left ATTRIBUTE_UNUSED,
 }
 
 static bool
-obj_mach_o_in_different_subsection (symbolS *a, symbolS *b)
+obj_mach_o_in_different_subsection (symbolS *a, segT aseg, valueT offset,
+                                   symbolS *b)
 {
   fragS *fa;
   fragS *fb;
@@ -1877,7 +1878,10 @@ obj_mach_o_in_different_subsection (symbolS *a, symbolS *b)
       return true;
     }
 
-  fa = symbol_get_frag (a);
+  if (symbol_section_p (a) && aseg != NULL)
+    fa = get_frag_for_address (NULL, seg_info (aseg), offset);
+  else
+    fa = symbol_get_frag (a);
   fb = symbol_get_frag (b);
   if (fa == NULL || fb == NULL)
     {
@@ -1893,7 +1897,8 @@ obj_mach_o_force_reloc_sub_same (fixS *fix, segT seg)
 {
   if (! SEG_NORMAL (seg))
     return true;
-  return obj_mach_o_in_different_subsection (fix->fx_addsy, fix->fx_subsy);
+  return obj_mach_o_in_different_subsection (fix->fx_addsy, seg,
+                                            fix->fx_offset, fix->fx_subsy);
 }
 
 bool
@@ -1902,7 +1907,7 @@ obj_mach_o_force_reloc_sub_local (fixS *fix, segT seg ATTRIBUTE_UNUSED)
   symbolS *fragsym = fix->fx_frag->obj_frag_data.subsection;
   if (fragsym == NULL)
     return false;
-  return obj_mach_o_in_different_subsection (fix->fx_subsy, fragsym);
+  return obj_mach_o_in_different_subsection (fix->fx_subsy, NULL, 0, fragsym);
 }
 
 bool
@@ -1916,16 +1921,18 @@ obj_mach_o_force_reloc (fixS *fix)
   if (fix->fx_addsy != NULL)
     {
       symbolS *subsec = fix->fx_frag->obj_frag_data.subsection;
-      symbolS *targ = fix->fx_addsy;
 
       /* There might be no subsections at all.  */
       if (subsec == NULL)
        return false;
 
-      if (S_GET_SEGMENT (targ) == absolute_section)
+      symbolS *targ = fix->fx_addsy;
+      segT targseg = S_GET_SEGMENT (targ);
+      if (targseg == absolute_section)
        return false;
 
-      return obj_mach_o_in_different_subsection (targ, subsec);
+      return obj_mach_o_in_different_subsection (targ, targseg,
+                                                fix->fx_offset, subsec);
     }
   return false;
 }
index c2d8202bd2ebe0be534fc1946a7a135427c27385..2649fdcf94ebc3b07f6492d68ff5eaf2cb4f86e0 100644 (file)
@@ -1,7 +1,6 @@
 #as: --divide
 #objdump: -dw
 #name: .insn (32-bit code)
-#xfail: *-*-darwin*
 
 .*: +file format .*
 
index 9bb47857936099246cd07b99c04b83070109ce84..9514c3df42e9f90ecf28825cef767cf30de79c95 100644 (file)
@@ -1228,33 +1228,41 @@ install_reloc (asection *sec, arelent *reloc, fragS *fragp,
     }
 }
 
-static fragS *
-get_frag_for_reloc (fragS *last_frag,
-                   const segment_info_type *seginfo,
-                   const struct reloc_list *r)
+fragS *
+get_frag_for_address (fragS *last_frag,
+                     const segment_info_type *seginfo,
+                     addressT addr)
 {
   fragS *f;
 
   for (f = last_frag; f != NULL; f = f->fr_next)
-    if (f->fr_address <= r->u.b.r.address
-       && r->u.b.r.address < f->fr_address + f->fr_fix)
+    if (f->fr_address <= addr && addr < f->fr_address + f->fr_fix)
       return f;
 
   for (f = seginfo->frchainP->frch_root; f != NULL; f = f->fr_next)
-    if (f->fr_address <= r->u.b.r.address
-       && r->u.b.r.address < f->fr_address + f->fr_fix)
+    if (f->fr_address <= addr && addr < f->fr_address + f->fr_fix)
       return f;
 
   for (f = seginfo->frchainP->frch_root; f != NULL; f = f->fr_next)
-    if (f->fr_address <= r->u.b.r.address
-       && r->u.b.r.address <= f->fr_address + f->fr_fix)
+    if (f->fr_address <= addr && addr <= f->fr_address + f->fr_fix)
       return f;
 
-  as_bad_where (r->file, r->line,
-               _("reloc not within (fixed part of) section"));
   return NULL;
 }
 
+static fragS *
+get_frag_for_reloc (fragS *last_frag,
+                   const segment_info_type *seginfo,
+                   const struct reloc_list *r)
+{
+  fragS *f = get_frag_for_address (last_frag, seginfo, r->u.b.r.address);
+
+  if (f == NULL)
+    as_bad_where (r->file, r->line,
+                 _("reloc not within (fixed part of) section"));
+  return f;
+}
+
 static void
 write_relocs (bfd *abfd ATTRIBUTE_UNUSED, asection *sec,
              void *xxx ATTRIBUTE_UNUSED)
index 7281930c2d6c70bfa9e0bc7ab74102ec0eb83d01..bc5260a2efdbb8fde00a849b4a1e928d1212463d 100644 (file)
@@ -188,5 +188,8 @@ extern fixS *fix_new_exp (fragS *, unsigned long, unsigned long,
                          const expressionS *, int, bfd_reloc_code_real_type);
 extern void write_print_statistics (FILE *);
 extern void as_bad_subtract (fixS *);
+struct segment_info_struct;
+extern fragS *get_frag_for_address (fragS *, const struct segment_info_struct *,
+                                   addressT);
 
 #endif /* __write_h__ */