[binutils-gdb] macho section symbol handling

Alan Modra via Binutils-cvs <[email protected]>
Newsgroups gmane.comp.gnu.binutils.cvs
Message-ID <[email protected]>
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=6c5eabaf45bed70acc2e64d8846ccb2eb0752e7e

commit 6c5eabaf45bed70acc2e64d8846ccb2eb0752e7e
Author: Alan Modra <[email protected]>
Date:   Mon Jun 1 18:28:11 2026 +0930

    macho section symbol handling
    
    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.

Diff:
---
 gas/config/obj-macho.c           | 21 ++++++++++++++-------
 gas/testsuite/gas/i386/insn-32.d |  1 -
 gas/write.c                      | 32 ++++++++++++++++++++------------
 gas/write.h                      |  3 +++
 4 files changed, 37 insertions(+), 20 deletions(-)

diff --git a/gas/config/obj-macho.c b/gas/config/obj-macho.c
index 6de2410e1a7..bf6f2758bc7 100644
--- a/gas/config/obj-macho.c
+++ b/gas/config/obj-macho.c
@@ -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;
 }
diff --git a/gas/testsuite/gas/i386/insn-32.d b/gas/testsuite/gas/i386/insn-32.d
index c2d8202bd2e..2649fdcf94e 100644
--- a/gas/testsuite/gas/i386/insn-32.d
+++ b/gas/testsuite/gas/i386/insn-32.d
@@ -1,7 +1,6 @@
 #as: --divide
 #objdump: -dw
 #name: .insn (32-bit code)
-#xfail: *-*-darwin*
 
 .*: +file format .*
 
diff --git a/gas/write.c b/gas/write.c
index 9bb47857936..9514c3df42e 100644
--- a/gas/write.c
+++ b/gas/write.c
@@ -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)
diff --git a/gas/write.h b/gas/write.h
index 7281930c2d6..bc5260a2efd 100644
--- a/gas/write.h
+++ b/gas/write.h
@@ -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__ */
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.