macos: Support external functions

these are resolved non-lazy for now.  We only need to generate
the jump stub (using the GOT slot that will be initialized due
to the non-lazy pointer marking, like with data symbols).  On
x86-64 we don't even need special marking of these stubs (with
S_SYMBOL_STUBS and associated additional indirect symbol entries),
as that's only used on i386 (where the stubs are self-modifying).

So, this now works:

extern int _printf(const char*, ...);
int _start(void)
{
  _printf("hello\n");
  return 0;
}
This commit is contained in:
Michael Matz 2020-05-18 04:35:38 +02:00
parent d82e64c163
commit 84c3fecf5e

View File

@ -215,7 +215,8 @@ struct macho {
} sk_to_sect[sk_last]; } sk_to_sect[sk_last];
int *elfsectomacho; int *elfsectomacho;
int *e2msym; int *e2msym;
Section *linkedit, *symtab, *strtab, *wdata, *indirsyms; Section *linkedit, *symtab, *strtab, *wdata, *indirsyms, *stubs;
int stubsym;
uint32_t ilocal, iextdef, iundef; uint32_t ilocal, iextdef, iundef;
}; };
@ -297,7 +298,7 @@ static void check_relocs(TCCState *s1, struct macho *mo)
Section *s; Section *s;
ElfW_Rel *rel; ElfW_Rel *rel;
ElfW(Sym) *sym; ElfW(Sym) *sym;
int i, type, gotplt_entry, sym_index; int i, type, gotplt_entry, sym_index, for_code;
struct sym_attr *attr; struct sym_attr *attr;
s1->got = new_section(s1, ".got", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); s1->got = new_section(s1, ".got", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
@ -309,6 +310,7 @@ static void check_relocs(TCCState *s1, struct macho *mo)
for_each_elem(s, 0, rel, ElfW_Rel) { for_each_elem(s, 0, rel, ElfW_Rel) {
type = ELFW(R_TYPE)(rel->r_info); type = ELFW(R_TYPE)(rel->r_info);
gotplt_entry = gotplt_entry_type(type); gotplt_entry = gotplt_entry_type(type);
for_code = code_reloc(type);
/* We generate a non-lazy pointer for used undefined symbols /* We generate a non-lazy pointer for used undefined symbols
and for defined symbols that must have a place for their and for defined symbols that must have a place for their
address due to codegen (i.e. a reloc requiring a got slot). */ address due to codegen (i.e. a reloc requiring a got slot). */
@ -317,10 +319,11 @@ static void check_relocs(TCCState *s1, struct macho *mo)
if (sym->st_shndx == SHN_UNDEF if (sym->st_shndx == SHN_UNDEF
|| gotplt_entry == ALWAYS_GOTPLT_ENTRY) { || gotplt_entry == ALWAYS_GOTPLT_ENTRY) {
attr = get_sym_attr(s1, sym_index, 1); attr = get_sym_attr(s1, sym_index, 1);
if (!attr->plt_offset) { if (!attr->dyn_index) {
uint32_t *pi = section_ptr_add(mo->indirsyms, sizeof(*pi)); uint32_t *pi = section_ptr_add(mo->indirsyms, sizeof(*pi));
attr->got_offset = s1->got->data_offset; attr->got_offset = s1->got->data_offset;
attr->plt_offset = 1; /* used as flag */ attr->plt_offset = -1;
attr->dyn_index = 1; /* used as flag */
section_ptr_add(s1->got, PTR_SIZE); section_ptr_add(s1->got, PTR_SIZE);
if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) { if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) {
if (sym->st_shndx == SHN_UNDEF) if (sym->st_shndx == SHN_UNDEF)
@ -329,11 +332,25 @@ static void check_relocs(TCCState *s1, struct macho *mo)
/* The pointer slot we generated must point to the /* The pointer slot we generated must point to the
symbol, whose address is only known after layout, symbol, whose address is only known after layout,
so register a simply relocation for that. */ so register a simply relocation for that. */
put_elf_reloc (s1->symtab, s1->got, attr->got_offset, put_elf_reloc(s1->symtab, s1->got, attr->got_offset,
R_DATA_PTR, sym_index); R_DATA_PTR, sym_index);
} else } else
*pi = mo->e2msym[sym_index]; *pi = mo->e2msym[sym_index];
} }
if (for_code) {
if (attr->plt_offset == -1) {
uint8_t *jmp;
attr->plt_offset = mo->stubs->data_offset;
jmp = section_ptr_add(mo->stubs, 6);
jmp[0] = 0xff; /* jmpq *ofs(%rip) */
jmp[1] = 0x25;
put_elf_reloc(s1->symtab, mo->stubs,
attr->plt_offset + 2,
R_X86_64_GOTPCREL, sym_index);
}
rel->r_info = ELFW(R_INFO)(mo->stubsym, type);
rel->r_addend += attr->plt_offset;
}
} }
} }
} }
@ -472,6 +489,13 @@ static void create_symtab(TCCState *s1, struct macho *mo)
int sym_index, sym_end; int sym_index, sym_end;
struct nlist_64 *pn; struct nlist_64 *pn;
/* Stub creation belongs to check_relocs, but we need to create
the symbol now, so its included in the sorting. */
mo->stubs = new_section(s1, "__stubs", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR);
mo->stubsym = put_elf_sym(s1->symtab, 0, 0,
ELFW(ST_INFO)(STB_LOCAL, STT_NOTYPE), 0,
mo->stubs->sh_num, ".__stubs");
mo->symtab = new_section(s1, "LESYMTAB", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE); mo->symtab = new_section(s1, "LESYMTAB", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);
mo->strtab = new_section(s1, "LESTRTAB", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE); mo->strtab = new_section(s1, "LESTRTAB", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);
put_elf_str(mo->strtab, " "); /* Mach-O starts strtab with a space */ put_elf_str(mo->strtab, " "); /* Mach-O starts strtab with a space */