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.
@@ -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;
}
@@ -1,7 +1,6 @@
#as: --divide
#objdump: -dw
#name: .insn (32-bit code)
-#xfail: *-*-darwin*
.*: +file format .*
@@ -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)
@@ -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__ */