History

macos: dynamic symbol table and __got

this now sorts the symbols properly (local, global defined, undefined; the latter two by name), marks the three ranges within LC_DYSYMTAB, generates a __got section (non-lazy pointers) and slots for relocations which need them, and the indirect symbol mapping for them. This doesn't yet deal with undefined symbols. But it means compared to last example now this also works, i.e. read access to _global_ data: % cat simple3.c int loc = 42; int _start(void) { return loc - 42; }

Michael Matz committed 6 years ago

Commit 6ebd4631 parent bbccb131 file · +114 −16Browse files

Unified · Split

tccmacho.c+114−16
@@ -214,7 +214,9 @@ struct macho { · 213 unmodified lines
214214 int machosect;
215215 } sk_to_sect[sk_last];
216216 int *elfsectomacho;
217− Section *linkedit, *symtab, *strtab, *wdata;
217+ int *e2msym;
218+ Section *linkedit, *symtab, *strtab, *wdata, *indirsyms;
219+ uint32_t ilocal, iextdef, iundef;
218220 };
219221
220222 #define SHT_LINKEDIT (SHT_LOOS + 42)
@@ -289,25 +291,78 @@ static void * add_dylib(struct macho *mo, char *name) · 68 unmodified lines
289291 return add_lc(mo, lc);
290292 }
291293
292−static int check_symbols(TCCState *s1)
294+static void check_relocs(TCCState *s1, struct macho *mo)
295+{
296+ Section *s;
297+ ElfW_Rel *rel;
298+ ElfW(Sym) *sym;
299+ int i, type, gotplt_entry, sym_index;
300+ struct sym_attr *attr;
301+
302+ s1->got = new_section(s1, ".got", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
303+ mo->indirsyms = new_section(s1, "LEINDIR", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);
304+ for (i = 1; i < s1->nb_sections; i++) {
305+ s = s1->sections[i];
306+ if (s->sh_type != SHT_RELX)
307+ continue;
308+ for_each_elem(s, 0, rel, ElfW_Rel) {
309+ type = ELFW(R_TYPE)(rel->r_info);
310+ gotplt_entry = gotplt_entry_type(type);
311+ /* We generate a non-lazy pointer for used undefined symbols
312+ and for defined symbols that must have a place for their
313+ address due to codegen (i.e. a reloc requiring a got slot). */
314+ sym_index = ELFW(R_SYM)(rel->r_info);
315+ sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
316+ if (sym->st_shndx == SHN_UNDEF
317+ || gotplt_entry == ALWAYS_GOTPLT_ENTRY) {
318+ attr = get_sym_attr(s1, sym_index, 1);
319+ if (!attr->plt_offset) {
320+ uint32_t *pi = section_ptr_add(mo->indirsyms, sizeof(*pi));
321+ attr->got_offset = s1->got->data_offset;
322+ attr->plt_offset = 1; /* used as flag */
323+ section_ptr_add(s1->got, PTR_SIZE);
324+ *pi = mo->e2msym[sym_index];
325+ }
326+ }
327+ }
328+ }
329+}
330+
331+static int check_symbols(TCCState *s1, struct macho *mo)
293332 {
294333 int sym_index, sym_end;
295334 int ret = 0;
296335
336+ mo->ilocal = mo->iextdef = mo->iundef = -1;
297337 sym_end = symtab_section->data_offset / sizeof(ElfW(Sym));
298338 for (sym_index = 1; sym_index < sym_end; ++sym_index) {
299− ElfW(Sym) *sym = (ElfW(Sym) *)symtab_section->data + sym_index;
339+ int elf_index = ((struct nlist_64 *)mo->symtab->data + sym_index - 1)->n_value;
340+ ElfW(Sym) *sym = (ElfW(Sym) *)symtab_section->data + elf_index;
300341 const char *name = (char*)symtab_section->link->data + sym->st_name;
301342 unsigned type = ELFW(ST_TYPE)(sym->st_info);
302343 unsigned bind = ELFW(ST_BIND)(sym->st_info);
303344 unsigned vis = ELFW(ST_VISIBILITY)(sym->st_other);
304345
305− printf("%4d: %09llx %4d %4d %4d %3d %s\n",
306− sym_index, sym->st_value,
346+ printf("%4d (%4d): %09llx %4d %4d %4d %3d %s\n",
347+ sym_index, elf_index, sym->st_value,
307348 type, bind, vis, sym->st_shndx, name);
308− if (sym->st_shndx == SHN_UNDEF) {
349+ if (bind == STB_LOCAL) {
350+ if (mo->ilocal == -1)
351+ mo->ilocal = sym_index - 1;
352+ if (mo->iextdef != -1 || mo->iundef != -1)
353+ tcc_error("local syms after global ones");
354+ } else if (sym->st_shndx != SHN_UNDEF) {
355+ if (mo->iextdef == -1)
356+ mo->iextdef = sym_index - 1;
357+ if (mo->iundef != -1)
358+ tcc_error("external defined symbol after undefined");
359+ } else if (sym->st_shndx == SHN_UNDEF) {
360+ if (mo->iundef == -1)
361+ mo->iundef = sym_index - 1;
309362 if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK)
310363 continue;
364+ if (get_sym_attr(s1, elf_index, 0))
365+ continue;
311366 tcc_error_noabort("undefined symbol '%s'", name);
312367 ret = -1;
313368 }
@@ -315,12 +370,11 @@ static int check_symbols(TCCState *s1) · 1 unmodified line
315370 return ret;
316371 }
317372
318−static void convert_symbol(TCCState *s1, struct macho *mo, struct nlist_64 *pn, ElfSym *sym)
373+static void convert_symbol(TCCState *s1, struct macho *mo, struct nlist_64 *pn)
319374 {
320375 struct nlist_64 n = *pn;
376+ ElfSym *sym = (ElfW(Sym) *)symtab_section->data + pn->n_value;
321377 const char *name = (char*)symtab_section->link->data + sym->st_name;
322− if (sym != (ElfW(Sym) *)symtab_section->data + pn->n_value)
323− tcc_error("blaeh");
324378 switch(ELFW(ST_TYPE)(sym->st_info)) {
325379 case STT_NOTYPE:
326380 case STT_OBJECT:
@@ -361,9 +415,33 @@ static void convert_symbols(TCCState *s1, struct macho *mo) · 34 unmodified lines
361415
362416 sym_end = symtab_section->data_offset / sizeof(ElfW(Sym));
363417 for (sym_index = 1; sym_index < sym_end; ++sym_index) {
364− ElfW(Sym) *sym = (ElfW(Sym) *)symtab_section->data + sym_index;
365− convert_symbol(s1, mo, pn + sym_index - 1, sym);
418+ convert_symbol(s1, mo, pn + sym_index - 1);
419+ }
420+}
421+
422+static int machosymcmp(const void *_a, const void *_b)
423+{
424+ TCCState *s1 = tcc_state;
425+ int ea = ((struct nlist_64 *)_a)->n_value;
426+ int eb = ((struct nlist_64 *)_b)->n_value;
427+ ElfSym *sa = (ElfSym *)symtab_section->data + ea;
428+ ElfSym *sb = (ElfSym *)symtab_section->data + eb;
429+ int r;
430+ r = (ELFW(ST_BIND)(sb->st_info) == STB_LOCAL)
431+ - (ELFW(ST_BIND)(sa->st_info) == STB_LOCAL);
432+ if (r)
433+ return r;
434+ r = (sb->st_shndx == SHN_UNDEF) - (sa->st_shndx == SHN_UNDEF);
435+ if (r)
436+ return r;
437+ if (ELFW(ST_BIND)(sa->st_info) != STB_LOCAL) {
438+ const char * na = (char*)symtab_section->link->data + sa->st_name;
439+ const char * nb = (char*)symtab_section->link->data + sb->st_name;
440+ r = strcmp(na, nb);
441+ if (r)
442+ return r;
366443 }
444+ return ea - eb;
367445 }
368446
369447 static void create_symtab(TCCState *s1, struct macho *mo)
@@ -373,7 +451,7 @@ static void create_symtab(TCCState *s1, struct macho *mo) · 3 unmodified lines
373451
374452 mo->symtab = new_section(s1, "LESYMTAB", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);
375453 mo->strtab = new_section(s1, "LESTRTAB", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);
376− put_elf_str(mo->strtab, " "); /* Mach-O start strtab with a space */
454+ put_elf_str(mo->strtab, " "); /* Mach-O starts strtab with a space */
377455 sym_end = symtab_section->data_offset / sizeof(ElfW(Sym));
378456 pn = section_ptr_add(mo->symtab, sizeof(*pn) * (sym_end - 1));
379457 for (sym_index = 1; sym_index < sym_end; ++sym_index) {
@@ -382,6 +460,14 @@ static void create_symtab(TCCState *s1, struct macho *mo) · 2 unmodified lines
382460 pn[sym_index - 1].n_strx = put_elf_str(mo->strtab, name);
383461 pn[sym_index - 1].n_value = sym_index;
384462 }
463+ tcc_enter_state(s1); /* qsort needs global state */
464+ qsort(pn, sym_end - 1, sizeof(*pn), machosymcmp);
465+ tcc_exit_state();
466+ mo->e2msym = tcc_malloc(sym_end * sizeof(*mo->e2msym));
467+ mo->e2msym[0] = -1;
468+ for (sym_index = 1; sym_index < sym_end; ++sym_index) {
469+ mo->e2msym[pn[sym_index - 1].n_value] = sym_index - 1;
470+ }
385471 }
386472
387473 struct {
@@ -391,6 +477,7 @@ struct { · 3 unmodified lines
391477 } skinfo[sk_last] = {
392478 [sk_text] = { 1, 0x80000400, "__text" },
393479 [sk_ro_data] = { 1, 0, "__rodata" },
480+ [sk_nl_ptr] = { 2, 6, "__got" }, /* S_NON_LAZY_SYMBOL_POINTERS */
394481 [sk_rw_data] = { 2, 0, "__data" },
395482 [sk_bss] = { 2, 1, "__bss" },
396483 [sk_linkedit] = { 3, 0, NULL },
@@ -453,8 +540,6 @@ static void collect_sections(TCCState *s1, struct macho *mo) · 56 unmodified lines
453540 /* LINKEDIT can't be empty (XXX remove once we have symbol table) */
454541 section_ptr_add(mo->linkedit, 256);
455542
456− create_symtab(s1, mo);
457−
458543 /* dyld requires a writable segment, but ignores zero-sized segments
459544 for this, so force to have some data. */
460545 mo->wdata = new_section(s1, " wdata", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
@@ -475,7 +560,9 @@ static void collect_sections(TCCState *s1, struct macho *mo) · 14 unmodified lines
475560 case SHT_RELX: sk = sk_discard; break;
476561 case SHT_LINKEDIT: sk = sk_linkedit; break;
477562 case SHT_PROGBITS:
478− if (flags & SHF_EXECINSTR)
563+ if (s == s1->got)
564+ sk = sk_nl_ptr;
565+ else if (flags & SHF_EXECINSTR)
479566 sk = sk_text;
480567 else if (flags & SHF_WRITE)
481568 sk = sk_rw_data;
@@ -584,6 +671,15 @@ static void collect_sections(TCCState *s1, struct macho *mo) · 102 unmodified lines
584671 symlc->nsyms = mo->symtab->data_offset / sizeof(struct nlist_64);
585672 symlc->stroff = mo->strtab->sh_offset;
586673 symlc->strsize = mo->strtab->data_offset;
674+
675+ dysymlc->iundefsym = mo->iundef == -1 ? symlc->nsyms : mo->iundef;
676+ dysymlc->iextdefsym = mo->iextdef == -1 ? dysymlc->iundefsym : mo->iextdef;
677+ dysymlc->ilocalsym = mo->ilocal == -1 ? dysymlc->iextdefsym : mo->ilocal;
678+ dysymlc->nlocalsym = dysymlc->iextdefsym - dysymlc->ilocalsym;
679+ dysymlc->nextdefsym = dysymlc->iundefsym - dysymlc->iextdefsym;
680+ dysymlc->nundefsym = symlc->nsyms - dysymlc->iundefsym;
681+ dysymlc->indirectsymoff = mo->indirsyms->sh_offset;
682+ dysymlc->nindirectsyms = mo->indirsyms->data_offset / sizeof(uint32_t);
587683 }
588684
589685 static void macho_write(TCCState *s1, struct macho *mo, FILE *fp)
@@ -659,7 +755,9 @@ ST_FUNC int macho_output_file(TCCState *s1, const char *filename) · 69 unmodified lines
659755 printf("<- %s\n", filename);
660756
661757 resolve_common_syms(s1);
662− ret = check_symbols(s1);
758+ create_symtab(s1, &mo);
759+ check_relocs(s1, &mo);
760+ ret = check_symbols(s1, &mo);
663761 if (!ret) {
664762 int i;
665763 Section *s;

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t