From: Alan Modra Date: Mon, 1 Jun 2026 08:58:11 +0000 (+0930) Subject: macho section symbol handling X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=6c5eabaf45bed70acc2e64d8846ccb2eb0752e7e;p=thirdparty%2Fbinutils-gdb.git 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 --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__ */