Index: bfd/ChangeLog =================================================================== RCS file: /cvs/src/src/bfd/ChangeLog,v retrieving revision 1.5584 diff -u -p -r1.5584 ChangeLog --- bfd/ChangeLog 11 Jan 2012 15:24:09 -0000 1.5584 +++ bfd/ChangeLog 12 Jan 2012 13:59:41 -0000 @@ -1,3 +1,10 @@ +2012-01-12 Iain Sandoe + + * mach-o.c (bfd_mach_o_count_indirect_symbols): New. + (bfd_mach_o_build_dysymtab_command): Populate indirect symbol table. + * mach-o.h (bfd_mach_o_asymbol): Move declaration to start of the + file. (bfd_mach_o_section): Add indirect_syms field. + 2012-01-11 Iain Sandoe * mach-o.c (bfd_mach_o_build_seg_command): Separate computation of Index: bfd/mach-o.c =================================================================== RCS file: /cvs/src/src/bfd/mach-o.c,v retrieving revision 1.95 diff -u -p -r1.95 mach-o.c --- bfd/mach-o.c 11 Jan 2012 15:24:10 -0000 1.95 +++ bfd/mach-o.c 12 Jan 2012 13:59:45 -0000 @@ -2079,6 +2079,33 @@ bfd_mach_o_build_seg_command (const char 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, @@ -2135,9 +2162,11 @@ bfd_mach_o_build_dysymtab_command (bfd * 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; @@ -2146,11 +2175,38 @@ bfd_mach_o_build_dysymtab_command (bfd * 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 + dsym->indirect_syms[n] = isyms[j]->symbol.udata.i; + } + } + break; + default: + break; + } } } Index: bfd/mach-o.h =================================================================== RCS file: /cvs/src/src/bfd/mach-o.h,v retrieving revision 1.41 diff -u -p -r1.41 mach-o.h --- bfd/mach-o.h 9 Jan 2012 10:47:45 -0000 1.41 +++ bfd/mach-o.h 12 Jan 2012 13:59:45 -0000 @@ -42,6 +42,18 @@ typedef struct bfd_mach_o_header } bfd_mach_o_header; +typedef struct bfd_mach_o_asymbol +{ + /* The actual symbol which the rest of BFD works with. */ + asymbol symbol; + + /* Mach-O symbol fields. */ + unsigned char n_type; + unsigned char n_sect; + unsigned short n_desc; +} +bfd_mach_o_asymbol; + #define BFD_MACH_O_SEGNAME_SIZE 16 #define BFD_MACH_O_SECTNAME_SIZE 16 @@ -64,6 +76,12 @@ typedef struct bfd_mach_o_section /* Corresponding bfd section. */ asection *bfdsection; + /* An array holding the indirect symbols for this section. + NULL values indicate local symbols. + The number of symbols is determined from the section size and type. */ + + bfd_mach_o_asymbol **indirect_syms; + /* Simply linked list. */ struct bfd_mach_o_section *next; } @@ -105,26 +123,12 @@ typedef struct bfd_mach_o_reloc_info } bfd_mach_o_reloc_info; -typedef struct bfd_mach_o_asymbol -{ - /* The actual symbol which the rest of BFD works with. */ - asymbol symbol; - - /* Mach-O symbol fields. */ - unsigned char n_type; - unsigned char n_sect; - unsigned short n_desc; -} -bfd_mach_o_asymbol; - /* The symbol table is sorted like this: (1) local. (otherwise in order of generation) (2) external defined (sorted by name) - (3) external undefined - (sorted by name) - (4) common + (3) external undefined / common (sorted by name) */ Index: gas/config/obj-macho.c =================================================================== RCS file: /cvs/src/src/gas/config/obj-macho.c,v retrieving revision 1.10 diff -u -p -r1.10 obj-macho.c --- gas/config/obj-macho.c 9 Jan 2012 10:47:47 -0000 1.10 +++ gas/config/obj-macho.c 12 Jan 2012 13:59:57 -0000 @@ -1032,6 +1032,7 @@ obj_mach_o_set_symbol_qualifier (symbolS case OBJ_MACH_O_SYM_PRIV_EXT: s->n_type |= BFD_MACH_O_N_PEXT ; + s->n_desc &= ~LAZY; /* The native tool switches this off too. */ /* We follow the system tools in marking PEXT as also global. */ /* Fall through. */ @@ -1131,13 +1132,77 @@ 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. */ +typedef struct obj_mach_o_indirect_sym +{ + symbolS *sym; + segT sect; + struct obj_mach_o_indirect_sym *next; +} obj_mach_o_indirect_sym; + +/* We store in order an maintain a pointer to the last one - to save reversing + later. */ +obj_mach_o_indirect_sym *indirect_syms; +obj_mach_o_indirect_sym *indirect_syms_tail; 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); + +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif + + if (obj_mach_o_is_static) + as_bad (_("use of .indirect_symbols requires `-dynamic'")); + + switch (sec->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: + { + obj_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; + + isym = (obj_mach_o_indirect_sym *) + xmalloc (sizeof (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. */ + isym->sym = sym; + isym->sect = now_seg; + isym->next = NULL; + if (indirect_syms == NULL) + indirect_syms = isym; + else + indirect_syms_tail->next = isym; + indirect_syms_tail = isym; + } + 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 +1296,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 +1335,25 @@ obj_mach_o_type_for_symbol (bfd_mach_o_a 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. */ + + if (S_IS_LOCAL (sp)) + return; + + 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 +1382,41 @@ void obj_macho_frob_label (struct symbol 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. */ + if (S_IS_LOCAL (sp)) + return 0; + + 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 do comm. */ + s->n_type |= BFD_MACH_O_N_EXT; + S_SET_EXTERNAL (sp); } else { @@ -1353,6 +1435,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 +1471,125 @@ obj_macho_frob_symbol (struct symbol *sp return 0; } +static void +obj_mach_o_set_indirect_symbols (bfd *abfd, asection *sec, + void *xxx ATTRIBUTE_UNUSED) +{ + bfd_vma sect_size = bfd_section_size (abfd, sec); + bfd_mach_o_section *ms = bfd_mach_o_get_mach_o_section (sec); + unsigned lazy = 0; + + /* See if we have any indirect syms to consider. */ + if (indirect_syms == NULL) + return; + + /* Process indirect symbols. + Check for errors, if OK attach them as a flat array to the section + for which they are defined. */ + + switch (ms->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: + { + unsigned int nactual = 0; + unsigned int ncalc; + obj_mach_o_indirect_sym *isym; + obj_mach_o_indirect_sym *list = NULL; + obj_mach_o_indirect_sym *list_tail = NULL; + unsigned long eltsiz = + bfd_mach_o_section_get_entry_size (abfd, ms); + + for (isym = indirect_syms; isym != NULL; isym = isym->next) + { + if (isym->sect == sec) + { + nactual++; + if (list == NULL) + list = isym; + else + list_tail->next = isym; + list_tail = isym; + } + } + + /* If none are in this section, stop here. */ + if (nactual == 0) + break; + + /* If we somehow added indirect symbols to a section with a zero + entry size, we're dead ... */ + gas_assert (eltsiz != 0); + + ncalc = (unsigned int) (sect_size / eltsiz); + if (nactual != ncalc) + as_bad (_("the number of .indirect_symbols defined in section %s" + " does not match the number expected (%d defined, %d" + " expected)"), sec->name, nactual, ncalc); + else + { + unsigned n; + bfd_mach_o_asymbol *sym; + 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); + } + + for (isym = list, n = 0; isym != NULL; isym = isym->next, n++) + { + /* 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. */ + if (S_IS_LOCAL (isym->sym) && ! lazy) + ; + else + { + sym = (bfd_mach_o_asymbol *)symbol_get_bfdsym (isym->sym); + if (sym == NULL) + ; + /* If the symbols is external ... */ + else if (S_IS_EXTERNAL (isym->sym) + || (sym->n_type & BFD_MACH_O_N_EXT) + || ! S_IS_DEFINED (isym->sym) + || lazy) + { + 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 + && ! (sym->n_type & BFD_MACH_O_N_PEXT) + && (sym->n_type & BFD_MACH_O_N_EXT)) + sym->n_desc |= lazy; + ms->indirect_syms[n] = sym; + } + } + } + } + } + break; + + default: + break; + } +} + +/* The process of relocation could alter what's externally visible, thus we + leave setting the indirect symbols until last. */ + +void +obj_mach_o_frob_file_after_relocs (void) +{ + bfd_map_over_sections (stdoutput, obj_mach_o_set_indirect_symbols, (char *) 0); +} + /* Support stabs for mach-o. */ void Index: gas/config/obj-macho.h =================================================================== RCS file: /cvs/src/src/gas/config/obj-macho.h,v retrieving revision 1.5 diff -u -p -r1.5 obj-macho.h --- gas/config/obj-macho.h 9 Jan 2012 10:47:47 -0000 1.5 +++ gas/config/obj-macho.h 12 Jan 2012 14:00:04 -0000 @@ -62,6 +62,9 @@ extern void obj_macho_frob_label (struct #define obj_frob_symbol(s, punt) punt = obj_macho_frob_symbol(s) extern int obj_macho_frob_symbol (struct symbol *); +#define obj_frob_file_after_relocs obj_mach_o_frob_file_after_relocs +extern void obj_mach_o_frob_file_after_relocs (void); + #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) Index: include/mach-o/ChangeLog =================================================================== RCS file: /cvs/src/src/include/mach-o/ChangeLog,v retrieving revision 1.7 diff -u -p -r1.7 ChangeLog --- include/mach-o/ChangeLog 4 Jan 2012 10:37:36 -0000 1.7 +++ include/mach-o/ChangeLog 12 Jan 2012 14:00:04 -0000 @@ -1,3 +1,8 @@ +2012-01-12 Iain Sandoe + + * loader.h (BFD_MACH_O_INDIRECT_SYM_LOCAL): New. + (BFD_MACH_O_INDIRECT_SYM_ABS): New + 2012-01-04 Tristan Gingold * external.h (mach_o_fvmlib_command_external): New structure. Index: include/mach-o/loader.h =================================================================== RCS file: /cvs/src/src/include/mach-o/loader.h,v retrieving revision 1.5 diff -u -p -r1.5 loader.h --- include/mach-o/loader.h 4 Jan 2012 10:25:14 -0000 1.5 +++ include/mach-o/loader.h 12 Jan 2012 14:00:04 -0000 @@ -320,6 +320,9 @@ bfd_mach_o_section_attribute; #define BFD_MACH_O_N_NO_DEAD_STRIP 0x20 #define BFD_MACH_O_N_WEAK_REF 0x40 #define BFD_MACH_O_N_WEAK_DEF 0x80 + +#define BFD_MACH_O_INDIRECT_SYM_LOCAL 0x80000000 +#define BFD_MACH_O_INDIRECT_SYM_ABS 0x40000000 /* Thread constants. */