/* Mach-O support for BFD.
- Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
- 2009, 2010, 2011, 2012
- Free Software Foundation, Inc.
+ Copyright 1999-2013 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
{
return mach_o_wide_p (&bfd_mach_o_get_data (abfd)->header);
}
-
+
/* Tables to translate well known Mach-O segment/section names to bfd
names. Use of canonical names (such as .text or .debug_frame) is required
by gdb. */
/* __TEXT Segment. */
static const mach_o_section_name_xlat text_section_names_xlat[] =
{
- { ".text", "__text",
+ { ".text", "__text",
SEC_CODE | SEC_LOAD, BFD_MACH_O_S_REGULAR,
BFD_MACH_O_S_ATTR_PURE_INSTRUCTIONS, 0},
{ ".const", "__const",
SEC_CODE | SEC_LOAD, BFD_MACH_O_S_REGULAR,
BFD_MACH_O_S_ATTR_NONE, 0},
{ ".eh_frame", "__eh_frame",
- SEC_READONLY | SEC_LOAD, BFD_MACH_O_S_COALESCED,
+ SEC_READONLY | SEC_DATA | SEC_LOAD, BFD_MACH_O_S_COALESCED,
BFD_MACH_O_S_ATTR_LIVE_SUPPORT
| BFD_MACH_O_S_ATTR_STRIP_STATIC_SYMS
- | BFD_MACH_O_S_ATTR_NO_TOC, 3},
+ | BFD_MACH_O_S_ATTR_NO_TOC, 2},
{ NULL, NULL, 0, 0, 0, 0}
};
{ ".debug_macro", "__debug_macro",
SEC_DEBUGGING, BFD_MACH_O_S_REGULAR,
BFD_MACH_O_S_ATTR_DEBUG, 0},
+ { ".debug_gdb_scripts", "__debug_gdb_scri",
+ SEC_DEBUGGING, BFD_MACH_O_S_REGULAR,
+ BFD_MACH_O_S_ATTR_DEBUG, 0},
{ NULL, NULL, 0, 0, 0, 0}
};
/* Fetch the translation from a Mach-O section designation (segment, section)
as a bfd short name, if one exists. Otherwise return NULL.
-
+
Allow the segment and section names to be unterminated 16 byte arrays. */
const mach_o_section_name_xlat *
BFD_MACH_O_SECTNAME_SIZE) == 0)
return sec;
- return NULL;
+ return NULL;
}
/* If the bfd_name for this section is a 'canonical' form for which we
- know the Mach-O data, return the segment name and the data for the
+ know the Mach-O data, return the segment name and the data for the
Mach-O equivalent. Otherwise return NULL. */
const mach_o_section_name_xlat *
return sec;
}
- return NULL;
+ return NULL;
}
/* Convert Mach-O section name to BFD.
- Try to use standard/canonical names, for which we have tables including
+ Try to use standard/canonical names, for which we have tables including
default flag settings - which are returned. Otherwise forge a new name
in the form "<segmentname>.<sectionname>" this will be prefixed with
LC_SEGMENT. if the segment name does not begin with an underscore.
*name = NULL;
*flags = SEC_NO_FLAGS;
- /* First search for a canonical name...
+ /* First search for a canonical name...
xlat will be non-null if there is an entry for segname, secname. */
xlat = bfd_mach_o_section_data_for_mach_sect (abfd, segname, secname);
if (xlat)
return the translation table - which contains defaults for flags,
type, attribute and default alignment data.
- Otherwise, expand the bfd_name (assumed to be in the form
+ Otherwise, expand the bfd_name (assumed to be in the form
"[LC_SEGMENT.]<segmentname>.<sectionname>") and return NULL. */
static const mach_o_section_name_xlat *
{
if (osection->used_by_bfd == NULL)
osection->used_by_bfd = isection->used_by_bfd;
- else
+ else
if (isection->used_by_bfd != NULL)
- memcpy (osection->used_by_bfd, isection->used_by_bfd,
+ memcpy (osection->used_by_bfd, isection->used_by_bfd,
sizeof (bfd_mach_o_section));
-
+
if (osection->used_by_bfd != NULL)
((bfd_mach_o_section *)osection->used_by_bfd)->bfdsection = osection;
/* This allows us to set up to 32 bits of flags (unless we invent some
fiendish scheme to subdivide). For now, we'll just set the file flags
without error checking - just overwrite. */
-
+
bfd_boolean
bfd_mach_o_bfd_set_private_flags (bfd *abfd, flagword flags)
{
names = (char *) (s + count);
nul_name = names;
*names++ = 0;
-
+
n = 0;
for (i = 0; i < mdata->nsects; i++)
{
unsigned int first, last;
bfd_vma addr;
bfd_vma entry_size;
-
+
switch (sec->flags & BFD_MACH_O_SECTION_TYPE_MASK)
{
case BFD_MACH_O_S_NON_LAZY_SYMBOL_POINTERS:
s->section = sec->bfdsection;
s->value = addr - sec->addr;
s->udata.p = NULL;
-
+
if (isym < symtab->nsyms
&& symtab->symbols[isym].symbol.name)
{
return (asect->reloc_count + 1) * sizeof (arelent *);
}
+/* In addition to the need to byte-swap the symbol number, the bit positions
+ of the fields in the relocation information vary per target endian-ness. */
+
+static void
+bfd_mach_o_swap_in_non_scattered_reloc (bfd *abfd, bfd_mach_o_reloc_info *rel,
+ unsigned char *fields)
+{
+ unsigned char info = fields[3];
+
+ if (bfd_big_endian (abfd))
+ {
+ rel->r_value = (fields[0] << 16) | (fields[1] << 8) | fields[2];
+ rel->r_type = (info >> BFD_MACH_O_BE_TYPE_SHIFT) & BFD_MACH_O_TYPE_MASK;
+ rel->r_pcrel = (info & BFD_MACH_O_BE_PCREL) ? 1 : 0;
+ rel->r_length = (info >> BFD_MACH_O_BE_LENGTH_SHIFT)
+ & BFD_MACH_O_LENGTH_MASK;
+ rel->r_extern = (info & BFD_MACH_O_BE_EXTERN) ? 1 : 0;
+ }
+ else
+ {
+ rel->r_value = (fields[2] << 16) | (fields[1] << 8) | fields[0];
+ rel->r_type = (info >> BFD_MACH_O_LE_TYPE_SHIFT) & BFD_MACH_O_TYPE_MASK;
+ rel->r_pcrel = (info & BFD_MACH_O_LE_PCREL) ? 1 : 0;
+ rel->r_length = (info >> BFD_MACH_O_LE_LENGTH_SHIFT)
+ & BFD_MACH_O_LENGTH_MASK;
+ rel->r_extern = (info & BFD_MACH_O_LE_EXTERN) ? 1 : 0;
+ }
+}
+
static int
bfd_mach_o_canonicalize_one_reloc (bfd *abfd,
struct mach_o_reloc_info_external *raw,
bfd_mach_o_backend_data *bed = bfd_mach_o_get_backend_data (abfd);
bfd_mach_o_reloc_info reloc;
bfd_vma addr;
- bfd_vma symnum;
asymbol **sym;
addr = bfd_get_32 (abfd, raw->r_address);
- symnum = bfd_get_32 (abfd, raw->r_symbolnum);
-
+ res->sym_ptr_ptr = NULL;
+ res->addend = 0;
+
if (addr & BFD_MACH_O_SR_SCATTERED)
{
unsigned int j;
+ bfd_vma symnum = bfd_get_32 (abfd, raw->r_symbolnum);
- /* Scattered relocation.
- Extract section and offset from r_value. */
- res->sym_ptr_ptr = NULL;
- res->addend = 0;
+ /* Scattered relocation, can't be extern. */
+ reloc.r_scattered = 1;
+ reloc.r_extern = 0;
+
+ /* Extract section and offset from r_value (symnum). */
+ reloc.r_value = symnum;
+ /* FIXME: This breaks when a symbol in a reloc exactly follows the
+ end of the data for the section (e.g. in a calculation of section
+ data length). At present, the symbol will end up associated with
+ the following section or, if it falls within alignment padding, as
+ null - which will assert later. */
for (j = 0; j < mdata->nsects; j++)
{
bfd_mach_o_section *sect = mdata->sections[j];
break;
}
}
- res->address = BFD_MACH_O_GET_SR_ADDRESS (addr);
+
+ /* Extract the info and address fields from r_address. */
reloc.r_type = BFD_MACH_O_GET_SR_TYPE (addr);
reloc.r_length = BFD_MACH_O_GET_SR_LENGTH (addr);
reloc.r_pcrel = addr & BFD_MACH_O_SR_PCREL;
- reloc.r_scattered = 1;
+ reloc.r_address = BFD_MACH_O_GET_SR_TYPE (addr);
+ res->address = BFD_MACH_O_GET_SR_ADDRESS (addr);
}
else
{
- unsigned int num = BFD_MACH_O_GET_R_SYMBOLNUM (symnum);
- res->addend = 0;
- res->address = addr;
- if (symnum & BFD_MACH_O_R_EXTERN)
- {
- sym = syms + num;
- reloc.r_extern = 1;
- }
+ unsigned int num;
+
+ /* Non-scattered relocation. */
+ reloc.r_scattered = 0;
+
+ /* The value and info fields have to be extracted dependent on target
+ endian-ness. */
+ bfd_mach_o_swap_in_non_scattered_reloc (abfd, &reloc, raw->r_symbolnum);
+ num = reloc.r_value;
+
+ if (reloc.r_extern)
+ {
+ /* An external symbol number. */
+ sym = syms + num;
+ }
+ else if (num == 0x00ffffff)
+ {
+ /* The 'symnum' in a non-scattered PAIR is 0x00ffffff. But as this
+ is generic code, we don't know wether this is really a PAIR.
+ This value is almost certainly not a valid section number, hence
+ this specific case to avoid an assertion failure.
+ Target specific swap_reloc_in routine should adjust that. */
+ sym = bfd_abs_section_ptr->symbol_ptr_ptr;
+ }
else
{
+ /* A section number. */
BFD_ASSERT (num != 0);
BFD_ASSERT (num <= mdata->nsects);
+
sym = mdata->sections[num - 1]->bfdsection->symbol_ptr_ptr;
/* For a symbol defined in section S, the addend (stored in the
binary) contains the address of the section. To comply with
- bfd conventio, substract the section address.
+ bfd convention, subtract the section address.
Use the address from the header, so that the user can modify
the vma of the section. */
res->addend = -mdata->sections[num - 1]->addr;
- reloc.r_extern = 0;
}
+ /* Note: Pairs for PPC LO/HI/HA are not scattered, but contain the offset
+ in the lower 16bits of the address value. So we have to find the
+ 'symbol' from the preceding reloc. We do this even though the
+ section symbol is probably not needed here, because NULL symbol
+ values cause an assert in generic BFD code. This must be done in
+ the PPC swap_reloc_in routine. */
res->sym_ptr_ptr = sym;
- reloc.r_type = BFD_MACH_O_GET_R_TYPE (symnum);
- reloc.r_length = BFD_MACH_O_GET_R_LENGTH (symnum);
- reloc.r_pcrel = (symnum & BFD_MACH_O_R_PCREL) ? 1 : 0;
- reloc.r_scattered = 0;
+
+ /* The 'address' is just r_address.
+ ??? maybe this should be masked with 0xffffff for safety. */
+ res->address = addr;
+ reloc.r_address = addr;
}
-
+
+ /* We have set up a reloc with all the information present, so the swapper
+ can modify address, value and addend fields, if necessary, to convey
+ information in the generic BFD reloc that is mach-o specific. */
+
if (!(*bed->_bfd_mach_o_swap_reloc_in)(res, &reloc))
return -1;
return 0;
return i;
}
+/* In addition to the need to byte-swap the symbol number, the bit positions
+ of the fields in the relocation information vary per target endian-ness. */
+
+static void
+bfd_mach_o_swap_out_non_scattered_reloc (bfd *abfd, unsigned char *fields,
+ bfd_mach_o_reloc_info *rel)
+{
+ unsigned char info = 0;
+
+ BFD_ASSERT (rel->r_type <= 15);
+ BFD_ASSERT (rel->r_length <= 3);
+
+ if (bfd_big_endian (abfd))
+ {
+ fields[0] = (rel->r_value >> 16) & 0xff;
+ fields[1] = (rel->r_value >> 8) & 0xff;
+ fields[2] = rel->r_value & 0xff;
+ info |= rel->r_type << BFD_MACH_O_BE_TYPE_SHIFT;
+ info |= rel->r_pcrel ? BFD_MACH_O_BE_PCREL : 0;
+ info |= rel->r_length << BFD_MACH_O_BE_LENGTH_SHIFT;
+ info |= rel->r_extern ? BFD_MACH_O_BE_EXTERN : 0;
+ }
+ else
+ {
+ fields[2] = (rel->r_value >> 16) & 0xff;
+ fields[1] = (rel->r_value >> 8) & 0xff;
+ fields[0] = rel->r_value & 0xff;
+ info |= rel->r_type << BFD_MACH_O_LE_TYPE_SHIFT;
+ info |= rel->r_pcrel ? BFD_MACH_O_LE_PCREL : 0;
+ info |= rel->r_length << BFD_MACH_O_LE_LENGTH_SHIFT;
+ info |= rel->r_extern ? BFD_MACH_O_LE_EXTERN : 0;
+ }
+ fields[3] = info;
+}
+
static bfd_boolean
bfd_mach_o_write_relocs (bfd *abfd, bfd_mach_o_section *section)
{
- bfd_mach_o_data_struct *mdata = bfd_mach_o_get_data (abfd);
unsigned int i;
arelent **entries;
asection *sec;
if (bed->_bfd_mach_o_swap_reloc_out == NULL)
return TRUE;
- /* Allocate relocation room. */
- mdata->filelen = FILE_ALIGN(mdata->filelen, 2);
- section->nreloc = sec->reloc_count;
- sec->rel_filepos = mdata->filelen;
- section->reloff = sec->rel_filepos;
- mdata->filelen += sec->reloc_count * BFD_MACH_O_RELENT_SIZE;
-
if (bfd_seek (abfd, section->reloff, SEEK_SET) != 0)
return FALSE;
}
else
{
- unsigned long v;
-
bfd_put_32 (abfd, pinfo->r_address, raw.r_address);
- v = BFD_MACH_O_SET_R_SYMBOLNUM (pinfo->r_value)
- | (pinfo->r_pcrel ? BFD_MACH_O_R_PCREL : 0)
- | BFD_MACH_O_SET_R_LENGTH (pinfo->r_length)
- | (pinfo->r_extern ? BFD_MACH_O_R_EXTERN : 0)
- | BFD_MACH_O_SET_R_TYPE (pinfo->r_type);
- bfd_put_32 (abfd, v, raw.r_symbolnum);
+ bfd_mach_o_swap_out_non_scattered_reloc (abfd, raw.r_symbolnum,
+ pinfo);
}
if (bfd_bwrite (&raw, BFD_MACH_O_RELENT_SIZE, abfd)
bfd_h_put_32 (abfd, seg->initprot, raw.initprot);
bfd_h_put_32 (abfd, seg->nsects, raw.nsects);
bfd_h_put_32 (abfd, seg->flags, raw.flags);
-
+
if (bfd_seek (abfd, command->offset + BFD_MACH_O_LC_SIZE, SEEK_SET) != 0
|| bfd_bwrite (&raw, sizeof (raw), abfd) != sizeof (raw))
return -1;
{
bfd_size_type str_index;
bfd_mach_o_asymbol *s = (bfd_mach_o_asymbol *)symbols[i];
-
+
if (s->symbol.name == 0 || s->symbol.name[0] == '\0')
/* An index of 0 always means the empty string. */
str_index = 0;
return FALSE;
}
}
-
+
if (cmd->nindirectsyms > 0)
{
unsigned int i;
bfd_h_put_32 (abfd, cmd->indirect_syms[i], &raw);
if (bfd_bwrite (raw, sizeof (raw), abfd) != sizeof (raw))
return FALSE;
- }
+ }
}
if (cmd->nextrefsyms != 0)
}
else
s->n_type = BFD_MACH_O_N_SECT;
-
+
if (s->symbol.flags & BSF_GLOBAL)
s->n_type |= BFD_MACH_O_N_EXT;
}
unsigned nsect;
nsect = bfd_count_sections (abfd);
-
+
/* Don't do it if it's already set - assume the application knows what it's
doing. */
if (mdata->nsects == nsect
return TRUE;
mdata->nsects = nsect;
- mdata->sections = bfd_alloc (abfd,
+ mdata->sections = bfd_alloc (abfd,
mdata->nsects * sizeof (bfd_mach_o_section *));
if (mdata->sections == NULL)
return FALSE;
" maximum is 255,\n"), nsect);
/* Create Mach-O sections.
- Section type, attribute and align should have been set when the
+ Section type, attribute and align should have been set when the
section was created - either read in or specified. */
target_index = 0;
for (sec = abfd->sections; sec; sec = sec->next)
msect->addr = bfd_get_section_vma (abfd, sec);
msect->size = bfd_get_section_size (sec);
- /* Use the largest alignment set, in case it was bumped after the
+ /* Use the largest alignment set, in case it was bumped after the
section was created. */
msect->align = msect->align > bfd_align ? msect->align : bfd_align;
/* Count the number of sections in the list for the segment named.
The special case of NULL or "" for the segment name is valid for
- an MH_OBJECT file and means 'all sections available'.
-
- Requires that the sections table in mdata be filled in.
+ an MH_OBJECT file and means 'all sections available'.
+
+ Requires that the sections table in mdata be filled in.
Returns the number of sections (0 is valid).
Any number > 255 signals an invalid section count, although we will,
perhaps, allow the file to be written (in line with Darwin tools up
- to XCode 4).
-
+ to XCode 4).
+
A section count of (unsigned long) -1 signals a definite error. */
static unsigned long
/* TODO: fix this up for non-MH_OBJECT cases. */
seg->vmaddr = 0;
+ seg->vmsize = 0;
seg->fileoff = mdata->filelen;
seg->filesize = 0;
seg->sect_head = NULL;
seg->sect_tail = NULL;
- /* Append sections to the segment. */
+ /* Append sections to the segment.
+
+ This is a little tedious, we have to honor the need to account zerofill
+ sections after all the rest. This forces us to do the calculation of
+ total vmsize in three passes so that any alignment increments are
+ properly accounted. */
for (i = 0; i < mdata->nsects; ++i)
{
/* If we're not making an MH_OBJECT, check whether this section is from
our segment, and skip if not. Otherwise, just add all sections. */
- if (! is_mho
+ if (! is_mho
&& strncmp (segment, s->segname, BFD_MACH_O_SEGNAME_SIZE) != 0)
continue;
+ /* Although we account for zerofill section sizes in vm order, they are
+ placed in the file in source sequence. */
bfd_mach_o_append_section_to_segment (seg, sec);
+ s->offset = 0;
- if (s->size == 0)
- s->offset = 0;
- else
+ /* Zerofill sections have zero file size & offset,
+ and are not written. */
+ if ((s->flags & BFD_MACH_O_SECTION_TYPE_MASK) == BFD_MACH_O_S_ZEROFILL
+ || (s->flags & BFD_MACH_O_SECTION_TYPE_MASK)
+ == BFD_MACH_O_S_GB_ZEROFILL)
+ continue;
+
+ if (s->size > 0)
{
+ seg->vmsize = FILE_ALIGN (seg->vmsize, s->align);
+ seg->vmsize += s->size;
+
+ seg->filesize = FILE_ALIGN (seg->filesize, s->align);
+ seg->filesize += s->size;
+
mdata->filelen = FILE_ALIGN (mdata->filelen, s->align);
s->offset = mdata->filelen;
}
sec->filepos = s->offset;
-
mdata->filelen += s->size;
}
- seg->filesize = mdata->filelen - seg->fileoff;
- seg->vmsize = seg->filesize;
+ /* Now pass through again, for zerofill, only now we just update the vmsize. */
+ for (i = 0; i < mdata->nsects; ++i)
+ {
+ bfd_mach_o_section *s = mdata->sections[i];
+
+ if ((s->flags & BFD_MACH_O_SECTION_TYPE_MASK) != BFD_MACH_O_S_ZEROFILL)
+ continue;
+
+ if (! is_mho
+ && strncmp (segment, s->segname, BFD_MACH_O_SEGNAME_SIZE) != 0)
+ continue;
+
+ if (s->size > 0)
+ {
+ seg->vmsize = FILE_ALIGN (seg->vmsize, s->align);
+ seg->vmsize += s->size;
+ }
+ }
+
+ /* Now pass through again, for zerofill_GB. */
+ for (i = 0; i < mdata->nsects; ++i)
+ {
+ bfd_mach_o_section *s = mdata->sections[i];
+
+ if ((s->flags & BFD_MACH_O_SECTION_TYPE_MASK) != BFD_MACH_O_S_GB_ZEROFILL)
+ continue;
+
+ if (! is_mho
+ && strncmp (segment, s->segname, BFD_MACH_O_SEGNAME_SIZE) != 0)
+ continue;
+
+ if (s->size > 0)
+ {
+ seg->vmsize = FILE_ALIGN (seg->vmsize, s->align);
+ seg->vmsize += s->size;
+ }
+ }
+
+ /* Allocate space for the relocations. */
+ mdata->filelen = FILE_ALIGN(mdata->filelen, 2);
+
+ for (i = 0; i < mdata->nsects; ++i)
+ {
+ bfd_mach_o_section *ms = mdata->sections[i];
+ asection *sec = ms->bfdsection;
+
+ if ((ms->nreloc = sec->reloc_count) == 0)
+ {
+ ms->reloff = 0;
+ continue;
+ }
+ sec->rel_filepos = mdata->filelen;
+ ms->reloff = sec->rel_filepos;
+ mdata->filelen += sec->reloc_count * BFD_MACH_O_RELENT_SIZE;
+ }
return TRUE;
}
+/* Count the number of indirect symbols in the image.
+ Requires that the sections are in their final order. */
+
+static unsigned int
+bfd_mach_o_count_indirect_symbols (bfd *abfd, bfd_mach_o_data_struct *mdata)
+{
+ unsigned int i;
+ unsigned int nisyms = 0;
+
+ for (i = 0; i < mdata->nsects; ++i)
+ {
+ bfd_mach_o_section *sec = mdata->sections[i];
+
+ switch (sec->flags & BFD_MACH_O_SECTION_TYPE_MASK)
+ {
+ case BFD_MACH_O_S_NON_LAZY_SYMBOL_POINTERS:
+ case BFD_MACH_O_S_LAZY_SYMBOL_POINTERS:
+ case BFD_MACH_O_S_SYMBOL_STUBS:
+ nisyms += bfd_mach_o_section_get_nbr_indirect (abfd, sec);
+ break;
+ default:
+ break;
+ }
+ }
+ return nisyms;
+}
+
static bfd_boolean
bfd_mach_o_build_dysymtab_command (bfd *abfd,
bfd_mach_o_data_struct *mdata,
}
dsym->nextdefsym = i - dsym->nlocalsym;
dsym->iundefsym = dsym->nextdefsym + dsym->iextdefsym;
- dsym->nundefsym = bfd_get_symcount (abfd)
- - dsym->nlocalsym
+ dsym->nundefsym = bfd_get_symcount (abfd)
+ - dsym->nlocalsym
- dsym->nextdefsym;
}
else
dsym->nundefsym = 0;
}
+ dsym->nindirectsyms = bfd_mach_o_count_indirect_symbols (abfd, mdata);
if (dsym->nindirectsyms > 0)
{
unsigned i;
+ unsigned n;
mdata->filelen = FILE_ALIGN (mdata->filelen, 2);
dsym->indirectsymoff = mdata->filelen;
mdata->filelen += dsym->nindirectsyms * 4;
-
+
dsym->indirect_syms = bfd_zalloc (abfd, dsym->nindirectsyms * 4);
if (dsym->indirect_syms == NULL)
return FALSE;
-
- /* So fill in the indices. */
- for (i = 0; i < dsym->nindirectsyms; ++i)
+
+ n = 0;
+ for (i = 0; i < mdata->nsects; ++i)
{
- /* TODO: fill in the table. */
+ bfd_mach_o_section *sec = mdata->sections[i];
+
+ switch (sec->flags & BFD_MACH_O_SECTION_TYPE_MASK)
+ {
+ case BFD_MACH_O_S_NON_LAZY_SYMBOL_POINTERS:
+ case BFD_MACH_O_S_LAZY_SYMBOL_POINTERS:
+ case BFD_MACH_O_S_SYMBOL_STUBS:
+ {
+ unsigned j, num;
+ bfd_mach_o_asymbol **isyms = sec->indirect_syms;
+
+ num = bfd_mach_o_section_get_nbr_indirect (abfd, sec);
+ if (isyms == NULL || num == 0)
+ break;
+ /* Record the starting index in the reserved1 field. */
+ sec->reserved1 = n;
+ for (j = 0; j < num; j++, n++)
+ {
+ if (isyms[j] == NULL)
+ dsym->indirect_syms[n] = BFD_MACH_O_INDIRECT_SYM_LOCAL;
+ else if (isyms[j]->symbol.section == bfd_abs_section_ptr
+ && ! (isyms[j]->n_type & BFD_MACH_O_N_EXT))
+ dsym->indirect_syms[n] = BFD_MACH_O_INDIRECT_SYM_LOCAL
+ | BFD_MACH_O_INDIRECT_SYM_ABS;
+ else
+ dsym->indirect_syms[n] = isyms[j]->symbol.udata.i;
+ }
+ }
+ break;
+ default:
+ break;
+ }
}
}
bfd_mach_o_build_commands (bfd *abfd)
{
bfd_mach_o_data_struct *mdata = bfd_mach_o_get_data (abfd);
- unsigned int wide = mach_o_wide_p (&mdata->header);
- bfd_mach_o_segment_command *seg = NULL;
- bfd_mach_o_load_command *cmd;
- bfd_mach_o_load_command *symtab_cmd;
- unsigned symcind;
+ unsigned wide = mach_o_wide_p (&mdata->header);
+ int segcmd_idx = -1;
+ int symtab_idx = -1;
+ int dysymtab_idx = -1;
+ unsigned long base_offset = 0;
/* Return now if commands are already present. */
if (mdata->header.ncmds)
if (!bfd_mach_o_mangle_symbols (abfd))
return FALSE;
- /* It's valid to have a file with only absolute symbols... */
+ /* Very simple command set (only really applicable to MH_OBJECTs):
+ All the commands are optional - present only when there is suitable data.
+ (i.e. it is valid to have an empty file)
+
+ a command (segment) to contain all the sections,
+ command for the symbol table,
+ a command for the dysymtab.
+
+ ??? maybe we should assert that this is an MH_OBJECT? */
+
if (mdata->nsects > 0)
{
+ segcmd_idx = 0;
mdata->header.ncmds = 1;
- symcind = 1;
}
- else
- symcind = 0;
- /* It's OK to have a file with only section statements. */
if (bfd_get_symcount (abfd) > 0)
- mdata->header.ncmds += 1;
+ {
+ mdata->header.ncmds++;
+ symtab_idx = segcmd_idx + 1; /* 0 if the seg command is absent. */
+ }
- /* Very simple version (only really applicable to MH_OBJECTs):
- a command (segment) to contain all the sections,
- a command for the symbol table
- a n (optional) command for the dysymtab.
+ /* FIXME:
+ This is a rather crude test for whether we should build a dysymtab. */
+ if (bfd_mach_o_should_emit_dysymtab ()
+ && bfd_get_symcount (abfd))
+ {
+ mdata->header.ncmds++;
+ /* If there should be a case where a dysymtab could be emitted without
+ a symtab (seems improbable), this would need amending. */
+ dysymtab_idx = symtab_idx + 1;
+ }
- ??? maybe we should assert that this is an MH_OBJECT? */
+ if (wide)
+ base_offset = BFD_MACH_O_HEADER_64_SIZE;
+ else
+ base_offset = BFD_MACH_O_HEADER_SIZE;
- if (bfd_mach_o_should_emit_dysymtab ()
- && bfd_get_symcount (abfd) > 0)
- mdata->header.ncmds += 1;
+ /* Well, we must have a header, at least. */
+ mdata->filelen = base_offset;
- /* A bit weird, but looks like no content;
+ /* A bit unusual, but no content is valid;
as -n empty.s -o empty.o */
if (mdata->header.ncmds == 0)
return TRUE;
if (mdata->commands == NULL)
return FALSE;
- if (mdata->nsects > 0)
- {
- cmd = &mdata->commands[0];
- seg = &cmd->command.segment;
+ if (segcmd_idx >= 0)
+ {
+ bfd_mach_o_load_command *cmd = &mdata->commands[segcmd_idx];
+ bfd_mach_o_segment_command *seg = &cmd->command.segment;
/* Count the segctions in the special blank segment used for MH_OBJECT. */
seg->nsects = bfd_mach_o_count_sections_for_seg (NULL, mdata);
return FALSE;
/* Init segment command. */
+ cmd->offset = base_offset;
if (wide)
{
cmd->type = BFD_MACH_O_LC_SEGMENT_64;
- cmd->offset = BFD_MACH_O_HEADER_64_SIZE;
cmd->len = BFD_MACH_O_LC_SEGMENT_64_SIZE
+ BFD_MACH_O_SECTION_64_SIZE * seg->nsects;
}
else
{
cmd->type = BFD_MACH_O_LC_SEGMENT;
- cmd->offset = BFD_MACH_O_HEADER_SIZE;
cmd->len = BFD_MACH_O_LC_SEGMENT_SIZE
+ BFD_MACH_O_SECTION_SIZE * seg->nsects;
}
+
cmd->type_required = FALSE;
mdata->header.sizeofcmds = cmd->len;
- mdata->filelen = cmd->offset + cmd->len;
+ mdata->filelen += cmd->len;
}
- if (bfd_get_symcount (abfd) > 0)
+ if (symtab_idx >= 0)
{
/* Init symtab command. */
- symtab_cmd = &mdata->commands[symcind];
-
- symtab_cmd->type = BFD_MACH_O_LC_SYMTAB;
- if (symcind > 0)
- symtab_cmd->offset = mdata->commands[0].offset
- + mdata->commands[0].len;
- else
- symtab_cmd->offset = 0;
- symtab_cmd->len = 6 * 4;
- symtab_cmd->type_required = FALSE;
-
- mdata->header.sizeofcmds += symtab_cmd->len;
- mdata->filelen += symtab_cmd->len;
+ bfd_mach_o_load_command *cmd = &mdata->commands[symtab_idx];
+
+ cmd->type = BFD_MACH_O_LC_SYMTAB;
+ cmd->offset = base_offset;
+ if (segcmd_idx >= 0)
+ cmd->offset += mdata->commands[segcmd_idx].len;
+
+ cmd->len = sizeof (struct mach_o_symtab_command_external)
+ + BFD_MACH_O_LC_SIZE;
+ cmd->type_required = FALSE;
+ mdata->header.sizeofcmds += cmd->len;
+ mdata->filelen += cmd->len;
}
- /* If required, setup symtab command. */
- if (bfd_mach_o_should_emit_dysymtab ()
- && bfd_get_symcount (abfd) > 0)
+ /* If required, setup symtab command, see comment above about the quality
+ of this test. */
+ if (dysymtab_idx >= 0)
{
- cmd = &mdata->commands[symcind+1];
+ bfd_mach_o_load_command *cmd = &mdata->commands[dysymtab_idx];
+
cmd->type = BFD_MACH_O_LC_DYSYMTAB;
- cmd->offset = symtab_cmd->offset + symtab_cmd->len;
+ if (symtab_idx >= 0)
+ cmd->offset = mdata->commands[symtab_idx].offset
+ + mdata->commands[symtab_idx].len;
+ else if (segcmd_idx >= 0)
+ cmd->offset = mdata->commands[segcmd_idx].offset
+ + mdata->commands[segcmd_idx].len;
+ else
+ cmd->offset = base_offset;
+
cmd->type_required = FALSE;
- cmd->len = 18 * 4 + BFD_MACH_O_LC_SIZE;
+ cmd->len = sizeof (struct mach_o_dysymtab_command_external)
+ + BFD_MACH_O_LC_SIZE;
mdata->header.sizeofcmds += cmd->len;
mdata->filelen += cmd->len;
/* So, now we have sized the commands and the filelen set to that.
Now we can build the segment command and set the section file offsets. */
- if (mdata->nsects > 0
- && ! bfd_mach_o_build_seg_command (NULL, mdata, seg))
+ if (segcmd_idx >= 0
+ && ! bfd_mach_o_build_seg_command
+ (NULL, mdata, &mdata->commands[segcmd_idx].command.segment))
return FALSE;
/* If we're doing a dysymtab, cmd points to its load command. */
- if (bfd_mach_o_should_emit_dysymtab ()
- && bfd_get_symcount (abfd) > 0
- && ! bfd_mach_o_build_dysymtab_command (abfd, mdata,
- &mdata->commands[symcind+1]))
+ if (dysymtab_idx >= 0
+ && ! bfd_mach_o_build_dysymtab_command (abfd, mdata,
+ &mdata->commands[dysymtab_idx]))
return FALSE;
/* The symtab command is filled in when the symtab is written. */
if (mach_o_wide_p (header))
header->reserved = (*get32) (raw.reserved);
+ else
+ header->reserved = 0;
return TRUE;
}
if (xlat != NULL)
{
s->flags = xlat->macho_sectype | xlat->macho_secattr;
- s->align = xlat->sectalign > bfdalign ? xlat->sectalign
+ s->align = xlat->sectalign > bfdalign ? xlat->sectalign
: bfdalign;
- bfd_set_section_alignment (abfd, sec, s->align);
+ (void) bfd_set_section_alignment (abfd, sec, s->align);
bfd_flags = bfd_get_section_flags (abfd, sec);
if (bfd_flags == SEC_NO_FLAGS)
bfd_set_section_flags (abfd, sec, xlat->bfd_flags);
return TRUE;
}
+static bfd_boolean
+bfd_mach_o_read_main (bfd *abfd, bfd_mach_o_load_command *command)
+{
+ bfd_mach_o_main_command *cmd = &command->command.main;
+ struct mach_o_entry_point_command_external raw;
+
+ if (bfd_seek (abfd, command->offset + BFD_MACH_O_LC_SIZE, SEEK_SET) != 0
+ || bfd_bread (&raw, sizeof (raw), abfd) != sizeof (raw))
+ return FALSE;
+
+ cmd->entryoff = bfd_get_64 (abfd, raw.entryoff);
+ cmd->stacksize = bfd_get_64 (abfd, raw.stacksize);
+ return TRUE;
+}
+
+static bfd_boolean
+bfd_mach_o_read_source_version (bfd *abfd, bfd_mach_o_load_command *command)
+{
+ bfd_mach_o_source_version_command *cmd = &command->command.source_version;
+ struct mach_o_source_version_command_external raw;
+ bfd_uint64_t ver;
+
+ if (bfd_seek (abfd, command->offset + BFD_MACH_O_LC_SIZE, SEEK_SET) != 0
+ || bfd_bread (&raw, sizeof (raw), abfd) != sizeof (raw))
+ return FALSE;
+
+ ver = bfd_get_64 (abfd, raw.version);
+ /* Note: we use a serie of shift to avoid shift > 32 (for which gcc
+ generates warnings) in case of the host doesn't support 64 bit
+ integers. */
+ cmd->e = ver & 0x3ff;
+ ver >>= 10;
+ cmd->d = ver & 0x3ff;
+ ver >>= 10;
+ cmd->c = ver & 0x3ff;
+ ver >>= 10;
+ cmd->b = ver & 0x3ff;
+ ver >>= 10;
+ cmd->a = ver & 0xffffff;
+ return TRUE;
+}
+
static int
bfd_mach_o_read_segment (bfd *abfd,
bfd_mach_o_load_command *command,
case BFD_MACH_O_LC_CODE_SIGNATURE:
case BFD_MACH_O_LC_SEGMENT_SPLIT_INFO:
case BFD_MACH_O_LC_FUNCTION_STARTS:
+ case BFD_MACH_O_LC_DATA_IN_CODE:
+ case BFD_MACH_O_LC_DYLIB_CODE_SIGN_DRS:
if (bfd_mach_o_read_linkedit (abfd, command) != 0)
return -1;
break;
if (!bfd_mach_o_read_version_min (abfd, command))
return -1;
break;
+ case BFD_MACH_O_LC_MAIN:
+ if (!bfd_mach_o_read_main (abfd, command))
+ return -1;
+ break;
+ case BFD_MACH_O_LC_SOURCE_VERSION:
+ if (!bfd_mach_o_read_source_version (abfd, command))
+ return -1;
+ break;
default:
(*_bfd_error_handler)(_("%B: unknown load command 0x%lx"),
abfd, (unsigned long) command->type);
cmd = &mdata->commands[i].command.thread;
break;
}
+ else if (mdata->commands[i].type == BFD_MACH_O_LC_MAIN
+ && mdata->nsects > 1)
+ {
+ bfd_mach_o_main_command *main_cmd = &mdata->commands[i].command.main;
+ bfd_mach_o_section *text_sect = mdata->sections[0];
+ if (text_sect)
+ {
+ abfd->start_address = main_cmd->entryoff
+ + (text_sect->addr - text_sect->offset);
+ return TRUE;
+ }
+ }
+ /* An object file has no start address, so do not fail if not found. */
if (cmd == NULL)
- return FALSE;
+ return TRUE;
/* FIXME: create a subtarget hook ? */
for (i = 0; i < cmd->nflavours; i++)
}
}
- if (bfd_mach_o_scan_start_address (abfd) < 0)
+ /* Sections should be flatten before scanning start address. */
+ bfd_mach_o_flatten_sections (abfd);
+ if (!bfd_mach_o_scan_start_address (abfd))
return FALSE;
- bfd_mach_o_flatten_sections (abfd);
return TRUE;
}
{
bfd_mach_o_data_struct *mdata = NULL;
- mdata = bfd_alloc (abfd, sizeof (bfd_mach_o_data_struct));
+ mdata = bfd_zalloc (abfd, sizeof (bfd_mach_o_data_struct));
if (mdata == NULL)
return FALSE;
abfd->tdata.mach_o_data = mdata;
bfd_mach_o_filetype filetype,
bfd_mach_o_cpu_type cputype)
{
- struct bfd_preserve preserve;
bfd_mach_o_header header;
+ bfd_mach_o_data_struct *mdata;
- preserve.marker = NULL;
if (!bfd_mach_o_read_header (abfd, &header))
goto wrong;
}
}
- preserve.marker = bfd_zalloc (abfd, sizeof (bfd_mach_o_data_struct));
- if (preserve.marker == NULL
- || !bfd_preserve_save (abfd, &preserve))
+ mdata = (bfd_mach_o_data_struct *) bfd_zalloc (abfd, sizeof (*mdata));
+ if (mdata == NULL)
goto fail;
- if (!bfd_mach_o_scan (abfd, &header,
- (bfd_mach_o_data_struct *) preserve.marker))
+ if (!bfd_mach_o_scan (abfd, &header, mdata))
goto wrong;
- bfd_preserve_finish (abfd, &preserve);
return abfd->xvec;
wrong:
bfd_set_error (bfd_error_wrong_format);
fail:
- if (preserve.marker != NULL)
- bfd_preserve_restore (abfd, &preserve);
return NULL;
}
if (ap)
{
/* Use the architecture name if known. */
- abfd->filename = ap->printable_name;
+ abfd->filename = xstrdup (ap->printable_name);
}
else
{
/* Forge a uniq id. */
const size_t namelen = 2 + 8 + 1 + 2 + 8 + 1;
- char *name = bfd_alloc (abfd, namelen);
+ char *name = xmalloc (namelen);
snprintf (name, namelen, "0x%lx-0x%lx",
entry->cputype, entry->cpusubtype);
abfd->filename = name;
}
- areltdata = bfd_zalloc (abfd, sizeof (struct areltdata));
+ areltdata = bfd_zmalloc (sizeof (struct areltdata));
areltdata->parsed_size = entry->size;
abfd->arelt_data = areltdata;
abfd->iostream = NULL;
if (_bfd_dwarf2_find_nearest_line (abfd, dwarf_debug_sections,
section, symbols, offset,
filename_ptr, functionname_ptr,
- line_ptr, 0,
+ line_ptr, NULL, 0,
&mdata->dwarf2_find_line_info))
return TRUE;
return FALSE;
}
}
+ if (bfd_get_format (abfd) == bfd_archive
+ && abfd->xvec == &mach_o_fat_vec)
+ return TRUE;
return _bfd_generic_close_and_cleanup (abfd);
}
return TRUE;
}
-#define bfd_mach_o_bfd_reloc_type_lookup _bfd_norelocs_bfd_reloc_type_lookup
+#define bfd_mach_o_bfd_reloc_type_lookup _bfd_norelocs_bfd_reloc_type_lookup
#define bfd_mach_o_bfd_reloc_name_lookup _bfd_norelocs_bfd_reloc_name_lookup
#define bfd_mach_o_swap_reloc_in NULL