diff --git a/tccelf.c b/tccelf.c index 932cf031..38d3e3e7 100644 --- a/tccelf.c +++ b/tccelf.c @@ -802,9 +802,18 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s) #elif defined(TCC_TARGET_X86_64) case R_X86_64_64: if (s1->output_type == TCC_OUTPUT_DLL) { - qrel->r_info = ELFW(R_INFO)(0, R_X86_64_RELATIVE); - qrel->r_addend = *(long long *)ptr + val; - qrel++; + esym_index = s1->symtab_to_dynsym[sym_index]; + qrel->r_offset = rel->r_offset; + if (esym_index) { + qrel->r_info = ELFW(R_INFO)(esym_index, R_X86_64_64); + qrel->r_addend = rel->r_addend; + qrel++; + break; + } else { + qrel->r_info = ELFW(R_INFO)(0, R_X86_64_RELATIVE); + qrel->r_addend = *(long long *)ptr + val; + qrel++; + } } *(long long *)ptr += val; break; @@ -1013,6 +1022,7 @@ static void put_got_entry(TCCState *s1, ElfW(Sym) *sym; unsigned long offset; int *ptr; + struct sym_attr *symattr; if (!s1->got) build_got(s1); @@ -1037,7 +1047,10 @@ static void put_got_entry(TCCState *s1, got_entry_present = 1; } - alloc_sym_attr(s1, sym_index)->got_offset = s1->got->data_offset; + symattr = alloc_sym_attr(s1, sym_index); + /* Only store the GOT offset if it's not generated for the PLT entry. */ + if (!need_plt_entry) + symattr->got_offset = s1->got->data_offset; if (s1->dynsym) { sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; @@ -1048,6 +1061,7 @@ static void put_got_entry(TCCState *s1, Section *plt; uint8_t *p; int modrm; + unsigned long relofs; #if defined(TCC_OUTPUT_DLL_WITH_PLT) modrm = 0x25; @@ -1072,12 +1086,21 @@ static void put_got_entry(TCCState *s1, put32(p + 8, PTR_SIZE * 2); } + /* The PLT slot refers to the relocation entry it needs + via offset. The reloc entry is created below, so its + offset is the current data_offset. */ + relofs = s1->got->reloc ? s1->got->reloc->data_offset : 0; p = section_ptr_add(plt, 16); p[0] = 0xff; /* jmp *(got + x) */ p[1] = modrm; put32(p + 2, s1->got->data_offset); p[6] = 0x68; /* push $xxx */ - put32(p + 7, (plt->data_offset - 32) >> 1); +#ifdef TCC_TARGET_X86_64 + /* On x86-64, the relocation is referred to by _index_. */ + put32(p + 7, relofs / sizeof (ElfW_Rel)); +#else + put32(p + 7, relofs); +#endif p[11] = 0xe9; /* jmp plt_start */ put32(p + 12, -(plt->data_offset)); @@ -1087,7 +1110,7 @@ static void put_got_entry(TCCState *s1, if (s1->output_type == TCC_OUTPUT_EXE) #endif offset = plt->data_offset - 16; - s1->sym_attrs[sym_index].has_plt_entry = 1; + symattr->has_plt_entry = 1; } #elif defined(TCC_TARGET_ARM) if (need_plt_entry) { @@ -1109,7 +1132,7 @@ static void put_got_entry(TCCState *s1, put32(p+12, 0xe5bef008); /* ldr pc, [lr, #8]! */ } - if (s1->sym_attrs[sym_index].plt_thumb_stub) { + if (symattr->plt_thumb_stub) { p = section_ptr_add(plt, 20); put32(p, 0x4778); /* bx pc */ put32(p+2, 0x46c0); /* nop */ @@ -1125,27 +1148,23 @@ static void put_got_entry(TCCState *s1, the PLT */ if (s1->output_type == TCC_OUTPUT_EXE) offset = plt->data_offset - 16; - s1->sym_attrs[sym_index].has_plt_entry = 1; + symattr->has_plt_entry = 1; } #elif defined(TCC_TARGET_C67) tcc_error("C67 got not implemented"); #else #error unsupported CPU #endif + /* XXX This might generate multiple syms for name. */ index = put_elf_sym(s1->dynsym, offset, size, info, 0, sym->st_shndx, name); - if (got_entry_present) { - put_elf_reloc(s1->dynsym, s1->got, - s1->sym_attrs[sym_index].got_offset, - reloc_type, index); - return; - } - - /* put a got entry */ + /* Create the relocation (it's against the GOT for PLT + and GOT relocs). */ put_elf_reloc(s1->dynsym, s1->got, s1->got->data_offset, reloc_type, index); } + /* And now create the GOT slot itself. */ ptr = section_ptr_add(s1->got, PTR_SIZE); *ptr = 0; } @@ -1697,26 +1716,11 @@ static void export_global_syms(TCCState *s1) s1->symtab_to_dynsym = tcc_mallocz(sizeof(int) * nb_syms); for_each_elem(symtab_section, 1, sym, ElfW(Sym)) { if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { -#if defined(TCC_OUTPUT_DLL_WITH_PLT) - int type = ELFW(ST_TYPE)(sym->st_info); - if ((type == STT_FUNC || type == STT_GNU_IFUNC) - && sym->st_shndx == SHN_UNDEF) { - int visibility = ELFW(ST_BIND)(sym->st_info); - put_got_entry(s1, R_JMP_SLOT, sym->st_size, - ELFW(ST_INFO)(visibility, STT_FUNC), - sym - (ElfW(Sym) *) symtab_section->data); - } else if (type == STT_OBJECT) { - put_got_entry(s1, R_X86_64_GLOB_DAT, sym->st_size, sym->st_info, - sym - (ElfW(Sym) *) symtab_section->data); - } else -#endif - { - name = (char *) symtab_section->link->data + sym->st_name; - dynindex = put_elf_sym(s1->dynsym, sym->st_value, sym->st_size, - sym->st_info, 0, sym->st_shndx, name); - index = sym - (ElfW(Sym) *) symtab_section->data; - s1->symtab_to_dynsym[index] = dynindex; - } + name = (char *) symtab_section->link->data + sym->st_name; + dynindex = put_elf_sym(s1->dynsym, sym->st_value, sym->st_size, + sym->st_info, 0, sym->st_shndx, name); + index = sym - (ElfW(Sym) *) symtab_section->data; + s1->symtab_to_dynsym[index] = dynindex; } } } diff --git a/x86_64-gen.c b/x86_64-gen.c index fc4178ec..9a9221d0 100644 --- a/x86_64-gen.c +++ b/x86_64-gen.c @@ -604,7 +604,7 @@ static void gcall_or_jmp(int is_jmp) if (vtop->r & VT_SYM) { /* relocation case */ greloc(cur_text_section, vtop->sym, - ind + 1, R_X86_64_PC32); + ind + 1, R_X86_64_PLT32); } else { /* put an empty PC32 relocation */ put_elf_reloc(symtab_section, cur_text_section,