]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
i386-darwin regression
authorAlan Modra <amodra@gmail.com>
Mon, 1 Jun 2026 08:58:01 +0000 (18:28 +0930)
committerAlan Modra <amodra@gmail.com>
Mon, 1 Jun 2026 08:58:01 +0000 (18:28 +0930)
Commit cc28c46227cd caused testsuite regressions on i386-darwin:
i386-darwin  +FAIL: i386 intel-ok (directive)
i386-darwin  +FAIL: i386 intel-ok (cmdline option)

Reduced testcase:
.intel_syntax noprefix
mov eax, [offset x] - [1]
This triggers an obj_mach_o_check_before_writing error, because x
is indeed undefined.  However, the error is nonsense because fx_subsy
is the absolute value 1, and that should just result in a relocation
against x with an addend of -1.

What's more, obj_mach_o_check_before_writing runs before symbols
are resolved.  At that point undefined symbols may be wrapped in an
expression symbol.  Expression symbols are S_IS_DEFINED, which is
why the error did not trigger until commit cc28c46227cd simplified
away the expression symbol wrapper.  So obj_mach_o_check_before_writing
is ineffective in some cases and overly restrictive in others.  If
something like it is necessary the correct place to do so is after
fixups have been simplified.  In fact there is a sufficient check in
write.c:fixup_segment but the macho support disables it by defining
TC_VALIDATE_FIX_SUB to 1.

This patch reverts commit 16a87420985f (see
https://sourceware.org/pipermail/binutils/2012-February/075591.html),
and removes the define of TC_VALIDATE_FIX_SUB for macho.  I'm sure it
is wrong to whitewash fixups by using TC_VALIDATE_FIX_SUB in this way.
Any fx_subsy that is left at that point will be ignored by the x86
md_apply_fix and tc_gen_reloc functions, except for a few special
cases.  That will result in incorrect relocations.

The patch also corrects obj_mach_o_force_reloc_sub_local.  Since this
is a predicate testing whether fx_subsy can be eliminated (and the
fixup made pc-relative) it ought to be testing for fx_subsy in the
same subsection as the fixup frag.  This cures "FAIL: i386 sub".

* config/obj-macho.c (obj_mach_o_check_before_writing): Delete.
(obj_mach_o_pre_output_hook): Delete.
(obj_mach_o_in_different_subsection): Make static.  Return bool.
(obj_mach_o_force_reloc_sub_same): Return bool.
(obj_mach_o_force_reloc_sub_local): Rewrite to check fx_subsy.
(obj_mach_o_force_reloc): Return bool.
* config/obj-macho.h (md_pre_output_hook): Don't define.
(obj_mach_o_in_different_subsection): Delete.
(obj_mach_o_force_reloc, obj_mach_o_force_reloc_sub_same),
(obj_mach_o_force_reloc_sub_local): Update.
* config/tc-i386.h (TC_VALIDATE_FIX_SUB <OBJ_MACH_O>): Likewise.

gas/config/obj-macho.c
gas/config/obj-macho.h
gas/config/tc-i386.h

index 5b16e7512b4872fe48ce8d3a8357bde33c918014..6de2410e1a70aa4faf3de075e2883f4772927463 100644 (file)
@@ -1554,68 +1554,6 @@ obj_mach_o_process_stab (int what, const char *string,
   s->symbol.udata.i = SYM_MACHO_FIELDS_NOT_VALIDATED;
 }
 
-/* This is a place to check for any errors that we can't detect until we know
-   what remains undefined at the end of assembly.  */
-
-static void
-obj_mach_o_check_before_writing (bfd *abfd ATTRIBUTE_UNUSED,
-                                asection *sec,
-                                void *unused ATTRIBUTE_UNUSED)
-{
-  fixS *fixP;
-  struct frchain *frchp;
-  segment_info_type *seginfo = seg_info (sec);
-
-  if (seginfo == NULL)
-    return;
-
-  /* We are not allowed subtractions where either of the operands is
-     undefined.  So look through the frags for any fixes to check.  */
-  for (frchp = seginfo->frchainP; frchp != NULL; frchp = frchp->frch_next)
-   for (fixP = frchp->fix_root; fixP != NULL; fixP = fixP->fx_next)
-    {
-      if (fixP->fx_addsy != NULL
-         && fixP->fx_subsy != NULL
-         && (! S_IS_DEFINED (fixP->fx_addsy)
-             || ! S_IS_DEFINED (fixP->fx_subsy)))
-       {
-         segT add_symbol_segment = S_GET_SEGMENT (fixP->fx_addsy);
-         segT sub_symbol_segment = S_GET_SEGMENT (fixP->fx_subsy);
-
-         if (! S_IS_DEFINED (fixP->fx_addsy)
-             && S_IS_DEFINED (fixP->fx_subsy))
-           {
-             as_bad_where (fixP->fx_file, fixP->fx_line,
-               _("`%s' can't be undefined in `%s' - `%s' {%s section}"),
-               S_GET_NAME (fixP->fx_addsy), S_GET_NAME (fixP->fx_addsy),
-               S_GET_NAME (fixP->fx_subsy), segment_name (sub_symbol_segment));
-           }
-         else if (! S_IS_DEFINED (fixP->fx_subsy)
-                  && S_IS_DEFINED (fixP->fx_addsy))
-           {
-             as_bad_where (fixP->fx_file, fixP->fx_line,
-               _("`%s' can't be undefined in `%s' {%s section} - `%s'"),
-               S_GET_NAME (fixP->fx_subsy), S_GET_NAME (fixP->fx_addsy),
-               segment_name (add_symbol_segment), S_GET_NAME (fixP->fx_subsy));
-           }
-         else
-           {
-             as_bad_where (fixP->fx_file, fixP->fx_line,
-               _("`%s' and `%s' can't be undefined in `%s' - `%s'"),
-               S_GET_NAME (fixP->fx_addsy), S_GET_NAME (fixP->fx_subsy),
-               S_GET_NAME (fixP->fx_addsy), S_GET_NAME (fixP->fx_subsy));
-           }
-       }
-    }
-}
-
-/* Do any checks that we can't complete without knowing what's undefined.  */
-void
-obj_mach_o_pre_output_hook (void)
-{
-  bfd_map_over_sections (stdoutput, obj_mach_o_check_before_writing, NULL);
-}
-
 /* Here we count up frags in each subsection (where a sub-section is defined
    as starting with a non-local symbol).
    Note that, if there are no non-local symbols in a section, all the frags will
@@ -1925,7 +1863,7 @@ obj_mach_o_allow_local_subtract (expressionS * left ATTRIBUTE_UNUSED,
   return obj_mach_o_is_frame_section (seg);
 }
 
-int
+static bool
 obj_mach_o_in_different_subsection (symbolS *a, symbolS *b)
 {
   fragS *fa;
@@ -1936,7 +1874,7 @@ obj_mach_o_in_different_subsection (symbolS *a, symbolS *b)
       || !S_IS_DEFINED (b))
     {
       /* Not in the same segment, or undefined symbol.  */
-      return 1;
+      return true;
     }
 
   fa = symbol_get_frag (a);
@@ -1944,31 +1882,34 @@ obj_mach_o_in_different_subsection (symbolS *a, symbolS *b)
   if (fa == NULL || fb == NULL)
     {
       /* One of the symbols is not in a subsection.  */
-      return 1;
+      return true;
     }
 
   return fa->obj_frag_data.subsection != fb->obj_frag_data.subsection;
 }
 
-int
+bool
 obj_mach_o_force_reloc_sub_same (fixS *fix, segT seg)
 {
   if (! SEG_NORMAL (seg))
-    return 1;
+    return true;
   return obj_mach_o_in_different_subsection (fix->fx_addsy, fix->fx_subsy);
 }
 
-int
+bool
 obj_mach_o_force_reloc_sub_local (fixS *fix, segT seg ATTRIBUTE_UNUSED)
 {
-  return obj_mach_o_in_different_subsection (fix->fx_addsy, fix->fx_subsy);
+  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);
 }
 
-int
+bool
 obj_mach_o_force_reloc (fixS *fix)
 {
   if (generic_force_reloc (fix))
-    return 1;
+    return true;
 
   /* Force a reloc if the target is not in the same subsection.
      FIXME: handle (a - b) where a and b belongs to the same subsection ?  */
@@ -1979,12 +1920,12 @@ obj_mach_o_force_reloc (fixS *fix)
 
       /* There might be no subsections at all.  */
       if (subsec == NULL)
-        return 0;
+       return false;
 
       if (S_GET_SEGMENT (targ) == absolute_section)
-        return 0;
+       return false;
 
       return obj_mach_o_in_different_subsection (targ, subsec);
     }
-  return 0;
+  return false;
 }
index 6e4b7b6d17837939a23717dbcba08934c3645c2f..eac0afdf407be41bb34255309a1565f377a1b7e4 100644 (file)
@@ -87,9 +87,6 @@ struct obj_mach_o_frag_data
 
 #define OBJ_FRAG_TYPE struct obj_mach_o_frag_data
 
-#define md_pre_output_hook obj_mach_o_pre_output_hook()
-extern void obj_mach_o_pre_output_hook(void);
-
 #define md_pre_relax_hook obj_mach_o_pre_relax_hook()
 extern void obj_mach_o_pre_relax_hook (void);
 
@@ -111,9 +108,8 @@ extern int obj_mach_o_allow_local_subtract (expressionS *, expressionS *,
                                            segT);
 
 struct fix;
-extern int obj_mach_o_in_different_subsection (symbolS *a, symbolS *b);
-extern int obj_mach_o_force_reloc (struct fix *fix);
-extern int obj_mach_o_force_reloc_sub_same (struct fix *fix, segT seg);
-extern int obj_mach_o_force_reloc_sub_local (struct fix *fix, segT seg);
+extern bool obj_mach_o_force_reloc (struct fix *);
+extern bool obj_mach_o_force_reloc_sub_same (struct fix *, segT);
+extern bool obj_mach_o_force_reloc_sub_local (struct fix *, segT);
 
 #endif /* _OBJ_MACH_O_H */
index bd3f4b5b59e394d712321ad840658f19c12187a5..20e5334d14e604eef7bba2d165a206fcf4847f7c 100644 (file)
@@ -506,8 +506,6 @@ void tc_pe_dwarf2_emit_offset (symbolS *, unsigned int);
 #define TC_FORCE_RELOCATION_SUB_LOCAL(FIX,SEG) \
        (obj_mach_o_force_reloc_sub_local (FIX, SEG))
 
-#define TC_VALIDATE_FIX_SUB(FIX, SEG) 1
-
 #endif /* OBJ_MACH_O */
 
 #endif /* TC_I386 */