History

Improve put_got_entry doc and structure

Thomas Preud'homme committed 10 years ago

Commit f924d0c1 parent 64b5ee22 files · +142 −139Browse files

Unified · Split

2 files
  1. tcc.h +3 −0
  2. tccelf.c +139 −139
tcc.h+3−0
@@ -1325,6 +1325,9 @@ ST_FUNC void tccelf_new(TCCState *s); · 1324 unmodified lines
13251325 ST_FUNC void tccelf_delete(TCCState *s);
13261326 ST_FUNC void tccelf_stab_new(TCCState *s);
13271327
1328+/* return offset of 'ptr' from start of section 'sec' */
1329+#define OFFSET_FROM_SECTION_START(sec, ptr) ((size_t)ptr - (size_t)sec->data)
1330+
13281331 ST_FUNC Section *new_section(TCCState *s1, const char *name, int sh_type, int sh_flags);
13291332 ST_FUNC void section_realloc(Section *sec, unsigned long new_size);
13301333 ST_FUNC void *section_ptr_add(Section *sec, addr_t size);
tccelf.c+139−139
@@ -1295,44 +1295,35 @@ static void build_got(TCCState *s1) · 1294 unmodified lines
12951295 #endif
12961296 }
12971297
1298−/* put a got or plt entry corresponding to a symbol in symtab_section. 'size'
1299− and 'info' can be modifed if more precise info comes from the DLL.
1300− Returns offset of GOT or PLT slot. */
1298+/* Create a GOT and (for function call) a PLT entry corresponding to a symbol
1299+ in s1->symtab. When creating the dynamic symbol table entry for the GOT
1300+ relocation, use 'size' and 'info' for the corresponding symbol metadata.
1301+ Returns the offset of the GOT or (if any) PLT entry. */
13011302 static unsigned long put_got_entry(TCCState *s1,
13021303 int reloc_type, unsigned long size, int info,
13031304 int sym_index)
13041305 {
1305− int index, need_plt_entry;
1306+ int index, need_plt_entry = 0;
13061307 const char *name;
13071308 ElfW(Sym) *sym;
13081309 unsigned long offset;
13091310 int *ptr;
1311+ size_t got_offset;
13101312 struct sym_attr *symattr;
13111313
1314+ need_plt_entry = (reloc_type == R_JMP_SLOT);
1315+
13121316 if (!s1->got)
13131317 build_got(s1);
13141318
1315− need_plt_entry =
1316−#ifdef TCC_TARGET_X86_64
1317− (reloc_type == R_X86_64_JUMP_SLOT);
1318−#elif defined(TCC_TARGET_I386)
1319− (reloc_type == R_386_JMP_SLOT);
1320−#elif defined(TCC_TARGET_ARM)
1321− (reloc_type == R_ARM_JUMP_SLOT);
1322−#elif defined(TCC_TARGET_ARM64)
1323− (reloc_type == R_AARCH64_JUMP_SLOT);
1324−#else
1325− 0;
1326−#endif
1327−
1319+ /* create PLT if needed */
13281320 if (need_plt_entry && !s1->plt) {
1329− /* add PLT */
13301321 s1->plt = new_section(s1, ".plt", SHT_PROGBITS,
13311322 SHF_ALLOC | SHF_EXECINSTR);
13321323 s1->plt->sh_entsize = 4;
13331324 }
13341325
1335− /* If a got/plt entry already exists for that symbol, no need to add one */
1326+ /* already a GOT and/or PLT entry, no need to add one */
13361327 if (sym_index < s1->nb_sym_attrs) {
13371328 if (need_plt_entry && s1->sym_attrs[sym_index].plt_offset)
13381329 return s1->sym_attrs[sym_index].plt_offset;
@@ -1342,152 +1333,161 @@ static unsigned long put_got_entry(TCCState *s1, · 3 unmodified lines
13421333
13431334 symattr = alloc_sym_attr(s1, sym_index);
13441335
1345− /* Only store the GOT offset if it's not generated for the PLT entry. */
1336+ /* create the GOT entry */
1337+ ptr = section_ptr_add(s1->got, PTR_SIZE);
1338+ *ptr = 0;
1339+ got_offset = OFFSET_FROM_SECTION_START (s1->got, ptr);
1340+
1341+ /* In case a function is both called and its address taken 2 GOT entries
1342+ are created, one for taking the address (GOT) and the other for the PLT
1343+ entry (PLTGOT). We don't record the offset of the PLTGOT entry in the
1344+ got_offset field since it might overwrite the offset of a GOT entry.
1345+ Besides, for PLT entry the static relocation is against the PLT entry
1346+ and the dynamic relocation for PLTGOT is created in this function. */
13461347 if (!need_plt_entry)
1347− symattr->got_offset = s1->got->data_offset;
1348+ symattr->got_offset = got_offset;
13481349
1349− sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
1350+ sym = &((ElfW(Sym) *) symtab_section->data)[sym_index];
13501351 name = (char *) symtab_section->link->data + sym->st_name;
13511352 offset = sym->st_value;
1353+
1354+ /* create PLT entry */
1355+ if (need_plt_entry) {
13521356 #if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64)
1353− if (need_plt_entry) {
1354− Section *plt;
1355− uint8_t *p;
1356− int modrm;
1357− unsigned long relofs;
1357+ Section *plt;
1358+ uint8_t *p;
1359+ int modrm;
1360+ unsigned long relofs;
13581361
13591362 #if defined(TCC_OUTPUT_DLL_WITH_PLT)
1360− modrm = 0x25;
1363+ modrm = 0x25;
13611364 #else
1362− /* if we build a DLL, we add a %ebx offset */
1363− if (s1->output_type == TCC_OUTPUT_DLL)
1364− modrm = 0xa3;
1365− else
1366− modrm = 0x25;
1365+ /* if we build a DLL, we add a %ebx offset */
1366+ if (s1->output_type == TCC_OUTPUT_DLL)
1367+ modrm = 0xa3;
1368+ else
1369+ modrm = 0x25;
13671370 #endif
13681371
1369− /* add a PLT entry */
1370− plt = s1->plt;
1371− if (plt->data_offset == 0) {
1372− /* first plt entry */
1373− p = section_ptr_add(plt, 16);
1374− p[0] = 0xff; /* pushl got + PTR_SIZE */
1375− p[1] = modrm + 0x10;
1376− write32le(p + 2, PTR_SIZE);
1377− p[6] = 0xff; /* jmp *(got + PTR_SIZE * 2) */
1378− p[7] = modrm;
1379− write32le(p + 8, PTR_SIZE * 2);
1380− }
1381−
1382− /* The PLT slot refers to the relocation entry it needs
1383− via offset. The reloc entry is created below, so its
1384− offset is the current data_offset. */
1385− relofs = s1->got->reloc ? s1->got->reloc->data_offset : 0;
1386− symattr->plt_offset = plt->data_offset;
1372+ plt = s1->plt;
1373+ /* empty PLT: create PLT0 entry that pushes the library indentifier
1374+ (GOT + PTR_SIZE) and jumps to ld.so resolution routine
1375+ (GOT + 2 * PTR_SIZE) */
1376+ if (plt->data_offset == 0) {
13871377 p = section_ptr_add(plt, 16);
1388− p[0] = 0xff; /* jmp *(got + x) */
1389− p[1] = modrm;
1390− write32le(p + 2, s1->got->data_offset);
1391− p[6] = 0x68; /* push $xxx */
1378+ p[0] = 0xff; /* pushl got + PTR_SIZE */
1379+ p[1] = modrm + 0x10;
1380+ write32le(p + 2, PTR_SIZE);
1381+ p[6] = 0xff; /* jmp *(got + PTR_SIZE * 2) */
1382+ p[7] = modrm;
1383+ write32le(p + 8, PTR_SIZE * 2);
1384+ }
1385+
1386+ /* The PLT slot refers to the relocation entry it needs via offset.
1387+ The reloc entry is created below, so its offset is the current
1388+ data_offset */
1389+ relofs = s1->got->reloc ? s1->got->reloc->data_offset : 0;
1390+ symattr->plt_offset = plt->data_offset;
1391+
1392+ /* Jump to GOT entry where ld.so initially put the address of ip + 4 */
1393+ p = section_ptr_add(plt, 16);
1394+ p[0] = 0xff; /* jmp *(got + x) */
1395+ p[1] = modrm;
1396+ write32le(p + 2, got_offset);
1397+ p[6] = 0x68; /* push $xxx */
13921398 #ifdef TCC_TARGET_X86_64
1393− /* On x86-64, the relocation is referred to by _index_. */
1394− write32le(p + 7, relofs / sizeof (ElfW_Rel));
1399+ /* On x86-64, the relocation is referred to by _index_ */
1400+ write32le(p + 7, relofs / sizeof (ElfW_Rel));
13951401 #else
1396− write32le(p + 7, relofs);
1402+ write32le(p + 7, relofs);
13971403 #endif
1398− p[11] = 0xe9; /* jmp plt_start */
1399− write32le(p + 12, -(plt->data_offset));
1400−
1401− /* If this was an UNDEF symbol set the offset in the
1402− dynsymtab to the PLT slot, so that PC32 relocs to it
1403− can be resolved. */
1404− if (sym->st_shndx == SHN_UNDEF)
1405− offset = plt->data_offset - 16;
1406− }
1407−#elif defined(TCC_TARGET_ARM)
1408− if (need_plt_entry) {
1409− Section *plt;
1410− uint8_t *p;
1411−
1412− /* if we build a DLL, we add a %ebx offset */
1413− if (s1->output_type == TCC_OUTPUT_DLL)
1414− tcc_error("DLLs unimplemented!");
1415−
1416− /* add a PLT entry */
1417− plt = s1->plt;
1418− if (plt->data_offset == 0) {
1419− /* first plt entry */
1420− p = section_ptr_add(plt, 16);
1421− write32le(p, 0xe52de004); /* push {lr} */
1422− write32le(p+4, 0xe59fe010); /* ldr lr, [pc, #16] */
1423− write32le(p+8, 0xe08fe00e); /* add lr, pc, lr */
1424− write32le(p+12, 0xe5bef008); /* ldr pc, [lr, #8]! */
1425− }
1404+ p[11] = 0xe9; /* jmp plt_start */
1405+ write32le(p + 12, -(plt->data_offset));
14261406
1427− symattr->plt_offset = plt->data_offset;
1428− if (symattr->plt_thumb_stub) {
1429− p = section_ptr_add(plt, 20);
1430− write32le(p, 0x4778); /* bx pc */
1431− write32le(p+2, 0x46c0); /* nop */
1432− p += 4;
1433− } else
1434− p = section_ptr_add(plt, 16);
1435− write32le(p, 0xe59fc004); /* ldr ip, [pc, #4] ; GOT entry offset */
1436− write32le(p+4, 0xe08fc00c); /* add ip, pc, ip ; addr of GOT entry */
1437− write32le(p+8, 0xe59cf000); /* ldr pc, [ip] ; jump to GOT entry */
1438− write32le(p+12, s1->got->data_offset); /* GOT entry off once patched */
1439−
1440− /* the symbol is modified so that it will be relocated to
1441− the PLT */
1442− if (sym->st_shndx == SHN_UNDEF)
1443− offset = plt->data_offset - 16;
1444− }
1445−#elif defined(TCC_TARGET_ARM64)
1446− if (need_plt_entry) {
1447− Section *plt;
1448− uint8_t *p;
1449−
1450− if (s1->output_type == TCC_OUTPUT_DLL)
1451− tcc_error("DLLs unimplemented!");
1452−
1453− plt = s1->plt;
1454− if (plt->data_offset == 0)
1455− section_ptr_add(plt, 32);
1456− symattr->plt_offset = plt->data_offset;
1407+ /* If this was an UNDEF symbol set the offset in the dynsymtab to the
1408+ PLT slot, so that PC32 relocs to it can be resolved */
1409+ if (sym->st_shndx == SHN_UNDEF)
1410+ offset = plt->data_offset - 16;
1411+#elif defined(TCC_TARGET_ARM)
1412+ Section *plt;
1413+ uint8_t *p;
1414+
1415+ /* when building a DLL, GOT entry accesses must be done relative to
1416+ start of GOT (see x86_64 examble above) */
1417+ if (s1->output_type == TCC_OUTPUT_DLL)
1418+ tcc_error("DLLs unimplemented!");
1419+
1420+ plt = s1->plt;
1421+ /* empty PLT: create PLT0 entry that push address of call site and
1422+ jump to ld.so resolution routine (GOT + 8) */
1423+ if (plt->data_offset == 0) {
14571424 p = section_ptr_add(plt, 16);
1458− write32le(p, s1->got->data_offset);
1459− write32le(p + 4, (uint64_t)s1->got->data_offset >> 32);
1425+ write32le(p, 0xe52de004); /* push {lr} */
1426+ write32le(p+4, 0xe59fe010); /* ldr lr, [pc, #16] */
1427+ write32le(p+8, 0xe08fe00e); /* add lr, pc, lr */
1428+ write32le(p+12, 0xe5bef008); /* ldr pc, [lr, #8]! */
1429+ }
14601430
1461− if (sym->st_shndx == SHN_UNDEF)
1462− offset = plt->data_offset - 16;
1431+ symattr->plt_offset = plt->data_offset;
1432+ if (symattr->plt_thumb_stub) {
1433+ p = section_ptr_add(plt, 4);
1434+ write32le(p, 0x4778); /* bx pc */
1435+ write32le(p+2, 0x46c0); /* nop */
14631436 }
1437+ p = section_ptr_add(plt, 16);
1438+ /* Jump to GOT entry where ld.so initially put address of PLT0 */
1439+ write32le(p, 0xe59fc004); /* ldr ip, [pc, #4] */
1440+ write32le(p+4, 0xe08fc00c); /* add ip, pc, ip */
1441+ write32le(p+8, 0xe59cf000); /* ldr pc, [ip] */
1442+ /* p + 12 contains offset to GOT entry once patched by relocate_plt */
1443+ write32le(p+12, got_offset);
1444+
1445+ /* the symbol is modified so that it will be relocated to the PLT */
1446+ if (sym->st_shndx == SHN_UNDEF)
1447+ offset = plt->data_offset - 16;
1448+#elif defined(TCC_TARGET_ARM64)
1449+ Section *plt;
1450+ uint8_t *p;
1451+
1452+ if (s1->output_type == TCC_OUTPUT_DLL)
1453+ tcc_error("DLLs unimplemented!");
1454+
1455+ plt = s1->plt;
1456+ if (plt->data_offset == 0)
1457+ section_ptr_add(plt, 32);
1458+ symattr->plt_offset = plt->data_offset;
1459+ p = section_ptr_add(plt, 16);
1460+ write32le(p, got_offset);
1461+ write32le(p + 4, (uint64_t) got_offset >> 32);
1462+
1463+ if (sym->st_shndx == SHN_UNDEF)
1464+ offset = plt->data_offset - 16;
14641465 #elif defined(TCC_TARGET_C67)
1465− if (s1->dynsym) {
14661466 tcc_error("C67 got not implemented");
1467− }
14681467 #else
14691468 #error unsupported CPU
14701469 #endif
1470+ }
1471+
1472+ /* Create the GOT relocation that will insert the address of the object or
1473+ function of interest in the GOT entry. This is a static relocation for
1474+ memory output (dlsym will give us the address of symbols) and dynamic
1475+ relocation otherwise (executable and DLLs). The relocation should be
1476+ done lazily for GOT entry with *_JUMP_SLOT relocation type (the one
1477+ associated to a PLT entry) but is currently done at load time for an
1478+ unknown reason. */
14711479 if (s1->dynsym) {
1480+ /* create the dynamic symbol table entry that the relocation refers to
1481+ in its r_info field to identify the symbol */
14721482 /* XXX This might generate multiple syms for name. */
1473− index = put_elf_sym(s1->dynsym, offset,
1474− size, info, 0, sym->st_shndx, name);
1475− /* Create the relocation (it's against the GOT for PLT
1476− and GOT relocs). */
1477− put_elf_reloc(s1->dynsym, s1->got,
1478− s1->got->data_offset,
1479− reloc_type, index);
1483+ index = put_elf_sym(s1->dynsym, offset, size, info, 0, sym->st_shndx,
1484+ name);
1485+ put_elf_reloc(s1->dynsym, s1->got, got_offset, reloc_type, index);
14801486 } else {
1481− /* Without .dynsym (i.e. static link or memory output) we
1482− still need relocs against the generated got, so as to fill
1483− the entries with the symbol values (determined later). */
1484− put_elf_reloc(symtab_section, s1->got,
1485− s1->got->data_offset,
1486− reloc_type, sym_index);
1487− }
1488− /* And now create the GOT slot itself. */
1489− ptr = section_ptr_add(s1->got, PTR_SIZE);
1490− *ptr = 0;
1487+ put_elf_reloc(symtab_section, s1->got, got_offset, reloc_type,
1488+ sym_index);
1489+ }
1490+
14911491 if (need_plt_entry)
14921492 return symattr->plt_offset;
14931493 else

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