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
214 int machosect;214 int machosect;
215 } sk_to_sect[sk_last];215 } sk_to_sect[sk_last];
216 int *elfsectomacho;216 int *elfsectomacho;
217 Section *linkedit, *symtab, *strtab, *wdata;217 int *e2msym;
218 Section *linkedit, *symtab, *strtab, *wdata, *indirsyms;
219 uint32_t ilocal, iextdef, iundef;
218};220};
219 221
220#define SHT_LINKEDIT (SHT_LOOS + 42)222#define SHT_LINKEDIT (SHT_LOOS + 42)
@@ -289,25 +291,78 @@ static void * add_dylib(struct macho *mo, char *name) · 68 unmodified lines
289 return add_lc(mo, lc);291 return add_lc(mo, lc);
290}292}
291 293
292static int check_symbols(TCCState *s1)294static 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
331static int check_symbols(TCCState *s1, struct macho *mo)
293{332{
294 int sym_index, sym_end;333 int sym_index, sym_end;
295 int ret = 0;334 int ret = 0;
296 335
336 mo->ilocal = mo->iextdef = mo->iundef = -1;
297 sym_end = symtab_section->data_offset / sizeof(ElfW(Sym));337 sym_end = symtab_section->data_offset / sizeof(ElfW(Sym));
298 for (sym_index = 1; sym_index < sym_end; ++sym_index) {338 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;
300 const char *name = (char*)symtab_section->link->data + sym->st_name;341 const char *name = (char*)symtab_section->link->data + sym->st_name;
301 unsigned type = ELFW(ST_TYPE)(sym->st_info);342 unsigned type = ELFW(ST_TYPE)(sym->st_info);
302 unsigned bind = ELFW(ST_BIND)(sym->st_info);343 unsigned bind = ELFW(ST_BIND)(sym->st_info);
303 unsigned vis = ELFW(ST_VISIBILITY)(sym->st_other);344 unsigned vis = ELFW(ST_VISIBILITY)(sym->st_other);
304 345
305 printf("%4d: %09llx %4d %4d %4d %3d %s\n",346 printf("%4d (%4d): %09llx %4d %4d %4d %3d %s\n",
306 sym_index, sym->st_value,347 sym_index, elf_index, sym->st_value,
307 type, bind, vis, sym->st_shndx, name);348 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;
309 if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK)362 if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK)
310 continue;363 continue;
364 if (get_sym_attr(s1, elf_index, 0))
365 continue;
311 tcc_error_noabort("undefined symbol '%s'", name);366 tcc_error_noabort("undefined symbol '%s'", name);
312 ret = -1;367 ret = -1;
313 }368 }
@@ -315,12 +370,11 @@ static int check_symbols(TCCState *s1) · 1 unmodified line
315 return ret;370 return ret;
316}371}
317 372
318static void convert_symbol(TCCState *s1, struct macho *mo, struct nlist_64 *pn, ElfSym *sym)373static void convert_symbol(TCCState *s1, struct macho *mo, struct nlist_64 *pn)
319{374{
320 struct nlist_64 n = *pn;375 struct nlist_64 n = *pn;
376 ElfSym *sym = (ElfW(Sym) *)symtab_section->data + pn->n_value;
321 const char *name = (char*)symtab_section->link->data + sym->st_name;377 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");
324 switch(ELFW(ST_TYPE)(sym->st_info)) {378 switch(ELFW(ST_TYPE)(sym->st_info)) {
325 case STT_NOTYPE:379 case STT_NOTYPE:
326 case STT_OBJECT:380 case STT_OBJECT:
@@ -361,9 +415,33 @@ static void convert_symbols(TCCState *s1, struct macho *mo) · 34 unmodified lines
361 415
362 sym_end = symtab_section->data_offset / sizeof(ElfW(Sym));416 sym_end = symtab_section->data_offset / sizeof(ElfW(Sym));
363 for (sym_index = 1; sym_index < sym_end; ++sym_index) {417 for (sym_index = 1; sym_index < sym_end; ++sym_index) {
364 ElfW(Sym) *sym = (ElfW(Sym) *)symtab_section->data + sym_index;418 convert_symbol(s1, mo, pn + sym_index - 1);
365 convert_symbol(s1, mo, pn + sym_index - 1, sym);419 }
420}
421
422static 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;
366 }443 }
444 return ea - eb;
367}445}
368 446
369static void create_symtab(TCCState *s1, struct macho *mo)447static void create_symtab(TCCState *s1, struct macho *mo)
@@ -373,7 +451,7 @@ static void create_symtab(TCCState *s1, struct macho *mo) · 3 unmodified lines
373 451
374 mo->symtab = new_section(s1, "LESYMTAB", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);452 mo->symtab = new_section(s1, "LESYMTAB", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);
375 mo->strtab = new_section(s1, "LESTRTAB", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);453 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 */
377 sym_end = symtab_section->data_offset / sizeof(ElfW(Sym));455 sym_end = symtab_section->data_offset / sizeof(ElfW(Sym));
378 pn = section_ptr_add(mo->symtab, sizeof(*pn) * (sym_end - 1));456 pn = section_ptr_add(mo->symtab, sizeof(*pn) * (sym_end - 1));
379 for (sym_index = 1; sym_index < sym_end; ++sym_index) {457 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
382 pn[sym_index - 1].n_strx = put_elf_str(mo->strtab, name);460 pn[sym_index - 1].n_strx = put_elf_str(mo->strtab, name);
383 pn[sym_index - 1].n_value = sym_index;461 pn[sym_index - 1].n_value = sym_index;
384 }462 }
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 }
385}471}
386 472
387struct {473struct {
@@ -391,6 +477,7 @@ struct { · 3 unmodified lines
391} skinfo[sk_last] = {477} skinfo[sk_last] = {
392 [sk_text] = { 1, 0x80000400, "__text" },478 [sk_text] = { 1, 0x80000400, "__text" },
393 [sk_ro_data] = { 1, 0, "__rodata" },479 [sk_ro_data] = { 1, 0, "__rodata" },
480 [sk_nl_ptr] = { 2, 6, "__got" }, /* S_NON_LAZY_SYMBOL_POINTERS */
394 [sk_rw_data] = { 2, 0, "__data" },481 [sk_rw_data] = { 2, 0, "__data" },
395 [sk_bss] = { 2, 1, "__bss" },482 [sk_bss] = { 2, 1, "__bss" },
396 [sk_linkedit] = { 3, 0, NULL },483 [sk_linkedit] = { 3, 0, NULL },
@@ -453,8 +540,6 @@ static void collect_sections(TCCState *s1, struct macho *mo) · 56 unmodified lines
453 /* LINKEDIT can't be empty (XXX remove once we have symbol table) */540 /* LINKEDIT can't be empty (XXX remove once we have symbol table) */
454 section_ptr_add(mo->linkedit, 256);541 section_ptr_add(mo->linkedit, 256);
455 542
456 create_symtab(s1, mo);
457
458 /* dyld requires a writable segment, but ignores zero-sized segments543 /* dyld requires a writable segment, but ignores zero-sized segments
459 for this, so force to have some data. */544 for this, so force to have some data. */
460 mo->wdata = new_section(s1, " wdata", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);545 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
475 case SHT_RELX: sk = sk_discard; break;560 case SHT_RELX: sk = sk_discard; break;
476 case SHT_LINKEDIT: sk = sk_linkedit; break;561 case SHT_LINKEDIT: sk = sk_linkedit; break;
477 case SHT_PROGBITS:562 case SHT_PROGBITS:
478 if (flags & SHF_EXECINSTR)563 if (s == s1->got)
564 sk = sk_nl_ptr;
565 else if (flags & SHF_EXECINSTR)
479 sk = sk_text;566 sk = sk_text;
480 else if (flags & SHF_WRITE)567 else if (flags & SHF_WRITE)
481 sk = sk_rw_data;568 sk = sk_rw_data;
@@ -584,6 +671,15 @@ static void collect_sections(TCCState *s1, struct macho *mo) · 102 unmodified lines
584 symlc->nsyms = mo->symtab->data_offset / sizeof(struct nlist_64);671 symlc->nsyms = mo->symtab->data_offset / sizeof(struct nlist_64);
585 symlc->stroff = mo->strtab->sh_offset;672 symlc->stroff = mo->strtab->sh_offset;
586 symlc->strsize = mo->strtab->data_offset;673 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);
587}683}
588 684
589static void macho_write(TCCState *s1, struct macho *mo, FILE *fp)685static 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
659 printf("<- %s\n", filename);755 printf("<- %s\n", filename);
660 756
661 resolve_common_syms(s1);757 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);
663 if (!ret) {761 if (!ret) {
664 int i;762 int i;
665 Section *s;763 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