/* Mach-O object file format
- Copyright 2009, 2011, 2012 Free Software Foundation, Inc.
+ Copyright (C) 2009-2020 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
decorations. */
/* Mach-O supports multiple, named segments each of which may contain
- multiple named sections. Thus the concept of subsectioning is
+ multiple named sections. Thus the concept of subsectioning is
handled by (say) having a __TEXT segment with appropriate flags from
- which subsections are generated like __text, __const etc.
-
+ which subsections are generated like __text, __const etc.
+
The well-known as short-hand section switch directives like .text, .data
- etc. are mapped onto predefined segment/section pairs using facilites
+ etc. are mapped onto predefined segment/section pairs using facilities
supplied by the mach-o port of bfd.
-
+
A number of additional mach-o short-hand section switch directives are
also defined. */
/* TODO: Implement the "-n" command line option to suppress the initial
switch to the text segment. */
+
static int obj_mach_o_start_with_text_section = 1;
/* Allow for special re-ordering on output. */
subseg_set (text_section, 0);
if (obj_mach_o_is_static)
{
- bfd_mach_o_section *mo_sec
+ bfd_mach_o_section *mo_sec
= bfd_mach_o_get_mach_o_section (text_section);
mo_sec->flags &= ~BFD_MACH_O_S_ATTR_PURE_INSTRUCTIONS;
}
/* This will put at most 16 characters (terminated by a ',' or newline) from
the input stream into dest. If there are more than 16 chars before the
delimiter, a warning is given and the string is truncated. On completion of
- this function, input_line_pointer will point to the char after the ',' or
- to the newline.
-
+ this function, input_line_pointer will point to the char after the ',' or
+ to the newline.
+
It trims leading and trailing space. */
static int
SKIP_WHITESPACE ();
namstart = input_line_pointer;
- while ( (c = *input_line_pointer) != ','
+ while ( (c = *input_line_pointer) != ','
&& !is_end_of_line[(unsigned char) c])
input_line_pointer++;
{
int len = input_line_pointer - namstart; /* could be zero. */
- /* lose any trailing space. */
- while (len > 0 && namstart[len-1] == ' ')
+ /* lose any trailing space. */
+ while (len > 0 && namstart[len-1] == ' ')
len--;
if (len > 16)
{
/* Build (or get) a section from the mach-o description - which includes
optional definitions for type, attributes, alignment and stub size.
-
+
BFD supplies default values for sections which have a canonical name. */
#define SECT_TYPE_SPECIFIED 0x0001
static segT
obj_mach_o_make_or_get_sect (char * segname, char * sectname,
- unsigned int specified_mask,
+ unsigned int specified_mask,
unsigned int usectype, unsigned int usecattr,
unsigned int ualign, offsetT stub_size)
{
attributes along with the canonical name. */
xlat = bfd_mach_o_section_data_for_mach_sect (stdoutput, segname, sectname);
- /* TODO: more checking of whether overides are acually allowed. */
+ /* TODO: more checking of whether overrides are actually allowed. */
if (xlat != NULL)
{
if ((sectype == BFD_MACH_O_S_ZEROFILL
|| sectype == BFD_MACH_O_S_GB_ZEROFILL)
&& sectype != usectype)
- as_bad (_("cannot overide zerofill section type for `%s,%s'"),
+ as_bad (_("cannot override zerofill section type for `%s,%s'"),
segname, sectname);
else
sectype = usectype;
/* There is no normal BFD section name for this section. Create one.
The name created doesn't really matter as it will never be written
on disk. */
- size_t seglen = strlen (segname);
- size_t sectlen = strlen (sectname);
- char *n;
-
- n = xmalloc (seglen + 1 + sectlen + 1);
- memcpy (n, segname, seglen);
- n[seglen] = '.';
- memcpy (n + seglen + 1, sectname, sectlen);
- n[seglen + 1 + sectlen] = 0;
- name = n;
+ name = concat (segname, ".", sectname, (char *) NULL);
if (specified_mask & SECT_TYPE_SPECIFIED)
sectype = usectype;
else
/* Sub-segments don't exists as is on Mach-O. */
sec = subseg_new (name, 0);
- oldflags = bfd_get_section_flags (stdoutput, sec);
+ oldflags = bfd_section_flags (sec);
msect = bfd_mach_o_get_mach_o_section (sec);
if (oldflags == SEC_NO_FLAGS)
&& (specified_mask & SECT_ATTR_SPECIFIED)
&& (secattr & BFD_MACH_O_S_ATTR_PURE_INSTRUCTIONS))
flags |= SEC_CODE;
-
+
if (flags == SEC_NO_FLAGS
&& (specified_mask & SECT_ATTR_SPECIFIED)
&& (secattr & BFD_MACH_O_S_ATTR_DEBUG))
flags |= SEC_DEBUGGING;
/* New, so just use the defaults or what's specified. */
- if (! bfd_set_section_flags (stdoutput, sec, flags))
+ if (!bfd_set_section_flags (sec, flags))
as_warn (_("failed to set flags for \"%s\": %s"),
- bfd_section_name (stdoutput, sec),
+ bfd_section_name (sec),
bfd_errmsg (bfd_get_error ()));
-
- strncpy (msect->segname, segname, sizeof (msect->segname));
- strncpy (msect->sectname, sectname, sizeof (msect->sectname));
+
+ strncpy (msect->segname, segname, BFD_MACH_O_SEGNAME_SIZE);
+ msect->segname[BFD_MACH_O_SEGNAME_SIZE] = 0;
+ strncpy (msect->sectname, sectname, BFD_MACH_O_SECTNAME_SIZE);
+ msect->sectname[BFD_MACH_O_SECTNAME_SIZE] = 0;
msect->align = secalign;
msect->flags = sectype | secattr;
-
+
if (sectype == BFD_MACH_O_S_ZEROFILL
|| sectype == BFD_MACH_O_S_GB_ZEROFILL)
seg_info (sec)->bss = 1;
White space is allowed everywhere between elements.
<segment> and <section> may be from 0 to 16 chars in length - they may
- contain spaces but leading and trailing space will be trimmed. It is
+ contain spaces but leading and trailing space will be trimmed. It is
mandatory that they be present (or that zero-length names are indicated
by ",,").
md_flush_pending_output ();
#endif
- /* Get the User's segment annd section names. */
+ /* Get the User's segment and section names. */
if (! obj_mach_o_get_section_names (segname, sectname, 17, 17))
return;
while (*input_line_pointer == '+');
/* Parse sizeof_stub. */
- if ((specified_mask & SECT_ATTR_SPECIFIED)
+ if ((specified_mask & SECT_ATTR_SPECIFIED)
&& *input_line_pointer == ',')
{
if (sectype != BFD_MACH_O_S_SYMBOL_STUBS)
sizeof_stub = get_absolute_expression ();
specified_mask |= SECT_STUB_SPECIFIED;
}
- else if ((specified_mask & SECT_ATTR_SPECIFIED)
+ else if ((specified_mask & SECT_ATTR_SPECIFIED)
&& sectype == BFD_MACH_O_S_SYMBOL_STUBS)
{
as_bad (_("missing sizeof_stub expression"));
}
}
- new_seg = obj_mach_o_make_or_get_sect (segname, sectname, specified_mask,
+ new_seg = obj_mach_o_make_or_get_sect (segname, sectname, specified_mask,
sectype, secattr, 0 /*align */,
sizeof_stub);
if (new_seg != NULL)
md_flush_pending_output ();
#endif
- /* Get the User's segment annd section names. */
+ /* Get the User's segment and section names. */
if (! obj_mach_o_get_section_names (segname, sectname, 17, 17))
return;
/* Parse variable definition, if present. */
if (*input_line_pointer == ',')
{
- /* Parse symbol, size [.align]
+ /* Parse symbol, size [.align]
We follow the method of s_common_internal, with the difference
that the symbol cannot be a duplicate-common. */
char *name;
char c;
char *p;
expressionS exp;
-
+
input_line_pointer++; /* Skip ',' */
SKIP_WHITESPACE ();
- name = input_line_pointer;
- c = get_symbol_end ();
+ c = get_symbol_name (&name);
/* Just after name is now '\0'. */
p = input_line_pointer;
*p = c;
goto done;
}
- SKIP_WHITESPACE ();
+ SKIP_WHITESPACE_AFTER_NAME ();
if (*input_line_pointer == ',')
input_line_pointer++;
name, (long) size, (long) exp.X_add_number);
*p = c; /* Restore the termination char. */
-
- SKIP_WHITESPACE ();
+
+ SKIP_WHITESPACE ();
if (*input_line_pointer == ',')
{
align = (unsigned int) parse_align (0);
/* else just a section definition. */
specified_mask |= SECT_TYPE_SPECIFIED;
- new_seg = obj_mach_o_make_or_get_sect (segname, sectname, specified_mask,
+ new_seg = obj_mach_o_make_or_get_sect (segname, sectname, specified_mask,
BFD_MACH_O_S_ZEROFILL,
BFD_MACH_O_S_ATTR_NONE,
align, (offsetT) 0 /*stub size*/);
S_CLEAR_EXTERNAL (sym);
}
-done:
+ done:
/* switch back to the section that was current before the .zerofill. */
subseg_set (old_seg, 0);
}
-static segT
+static segT
obj_mach_o_segT_from_bfd_name (const char *nam, int must_succeed)
{
const mach_o_section_name_xlat *xlat;
msect->flags = xlat->macho_sectype | xlat->macho_secattr;
msect->align = xlat->sectalign;
- if ((msect->flags & BFD_MACH_O_SECTION_TYPE_MASK)
+ if ((msect->flags & BFD_MACH_O_SECTION_TYPE_MASK)
== BFD_MACH_O_S_ZEROFILL)
seg_info (sec)->bss = 1;
}
obj_mach_o_objc_section (int sect_index)
{
segT section;
-
+
#ifdef md_flush_pending_output
md_flush_pending_output ();
#endif
/* This could be moved to the tc-xx files, but there is so little dependency
there, that the code might as well be shared. */
-struct opt_tgt_sect
+struct opt_tgt_sect
{
const char *name;
unsigned x86_val;
addressT align = 0;
bfd_mach_o_asymbol *s;
- SKIP_WHITESPACE ();
+ SKIP_WHITESPACE ();
/* Both comm and lcomm take an optional alignment, as a power
of two between 1 and 15. */
if (bss_section == NULL)
{
bss_section = obj_mach_o_segT_from_bfd_name (BSS_SECTION_NAME, 1);
- seg_info (bss_section)->bss = 1;
+ seg_info (bss_section)->bss = 1;
}
bss_alloc (symbolP, size, align);
s->n_type = BFD_MACH_O_N_SECT;
OBJ_MACH_O_FILE_PROP_MAX
} obj_mach_o_file_properties;
-static void
+static void
obj_mach_o_fileprop (int prop)
{
if (prop < 0 || prop >= OBJ_MACH_O_FILE_PROP_MAX)
as_fatal (_("internal error: bad file property ID %d"), prop);
-
+
switch ((obj_mach_o_file_properties) prop)
{
case OBJ_MACH_O_FILE_PROP_SUBSECTS_VIA_SYMS:
obj_mach_o_subsections_by_symbols = 1;
- if (!bfd_set_private_flags (stdoutput,
+ if (!bfd_set_private_flags (stdoutput,
BFD_MACH_O_MH_SUBSECTIONS_VIA_SYMBOLS))
as_bad (_("failed to set subsections by symbols"));
demand_empty_rest_of_line ();
}
}
-/* Temporary markers for symbol reference data.
+/* Temporary markers for symbol reference data.
Lazy will remain in place. */
#define LAZY 0x01
#define REFE 0x02
bfd_mach_o_asymbol *s = (bfd_mach_o_asymbol *) symbol_get_bfdsym (sym);
bfd_mach_o_section *sec;
int sectype = -1;
- int err = 0;
/* If the symbol is defined, then we can do more rigorous checking on
- the validity of the qualifiers. Otherwise, we are stuck with waiting
+ the validity of the qualifiers. Otherwise, we are stuck with waiting
until it's defined - or until write the file.
-
+
In certain cases (e.g. when a symbol qualifier is intended to introduce
an undefined symbol in a stubs section) we should check that the current
section is appropriate to the qualifier. */
as_bad (_("'%s' previously declared as '%s'."), s->symbol.name,
(s->n_type & BFD_MACH_O_N_PEXT) ? "private extern"
: "global" );
- err = 1;
+ s->symbol.udata.i = SYM_MACHO_FIELDS_UNSET;
+ return 1;
}
else
{
as_bad (_("'%s' can't be a weak_definition (currently only"
" supported in sections of type coalesced)"),
s->symbol.name);
- err = 1;
+ s->symbol.udata.i = SYM_MACHO_FIELDS_UNSET;
+ return 1;
}
else
s->n_desc |= BFD_MACH_O_N_WEAK_DEF;
/* We've seen some kind of qualifier - check validity if or when the entity
is defined. */
s->symbol.udata.i = SYM_MACHO_FIELDS_NOT_VALIDATED;
- return err;
+ return 0;
}
/* Respond to symbol qualifiers.
do
{
- name = input_line_pointer;
- c = get_symbol_end ();
+ c = get_symbol_name (&name);
symbolP = symbol_find_or_make (name);
obj_mach_o_set_symbol_qualifier (symbolP, ntype);
*input_line_pointer = c;
- SKIP_WHITESPACE ();
+ SKIP_WHITESPACE_AFTER_NAME ();
c = *input_line_pointer;
if (c == ',')
{
case BFD_MACH_O_S_NON_LAZY_SYMBOL_POINTERS:
{
obj_mach_o_indirect_sym *isym;
- char *name = input_line_pointer;
- char c = get_symbol_end ();
+ char *name;
+ char c = get_symbol_name (&name);
symbolS *sym = symbol_find_or_make (name);
unsigned int elsize =
bfd_mach_o_section_get_entry_size (stdoutput, sec);
as_bad (_("attempt to add an indirect_symbol to a stub or"
" reference section with a zero-sized element at %s"),
name);
- *input_line_pointer = c;
+ (void) restore_line_pointer (c);
ignore_rest_of_line ();
return;
- }
- *input_line_pointer = c;
+ }
+ (void) restore_line_pointer (c);
- /* The indirect symbols are validated after the symbol table is
- frozen, we must make sure that if a local symbol is used as an
+ /* The indirect symbols are validated after the symbol table is
+ frozen, we must make sure that if a local symbol is used as an
indirect, it is promoted to a 'real' one. Fetching the bfd sym
achieves this. */
symbol_get_bfdsym (sym);
- isym = (obj_mach_o_indirect_sym *)
- xmalloc (sizeof (obj_mach_o_indirect_sym));
+ isym = XNEW (obj_mach_o_indirect_sym);
/* Just record the data for now, we will validate it when we
compute the output in obj_mach_o_set_indirect_symbols. */
{ "debug_str", obj_mach_o_debug_section, 10}, /* extension. */
{ "debug_ranges", obj_mach_o_debug_section, 11}, /* extension. */
{ "debug_macro", obj_mach_o_debug_section, 12}, /* extension. */
-
+
{ "lazy_symbol_pointer", obj_mach_o_opt_tgt_section, 1},
{ "lazy_symbol_pointer2", obj_mach_o_opt_tgt_section, 2}, /* extension. */
{ "lazy_symbol_pointer3", obj_mach_o_opt_tgt_section, 3}, /* extension. */
{ "indirect_symbol", obj_mach_o_indirect_symbol, 0},
/* File flags. */
- { "subsections_via_symbols", obj_mach_o_fileprop,
+ { "subsections_via_symbols", obj_mach_o_fileprop,
OBJ_MACH_O_FILE_PROP_SUBSECTS_VIA_SYMS},
{NULL, NULL, 0}
return BFD_MACH_O_N_SECT;
}
+void
+obj_mach_o_frob_colon (const char *name)
+{
+ if (!bfd_is_local_label_name (stdoutput, name))
+ {
+ /* A non-local label will create a new subsection, so start a new
+ frag. */
+ frag_wane (frag_now);
+ frag_new (0);
+ }
+}
+
/* We need to check the correspondence between some kinds of symbols and their
sections. Common and BSS vars will seen via the obj_macho_comm() function.
-
+
The earlier we can pick up a problem, the better the diagnostics will be.
-
+
However, when symbol type information is attached, the symbol section will
quite possibly be unknown. So we are stuck with checking (most of the)
validity at the time the file is written (unfortunately, then one doesn't
are possibly incompatible with the section etc. that the symbol is defined
in. */
-void obj_macho_frob_label (struct symbol *sp)
+void obj_mach_o_frob_label (struct symbol *sp)
{
bfd_mach_o_asymbol *s;
unsigned base_type;
bfd_mach_o_section *sec;
int sectype = -1;
+ if (!bfd_is_local_label_name (stdoutput, S_GET_NAME (sp)))
+ {
+ /* If this is a non-local label, it should have started a new sub-
+ section. */
+ gas_assert (frag_now->obj_frag_data.subsection == NULL);
+ frag_now->obj_frag_data.subsection = sp;
+ }
+
/* Leave local symbols alone. */
if (S_IS_LOCAL (sp))
/* This is the base symbol type, that we mask in. */
base_type = obj_mach_o_type_for_symbol (s);
- sec = bfd_mach_o_get_mach_o_section (s->symbol.section);
+ sec = bfd_mach_o_get_mach_o_section (s->symbol.section);
if (sec != NULL)
sectype = sec->flags & BFD_MACH_O_SECTION_TYPE_MASK;
{
if ((s->n_desc & BFD_MACH_O_N_WEAK_DEF)
&& sectype != BFD_MACH_O_S_COALESCED)
- as_bad (_("'%s' can't be a weak_definition (currently only supported"
- " in sections of type coalesced)"), s->symbol.name);
+ {
+ as_bad (_("'%s' can't be a weak_definition (currently only supported"
+ " in sections of type coalesced)"), s->symbol.name);
+ /* Don't cascade errors. */
+ s->symbol.udata.i = SYM_MACHO_FIELDS_UNSET;
+ }
/* Have we changed from an undefined to defined ref? */
s->n_desc &= ~(REFE | LAZY);
(e.g. global + weak_def). */
int
-obj_macho_frob_symbol (struct symbol *sp)
+obj_mach_o_frob_symbol (struct symbol *sp)
{
bfd_mach_o_asymbol *s;
unsigned base_type;
return 0;
base_type = obj_mach_o_type_for_symbol (s);
- sec = bfd_mach_o_get_mach_o_section (s->symbol.section);
+ sec = bfd_mach_o_get_mach_o_section (s->symbol.section);
if (sec != NULL)
sectype = sec->flags & BFD_MACH_O_SECTION_TYPE_MASK;
{
/* Anything here that should be added that is non-standard. */
s->n_desc &= ~BFD_MACH_O_REFERENCE_MASK;
- s->symbol.udata.i = SYM_MACHO_FIELDS_NOT_VALIDATED;
- }
+ }
else if (s->symbol.udata.i == SYM_MACHO_FIELDS_NOT_VALIDATED)
{
/* Try to validate any combinations. */
return 0;
}
-/* Relocation rules are different in frame sections. */
+/* Support stabs for mach-o. */
-static int
-obj_mach_o_is_frame_section (segT sec)
+void
+obj_mach_o_process_stab (int what, const char *string,
+ int type, int other, int desc)
{
- int l;
- l = strlen (segment_name (sec));
- if ((l == 9 && strncmp (".eh_frame", segment_name (sec), 9) == 0)
- || (l == 12 && strncmp (".debug_frame", segment_name (sec), 12) == 0))
- return 1;
- return 0;
+ symbolS *symbolP;
+ bfd_mach_o_asymbol *s;
+
+ switch (what)
+ {
+ case 'd':
+ symbolP = symbol_new ("", now_seg, frag_now, frag_now_fix ());
+ /* Special stabd NULL name indicator. */
+ S_SET_NAME (symbolP, NULL);
+ break;
+
+ case 'n':
+ case 's':
+ symbolP = symbol_new (string, undefined_section,
+ &zero_address_frag, 0);
+ pseudo_set (symbolP);
+ break;
+
+ default:
+ as_bad(_("unrecognized stab type '%c'"), (char)what);
+ abort ();
+ break;
+ }
+
+ s = (bfd_mach_o_asymbol *) symbol_get_bfdsym (symbolP);
+ s->n_type = type;
+ s->n_desc = desc;
+ /* For stabd, this will eventually get overwritten by the section number. */
+ s->n_sect = other;
+
+ /* It's a debug symbol. */
+ s->symbol.flags |= BSF_DEBUGGING;
+
+ /* We've set it - so check it, if you can, but don't try to create the
+ flags. */
+ 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, (char *) 0);
+}
+
+/* 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
+ be attached as one anonymous subsection. */
+
+static void
+obj_mach_o_set_subsections (bfd *abfd ATTRIBUTE_UNUSED,
+ asection *sec,
+ void *unused ATTRIBUTE_UNUSED)
+{
+ segment_info_type *seginfo = seg_info (sec);
+ symbolS *cur_subsection = NULL;
+ struct obj_mach_o_symbol_data *cur_subsection_data = NULL;
+ fragS *frag;
+ frchainS *chain;
+
+ /* Protect against sections not created by gas. */
+ if (seginfo == NULL)
+ return;
+
+ /* Attach every frag to a subsection. */
+ for (chain = seginfo->frchainP; chain != NULL; chain = chain->frch_next)
+ for (frag = chain->frch_root; frag != NULL; frag = frag->fr_next)
+ {
+ if (frag->obj_frag_data.subsection == NULL)
+ frag->obj_frag_data.subsection = cur_subsection;
+ else
+ {
+ cur_subsection = frag->obj_frag_data.subsection;
+ cur_subsection_data = symbol_get_obj (cur_subsection);
+ cur_subsection_data->subsection_size = 0;
+ }
+ if (cur_subsection_data != NULL)
+ {
+ /* Update subsection size. */
+ cur_subsection_data->subsection_size += frag->fr_fix;
+ }
+ }
+}
+
+/* Handle mach-o subsections-via-symbols counting up frags belonging to each
+ sub-section. */
+
+void
+obj_mach_o_pre_relax_hook (void)
+{
+ bfd_map_over_sections (stdoutput, obj_mach_o_set_subsections, (char *) 0);
}
/* Zerofill and GB Zerofill sections must be sorted to follow all other
The native 'as' leaves the sections physically in the order they appear in
the source, and adjusts the section VMAs to meet the constraint.
-
+
We follow this for now - if nothing else, it makes comparison easier.
An alternative implementation would be to sort the sections as ld requires.
zerofill sections get VMAs after all others in their segment
GB zerofill get VMAs last.
-
+
As we go, we notice if we see any Zerofill or GB Zerofill sections, so that
we can skip the additional passes if there's nothing to do. */
obj_mach_o_set_section_vma (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, void *v_p)
{
bfd_mach_o_section *ms = bfd_mach_o_get_mach_o_section (sec);
- unsigned bfd_align = bfd_get_section_alignment (abfd, sec);
+ unsigned bfd_align = bfd_section_alignment (sec);
obj_mach_o_set_vma_data *p = (struct obj_mach_o_set_vma_data *)v_p;
unsigned sectype = (ms->flags & BFD_MACH_O_SECTION_TYPE_MASK);
unsigned zf;
/* We know the section size now - so make a vma for the section just
based on order. */
- ms->size = bfd_get_section_size (sec);
-
+ ms->size = bfd_section_size (sec);
+
/* Make sure that the align agrees, and set to the largest value chosen. */
ms->align = ms->align > bfd_align ? ms->align : bfd_align;
- bfd_set_section_alignment (abfd, sec, ms->align);
-
+ bfd_set_section_alignment (sec, ms->align);
+
p->vma += (1 << ms->align) - 1;
p->vma &= ~((1 << ms->align) - 1);
ms->addr = p->vma;
- bfd_set_section_vma (abfd, sec, p->vma);
+ bfd_set_section_vma (sec, p->vma);
p->vma += ms->size;
}
-/* (potentially) three passes over the sections, setting VMA. We skip the
+/* (potentially) three passes over the sections, setting VMA. We skip the
{gb}zerofill passes if we didn't see any of the relevant sections. */
void obj_mach_o_post_relax_hook (void)
obj_mach_o_set_vma_data d;
memset (&d, 0, sizeof (d));
-
+
bfd_map_over_sections (stdoutput, obj_mach_o_set_section_vma, (char *) &d);
if ((d.vma_pass = d.zerofill_seen) != 0)
bfd_map_over_sections (stdoutput, obj_mach_o_set_section_vma, (char *) &d);
obj_mach_o_set_indirect_symbols (bfd *abfd, asection *sec,
void *xxx ATTRIBUTE_UNUSED)
{
- bfd_vma sect_size = bfd_section_size (abfd, sec);
+ bfd_vma sect_size = bfd_section_size (sec);
bfd_mach_o_section *ms = bfd_mach_o_get_mach_o_section (sec);
unsigned lazy = 0;
obj_mach_o_indirect_sym *isym;
obj_mach_o_indirect_sym *list = NULL;
obj_mach_o_indirect_sym *list_tail = NULL;
- unsigned long eltsiz =
+ unsigned long eltsiz =
bfd_mach_o_section_get_entry_size (abfd, ms);
for (isym = indirect_syms; isym != NULL; isym = isym->next)
{
unsigned n;
bfd_mach_o_asymbol *sym;
+
+ /* FIXME: It seems that there can be more indirect symbols
+ than is computed by the loop above. So be paranoid and
+ allocate enough space for every symbol to be indirect.
+ See PR 21939 for an example of where this is needed. */
+ if (nactual < bfd_get_symcount (abfd))
+ nactual = bfd_get_symcount (abfd);
+
ms->indirect_syms =
bfd_zalloc (abfd,
nactual * sizeof (bfd_mach_o_asymbol *));
if (ms->indirect_syms == NULL)
- {
- as_fatal (_("internal error: failed to allocate %d indirect"
- "symbol pointers"), nactual);
- }
-
+ as_fatal (_("internal error: failed to allocate %d indirect"
+ "symbol pointers"), nactual);
+
for (isym = list, n = 0; isym != NULL; isym = isym->next, n++)
{
sym = (bfd_mach_o_asymbol *)symbol_get_bfdsym (isym->sym);
/* Array is init to NULL & NULL signals a local symbol
If the section is lazy-bound, we need to keep the
reference to the symbol, since dyld can override.
-
+
Absolute symbols are handled specially. */
if (sym->symbol.section == bfd_abs_section_ptr)
- ms->indirect_syms[n] = sym;
+ {
+ if (n >= nactual)
+ as_fatal (_("internal error: more indirect mach-o symbols than expected"));
+ ms->indirect_syms[n] = sym;
+ }
else if (S_IS_LOCAL (isym->sym) && ! lazy)
;
else
{
sym->n_desc &= ~LAZY;
/* ... it can be lazy, if not defined or hidden. */
- if ((sym->n_type & BFD_MACH_O_N_TYPE)
- == BFD_MACH_O_N_UNDF
+ if ((sym->n_type & BFD_MACH_O_N_TYPE)
+ == BFD_MACH_O_N_UNDF
&& ! (sym->n_type & BFD_MACH_O_N_PEXT)
&& (sym->n_type & BFD_MACH_O_N_EXT))
sym->n_desc |= lazy;
+ if (n >= nactual)
+ as_fatal (_("internal error: more indirect mach-o symbols than expected"));
ms->indirect_syms[n] = sym;
}
}
bfd_set_reloc (stdoutput, sec, rels, n);
}
-/* Support stabs for mach-o. */
+/* Relocation rules are different in frame sections. */
-void
-obj_mach_o_process_stab (int what, const char *string,
- int type, int other, int desc)
+static int
+obj_mach_o_is_frame_section (segT sec)
{
- symbolS *symbolP;
- bfd_mach_o_asymbol *s;
-
- switch (what)
- {
- case 'd':
- symbolP = symbol_new ("", now_seg, frag_now_fix (), frag_now);
- /* Special stabd NULL name indicator. */
- S_SET_NAME (symbolP, NULL);
- break;
-
- case 'n':
- case 's':
- symbolP = symbol_new (string, undefined_section, (valueT) 0,
- &zero_address_frag);
- pseudo_set (symbolP);
- break;
-
- default:
- as_bad(_("unrecognized stab type '%c'"), (char)what);
- abort ();
- break;
- }
-
- s = (bfd_mach_o_asymbol *) symbol_get_bfdsym (symbolP);
- s->n_type = type;
- s->n_desc = desc;
- /* For stabd, this will eventually get overwritten by the section number. */
- s->n_sect = other;
-
- /* It's a debug symbol. */
- s->symbol.flags |= BSF_DEBUGGING;
+ int l;
+ l = strlen (segment_name (sec));
+ if ((l == 9 && strncmp (".eh_frame", segment_name (sec), 9) == 0)
+ || (l == 12 && strncmp (".debug_frame", segment_name (sec), 12) == 0))
+ return 1;
+ return 0;
}
/* Unless we're in a frame section, we need to force relocs to be generated for
being made. */
int
-obj_mach_o_allow_local_subtract (expressionS * left ATTRIBUTE_UNUSED,
+obj_mach_o_allow_local_subtract (expressionS * left ATTRIBUTE_UNUSED,
expressionS * right ATTRIBUTE_UNUSED,
segT seg)
{
/* Allow in frame sections, otherwise emit a reloc. */
return obj_mach_o_is_frame_section (seg);
}
+
+int
+obj_mach_o_in_different_subsection (symbolS *a, symbolS *b)
+{
+ fragS *fa;
+ fragS *fb;
+
+ if (S_GET_SEGMENT (a) != S_GET_SEGMENT (b)
+ || !S_IS_DEFINED (a)
+ || !S_IS_DEFINED (b))
+ {
+ /* Not in the same segment, or undefined symbol. */
+ return 1;
+ }
+
+ fa = symbol_get_frag (a);
+ fb = symbol_get_frag (b);
+ if (fa == NULL || fb == NULL)
+ {
+ /* One of the symbols is not in a subsection. */
+ return 1;
+ }
+
+ return fa->obj_frag_data.subsection != fb->obj_frag_data.subsection;
+}
+
+int
+obj_mach_o_force_reloc_sub_same (fixS *fix, segT seg)
+{
+ if (! SEG_NORMAL (seg))
+ return 1;
+ return obj_mach_o_in_different_subsection (fix->fx_addsy, fix->fx_subsy);
+}
+
+int
+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);
+}
+
+int
+obj_mach_o_force_reloc (fixS *fix)
+{
+ if (generic_force_reloc (fix))
+ return 1;
+
+ /* 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 ? */
+ 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 0;
+
+ if (S_GET_SEGMENT (targ) == absolute_section)
+ return 0;
+
+ return obj_mach_o_in_different_subsection (targ, subsec);
+ }
+ return 0;
+}