[Patch macho/bfd/gas] .indirect_symbol, take 2.
Iain Sandoe
developer@sandoe-acoustics.co.uk
Mon Jan 9 13:00:00 GMT 2012
Here is a different implementation of the .indirect_symbol patch.
In this we keep indirect_symbols in a linked list in the section to
which they belong.
As of now, I can't see a reason to keep them in GAS as well.
If this is OK, then a TODO would be to populate the list when a mach-o
file is read in -
- this is nicely symmetrical -
- and means that sections can be reordered/removed without having to
cross-check the dysymtab.
The only thing that is less satisfactory, is that there is no way
(AFAICS) to mark a symbol as 'referenced by an indirect' which means
if one deletes (or wishes to delete) symbols - then one should cross-
check the usage from the indirect tables.
tests follow as separate patch (they've all be posted before anyway).
OK?
Iain
bfd:
* mach-o.c (bfd_mach_o_count_indirect_symbols): New.
(bfd_mach_o_build_dysymtab_command): Populate indirect table.
* mach-o.h (bfd_mach_o_section): Add fields for indirect symbol
lists.
gas:
* config/obj-macho.c (obj_mach_o_set_symbol_qualifier): Switch off
lazy for extern/private extern.
(obj_mach_o_indirect_symbol): New.
(obj_mach_o_placeholder): Remove.
(mach_o_pseudo_table): Use obj_mach_o_indirect_symbol.
(obj_macho_frob_label): Take care not to force local symbols into
the regular table.
(obj_macho_frob_symbol): Likewise. Ensure undefined and comm syms
have their fields set.
(obj_mach_o_frob_section): New.
* config/obj-macho.h (obj_frob_section): Define.
(obj_mach_o_frob_section): Declare.
bfd/mach-o.c | 63 +++++++++++++-
bfd/mach-o.h | 16 ++++
gas/config/obj-macho.c | 214 +++++++++++++++++++++++++++++++++++++++
++-------
gas/config/obj-macho.h | 3 +
4 files changed, 262 insertions(+), 34 deletions(-)
diff --git a/bfd/mach-o.c b/bfd/mach-o.c
index a1f6596..493116a 100644
--- a/bfd/mach-o.c
+++ b/bfd/mach-o.c
@@ -2067,6 +2067,33 @@ bfd_mach_o_build_seg_command (const char
*segment,
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,
@@ -2123,9 +2150,11 @@ bfd_mach_o_build_dysymtab_command (bfd *abfd,
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;
@@ -2134,11 +2163,37 @@ bfd_mach_o_build_dysymtab_command (bfd *abfd,
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:
+ {
+ bfd_mach_o_indirect_sym *isym = sec->indirectsyms;
+ if (isym == NULL)
+ break;
+ /* Record the starting index in the reserved1 field. */
+ sec->reserved1 = n;
+ do
+ {
+ dsym->indirect_syms[n] = isym->sym->symbol.udata.i;
+ n++;
+ /* Final safety net. */
+ if (n > dsym->nindirectsyms)
+ abort ();
+ }
+ while ((isym = isym->next) != NULL);
+ }
+ break;
+ default:
+ break;
+ }
}
}
diff --git a/bfd/mach-o.h b/bfd/mach-o.h
index ca810a0..31a4095 100644
--- a/bfd/mach-o.h
+++ b/bfd/mach-o.h
@@ -63,6 +63,12 @@ typedef struct bfd_mach_o_section
/* Corresponding bfd section. */
asection *bfdsection;
+
+ /* Linked list of indirect symbols for this section (only applies to
+ stub and reference sections). */
+ struct bfd_mach_o_indirect_sym *indirectsyms;
+ /* Pointer to the last indirect, to save reversing the list. */
+ struct bfd_mach_o_indirect_sym *lastindirectsym;
/* Simply linked list. */
struct bfd_mach_o_section *next;
@@ -117,6 +123,16 @@ typedef struct bfd_mach_o_asymbol
}
bfd_mach_o_asymbol;
+/* An element in a list of indirect symbols the root of which
+ is "indirectsyms" in the section to which they apply. */
+
+typedef struct bfd_mach_o_indirect_sym
+{
+ struct bfd_mach_o_indirect_sym *next;
+ struct bfd_mach_o_asymbol *sym;
+}
+bfd_mach_o_indirect_sym;
+
/* The symbol table is sorted like this:
(1) local.
(otherwise in order of generation)
diff --git a/gas/config/obj-macho.c b/gas/config/obj-macho.c
index 43f4fba..5d82977 100644
--- a/gas/config/obj-macho.c
+++ b/gas/config/obj-macho.c
@@ -39,6 +39,7 @@
#include "as.h"
#include "subsegs.h"
+#include "struc-symbol.h" /* For local symbol stuff in frob_label/
symbol. */
#include "symbols.h"
#include "write.h"
#include "mach-o.h"
@@ -1032,6 +1033,7 @@ obj_mach_o_set_symbol_qualifier (symbolS *sym,
int type)
case OBJ_MACH_O_SYM_PRIV_EXT:
s->n_type |= BFD_MACH_O_N_PEXT ;
+ s->n_desc &= ~LAZY; /* The native tool swithes this off too. */
/* We follow the system tools in marking PEXT as also global. */
/* Fall through. */
@@ -1131,13 +1133,74 @@ obj_mach_o_sym_qual (int ntype)
demand_empty_rest_of_line ();
}
-/* Dummy function to allow test-code to work while we are working
- on things. */
-
static void
-obj_mach_o_placeholder (int arg ATTRIBUTE_UNUSED)
+obj_mach_o_indirect_symbol (int arg ATTRIBUTE_UNUSED)
{
- ignore_rest_of_line ();
+ bfd_mach_o_section *sec = bfd_mach_o_get_mach_o_section (now_seg);
+ unsigned lazy = 0;
+
+#ifdef md_flush_pending_output
+ md_flush_pending_output ();
+#endif
+
+ switch (sec->flags & BFD_MACH_O_SECTION_TYPE_MASK)
+ {
+ case BFD_MACH_O_S_SYMBOL_STUBS:
+ case BFD_MACH_O_S_LAZY_SYMBOL_POINTERS:
+ lazy = LAZY;
+ /* Fall through. */
+ case BFD_MACH_O_S_NON_LAZY_SYMBOL_POINTERS:
+ {
+ bfd_mach_o_indirect_sym *isym;
+ char *name = input_line_pointer;
+ char c = get_symbol_end ();
+ symbolS *sym = symbol_find_or_make (name);
+ unsigned int elsize =
+ bfd_mach_o_section_get_entry_size (stdoutput, sec);
+
+ if (elsize == 0)
+ {
+ 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;
+ ignore_rest_of_line ();
+ return;
+ }
+
+ *input_line_pointer = c;
+
+ /* This should be allocated in bfd, since it is owned there. */
+ isym = (bfd_mach_o_indirect_sym *)
+ bfd_zalloc (stdoutput, sizeof (bfd_mach_o_indirect_sym));
+ if (isym == NULL)
+ abort ();
+
+ isym->sym = (bfd_mach_o_asymbol *) symbol_get_bfdsym (sym);
+ if (sec->indirectsyms == NULL)
+ sec->indirectsyms = isym;
+ else
+ sec->lastindirectsym->next = isym;
+ sec->lastindirectsym = isym;
+
+ /* We put in the lazy flag, it will get reset if the symbols is
later
+ defined, or if the symbol becomes private_extern. */
+ if (isym->sym->symbol.section == bfd_und_section_ptr
+ && ! (isym->sym->n_type & BFD_MACH_O_N_PEXT))
+ {
+ isym->sym->n_desc = lazy;
+ isym->sym->symbol.udata.i = SYM_MACHO_FIELDS_NOT_VALIDATED;
+ }
+ }
+ break;
+
+ default:
+ as_bad (_("an .indirect_symbol must be in a symbol pointer"
+ " or stub section."));
+ ignore_rest_of_line ();
+ return;
+ }
+ demand_empty_rest_of_line ();
}
const pseudo_typeS mach_o_pseudo_table[] =
@@ -1231,7 +1294,7 @@ const pseudo_typeS mach_o_pseudo_table[] =
{"no_dead_strip", obj_mach_o_sym_qual,
OBJ_MACH_O_SYM_NO_DEAD_STRIP},
{"weak", obj_mach_o_sym_qual, OBJ_MACH_O_SYM_WEAK}, /* ext */
- {"indirect_symbol", obj_mach_o_placeholder, 0},
+ {"indirect_symbol", obj_mach_o_indirect_symbol, 0},
/* File flags. */
{ "subsections_via_symbols", obj_mach_o_fileprop,
@@ -1270,15 +1333,33 @@ obj_mach_o_type_for_symbol (bfd_mach_o_asymbol
*s)
void obj_macho_frob_label (struct symbol *sp)
{
- bfd_mach_o_asymbol *s = (bfd_mach_o_asymbol *) symbol_get_bfdsym
(sp);
- /* This is the base symbol type, that we mask in. */
- unsigned base_type = obj_mach_o_type_for_symbol (s);
- bfd_mach_o_section *sec = bfd_mach_o_get_mach_o_section (s-
>symbol.section);
+ bfd_mach_o_asymbol *s;
+ unsigned base_type;
+ bfd_mach_o_section *sec;
int sectype = -1;
+ /* Leave local symbols alone (unless they've already been made into
a real
+ one). */
+
+ if (0 && sp->bsym == NULL)
+ {
+ if (((struct local_symbol *) sp)->lsy_section != reg_section)
+ return;
+ else
+ /* We have a local which has been added to the symbol table, so carry
+ on with the checking. */
+ sp = ((struct local_symbol *) sp)->u.lsy_sym;
+ }
+
+ s = (bfd_mach_o_asymbol *) symbol_get_bfdsym (sp);
+ /* Leave debug symbols alone. */
if ((s->n_type & BFD_MACH_O_N_STAB) != 0)
- return; /* Leave alone. */
-
+ return;
+
+ /* 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);
if (sec != NULL)
sectype = sec->flags & BFD_MACH_O_SECTION_TYPE_MASK;
@@ -1307,34 +1388,50 @@ void obj_macho_frob_label (struct symbol *sp)
int
obj_macho_frob_symbol (struct symbol *sp)
{
- bfd_mach_o_asymbol *s = (bfd_mach_o_asymbol *) symbol_get_bfdsym
(sp);
- unsigned base_type = obj_mach_o_type_for_symbol (s);
- bfd_mach_o_section *sec = bfd_mach_o_get_mach_o_section (s-
>symbol.section);
+ bfd_mach_o_asymbol *s;
+ unsigned base_type;
+ bfd_mach_o_section *sec;
int sectype = -1;
-
+
+ /* Leave local symbols alone (unless they've already been made into
a real
+ one). */
+
+ if (0 && sp->bsym == NULL)
+ {
+ if (((struct local_symbol *) sp)->lsy_section != reg_section)
+ return 0;
+ else
+ /* We have a local which has been added to the symbol table, so carry
+ on with the checking. */
+ sp = ((struct local_symbol *) sp)->u.lsy_sym;
+ }
+
+ s = (bfd_mach_o_asymbol *) symbol_get_bfdsym (sp);
+ /* Leave debug symbols alone. */
+ if ((s->n_type & BFD_MACH_O_N_STAB) != 0)
+ return 0;
+
+ base_type = obj_mach_o_type_for_symbol (s);
+ 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_type & BFD_MACH_O_N_STAB) != 0)
- return 0; /* Leave alone. */
- else if (s->symbol.section == bfd_und_section_ptr)
+ if (s->symbol.section == bfd_und_section_ptr)
{
/* ??? Do we really gain much from implementing this as well
as the
mach-o specific ones? */
if (s->symbol.flags & BSF_WEAK)
s->n_desc |= BFD_MACH_O_N_WEAK_REF;
- /* Undefined references, become extern. */
- if (s->n_desc & REFE)
- {
- s->n_desc &= ~REFE;
- s->n_type |= BFD_MACH_O_N_EXT;
- }
-
- /* So do undefined 'no_dead_strip's. */
- if (s->n_desc & BFD_MACH_O_N_NO_DEAD_STRIP)
- s->n_type |= BFD_MACH_O_N_EXT;
-
+ /* Undefined syms, become extern. */
+ s->n_type |= BFD_MACH_O_N_EXT;
+ S_SET_EXTERNAL (sp);
+ }
+ else if (s->symbol.section == bfd_com_section_ptr)
+ {
+ /* ... so to comm. */
+ s->n_type |= BFD_MACH_O_N_EXT;
+ S_SET_EXTERNAL (sp);
}
else
{
@@ -1353,6 +1450,7 @@ obj_macho_frob_symbol (struct symbol *sp)
{
/* 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)
{
@@ -1388,6 +1486,62 @@ obj_macho_frob_symbol (struct symbol *sp)
return 0;
}
+void
+obj_mach_o_frob_section (asection *sec)
+{
+ bfd_vma sect_size = bfd_section_size (stdoutput, sec);
+ bfd_mach_o_section *ms = bfd_mach_o_get_mach_o_section (sec);
+
+ /* Process indirect symbols to determine if we have errors there. */
+
+ switch (ms->flags & BFD_MACH_O_SECTION_TYPE_MASK)
+ {
+ case BFD_MACH_O_S_SYMBOL_STUBS:
+ case BFD_MACH_O_S_LAZY_SYMBOL_POINTERS:
+ case BFD_MACH_O_S_NON_LAZY_SYMBOL_POINTERS:
+ {
+ unsigned int nactual;
+ unsigned int ncalc;
+ bfd_mach_o_indirect_sym *isym = ms->indirectsyms;
+ unsigned long eltsiz =
+ bfd_mach_o_section_get_entry_size (stdoutput, ms);
+
+ /* If we somehow added indirect symbols to a section with a zero
+ entry size, we're dead ... */
+ if (eltsiz == 0 && isym != NULL)
+ abort ();
+
+ ncalc = (unsigned int) (sect_size / eltsiz);
+
+ nactual = 0;
+ if (isym != NULL)
+ do
+ {
+ /* Count it. */
+ nactual++;
+ if (isym->sym->symbol.section == bfd_und_section_ptr)
+ {
+ /* If the referenced symbol is undefined, make
+ it extern. */
+ isym->sym->n_type |= BFD_MACH_O_N_EXT;
+ isym->sym->symbol.flags |= BSF_GLOBAL;
+ }
+ }
+ while ((isym = isym->next) != NULL);
+
+ if (nactual != ncalc)
+ as_bad (_("there %s %d indirect_symbol%sin section %s but"
+ " %d %s expected"), (nactual == 1)?"is":"are", nactual,
+ (nactual == 1)?" ":"s ", sec->name, ncalc,
+ (ncalc == 1)?"is":"are");
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
/* Support stabs for mach-o. */
void
diff --git a/gas/config/obj-macho.h b/gas/config/obj-macho.h
index cbc3a4f..ceb1097 100644
--- a/gas/config/obj-macho.h
+++ b/gas/config/obj-macho.h
@@ -62,6 +62,9 @@ extern void obj_macho_frob_label (struct symbol *);
#define obj_frob_symbol(s, punt) punt = obj_macho_frob_symbol(s)
extern int obj_macho_frob_symbol (struct symbol *);
+#define obj_frob_section(s) obj_mach_o_frob_section(s)
+void obj_mach_o_frob_section (asection *);
+
#define EMIT_SECTION_SYMBOLS 0
#define OBJ_PROCESS_STAB(SEG,W,S,T,O,D)
obj_mach_o_process_stab(W,S,T,O,D)
More information about the Binutils
mailing list