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
1325ST_FUNC void tccelf_delete(TCCState *s);1325ST_FUNC void tccelf_delete(TCCState *s);
1326ST_FUNC void tccelf_stab_new(TCCState *s);1326ST_FUNC void tccelf_stab_new(TCCState *s);
1327 1327
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
1328ST_FUNC Section *new_section(TCCState *s1, const char *name, int sh_type, int sh_flags);1331ST_FUNC Section *new_section(TCCState *s1, const char *name, int sh_type, int sh_flags);
1329ST_FUNC void section_realloc(Section *sec, unsigned long new_size);1332ST_FUNC void section_realloc(Section *sec, unsigned long new_size);
1330ST_FUNC void *section_ptr_add(Section *sec, addr_t size);1333ST_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
1295#endif1295#endif
1296}1296}
1297 1297
1298/* put a got or plt entry corresponding to a symbol in symtab_section. 'size'1298/* Create a GOT and (for function call) a PLT entry corresponding to a symbol
1299 and 'info' can be modifed if more precise info comes from the DLL.1299 in s1->symtab. When creating the dynamic symbol table entry for the GOT
1300 Returns offset of GOT or PLT slot. */1300 relocation, use 'size' and 'info' for the corresponding symbol metadata.
1301 Returns the offset of the GOT or (if any) PLT entry. */
1301static unsigned long put_got_entry(TCCState *s1,1302static unsigned long put_got_entry(TCCState *s1,
1302 int reloc_type, unsigned long size, int info,1303 int reloc_type, unsigned long size, int info,
1303 int sym_index)1304 int sym_index)
1304{1305{
1305 int index, need_plt_entry;1306 int index, need_plt_entry = 0;
1306 const char *name;1307 const char *name;
1307 ElfW(Sym) *sym;1308 ElfW(Sym) *sym;
1308 unsigned long offset;1309 unsigned long offset;
1309 int *ptr;1310 int *ptr;
1311 size_t got_offset;
1310 struct sym_attr *symattr;1312 struct sym_attr *symattr;
1311 1313
1314 need_plt_entry = (reloc_type == R_JMP_SLOT);
1315
1312 if (!s1->got)1316 if (!s1->got)
1313 build_got(s1);1317 build_got(s1);
1314 1318
1315 need_plt_entry =1319 /* create PLT if needed */
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
1328 if (need_plt_entry && !s1->plt) {1320 if (need_plt_entry && !s1->plt) {
1329 /* add PLT */
1330 s1->plt = new_section(s1, ".plt", SHT_PROGBITS,1321 s1->plt = new_section(s1, ".plt", SHT_PROGBITS,
1331 SHF_ALLOC | SHF_EXECINSTR);1322 SHF_ALLOC | SHF_EXECINSTR);
1332 s1->plt->sh_entsize = 4;1323 s1->plt->sh_entsize = 4;
1333 }1324 }
1334 1325
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 */
1336 if (sym_index < s1->nb_sym_attrs) {1327 if (sym_index < s1->nb_sym_attrs) {
1337 if (need_plt_entry && s1->sym_attrs[sym_index].plt_offset)1328 if (need_plt_entry && s1->sym_attrs[sym_index].plt_offset)
1338 return s1->sym_attrs[sym_index].plt_offset;1329 return s1->sym_attrs[sym_index].plt_offset;
@@ -1342,152 +1333,161 @@ static unsigned long put_got_entry(TCCState *s1, · 3 unmodified lines
1342 1333
1343 symattr = alloc_sym_attr(s1, sym_index);1334 symattr = alloc_sym_attr(s1, sym_index);
1344 1335
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. */
1346 if (!need_plt_entry)1347 if (!need_plt_entry)
1347 symattr->got_offset = s1->got->data_offset;1348 symattr->got_offset = got_offset;
1348 1349
1349 sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];1350 sym = &((ElfW(Sym) *) symtab_section->data)[sym_index];
1350 name = (char *) symtab_section->link->data + sym->st_name;1351 name = (char *) symtab_section->link->data + sym->st_name;
1351 offset = sym->st_value;1352 offset = sym->st_value;
1353
1354 /* create PLT entry */
1355 if (need_plt_entry) {
1352#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64)1356#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64)
1353 if (need_plt_entry) {1357 Section *plt;
1354 Section *plt;1358 uint8_t *p;
1355 uint8_t *p;1359 int modrm;
1356 int modrm;1360 unsigned long relofs;
1357 unsigned long relofs;
1358 1361
1359#if defined(TCC_OUTPUT_DLL_WITH_PLT)1362#if defined(TCC_OUTPUT_DLL_WITH_PLT)
1360 modrm = 0x25;1363 modrm = 0x25;
1361#else1364#else
1362 /* if we build a DLL, we add a %ebx offset */1365 /* if we build a DLL, we add a %ebx offset */
1363 if (s1->output_type == TCC_OUTPUT_DLL)1366 if (s1->output_type == TCC_OUTPUT_DLL)
1364 modrm = 0xa3;1367 modrm = 0xa3;
1365 else1368 else
1366 modrm = 0x25;1369 modrm = 0x25;
1367#endif1370#endif
1368 1371
1369 /* add a PLT entry */1372 plt = s1->plt;
1370 plt = s1->plt;1373 /* empty PLT: create PLT0 entry that pushes the library indentifier
1371 if (plt->data_offset == 0) {1374 (GOT + PTR_SIZE) and jumps to ld.so resolution routine
1372 /* first plt entry */1375 (GOT + 2 * PTR_SIZE) */
1373 p = section_ptr_add(plt, 16);1376 if (plt->data_offset == 0) {
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;
1387 p = section_ptr_add(plt, 16);1377 p = section_ptr_add(plt, 16);
1388 p[0] = 0xff; /* jmp *(got + x) */1378 p[0] = 0xff; /* pushl got + PTR_SIZE */
1389 p[1] = modrm;1379 p[1] = modrm + 0x10;
1390 write32le(p + 2, s1->got->data_offset);1380 write32le(p + 2, PTR_SIZE);
1391 p[6] = 0x68; /* push $xxx */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 */
1392#ifdef TCC_TARGET_X86_641398#ifdef TCC_TARGET_X86_64
1393 /* On x86-64, the relocation is referred to by _index_. */1399 /* On x86-64, the relocation is referred to by _index_ */
1394 write32le(p + 7, relofs / sizeof (ElfW_Rel));1400 write32le(p + 7, relofs / sizeof (ElfW_Rel));
1395#else1401#else
1396 write32le(p + 7, relofs);1402 write32le(p + 7, relofs);
1397#endif1403#endif
1398 p[11] = 0xe9; /* jmp plt_start */1404 p[11] = 0xe9; /* jmp plt_start */
1399 write32le(p + 12, -(plt->data_offset));1405 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 }
1426 1406
1427 symattr->plt_offset = plt->data_offset;1407 /* If this was an UNDEF symbol set the offset in the dynsymtab to the
1428 if (symattr->plt_thumb_stub) {1408 PLT slot, so that PC32 relocs to it can be resolved */
1429 p = section_ptr_add(plt, 20);1409 if (sym->st_shndx == SHN_UNDEF)
1430 write32le(p, 0x4778); /* bx pc */1410 offset = plt->data_offset - 16;
1431 write32le(p+2, 0x46c0); /* nop */1411#elif defined(TCC_TARGET_ARM)
1432 p += 4;1412 Section *plt;
1433 } else1413 uint8_t *p;
1434 p = section_ptr_add(plt, 16);1414
1435 write32le(p, 0xe59fc004); /* ldr ip, [pc, #4] ; GOT entry offset */1415 /* when building a DLL, GOT entry accesses must be done relative to
1436 write32le(p+4, 0xe08fc00c); /* add ip, pc, ip ; addr of GOT entry */1416 start of GOT (see x86_64 examble above) */
1437 write32le(p+8, 0xe59cf000); /* ldr pc, [ip] ; jump to GOT entry */1417 if (s1->output_type == TCC_OUTPUT_DLL)
1438 write32le(p+12, s1->got->data_offset); /* GOT entry off once patched */1418 tcc_error("DLLs unimplemented!");
1439 1419
1440 /* the symbol is modified so that it will be relocated to1420 plt = s1->plt;
1441 the PLT */1421 /* empty PLT: create PLT0 entry that push address of call site and
1442 if (sym->st_shndx == SHN_UNDEF)1422 jump to ld.so resolution routine (GOT + 8) */
1443 offset = plt->data_offset - 16;1423 if (plt->data_offset == 0) {
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;
1457 p = section_ptr_add(plt, 16);1424 p = section_ptr_add(plt, 16);
1458 write32le(p, s1->got->data_offset);1425 write32le(p, 0xe52de004); /* push {lr} */
1459 write32le(p + 4, (uint64_t)s1->got->data_offset >> 32);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 }
1460 1430
1461 if (sym->st_shndx == SHN_UNDEF)1431 symattr->plt_offset = plt->data_offset;
1462 offset = plt->data_offset - 16;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 */
1463 }1436 }
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;
1464#elif defined(TCC_TARGET_C67)1465#elif defined(TCC_TARGET_C67)
1465 if (s1->dynsym) {
1466 tcc_error("C67 got not implemented");1466 tcc_error("C67 got not implemented");
1467 }
1468#else1467#else
1469#error unsupported CPU1468#error unsupported CPU
1470#endif1469#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. */
1471 if (s1->dynsym) {1479 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 */
1472 /* XXX This might generate multiple syms for name. */1482 /* XXX This might generate multiple syms for name. */
1473 index = put_elf_sym(s1->dynsym, offset,1483 index = put_elf_sym(s1->dynsym, offset, size, info, 0, sym->st_shndx,
1474 size, info, 0, sym->st_shndx, name);1484 name);
1475 /* Create the relocation (it's against the GOT for PLT1485 put_elf_reloc(s1->dynsym, s1->got, got_offset, reloc_type, index);
1476 and GOT relocs). */
1477 put_elf_reloc(s1->dynsym, s1->got,
1478 s1->got->data_offset,
1479 reloc_type, index);
1480 } else {1486 } else {
1481 /* Without .dynsym (i.e. static link or memory output) we1487 put_elf_reloc(symtab_section, s1->got, got_offset, reloc_type,
1482 still need relocs against the generated got, so as to fill1488 sym_index);
1483 the entries with the symbol values (determined later). */1489 }
1484 put_elf_reloc(symtab_section, s1->got,1490
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;
1491 if (need_plt_entry)1491 if (need_plt_entry)
1492 return symattr->plt_offset;1492 return symattr->plt_offset;
1493 else1493 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