Unified · Split
| @@ -20,6 +20,7 @@ · 19 unmodified lines | |||
| 20 | 20 | ||
| 21 | #include "tcc.h" | 21 | #include "tcc.h" |
| 22 | 22 | ||
| 23 | /* XXX: avoid static variable */ | ||
| 23 | static int new_undef_sym = 0; /* Is there a new undefined sym since last new_undef_sym() */ | 24 | static int new_undef_sym = 0; /* Is there a new undefined sym since last new_undef_sym() */ |
| 24 | 25 | ||
| 25 | ST_FUNC int put_elf_str(Section *s, const char *sym) | 26 | ST_FUNC int put_elf_str(Section *s, const char *sym) |
| @@ -429,6 +430,7 @@ ST_FUNC void relocate_syms(TCCState *s1, int do_resolve) · 403 unmodified lines | |||
| 429 | sh_num = sym->st_shndx; | 430 | sh_num = sym->st_shndx; |
| 430 | if (sh_num == SHN_UNDEF) { | 431 | if (sh_num == SHN_UNDEF) { |
| 431 | name = strtab_section->data + sym->st_name; | 432 | name = strtab_section->data + sym->st_name; |
| 433 | /* Use ld.so to resolve symbol for us (for tcc -run) */ | ||
| 432 | if (do_resolve) { | 434 | if (do_resolve) { |
| 433 | #if defined TCC_IS_NATIVE && !defined _WIN32 | 435 | #if defined TCC_IS_NATIVE && !defined _WIN32 |
| 434 | void *addr; | 436 | void *addr; |
| @@ -504,7 +506,8 @@ static addr_t add_jmp_table(TCCState *s1, int val) · 69 unmodified lines | |||
| 504 | #endif | 506 | #endif |
| 505 | #endif /* def TCC_HAS_RUNTIME_PLTGOT */ | 507 | #endif /* def TCC_HAS_RUNTIME_PLTGOT */ |
| 506 | 508 | ||
| 507 | /* relocate a given section (CPU dependent) */ | 509 | /* relocate a given section (CPU dependent) by applying the relocations |
| 510 | in the associated relocation section */ | ||
| 508 | ST_FUNC void relocate_section(TCCState *s1, Section *s) | 511 | ST_FUNC void relocate_section(TCCState *s1, Section *s) |
| 509 | { | 512 | { |
| 510 | Section *sr; | 513 | Section *sr; |
| @@ -1422,14 +1425,14 @@ ST_FUNC void tcc_add_linker_symbols(TCCState *s1) · 911 unmodified lines | |||
| 1422 | } | 1425 | } |
| 1423 | 1426 | ||
| 1424 | static void tcc_output_binary(TCCState *s1, FILE *f, | 1427 | static void tcc_output_binary(TCCState *s1, FILE *f, |
| 1425 | const int *section_order) | 1428 | const int *sec_order) |
| 1426 | { | 1429 | { |
| 1427 | Section *s; | 1430 | Section *s; |
| 1428 | int i, offset, size; | 1431 | int i, offset, size; |
| 1429 | 1432 | ||
| 1430 | offset = 0; | 1433 | offset = 0; |
| 1431 | for(i=1;i<s1->nb_sections;i++) { | 1434 | for(i=1;i<s1->nb_sections;i++) { |
| 1432 | s = s1->sections[section_order[i]]; | 1435 | s = s1->sections[sec_order[i]]; |
| 1433 | if (s->sh_type != SHT_NOBITS && | 1436 | if (s->sh_type != SHT_NOBITS && |
| 1434 | (s->sh_flags & SHF_ALLOC)) { | 1437 | (s->sh_flags & SHF_ALLOC)) { |
| 1435 | while (offset < s->sh_offset) { | 1438 | while (offset < s->sh_offset) { |
| @@ -1494,6 +1497,7 @@ ST_FUNC void fill_got_entry(TCCState *s1, ElfW_Rel *rel) · 58 unmodified lines | |||
| 1494 | put32(s1->got->data + offset, sym->st_value & 0xffffffff); | 1497 | put32(s1->got->data + offset, sym->st_value & 0xffffffff); |
| 1495 | } | 1498 | } |
| 1496 | 1499 | ||
| 1500 | /* Perform relocation to GOT or PLT entries */ | ||
| 1497 | ST_FUNC void fill_got(TCCState *s1) | 1501 | ST_FUNC void fill_got(TCCState *s1) |
| 1498 | { | 1502 | { |
| 1499 | Section *s; | 1503 | Section *s; |
| @@ -1509,301 +1513,213 @@ ST_FUNC void fill_got(TCCState *s1) · 9 unmodified lines | |||
| 1509 | continue; | 1513 | continue; |
| 1510 | for_each_elem(s, 0, rel, ElfW_Rel) { | 1514 | for_each_elem(s, 0, rel, ElfW_Rel) { |
| 1511 | switch (ELFW(R_TYPE) (rel->r_info)) { | 1515 | switch (ELFW(R_TYPE) (rel->r_info)) { |
| 1516 | #ifdef TCC_TARGET_X86_64 | ||
| 1512 | case R_X86_64_GOT32: | 1517 | case R_X86_64_GOT32: |
| 1513 | case R_X86_64_GOTPCREL: | 1518 | case R_X86_64_GOTPCREL: |
| 1514 | case R_X86_64_PLT32: | 1519 | case R_X86_64_PLT32: |
| 1515 | fill_got_entry(s1, rel); | 1520 | fill_got_entry(s1, rel); |
| 1516 | break; | 1521 | break; |
| 1522 | #endif | ||
| 1517 | } | 1523 | } |
| 1518 | } | 1524 | } |
| 1519 | } | 1525 | } |
| 1520 | } | 1526 | } |
| 1521 | 1527 | ||
| 1522 | 1528 | /* Bind symbols of executable: resolve undefined symbols from exported symbols | |
| 1523 | /* output an ELF file */ | 1529 | in shared libraries and export non local defined symbols to shared libraries |
| 1524 | /* XXX: suppress unneeded sections */ | 1530 | if -rdynamic switch was given on command line */ |
| 1525 | static int elf_output_file(TCCState *s1, const char *filename) | 1531 | static void bind_exe_dynsyms(TCCState *s1) |
| 1526 | { | 1532 | { |
| 1527 | ElfW(Ehdr) ehdr; | 1533 | const char *name; |
| 1528 | FILE *f; | 1534 | int sym_index, index; |
| 1529 | int fd, mode, ret; | 1535 | ElfW(Sym) *sym, *esym; |
| 1530 | int *section_order; | 1536 | int type; |
| 1531 | int shnum, i, phnum, file_offset, offset, size, j, sh_order_index, k; | ||
| 1532 | long long tmp; | ||
| 1533 | addr_t addr; | ||
| 1534 | Section *strsec, *s; | ||
| 1535 | ElfW(Shdr) shdr, *sh; | ||
| 1536 | ElfW(Phdr) *phdr, *ph; | ||
| 1537 | Section *interp, *dynamic, *dynstr; | ||
| 1538 | unsigned long saved_dynamic_data_offset; | ||
| 1539 | ElfW(Sym) *sym; | ||
| 1540 | int type, file_type; | ||
| 1541 | addr_t rel_addr, rel_size; | ||
| 1542 | #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) | ||
| 1543 | addr_t bss_addr, bss_size; | ||
| 1544 | #endif | ||
| 1545 | |||
| 1546 | file_type = s1->output_type; | ||
| 1547 | s1->nb_errors = 0; | ||
| 1548 | |||
| 1549 | if (file_type != TCC_OUTPUT_OBJ) { | ||
| 1550 | tcc_add_runtime(s1); | ||
| 1551 | } | ||
| 1552 | |||
| 1553 | phdr = NULL; | ||
| 1554 | section_order = NULL; | ||
| 1555 | interp = NULL; | ||
| 1556 | dynamic = NULL; | ||
| 1557 | dynstr = NULL; /* avoid warning */ | ||
| 1558 | saved_dynamic_data_offset = 0; /* avoid warning */ | ||
| 1559 | |||
| 1560 | if (file_type != TCC_OUTPUT_OBJ) { | ||
| 1561 | relocate_common_syms(); | ||
| 1562 | |||
| 1563 | tcc_add_linker_symbols(s1); | ||
| 1564 | |||
| 1565 | if (!s1->static_link) { | ||
| 1566 | const char *name; | ||
| 1567 | int sym_index, index; | ||
| 1568 | ElfW(Sym) *esym; | ||
| 1569 | |||
| 1570 | if (file_type == TCC_OUTPUT_EXE) { | ||
| 1571 | char *ptr; | ||
| 1572 | /* allow override the dynamic loader */ | ||
| 1573 | const char *elfint = getenv("LD_SO"); | ||
| 1574 | if (elfint == NULL) | ||
| 1575 | elfint = DEFAULT_ELFINTERP(s1); | ||
| 1576 | /* add interpreter section only if executable */ | ||
| 1577 | interp = new_section(s1, ".interp", SHT_PROGBITS, SHF_ALLOC); | ||
| 1578 | interp->sh_addralign = 1; | ||
| 1579 | ptr = section_ptr_add(interp, 1+strlen(elfint)); | ||
| 1580 | strcpy(ptr, elfint); | ||
| 1581 | } | ||
| 1582 | |||
| 1583 | /* add dynamic symbol table */ | ||
| 1584 | s1->dynsym = new_symtab(s1, ".dynsym", SHT_DYNSYM, SHF_ALLOC, | ||
| 1585 | ".dynstr", | ||
| 1586 | ".hash", SHF_ALLOC); | ||
| 1587 | dynstr = s1->dynsym->link; | ||
| 1588 | |||
| 1589 | /* add dynamic section */ | ||
| 1590 | dynamic = new_section(s1, ".dynamic", SHT_DYNAMIC, | ||
| 1591 | SHF_ALLOC | SHF_WRITE); | ||
| 1592 | dynamic->link = dynstr; | ||
| 1593 | dynamic->sh_entsize = sizeof(ElfW(Dyn)); | ||
| 1594 | |||
| 1595 | /* add PLT */ | ||
| 1596 | s1->plt = new_section(s1, ".plt", SHT_PROGBITS, | ||
| 1597 | SHF_ALLOC | SHF_EXECINSTR); | ||
| 1598 | s1->plt->sh_entsize = 4; | ||
| 1599 | |||
| 1600 | build_got(s1); | ||
| 1601 | |||
| 1602 | /* scan for undefined symbols and see if they are in the | ||
| 1603 | dynamic symbols. If a symbol STT_FUNC or STT_GNU_IFUNC | ||
| 1604 | is found, then we add it in the PLT. If a symbol | ||
| 1605 | STT_OBJECT is found, we add it in the .bss section with | ||
| 1606 | a suitable relocation */ | ||
| 1607 | if (file_type == TCC_OUTPUT_EXE) { | ||
| 1608 | for_each_elem(symtab_section, 1, sym, ElfW(Sym)) { | ||
| 1609 | if (sym->st_shndx == SHN_UNDEF) { | ||
| 1610 | name = symtab_section->link->data + sym->st_name; | ||
| 1611 | sym_index = find_elf_sym(s1->dynsymtab_section, name); | ||
| 1612 | if (sym_index) { | ||
| 1613 | esym = &((ElfW(Sym) *)s1->dynsymtab_section->data)[sym_index]; | ||
| 1614 | type = ELFW(ST_TYPE)(esym->st_info); | ||
| 1615 | if ((type == STT_FUNC) || (type == STT_GNU_IFUNC)) { | ||
| 1616 | /* Indirect functions shall have STT_FUNC type | ||
| 1617 | * in executable dynsym section. Indeed, a dlsym | ||
| 1618 | * call following a lazy resolution would pick | ||
| 1619 | * the symbol value from the executable dynsym | ||
| 1620 | * entry which would contain the address of the | ||
| 1621 | * function wanted by the caller of dlsym | ||
| 1622 | * instead of the address of the function that | ||
| 1623 | * would return that address */ | ||
| 1624 | put_got_entry(s1, R_JMP_SLOT, esym->st_size, | ||
| 1625 | ELFW(ST_INFO)(STB_GLOBAL,STT_FUNC), | ||
| 1626 | sym - (ElfW(Sym) *)symtab_section->data); | ||
| 1627 | } else if (type == STT_OBJECT) { | ||
| 1628 | unsigned long offset; | ||
| 1629 | ElfW(Sym) *dynsym; | ||
| 1630 | offset = bss_section->data_offset; | ||
| 1631 | /* XXX: which alignment ? */ | ||
| 1632 | offset = (offset + 16 - 1) & -16; | ||
| 1633 | index = put_elf_sym(s1->dynsym, offset, esym->st_size, | ||
| 1634 | esym->st_info, 0, | ||
| 1635 | bss_section->sh_num, name); | ||
| 1636 | /* Ensure R_COPY works for weak symbol aliases */ | ||
| 1637 | if (ELFW(ST_BIND)(esym->st_info) == STB_WEAK) { | ||
| 1638 | for_each_elem(s1->dynsymtab_section, 1, dynsym, ElfW(Sym)) { | ||
| 1639 | if ((dynsym->st_value == esym->st_value) | ||
| 1640 | && (ELFW(ST_BIND)(dynsym->st_info) == STB_GLOBAL)) { | ||
| 1641 | char *dynname; | ||
| 1642 | dynname = s1->dynsymtab_section->link->data | ||
| 1643 | + dynsym->st_name; | ||
| 1644 | put_elf_sym(s1->dynsym, offset, | ||
| 1645 | dynsym->st_size, | ||
| 1646 | dynsym->st_info, 0, | ||
| 1647 | bss_section->sh_num, | ||
| 1648 | dynname); | ||
| 1649 | break; | ||
| 1650 | } | ||
| 1651 | } | ||
| 1652 | } | ||
| 1653 | put_elf_reloc(s1->dynsym, bss_section, | ||
| 1654 | offset, R_COPY, index); | ||
| 1655 | offset += esym->st_size; | ||
| 1656 | bss_section->data_offset = offset; | ||
| 1657 | } | ||
| 1658 | } else { | ||
| 1659 | /* STB_WEAK undefined symbols are accepted */ | ||
| 1660 | /* XXX: _fp_hw seems to be part of the ABI, so we ignore | ||
| 1661 | it */ | ||
| 1662 | if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK || | ||
| 1663 | !strcmp(name, "_fp_hw")) { | ||
| 1664 | } else { | ||
| 1665 | tcc_error_noabort("undefined symbol '%s'", name); | ||
| 1666 | } | ||
| 1667 | } | ||
| 1668 | } else if (s1->rdynamic && | ||
| 1669 | ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { | ||
| 1670 | /* if -rdynamic option, then export all non | ||
| 1671 | local symbols */ | ||
| 1672 | name = symtab_section->link->data + sym->st_name; | ||
| 1673 | put_elf_sym(s1->dynsym, sym->st_value, sym->st_size, | ||
| 1674 | sym->st_info, 0, | ||
| 1675 | sym->st_shndx, name); | ||
| 1676 | } | ||
| 1677 | } | ||
| 1678 | |||
| 1679 | if (s1->nb_errors) | ||
| 1680 | goto fail; | ||
| 1681 | 1537 | ||
| 1682 | /* now look at unresolved dynamic symbols and export | 1538 | /* Resolve undefined symbols from dynamic symbols. When there is a match: |
| 1683 | corresponding symbol */ | 1539 | - if STT_FUNC or STT_GNU_IFUNC symbol -> add it in PLT |
| 1684 | for_each_elem(s1->dynsymtab_section, 1, esym, ElfW(Sym)) { | 1540 | - if STT_OBJECT symbol -> add it in .bss section with suitable reloc */ |
| 1685 | if (esym->st_shndx == SHN_UNDEF) { | 1541 | for_each_elem(symtab_section, 1, sym, ElfW(Sym)) { |
| 1686 | name = s1->dynsymtab_section->link->data + esym->st_name; | 1542 | if (sym->st_shndx == SHN_UNDEF) { |
| 1687 | sym_index = find_elf_sym(symtab_section, name); | 1543 | name = symtab_section->link->data + sym->st_name; |
| 1688 | if (sym_index) { | 1544 | sym_index = find_elf_sym(s1->dynsymtab_section, name); |
| 1689 | /* XXX: avoid adding a symbol if already | 1545 | if (sym_index) { |
| 1690 | present because of -rdynamic ? */ | 1546 | esym = &((ElfW(Sym) *)s1->dynsymtab_section->data)[sym_index]; |
| 1691 | sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; | 1547 | type = ELFW(ST_TYPE)(esym->st_info); |
| 1692 | put_elf_sym(s1->dynsym, sym->st_value, sym->st_size, | 1548 | if ((type == STT_FUNC) || (type == STT_GNU_IFUNC)) { |
| 1693 | sym->st_info, 0, | 1549 | /* Indirect functions shall have STT_FUNC type in executable |
| 1694 | sym->st_shndx, name); | 1550 | * dynsym section. Indeed, a dlsym call following a lazy |
| 1695 | } else { | 1551 | * resolution would pick the symbol value from the |
| 1696 | if (ELFW(ST_BIND)(esym->st_info) == STB_WEAK) { | 1552 | * executable dynsym entry which would contain the address |
| 1697 | /* weak symbols can stay undefined */ | 1553 | * of the function wanted by the caller of dlsym instead of |
| 1698 | } else { | 1554 | * the address of the function that would return that |
| 1699 | tcc_warning("undefined dynamic symbol '%s'", name); | 1555 | * address */ |
| 1556 | put_got_entry(s1, R_JMP_SLOT, esym->st_size, | ||
| 1557 | ELFW(ST_INFO)(STB_GLOBAL,STT_FUNC), | ||
| 1558 | sym - (ElfW(Sym) *)symtab_section->data); | ||
| 1559 | } else if (type == STT_OBJECT) { | ||
| 1560 | unsigned long offset; | ||
| 1561 | ElfW(Sym) *dynsym; | ||
| 1562 | offset = bss_section->data_offset; | ||
| 1563 | /* XXX: which alignment ? */ | ||
| 1564 | offset = (offset + 16 - 1) & -16; | ||
| 1565 | index = put_elf_sym(s1->dynsym, offset, esym->st_size, | ||
| 1566 | esym->st_info, 0, bss_section->sh_num, | ||
| 1567 | name); | ||
| 1568 | /* Ensure R_COPY works for weak symbol aliases */ | ||
| 1569 | if (ELFW(ST_BIND)(esym->st_info) == STB_WEAK) { | ||
| 1570 | for_each_elem(s1->dynsymtab_section, 1, dynsym, ElfW(Sym)) { | ||
| 1571 | if ((dynsym->st_value == esym->st_value) | ||
| 1572 | && (ELFW(ST_BIND)(dynsym->st_info) == STB_GLOBAL)) { | ||
| 1573 | char *dynname = s1->dynsymtab_section->link->data | ||
| 1574 | + dynsym->st_name; | ||
| 1575 | put_elf_sym(s1->dynsym, offset, dynsym->st_size, | ||
| 1576 | dynsym->st_info, 0, | ||
| 1577 | bss_section->sh_num, dynname); | ||
| 1578 | break; | ||
| 1700 | } | 1579 | } |
| 1701 | } | 1580 | } |
| 1702 | } | 1581 | } |
| 1582 | put_elf_reloc(s1->dynsym, bss_section, | ||
| 1583 | offset, R_COPY, index); | ||
| 1584 | offset += esym->st_size; | ||
| 1585 | bss_section->data_offset = offset; | ||
| 1703 | } | 1586 | } |
| 1704 | } else { | 1587 | } else { |
| 1705 | int nb_syms; | 1588 | /* STB_WEAK undefined symbols are accepted */ |
| 1706 | /* shared library case : we simply export all the global symbols */ | 1589 | /* XXX: _fp_hw seems to be part of the ABI, so we ignore it */ |
| 1707 | nb_syms = symtab_section->data_offset / sizeof(ElfW(Sym)); | 1590 | if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK || |
| 1708 | s1->symtab_to_dynsym = tcc_mallocz(sizeof(int) * nb_syms); | 1591 | !strcmp(name, "_fp_hw")) { |
| 1709 | for_each_elem(symtab_section, 1, sym, ElfW(Sym)) { | 1592 | } else { |
| 1710 | if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { | 1593 | tcc_error_noabort("undefined symbol '%s'", name); |
| 1711 | #if defined(TCC_OUTPUT_DLL_WITH_PLT) | ||
| 1712 | if ((ELFW(ST_TYPE)(sym->st_info) == STT_FUNC || | ||
| 1713 | ELFW(ST_TYPE)(sym->st_info) == STT_GNU_IFUNC) | ||
| 1714 | && sym->st_shndx == SHN_UNDEF) { | ||
| 1715 | int visibility = ELFW(ST_BIND)(sym->st_info); | ||
| 1716 | put_got_entry(s1, R_JMP_SLOT, sym->st_size, | ||
| 1717 | ELFW(ST_INFO)(visibility,STT_FUNC), | ||
| 1718 | sym - (ElfW(Sym) *)symtab_section->data); | ||
| 1719 | } | ||
| 1720 | else if (ELFW(ST_TYPE)(sym->st_info) == STT_OBJECT) { | ||
| 1721 | put_got_entry(s1, R_X86_64_GLOB_DAT, sym->st_size, | ||
| 1722 | sym->st_info, | ||
| 1723 | sym - (ElfW(Sym) *)symtab_section->data); | ||
| 1724 | } | ||
| 1725 | else | ||
| 1726 | #endif | ||
| 1727 | { | ||
| 1728 | name = symtab_section->link->data + sym->st_name; | ||
| 1729 | index = put_elf_sym(s1->dynsym, sym->st_value, sym->st_size, | ||
| 1730 | sym->st_info, 0, | ||
| 1731 | sym->st_shndx, name); | ||
| 1732 | s1->symtab_to_dynsym[sym - | ||
| 1733 | (ElfW(Sym) *)symtab_section->data] = | ||
| 1734 | index; | ||
| 1735 | } | ||
| 1736 | } | ||
| 1737 | } | 1594 | } |
| 1738 | } | 1595 | } |
| 1596 | } else if (s1->rdynamic && ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { | ||
| 1597 | /* if -rdynamic option, then export all non local symbols */ | ||
| 1598 | name = symtab_section->link->data + sym->st_name; | ||
| 1599 | put_elf_sym(s1->dynsym, sym->st_value, sym->st_size, sym->st_info, | ||
| 1600 | 0, sym->st_shndx, name); | ||
| 1601 | } | ||
| 1602 | } | ||
| 1603 | } | ||
| 1739 | 1604 | ||
| 1740 | build_got_entries(s1); | 1605 | /* Bind symbols of libraries: export non local symbols of executable that |
| 1606 | resolve undefined symbols of shared libraries */ | ||
| 1607 | static void bind_libs_dynsyms(TCCState *s1) | ||
| 1608 | { | ||
| 1609 | const char *name; | ||
| 1610 | int sym_index; | ||
| 1611 | ElfW(Sym) *sym, *esym; | ||
| 1741 | 1612 | ||
| 1742 | /* add a list of needed dlls */ | 1613 | /* now look at unresolved dynamic symbols and export |
| 1743 | for(i = 0; i < s1->nb_loaded_dlls; i++) { | 1614 | corresponding symbol */ |
| 1744 | DLLReference *dllref = s1->loaded_dlls[i]; | 1615 | for_each_elem(s1->dynsymtab_section, 1, esym, ElfW(Sym)) { |
| 1745 | if (dllref->level == 0) | 1616 | if (esym->st_shndx == SHN_UNDEF) { |
| 1746 | put_dt(dynamic, DT_NEEDED, put_elf_str(dynstr, dllref->name)); | 1617 | name = s1->dynsymtab_section->link->data + esym->st_name; |
| 1618 | sym_index = find_elf_sym(symtab_section, name); | ||
| 1619 | if (sym_index) { | ||
| 1620 | /* XXX: avoid adding a symbol if already present because of | ||
| 1621 | -rdynamic ? */ | ||
| 1622 | sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; | ||
| 1623 | put_elf_sym(s1->dynsym, sym->st_value, sym->st_size, | ||
| 1624 | sym->st_info, 0, sym->st_shndx, name); | ||
| 1625 | } else { | ||
| 1626 | /* weak symbols can stay undefined */ | ||
| 1627 | if (ELFW(ST_BIND)(esym->st_info) != STB_WEAK) | ||
| 1628 | tcc_warning("undefined dynamic symbol '%s'", name); | ||
| 1747 | } | 1629 | } |
| 1630 | } | ||
| 1631 | } | ||
| 1632 | } | ||
| 1748 | 1633 | ||
| 1749 | if (s1->rpath) | 1634 | /* Export all non local symbols (for shared libraries) */ |
| 1750 | put_dt(dynamic, DT_RPATH, put_elf_str(dynstr, s1->rpath)); | 1635 | static void export_global_syms(TCCState *s1) |
| 1636 | { | ||
| 1637 | int nb_syms, dynindex, index; | ||
| 1638 | const char *name; | ||
| 1639 | ElfW(Sym) *sym; | ||
| 1751 | 1640 | ||
| 1752 | /* XXX: currently, since we do not handle PIC code, we | 1641 | nb_syms = symtab_section->data_offset / sizeof(ElfW(Sym)); |
| 1753 | must relocate the readonly segments */ | 1642 | s1->symtab_to_dynsym = tcc_mallocz(sizeof(int) * nb_syms); |
| 1754 | if (file_type == TCC_OUTPUT_DLL) { | 1643 | for_each_elem(symtab_section, 1, sym, ElfW(Sym)) { |
| 1755 | if (s1->soname) | 1644 | if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { |
| 1756 | put_dt(dynamic, DT_SONAME, put_elf_str(dynstr, s1->soname)); | 1645 | #if defined(TCC_OUTPUT_DLL_WITH_PLT) |
| 1757 | put_dt(dynamic, DT_TEXTREL, 0); | 1646 | int type = ELFW(ST_TYPE)(sym->st_info); |
| 1647 | if ((type == STT_FUNC || type == STT_GNU_IFUNC) | ||
| 1648 | && sym->st_shndx == SHN_UNDEF) { | ||
| 1649 | int visibility = ELFW(ST_BIND)(sym->st_info); | ||
| 1650 | put_got_entry(s1, R_JMP_SLOT, sym->st_size, | ||
| 1651 | ELFW(ST_INFO)(visibility, STT_FUNC), | ||
| 1652 | sym - (ElfW(Sym) *) symtab_section->data); | ||
| 1653 | } else if (type == STT_OBJECT) { | ||
| 1654 | put_got_entry(s1, R_X86_64_GLOB_DAT, sym->st_size, sym->st_info, | ||
| 1655 | sym - (ElfW(Sym) *) symtab_section->data); | ||
| 1656 | } else | ||
| 1657 | #endif | ||
| 1658 | { | ||
| 1659 | name = symtab_section->link->data + sym->st_name; | ||
| 1660 | dynindex = put_elf_sym(s1->dynsym, sym->st_value, sym->st_size, | ||
| 1661 | sym->st_info, 0, sym->st_shndx, name); | ||
| 1662 | index = sym - (ElfW(Sym) *) symtab_section->data; | ||
| 1663 | s1->symtab_to_dynsym[index] = dynindex; | ||
| 1758 | } | 1664 | } |
| 1759 | |||
| 1760 | if (s1->symbolic) | ||
| 1761 | put_dt(dynamic, DT_SYMBOLIC, 0); | ||
| 1762 | |||
| 1763 | /* add necessary space for other entries */ | ||
| 1764 | saved_dynamic_data_offset = dynamic->data_offset; | ||
| 1765 | dynamic->data_offset += sizeof(ElfW(Dyn)) * EXTRA_RELITEMS; | ||
| 1766 | } else { | ||
| 1767 | /* still need to build got entries in case of static link */ | ||
| 1768 | build_got_entries(s1); | ||
| 1769 | } | 1665 | } |
| 1770 | } | 1666 | } |
| 1667 | } | ||
| 1771 | 1668 | ||
| 1772 | memset(&ehdr, 0, sizeof(ehdr)); | 1669 | /* relocate the PLT: compute addresses and offsets in the PLT now that final |
| 1773 | 1670 | address for PLT and GOT are known (see fill_program_header) */ | |
| 1774 | /* we add a section for symbols */ | 1671 | static void relocate_plt(TCCState *s1) |
| 1775 | strsec = new_section(s1, ".shstrtab", SHT_STRTAB, 0); | 1672 | { |
| 1776 | put_elf_str(strsec, ""); | 1673 | uint8_t *p, *p_end; |
| 1777 | 1674 | ||
| 1778 | /* compute number of sections */ | 1675 | p = s1->plt->data; |
| 1779 | shnum = s1->nb_sections; | 1676 | p_end = p + s1->plt->data_offset; |
| 1677 | if (p < p_end) { | ||
| 1678 | #if defined(TCC_TARGET_I386) | ||
| 1679 | put32(p + 2, get32(p + 2) + s1->got->sh_addr); | ||
| 1680 | put32(p + 8, get32(p + 8) + s1->got->sh_addr); | ||
| 1681 | p += 16; | ||
| 1682 | while (p < p_end) { | ||
| 1683 | put32(p + 2, get32(p + 2) + s1->got->sh_addr); | ||
| 1684 | p += 16; | ||
| 1685 | } | ||
| 1686 | #elif defined(TCC_TARGET_X86_64) | ||
| 1687 | int x = s1->got->sh_addr - s1->plt->sh_addr - 6; | ||
| 1688 | put32(p + 2, get32(p + 2) + x); | ||
| 1689 | put32(p + 8, get32(p + 8) + x - 6); | ||
| 1690 | p += 16; | ||
| 1691 | while (p < p_end) { | ||
| 1692 | put32(p + 2, get32(p + 2) + x + s1->plt->data - p); | ||
| 1693 | p += 16; | ||
| 1694 | } | ||
| 1695 | #elif defined(TCC_TARGET_ARM) | ||
| 1696 | int x; | ||
| 1697 | x=s1->got->sh_addr - s1->plt->sh_addr - 12; | ||
| 1698 | p += 16; | ||
| 1699 | while (p < p_end) { | ||
| 1700 | if (get32(p) == 0x46c04778) /* PLT Thumb stub present */ | ||
| 1701 | p += 4; | ||
| 1702 | put32(p + 12, x + get32(p + 12) + s1->plt->data - p); | ||
| 1703 | p += 16; | ||
| 1704 | } | ||
| 1705 | #elif defined(TCC_TARGET_C67) | ||
| 1706 | /* XXX: TODO */ | ||
| 1707 | #else | ||
| 1708 | #error unsupported CPU | ||
| 1709 | #endif | ||
| 1710 | } | ||
| 1711 | } | ||
| 1780 | 1712 | ||
| 1781 | /* this array is used to reorder sections in the output file */ | 1713 | /* Allocate strings for section names and decide if an unallocated section |
| 1782 | section_order = tcc_malloc(sizeof(int) * shnum); | 1714 | should be output. |
| 1783 | section_order[0] = 0; | ||
| 1784 | sh_order_index = 1; | ||
| 1785 | 1715 | ||
| 1786 | /* compute number of program headers */ | 1716 | NOTE: the strsec section comes last, so its size is also correct ! */ |
| 1787 | switch(file_type) { | 1717 | static void alloc_sec_names(TCCState *s1, int file_type, Section *strsec) |
| 1788 | default: | 1718 | { |
| 1789 | case TCC_OUTPUT_OBJ: | 1719 | int i; |
| 1790 | phnum = 0; | 1720 | Section *s; |
| 1791 | break; | ||
| 1792 | case TCC_OUTPUT_EXE: | ||
| 1793 | if (!s1->static_link) | ||
| 1794 | phnum = 4 + HAVE_PHDR; | ||
| 1795 | else | ||
| 1796 | phnum = 2; | ||
| 1797 | break; | ||
| 1798 | case TCC_OUTPUT_DLL: | ||
| 1799 | phnum = 3; | ||
| 1800 | break; | ||
| 1801 | } | ||
| 1802 | 1721 | ||
| 1803 | /* allocate strings for section names and decide if an unallocated | 1722 | /* Allocate strings for section names */ |
| 1804 | section should be output */ | ||
| 1805 | /* NOTE: the strsec section comes last, so its size is also | ||
| 1806 | correct ! */ | ||
| 1807 | for(i = 1; i < s1->nb_sections; i++) { | 1723 | for(i = 1; i < s1->nb_sections; i++) { |
| 1808 | s = s1->sections[i]; | 1724 | s = s1->sections[i]; |
| 1809 | s->sh_name = put_elf_str(strsec, s->name); | 1725 | s->sh_name = put_elf_str(strsec, s->name); |
| @@ -1825,17 +1741,41 @@ static int elf_output_file(TCCState *s1, const char *filename) · 15 unmodified lines | |||
| 1825 | s->sh_size = s->data_offset; | 1741 | s->sh_size = s->data_offset; |
| 1826 | } | 1742 | } |
| 1827 | } | 1743 | } |
| 1744 | } | ||
| 1828 | 1745 | ||
| 1829 | /* allocate program segment headers */ | 1746 | /* Info to be copied in dynamic section */ |
| 1830 | phdr = tcc_mallocz(phnum * sizeof(ElfW(Phdr))); | 1747 | struct dyn_inf { |
| 1748 | Section *dynamic; | ||
| 1749 | Section *dynstr; | ||
| 1750 | unsigned long dyn_rel_off; | ||
| 1751 | addr_t rel_addr; | ||
| 1752 | addr_t rel_size; | ||
| 1753 | #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) | ||
| 1754 | addr_t bss_addr; | ||
| 1755 | addr_t bss_size; | ||
| 1756 | #endif | ||
| 1757 | }; | ||
| 1758 | |||
| 1759 | /* Assign sections to segments and decide how are sections laid out when loaded | ||
| 1760 | in memory. This function also fills corresponding program headers. */ | ||
| 1761 | static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr, int phnum, | ||
| 1762 | Section *interp, struct dyn_inf *dyninf, | ||
| 1763 | int *sec_order) | ||
| 1764 | { | ||
| 1765 | int i, j, k, file_type, sh_order_index, file_offset; | ||
| 1766 | long long tmp; | ||
| 1767 | addr_t addr; | ||
| 1768 | ElfW(Phdr) *ph; | ||
| 1769 | Section *s; | ||
| 1831 | 1770 | ||
| 1832 | if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) { | 1771 | file_type = s1->output_type; |
| 1772 | sh_order_index = 1; | ||
| 1773 | if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) | ||
| 1833 | file_offset = sizeof(ElfW(Ehdr)) + phnum * sizeof(ElfW(Phdr)); | 1774 | file_offset = sizeof(ElfW(Ehdr)) + phnum * sizeof(ElfW(Phdr)); |
| 1834 | } else { | 1775 | else |
| 1835 | file_offset = 0; | 1776 | file_offset = 0; |
| 1836 | } | 1777 | |
| 1837 | if (phnum > 0) { | 1778 | if (phnum > 0) { |
| 1838 | /* compute section to program header mapping */ | ||
| 1839 | if (s1->has_text_addr) { | 1779 | if (s1->has_text_addr) { |
| 1840 | int a_offset, p_offset; | 1780 | int a_offset, p_offset; |
| 1841 | addr = s1->text_addr; | 1781 | addr = s1->text_addr; |
| @@ -1855,18 +1795,19 @@ static int elf_output_file(TCCState *s1, const char *filename) · 13 unmodified lines | |||
| 1855 | addr += (file_offset & (s1->section_align - 1)); | 1795 | addr += (file_offset & (s1->section_align - 1)); |
| 1856 | } | 1796 | } |
| 1857 | 1797 | ||
| 1858 | /* dynamic relocation table information, for .dynamic section */ | ||
| 1859 | rel_size = 0; | ||
| 1860 | rel_addr = 0; | ||
| 1861 | |||
| 1862 | #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) | ||
| 1863 | bss_addr = bss_size = 0; | ||
| 1864 | #endif | ||
| 1865 | /* leave one program header for the program interpreter */ | ||
| 1866 | ph = &phdr[0]; | 1798 | ph = &phdr[0]; |
| 1799 | /* Leave one program headers for the program interpreter and one for | ||
| 1800 | the program header table itself if needed. These are done later as | ||
| 1801 | they require section layout to be done first. */ | ||
| 1867 | if (interp) | 1802 | if (interp) |
| 1868 | ph += 1 + HAVE_PHDR; | 1803 | ph += 1 + HAVE_PHDR; |
| 1869 | 1804 | ||
| 1805 | /* dynamic relocation table information, for .dynamic section */ | ||
| 1806 | dyninf->rel_addr = dyninf->rel_size = 0; | ||
| 1807 | #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) | ||
| 1808 | dyninf->bss_addr = dyninf->bss_size = 0; | ||
| 1809 | #endif | ||
| 1810 | |||
| 1870 | for(j = 0; j < 2; j++) { | 1811 | for(j = 0; j < 2; j++) { |
| 1871 | ph->p_type = PT_LOAD; | 1812 | ph->p_type = PT_LOAD; |
| 1872 | if (j == 0) | 1813 | if (j == 0) |
| @@ -1875,8 +1816,10 @@ static int elf_output_file(TCCState *s1, const char *filename) · 2 unmodified lines | |||
| 1875 | ph->p_flags = PF_R | PF_W; | 1816 | ph->p_flags = PF_R | PF_W; |
| 1876 | ph->p_align = s1->section_align; | 1817 | ph->p_align = s1->section_align; |
| 1877 | 1818 | ||
| 1878 | /* we do the following ordering: interp, symbol tables, | 1819 | /* Decide the layout of sections loaded in memory. This must |
| 1879 | relocations, progbits, nobits */ | 1820 | be done before program headers are filled since they contain |
| 1821 | info about the layout. We do the following ordering: interp, | ||
| 1822 | symbol tables, relocations, progbits, nobits */ | ||
| 1880 | /* XXX: do faster and simpler sorting */ | 1823 | /* XXX: do faster and simpler sorting */ |
| 1881 | for(k = 0; k < 5; k++) { | 1824 | for(k = 0; k < 5; k++) { |
| 1882 | for(i = 1; i < s1->nb_sections; i++) { | 1825 | for(i = 1; i < s1->nb_sections; i++) { |
| @@ -1909,7 +1852,7 @@ static int elf_output_file(TCCState *s1, const char *filename) · 26 unmodified lines | |||
| 1909 | if (k != 3) | 1852 | if (k != 3) |
| 1910 | continue; | 1853 | continue; |
| 1911 | } | 1854 | } |
| 1912 | section_order[sh_order_index++] = i; | 1855 | sec_order[sh_order_index++] = i; |
| 1913 | 1856 | ||
| 1914 | /* section matches: we align it and add its size */ | 1857 | /* section matches: we align it and add its size */ |
| 1915 | tmp = addr; | 1858 | tmp = addr; |
| @@ -1929,17 +1872,17 @@ static int elf_output_file(TCCState *s1, const char *filename) · 13 unmodified lines | |||
| 1929 | if (s->sh_type == SHT_RELX) { | 1872 | if (s->sh_type == SHT_RELX) { |
| 1930 | #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) | 1873 | #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) |
| 1931 | if (!strcmp(strsec->data + s->sh_name, ".rel.got")) { | 1874 | if (!strcmp(strsec->data + s->sh_name, ".rel.got")) { |
| 1932 | rel_addr = addr; | 1875 | dyninf->rel_addr = addr; |
| 1933 | rel_size += s->sh_size; /* XXX only first rel. */ | 1876 | dyninf->rel_size += s->sh_size; /* XXX only first rel. */ |
| 1934 | } | 1877 | } |
| 1935 | if (!strcmp(strsec->data + s->sh_name, ".rel.bss")) { | 1878 | if (!strcmp(strsec->data + s->sh_name, ".rel.bss")) { |
| 1936 | bss_addr = addr; | 1879 | dyninf->bss_addr = addr; |
| 1937 | bss_size = s->sh_size; /* XXX only first rel. */ | 1880 | dyninf->bss_size = s->sh_size; /* XXX only first rel. */ |
| 1938 | } | 1881 | } |
| 1939 | #else | 1882 | #else |
| 1940 | if (rel_size == 0) | 1883 | if (dyninf->rel_size == 0) |
| 1941 | rel_addr = addr; | 1884 | dyninf->rel_addr = addr; |
| 1942 | rel_size += s->sh_size; | 1885 | dyninf->rel_size += s->sh_size; |
| 1943 | #endif | 1886 | #endif |
| 1944 | } | 1887 | } |
| 1945 | addr += s->sh_size; | 1888 | addr += s->sh_size; |
| @@ -1963,199 +1906,269 @@ static int elf_output_file(TCCState *s1, const char *filename) · 17 unmodified lines | |||
| 1963 | } | 1906 | } |
| 1964 | } | 1907 | } |
| 1965 | } | 1908 | } |
| 1909 | } | ||
| 1966 | 1910 | ||
| 1967 | /* if interpreter, then add corresponing program header */ | 1911 | /* all other sections come after */ |
| 1968 | if (interp) { | 1912 | for(i = 1; i < s1->nb_sections; i++) { |
| 1969 | ph = &phdr[0]; | 1913 | s = s1->sections[i]; |
| 1914 | if (phnum > 0 && (s->sh_flags & SHF_ALLOC)) | ||
| 1915 | continue; | ||
| 1916 | sec_order[sh_order_index++] = i; | ||
| 1970 | 1917 | ||
| 1971 | #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) | 1918 | file_offset = (file_offset + s->sh_addralign - 1) & |
| 1972 | { | 1919 | ~(s->sh_addralign - 1); |
| 1973 | int len = phnum * sizeof(ElfW(Phdr)); | 1920 | s->sh_offset = file_offset; |
| 1974 | 1921 | if (s->sh_type != SHT_NOBITS) | |
| 1975 | ph->p_type = PT_PHDR; | 1922 | file_offset += s->sh_size; |
| 1976 | ph->p_offset = sizeof(ElfW(Ehdr)); | 1923 | } |
| 1977 | ph->p_vaddr = interp->sh_addr - len; | ||
| 1978 | ph->p_paddr = ph->p_vaddr; | ||
| 1979 | ph->p_filesz = ph->p_memsz = len; | ||
| 1980 | ph->p_flags = PF_R | PF_X; | ||
| 1981 | ph->p_align = 4; /* interp->sh_addralign; */ | ||
| 1982 | ph++; | ||
| 1983 | } | ||
| 1984 | #endif | ||
| 1985 | 1924 | ||
| 1986 | ph->p_type = PT_INTERP; | 1925 | return file_offset; |
| 1987 | ph->p_offset = interp->sh_offset; | 1926 | } |
| 1988 | ph->p_vaddr = interp->sh_addr; | ||
| 1989 | ph->p_paddr = ph->p_vaddr; | ||
| 1990 | ph->p_filesz = interp->sh_size; | ||
| 1991 | ph->p_memsz = interp->sh_size; | ||
| 1992 | ph->p_flags = PF_R; | ||
| 1993 | ph->p_align = interp->sh_addralign; | ||
| 1994 | } | ||
| 1995 | 1927 | ||
| 1996 | /* if dynamic section, then add corresponing program header */ | 1928 | static void fill_unloadable_phdr(ElfW(Phdr) *phdr, int phnum, Section *interp, |
| 1997 | if (dynamic) { | 1929 | Section *dynamic) |
| 1998 | ph = &phdr[phnum - 1]; | 1930 | { |
| 1931 | ElfW(Phdr) *ph; | ||
| 1932 | |||
| 1933 | /* if interpreter, then add corresponding program header */ | ||
| 1934 | if (interp) { | ||
| 1935 | ph = &phdr[0]; | ||
| 1999 | 1936 | ||
| 2000 | ph->p_type = PT_DYNAMIC; | 1937 | if (HAVE_PHDR) |
| 2001 | ph->p_offset = dynamic->sh_offset; | 1938 | { |
| 2002 | ph->p_vaddr = dynamic->sh_addr; | 1939 | int len = phnum * sizeof(ElfW(Phdr)); |
| 1940 | |||
| 1941 | ph->p_type = PT_PHDR; | ||
| 1942 | ph->p_offset = sizeof(ElfW(Ehdr)); | ||
| 1943 | ph->p_vaddr = interp->sh_addr - len; | ||
| 2003 | ph->p_paddr = ph->p_vaddr; | 1944 | ph->p_paddr = ph->p_vaddr; |
| 2004 | ph->p_filesz = dynamic->sh_size; | 1945 | ph->p_filesz = ph->p_memsz = len; |
| 2005 | ph->p_memsz = dynamic->sh_size; | 1946 | ph->p_flags = PF_R | PF_X; |
| 2006 | ph->p_flags = PF_R | PF_W; | 1947 | ph->p_align = 4; /* interp->sh_addralign; */ |
| 2007 | ph->p_align = dynamic->sh_addralign; | 1948 | ph++; |
| 1949 | } | ||
| 2008 | 1950 | ||
| 2009 | /* put GOT dynamic section address */ | 1951 | ph->p_type = PT_INTERP; |
| 2010 | put32(s1->got->data, dynamic->sh_addr); | 1952 | ph->p_offset = interp->sh_offset; |
| 1953 | ph->p_vaddr = interp->sh_addr; | ||
| 1954 | ph->p_paddr = ph->p_vaddr; | ||
| 1955 | ph->p_filesz = interp->sh_size; | ||
| 1956 | ph->p_memsz = interp->sh_size; | ||
| 1957 | ph->p_flags = PF_R; | ||
| 1958 | ph->p_align = interp->sh_addralign; | ||
| 1959 | } | ||
| 2011 | 1960 | ||
| 2012 | /* relocate the PLT */ | 1961 | /* if dynamic section, then add corresponding program header */ |
| 2013 | if (file_type == TCC_OUTPUT_EXE | 1962 | if (dynamic) { |
| 2014 | #if defined(TCC_OUTPUT_DLL_WITH_PLT) | 1963 | ph = &phdr[phnum - 1]; |
| 2015 | || file_type == TCC_OUTPUT_DLL | 1964 | |
| 2016 | #endif | 1965 | ph->p_type = PT_DYNAMIC; |
| 2017 | ) { | 1966 | ph->p_offset = dynamic->sh_offset; |
| 2018 | uint8_t *p, *p_end; | 1967 | ph->p_vaddr = dynamic->sh_addr; |
| 1968 | ph->p_paddr = ph->p_vaddr; | ||
| 1969 | ph->p_filesz = dynamic->sh_size; | ||
| 1970 | ph->p_memsz = dynamic->sh_size; | ||
| 1971 | ph->p_flags = PF_R | PF_W; | ||
| 1972 | ph->p_align = dynamic->sh_addralign; | ||
| 1973 | } | ||
| 1974 | } | ||
| 2019 | 1975 | ||
| 2020 | p = s1->plt->data; | 1976 | /* Fill the dynamic section with tags describing the address and size of |
| 2021 | p_end = p + s1->plt->data_offset; | 1977 | sections */ |
| 2022 | if (p < p_end) { | 1978 | static void fill_dynamic(TCCState *s1, struct dyn_inf *dyninf) |
| 2023 | #if defined(TCC_TARGET_I386) | 1979 | { |
| 2024 | put32(p + 2, get32(p + 2) + s1->got->sh_addr); | 1980 | Section *dynamic; |
| 2025 | put32(p + 8, get32(p + 8) + s1->got->sh_addr); | ||
| 2026 | p += 16; | ||
| 2027 | while (p < p_end) { | ||
| 2028 | put32(p + 2, get32(p + 2) + s1->got->sh_addr); | ||
| 2029 | p += 16; | ||
| 2030 | } | ||
| 2031 | #elif defined(TCC_TARGET_X86_64) | ||
| 2032 | int x = s1->got->sh_addr - s1->plt->sh_addr - 6; | ||
| 2033 | put32(p + 2, get32(p + 2) + x); | ||
| 2034 | put32(p + 8, get32(p + 8) + x - 6); | ||
| 2035 | p += 16; | ||
| 2036 | while (p < p_end) { | ||
| 2037 | put32(p + 2, get32(p + 2) + x + s1->plt->data - p); | ||
| 2038 | p += 16; | ||
| 2039 | } | ||
| 2040 | #elif defined(TCC_TARGET_ARM) | ||
| 2041 | int x; | ||
| 2042 | x=s1->got->sh_addr - s1->plt->sh_addr - 12; | ||
| 2043 | p += 16; | ||
| 2044 | while (p < p_end) { | ||
| 2045 | if (get32(p) == 0x46c04778) /* PLT Thumb stub present */ | ||
| 2046 | p += 4; | ||
| 2047 | put32(p + 12, x + get32(p + 12) + s1->plt->data - p); | ||
| 2048 | p += 16; | ||
| 2049 | } | ||
| 2050 | #elif defined(TCC_TARGET_C67) | ||
| 2051 | /* XXX: TODO */ | ||
| 2052 | #else | ||
| 2053 | #error unsupported CPU | ||
| 2054 | #endif | ||
| 2055 | } | ||
| 2056 | } | ||
| 2057 | 1981 | ||
| 2058 | /* relocate symbols in .dynsym */ | 1982 | dynamic = dyninf->dynamic; |
| 2059 | for_each_elem(s1->dynsym, 1, sym, ElfW(Sym)) { | ||
| 2060 | if (sym->st_shndx == SHN_UNDEF) { | ||
| 2061 | /* relocate to the PLT if the symbol corresponds | ||
| 2062 | to a PLT entry */ | ||
| 2063 | if (sym->st_value) | ||
| 2064 | sym->st_value += s1->plt->sh_addr; | ||
| 2065 | } else if (sym->st_shndx < SHN_LORESERVE) { | ||
| 2066 | /* do symbol relocation */ | ||
| 2067 | sym->st_value += s1->sections[sym->st_shndx]->sh_addr; | ||
| 2068 | } | ||
| 2069 | } | ||
| 2070 | 1983 | ||
| 2071 | /* put dynamic section entries */ | 1984 | /* put dynamic section entries */ |
| 2072 | dynamic->data_offset = saved_dynamic_data_offset; | 1985 | dynamic->data_offset = dyninf->dyn_rel_off; |
| 2073 | put_dt(dynamic, DT_HASH, s1->dynsym->hash->sh_addr); | 1986 | put_dt(dynamic, DT_HASH, s1->dynsym->hash->sh_addr); |
| 2074 | put_dt(dynamic, DT_STRTAB, dynstr->sh_addr); | 1987 | put_dt(dynamic, DT_STRTAB, dyninf->dynstr->sh_addr); |
| 2075 | put_dt(dynamic, DT_SYMTAB, s1->dynsym->sh_addr); | 1988 | put_dt(dynamic, DT_SYMTAB, s1->dynsym->sh_addr); |
| 2076 | put_dt(dynamic, DT_STRSZ, dynstr->data_offset); | 1989 | put_dt(dynamic, DT_STRSZ, dyninf->dynstr->data_offset); |
| 2077 | put_dt(dynamic, DT_SYMENT, sizeof(ElfW(Sym))); | 1990 | put_dt(dynamic, DT_SYMENT, sizeof(ElfW(Sym))); |
| 2078 | #ifdef TCC_TARGET_X86_64 | 1991 | #ifdef TCC_TARGET_X86_64 |
| 2079 | put_dt(dynamic, DT_RELA, rel_addr); | 1992 | put_dt(dynamic, DT_RELA, dyninf->rel_addr); |
| 2080 | put_dt(dynamic, DT_RELASZ, rel_size); | 1993 | put_dt(dynamic, DT_RELASZ, dyninf->rel_size); |
| 2081 | put_dt(dynamic, DT_RELAENT, sizeof(ElfW_Rel)); | 1994 | put_dt(dynamic, DT_RELAENT, sizeof(ElfW_Rel)); |
| 2082 | #else | 1995 | #else |
| 2083 | #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) | 1996 | #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) |
| 2084 | put_dt(dynamic, DT_PLTGOT, s1->got->sh_addr); | 1997 | put_dt(dynamic, DT_PLTGOT, s1->got->sh_addr); |
| 2085 | put_dt(dynamic, DT_PLTRELSZ, rel_size); | 1998 | put_dt(dynamic, DT_PLTRELSZ, dyninf->rel_size); |
| 2086 | put_dt(dynamic, DT_JMPREL, rel_addr); | 1999 | put_dt(dynamic, DT_JMPREL, dyninf->rel_addr); |
| 2087 | put_dt(dynamic, DT_PLTREL, DT_REL); | 2000 | put_dt(dynamic, DT_PLTREL, DT_REL); |
| 2088 | put_dt(dynamic, DT_REL, bss_addr); | 2001 | put_dt(dynamic, DT_REL, dyninf->bss_addr); |
| 2089 | put_dt(dynamic, DT_RELSZ, bss_size); | 2002 | put_dt(dynamic, DT_RELSZ, dyninf->bss_size); |
| 2090 | #else | 2003 | #else |
| 2091 | put_dt(dynamic, DT_REL, rel_addr); | 2004 | put_dt(dynamic, DT_REL, dyninf->rel_addr); |
| 2092 | put_dt(dynamic, DT_RELSZ, rel_size); | 2005 | put_dt(dynamic, DT_RELSZ, dyninf->rel_size); |
| 2093 | put_dt(dynamic, DT_RELENT, sizeof(ElfW_Rel)); | 2006 | put_dt(dynamic, DT_RELENT, sizeof(ElfW_Rel)); |
| 2094 | #endif | 2007 | #endif |
| 2095 | #endif | 2008 | #endif |
| 2096 | if (s1->do_debug) | 2009 | if (s1->do_debug) |
| 2097 | put_dt(dynamic, DT_DEBUG, 0); | 2010 | put_dt(dynamic, DT_DEBUG, 0); |
| 2098 | put_dt(dynamic, DT_NULL, 0); | 2011 | put_dt(dynamic, DT_NULL, 0); |
| 2099 | } | 2012 | } |
| 2100 | 2013 | ||
| 2101 | ehdr.e_phentsize = sizeof(ElfW(Phdr)); | 2014 | /* Relocate remaining sections and symbols (that is those not related to |
| 2102 | ehdr.e_phnum = phnum; | 2015 | dynamic linking) */ |
| 2103 | ehdr.e_phoff = sizeof(ElfW(Ehdr)); | 2016 | static int final_sections_reloc(TCCState *s1) |
| 2104 | } | 2017 | { |
| 2018 | int i; | ||
| 2019 | Section *s; | ||
| 2105 | 2020 | ||
| 2106 | /* all other sections come after */ | 2021 | relocate_syms(s1, 0); |
| 2022 | |||
| 2023 | if (s1->nb_errors != 0) | ||
| 2024 | return -1; | ||
| 2025 | |||
| 2026 | /* relocate sections */ | ||
| 2027 | /* XXX: ignore sections with allocated relocations ? */ | ||
| 2107 | for(i = 1; i < s1->nb_sections; i++) { | 2028 | for(i = 1; i < s1->nb_sections; i++) { |
| 2108 | s = s1->sections[i]; | 2029 | s = s1->sections[i]; |
| 2109 | if (phnum > 0 && (s->sh_flags & SHF_ALLOC)) | 2030 | if (s->reloc && s != s1->got) |
| 2110 | continue; | 2031 | relocate_section(s1, s); |
| 2111 | section_order[sh_order_index++] = i; | 2032 | } |
| 2112 | 2033 | ||
| 2113 | file_offset = (file_offset + s->sh_addralign - 1) & | 2034 | /* relocate relocation entries if the relocation tables are |
| 2114 | ~(s->sh_addralign - 1); | 2035 | allocated in the executable */ |
| 2115 | s->sh_offset = file_offset; | 2036 | for(i = 1; i < s1->nb_sections; i++) { |
| 2116 | if (s->sh_type != SHT_NOBITS) | 2037 | s = s1->sections[i]; |
| 2117 | file_offset += s->sh_size; | 2038 | if ((s->sh_flags & SHF_ALLOC) && |
| 2039 | s->sh_type == SHT_RELX) { | ||
| 2040 | relocate_rel(s1, s); | ||
| 2041 | } | ||
| 2118 | } | 2042 | } |
| 2043 | return 0; | ||
| 2044 | } | ||
| 2119 | 2045 | ||
| 2120 | /* if building executable or DLL, then relocate each section | 2046 | /* Create an ELF file on disk. |
| 2121 | except the GOT which is already relocated */ | 2047 | This function handle ELF specific layout requirements */ |
| 2122 | if (file_type != TCC_OUTPUT_OBJ) { | 2048 | static void tcc_output_elf(TCCState *s1, FILE *f, int phnum, ElfW(Phdr) *phdr, |
| 2123 | relocate_syms(s1, 0); | 2049 | int file_offset, int *sec_order) |
| 2050 | { | ||
| 2051 | int i, shnum, offset, size, file_type; | ||
| 2052 | Section *s; | ||
| 2053 | ElfW(Ehdr) ehdr; | ||
| 2054 | ElfW(Shdr) shdr, *sh; | ||
| 2124 | 2055 | ||
| 2125 | if (s1->nb_errors != 0) { | 2056 | file_type = s1->output_type; |
| 2126 | fail: | 2057 | shnum = s1->nb_sections; |
| 2127 | ret = -1; | ||
| 2128 | goto the_end; | ||
| 2129 | } | ||
| 2130 | 2058 | ||
| 2131 | /* relocate sections */ | 2059 | memset(&ehdr, 0, sizeof(ehdr)); |
| 2132 | /* XXX: ignore sections with allocated relocations ? */ | 2060 | |
| 2133 | for(i = 1; i < s1->nb_sections; i++) { | 2061 | if (phnum > 0) { |
| 2134 | s = s1->sections[i]; | 2062 | ehdr.e_phentsize = sizeof(ElfW(Phdr)); |
| 2135 | if (s->reloc && s != s1->got) | 2063 | ehdr.e_phnum = phnum; |
| 2136 | relocate_section(s1, s); | 2064 | ehdr.e_phoff = sizeof(ElfW(Ehdr)); |
| 2137 | } | 2065 | } |
| 2138 | 2066 | ||
| 2139 | /* relocate relocation entries if the relocation tables are | 2067 | /* align to 4 */ |
| 2140 | allocated in the executable */ | 2068 | file_offset = (file_offset + 3) & -4; |
| 2141 | for(i = 1; i < s1->nb_sections; i++) { | 2069 | |
| 2142 | s = s1->sections[i]; | 2070 | /* fill header */ |
| 2143 | if ((s->sh_flags & SHF_ALLOC) && | 2071 | ehdr.e_ident[0] = ELFMAG0; |
| 2144 | s->sh_type == SHT_RELX) { | 2072 | ehdr.e_ident[1] = ELFMAG1; |
| 2145 | relocate_rel(s1, s); | 2073 | ehdr.e_ident[2] = ELFMAG2; |
| 2074 | ehdr.e_ident[3] = ELFMAG3; | ||
| 2075 | ehdr.e_ident[4] = ELFCLASSW; | ||
| 2076 | ehdr.e_ident[5] = ELFDATA2LSB; | ||
| 2077 | ehdr.e_ident[6] = EV_CURRENT; | ||
| 2078 | #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) | ||
| 2079 | ehdr.e_ident[EI_OSABI] = ELFOSABI_FREEBSD; | ||
| 2080 | #endif | ||
| 2081 | #ifdef TCC_TARGET_ARM | ||
| 2082 | #ifdef TCC_ARM_EABI | ||
| 2083 | ehdr.e_ident[EI_OSABI] = 0; | ||
| 2084 | ehdr.e_flags = EF_ARM_EABI_VER4; | ||
| 2085 | if (file_type == TCC_OUTPUT_EXE || file_type == TCC_OUTPUT_DLL) | ||
| 2086 | ehdr.e_flags |= EF_ARM_HASENTRY; | ||
| 2087 | if (s1->float_abi == ARM_HARD_FLOAT) | ||
| 2088 | ehdr.e_flags |= EF_ARM_VFP_FLOAT; | ||
| 2089 | else | ||
| 2090 | ehdr.e_flags |= EF_ARM_SOFT_FLOAT; | ||
| 2091 | #else | ||
| 2092 | ehdr.e_ident[EI_OSABI] = ELFOSABI_ARM; | ||
| 2093 | #endif | ||
| 2094 | #endif | ||
| 2095 | switch(file_type) { | ||
| 2096 | default: | ||
| 2097 | case TCC_OUTPUT_EXE: | ||
| 2098 | ehdr.e_type = ET_EXEC; | ||
| 2099 | ehdr.e_entry = get_elf_sym_addr(s1, "_start", 1); | ||
| 2100 | break; | ||
| 2101 | case TCC_OUTPUT_DLL: | ||
| 2102 | ehdr.e_type = ET_DYN; | ||
| 2103 | ehdr.e_entry = text_section->sh_addr; /* XXX: is it correct ? */ | ||
| 2104 | break; | ||
| 2105 | case TCC_OUTPUT_OBJ: | ||
| 2106 | ehdr.e_type = ET_REL; | ||
| 2107 | break; | ||
| 2108 | } | ||
| 2109 | ehdr.e_machine = EM_TCC_TARGET; | ||
| 2110 | ehdr.e_version = EV_CURRENT; | ||
| 2111 | ehdr.e_shoff = file_offset; | ||
| 2112 | ehdr.e_ehsize = sizeof(ElfW(Ehdr)); | ||
| 2113 | ehdr.e_shentsize = sizeof(ElfW(Shdr)); | ||
| 2114 | ehdr.e_shnum = shnum; | ||
| 2115 | ehdr.e_shstrndx = shnum - 1; | ||
| 2116 | |||
| 2117 | fwrite(&ehdr, 1, sizeof(ElfW(Ehdr)), f); | ||
| 2118 | fwrite(phdr, 1, phnum * sizeof(ElfW(Phdr)), f); | ||
| 2119 | offset = sizeof(ElfW(Ehdr)) + phnum * sizeof(ElfW(Phdr)); | ||
| 2120 | |||
| 2121 | sort_syms(s1, symtab_section); | ||
| 2122 | for(i = 1; i < s1->nb_sections; i++) { | ||
| 2123 | s = s1->sections[sec_order[i]]; | ||
| 2124 | if (s->sh_type != SHT_NOBITS) { | ||
| 2125 | if (s->sh_type == SHT_DYNSYM) | ||
| 2126 | patch_dynsym_undef(s1, s); | ||
| 2127 | while (offset < s->sh_offset) { | ||
| 2128 | fputc(0, f); | ||
| 2129 | offset++; | ||
| 2146 | } | 2130 | } |
| 2131 | size = s->sh_size; | ||
| 2132 | fwrite(s->data, 1, size, f); | ||
| 2133 | offset += size; | ||
| 2147 | } | 2134 | } |
| 2135 | } | ||
| 2148 | 2136 | ||
| 2149 | /* get entry point address */ | 2137 | /* output section headers */ |
| 2150 | if (file_type == TCC_OUTPUT_EXE) | 2138 | while (offset < ehdr.e_shoff) { |
| 2151 | ehdr.e_entry = get_elf_sym_addr(s1, "_start", 1); | 2139 | fputc(0, f); |
| 2152 | else | 2140 | offset++; |
| 2153 | ehdr.e_entry = text_section->sh_addr; /* XXX: is it correct ? */ | ||
| 2154 | } | 2141 | } |
| 2155 | if (file_type == TCC_OUTPUT_EXE && s1->static_link) | ||
| 2156 | fill_got(s1); | ||
| 2157 | 2142 | ||
| 2158 | /* write elf file */ | 2143 | for(i = 0; i < s1->nb_sections; i++) { |
| 2144 | sh = &shdr; | ||
| 2145 | memset(sh, 0, sizeof(ElfW(Shdr))); | ||
| 2146 | s = s1->sections[i]; | ||
| 2147 | if (s) { | ||
| 2148 | sh->sh_name = s->sh_name; | ||
| 2149 | sh->sh_type = s->sh_type; | ||
| 2150 | sh->sh_flags = s->sh_flags; | ||
| 2151 | sh->sh_entsize = s->sh_entsize; | ||
| 2152 | sh->sh_info = s->sh_info; | ||
| 2153 | if (s->link) | ||
| 2154 | sh->sh_link = s->link->sh_num; | ||
| 2155 | sh->sh_addralign = s->sh_addralign; | ||
| 2156 | sh->sh_addr = s->sh_addr; | ||
| 2157 | sh->sh_offset = s->sh_offset; | ||
| 2158 | sh->sh_size = s->sh_size; | ||
| 2159 | } | ||
| 2160 | fwrite(sh, 1, sizeof(ElfW(Shdr)), f); | ||
| 2161 | } | ||
| 2162 | } | ||
| 2163 | |||
| 2164 | /* Write an elf, coff or "binary" file */ | ||
| 2165 | static int tcc_write_elf_file(TCCState *s1, const char *filename, int phnum, | ||
| 2166 | ElfW(Phdr) *phdr, int file_offset, int *sec_order) | ||
| 2167 | { | ||
| 2168 | int fd, mode, file_type; | ||
| 2169 | FILE *f; | ||
| 2170 | |||
| 2171 | file_type = s1->output_type; | ||
| 2159 | if (file_type == TCC_OUTPUT_OBJ) | 2172 | if (file_type == TCC_OUTPUT_OBJ) |
| 2160 | mode = 0666; | 2173 | mode = 0666; |
| 2161 | else | 2174 | else |
| @@ -2164,121 +2177,218 @@ static int elf_output_file(TCCState *s1, const char *filename) · 2 unmodified lines | |||
| 2164 | fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, mode); | 2177 | fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, mode); |
| 2165 | if (fd < 0) { | 2178 | if (fd < 0) { |
| 2166 | tcc_error_noabort("could not write '%s'", filename); | 2179 | tcc_error_noabort("could not write '%s'", filename); |
| 2167 | goto fail; | 2180 | return -1; |
| 2168 | } | 2181 | } |
| 2169 | f = fdopen(fd, "wb"); | 2182 | f = fdopen(fd, "wb"); |
| 2170 | if (s1->verbose) | 2183 | if (s1->verbose) |
| 2171 | printf("<- %s\n", filename); | 2184 | printf("<- %s\n", filename); |
| 2172 | 2185 | ||
| 2173 | #ifdef TCC_TARGET_COFF | 2186 | #ifdef TCC_TARGET_COFF |
| 2174 | if (s1->output_format == TCC_OUTPUT_FORMAT_COFF) { | 2187 | if (s1->output_format == TCC_OUTPUT_FORMAT_COFF) |
| 2175 | tcc_output_coff(s1, f); | 2188 | tcc_output_coff(s1, f); |
| 2176 | } else | 2189 | else |
| 2177 | #endif | ||
| 2178 | if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) { | ||
| 2179 | sort_syms(s1, symtab_section); | ||
| 2180 | |||
| 2181 | /* align to 4 */ | ||
| 2182 | file_offset = (file_offset + 3) & -4; | ||
| 2183 | |||
| 2184 | /* fill header */ | ||
| 2185 | ehdr.e_ident[0] = ELFMAG0; | ||
| 2186 | ehdr.e_ident[1] = ELFMAG1; | ||
| 2187 | ehdr.e_ident[2] = ELFMAG2; | ||
| 2188 | ehdr.e_ident[3] = ELFMAG3; | ||
| 2189 | ehdr.e_ident[4] = ELFCLASSW; | ||
| 2190 | ehdr.e_ident[5] = ELFDATA2LSB; | ||
| 2191 | ehdr.e_ident[6] = EV_CURRENT; | ||
| 2192 | #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) | ||
| 2193 | ehdr.e_ident[EI_OSABI] = ELFOSABI_FREEBSD; | ||
| 2194 | #endif | ||
| 2195 | #ifdef TCC_TARGET_ARM | ||
| 2196 | #ifdef TCC_ARM_EABI | ||
| 2197 | ehdr.e_ident[EI_OSABI] = 0; | ||
| 2198 | ehdr.e_flags = EF_ARM_EABI_VER4; | ||
| 2199 | if (file_type == TCC_OUTPUT_EXE || file_type == TCC_OUTPUT_DLL) | ||
| 2200 | ehdr.e_flags |= EF_ARM_HASENTRY; | ||
| 2201 | if (s1->float_abi == ARM_HARD_FLOAT) | ||
| 2202 | ehdr.e_flags |= EF_ARM_VFP_FLOAT; | ||
| 2203 | else | ||
| 2204 | ehdr.e_flags |= EF_ARM_SOFT_FLOAT; | ||
| 2205 | #else | ||
| 2206 | ehdr.e_ident[EI_OSABI] = ELFOSABI_ARM; | ||
| 2207 | #endif | ||
| 2208 | #endif | 2190 | #endif |
| 2209 | switch(file_type) { | 2191 | if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) |
| 2210 | default: | 2192 | tcc_output_elf(s1, f, phnum, phdr, file_offset, sec_order); |
| 2211 | case TCC_OUTPUT_EXE: | 2193 | else |
| 2212 | ehdr.e_type = ET_EXEC; | 2194 | tcc_output_binary(s1, f, sec_order); |
| 2213 | break; | 2195 | fclose(f); |
| 2214 | case TCC_OUTPUT_DLL: | 2196 | |
| 2215 | ehdr.e_type = ET_DYN; | 2197 | return 0; |
| 2216 | break; | 2198 | } |
| 2217 | case TCC_OUTPUT_OBJ: | 2199 | |
| 2218 | ehdr.e_type = ET_REL; | 2200 | /* Output an elf, coff or binary file */ |
| 2219 | break; | 2201 | /* XXX: suppress unneeded sections */ |
| 2220 | } | 2202 | static int elf_output_file(TCCState *s1, const char *filename) |
| 2221 | ehdr.e_machine = EM_TCC_TARGET; | 2203 | { |
| 2222 | ehdr.e_version = EV_CURRENT; | 2204 | int i, ret, phnum, shnum, file_type, file_offset, *sec_order; |
| 2223 | ehdr.e_shoff = file_offset; | 2205 | struct dyn_inf dyninf; |
| 2224 | ehdr.e_ehsize = sizeof(ElfW(Ehdr)); | 2206 | ElfW(Phdr) *phdr; |
| 2225 | ehdr.e_shentsize = sizeof(ElfW(Shdr)); | 2207 | ElfW(Sym) *sym; |
| 2226 | ehdr.e_shnum = shnum; | 2208 | Section *strsec, *interp, *dynamic, *dynstr; |
| 2227 | ehdr.e_shstrndx = shnum - 1; | 2209 | |
| 2228 | 2210 | file_type = s1->output_type; | |
| 2229 | fwrite(&ehdr, 1, sizeof(ElfW(Ehdr)), f); | 2211 | s1->nb_errors = 0; |
| 2230 | fwrite(phdr, 1, phnum * sizeof(ElfW(Phdr)), f); | 2212 | |
| 2231 | offset = sizeof(ElfW(Ehdr)) + phnum * sizeof(ElfW(Phdr)); | 2213 | /* if linking, also link in runtime libraries (libc, libgcc, etc.) */ |
| 2232 | 2214 | if (file_type != TCC_OUTPUT_OBJ) { | |
| 2233 | for(i=1;i<s1->nb_sections;i++) { | 2215 | tcc_add_runtime(s1); |
| 2234 | s = s1->sections[section_order[i]]; | 2216 | } |
| 2235 | if (s->sh_type != SHT_NOBITS) { | 2217 | |
| 2236 | if (s->sh_type == SHT_DYNSYM) | 2218 | phdr = NULL; |
| 2237 | patch_dynsym_undef(s1, s); | 2219 | sec_order = NULL; |
| 2238 | while (offset < s->sh_offset) { | 2220 | interp = dynamic = dynstr = NULL; /* avoid warning */ |
| 2239 | fputc(0, f); | 2221 | dyninf.dyn_rel_off = 0; /* avoid warning */ |
| 2240 | offset++; | 2222 | |
| 2223 | if (file_type != TCC_OUTPUT_OBJ) { | ||
| 2224 | relocate_common_syms(); | ||
| 2225 | |||
| 2226 | tcc_add_linker_symbols(s1); | ||
| 2227 | |||
| 2228 | if (!s1->static_link) { | ||
| 2229 | if (file_type == TCC_OUTPUT_EXE) { | ||
| 2230 | char *ptr; | ||
| 2231 | /* allow override the dynamic loader */ | ||
| 2232 | const char *elfint = getenv("LD_SO"); | ||
| 2233 | if (elfint == NULL) | ||
| 2234 | elfint = DEFAULT_ELFINTERP(s1); | ||
| 2235 | /* add interpreter section only if executable */ | ||
| 2236 | interp = new_section(s1, ".interp", SHT_PROGBITS, SHF_ALLOC); | ||
| 2237 | interp->sh_addralign = 1; | ||
| 2238 | ptr = section_ptr_add(interp, 1 + strlen(elfint)); | ||
| 2239 | strcpy(ptr, elfint); | ||
| 2240 | } | ||
| 2241 | |||
| 2242 | /* add dynamic symbol table */ | ||
| 2243 | s1->dynsym = new_symtab(s1, ".dynsym", SHT_DYNSYM, SHF_ALLOC, | ||
| 2244 | ".dynstr", | ||
| 2245 | ".hash", SHF_ALLOC); | ||
| 2246 | dynstr = s1->dynsym->link; | ||
| 2247 | |||
| 2248 | /* add dynamic section */ | ||
| 2249 | dynamic = new_section(s1, ".dynamic", SHT_DYNAMIC, | ||
| 2250 | SHF_ALLOC | SHF_WRITE); | ||
| 2251 | dynamic->link = dynstr; | ||
| 2252 | dynamic->sh_entsize = sizeof(ElfW(Dyn)); | ||
| 2253 | |||
| 2254 | /* add PLT */ | ||
| 2255 | s1->plt = new_section(s1, ".plt", SHT_PROGBITS, | ||
| 2256 | SHF_ALLOC | SHF_EXECINSTR); | ||
| 2257 | s1->plt->sh_entsize = 4; | ||
| 2258 | |||
| 2259 | build_got(s1); | ||
| 2260 | |||
| 2261 | if (file_type == TCC_OUTPUT_EXE) { | ||
| 2262 | bind_exe_dynsyms(s1); | ||
| 2263 | |||
| 2264 | if (s1->nb_errors) { | ||
| 2265 | ret = -1; | ||
| 2266 | goto the_end; | ||
| 2241 | } | 2267 | } |
| 2242 | size = s->sh_size; | 2268 | |
| 2243 | fwrite(s->data, 1, size, f); | 2269 | bind_libs_dynsyms(s1); |
| 2244 | offset += size; | 2270 | } else /* shared library case: simply export all global symbols */ |
| 2271 | export_global_syms(s1); | ||
| 2272 | |||
| 2273 | build_got_entries(s1); | ||
| 2274 | |||
| 2275 | /* add a list of needed dlls */ | ||
| 2276 | for(i = 0; i < s1->nb_loaded_dlls; i++) { | ||
| 2277 | DLLReference *dllref = s1->loaded_dlls[i]; | ||
| 2278 | if (dllref->level == 0) | ||
| 2279 | put_dt(dynamic, DT_NEEDED, put_elf_str(dynstr, dllref->name)); | ||
| 2245 | } | 2280 | } |
| 2246 | } | ||
| 2247 | 2281 | ||
| 2248 | /* output section headers */ | 2282 | if (s1->rpath) |
| 2249 | while (offset < ehdr.e_shoff) { | 2283 | put_dt(dynamic, DT_RPATH, put_elf_str(dynstr, s1->rpath)); |
| 2250 | fputc(0, f); | 2284 | |
| 2251 | offset++; | 2285 | /* XXX: currently, since we do not handle PIC code, we |
| 2286 | must relocate the readonly segments */ | ||
| 2287 | if (file_type == TCC_OUTPUT_DLL) { | ||
| 2288 | if (s1->soname) | ||
| 2289 | put_dt(dynamic, DT_SONAME, put_elf_str(dynstr, s1->soname)); | ||
| 2290 | put_dt(dynamic, DT_TEXTREL, 0); | ||
| 2291 | } | ||
| 2292 | |||
| 2293 | if (s1->symbolic) | ||
| 2294 | put_dt(dynamic, DT_SYMBOLIC, 0); | ||
| 2295 | |||
| 2296 | /* add necessary space for other entries */ | ||
| 2297 | dyninf.dyn_rel_off = dynamic->data_offset; | ||
| 2298 | dynamic->data_offset += sizeof(ElfW(Dyn)) * EXTRA_RELITEMS; | ||
| 2299 | } else { | ||
| 2300 | /* still need to build got entries in case of static link */ | ||
| 2301 | build_got_entries(s1); | ||
| 2252 | } | 2302 | } |
| 2303 | } | ||
| 2253 | 2304 | ||
| 2254 | for(i=0;i<s1->nb_sections;i++) { | 2305 | /* we add a section for symbols */ |
| 2255 | sh = &shdr; | 2306 | strsec = new_section(s1, ".shstrtab", SHT_STRTAB, 0); |
| 2256 | memset(sh, 0, sizeof(ElfW(Shdr))); | 2307 | put_elf_str(strsec, ""); |
| 2257 | s = s1->sections[i]; | 2308 | |
| 2258 | if (s) { | 2309 | /* compute number of sections */ |
| 2259 | sh->sh_name = s->sh_name; | 2310 | shnum = s1->nb_sections; |
| 2260 | sh->sh_type = s->sh_type; | 2311 | |
| 2261 | sh->sh_flags = s->sh_flags; | 2312 | /* this array is used to reorder sections in the output file */ |
| 2262 | sh->sh_entsize = s->sh_entsize; | 2313 | sec_order = tcc_malloc(sizeof(int) * shnum); |
| 2263 | sh->sh_info = s->sh_info; | 2314 | sec_order[0] = 0; |
| 2264 | if (s->link) | 2315 | |
| 2265 | sh->sh_link = s->link->sh_num; | 2316 | /* compute number of program headers */ |
| 2266 | sh->sh_addralign = s->sh_addralign; | 2317 | switch(file_type) { |
| 2267 | sh->sh_addr = s->sh_addr; | 2318 | default: |
| 2268 | sh->sh_offset = s->sh_offset; | 2319 | case TCC_OUTPUT_OBJ: |
| 2269 | sh->sh_size = s->sh_size; | 2320 | phnum = 0; |
| 2321 | break; | ||
| 2322 | case TCC_OUTPUT_EXE: | ||
| 2323 | if (!s1->static_link) | ||
| 2324 | phnum = 4 + HAVE_PHDR; | ||
| 2325 | else | ||
| 2326 | phnum = 2; | ||
| 2327 | break; | ||
| 2328 | case TCC_OUTPUT_DLL: | ||
| 2329 | phnum = 3; | ||
| 2330 | break; | ||
| 2331 | } | ||
| 2332 | |||
| 2333 | /* Allocate strings for section names */ | ||
| 2334 | alloc_sec_names(s1, file_type, strsec); | ||
| 2335 | |||
| 2336 | /* allocate program segment headers */ | ||
| 2337 | phdr = tcc_mallocz(phnum * sizeof(ElfW(Phdr))); | ||
| 2338 | |||
| 2339 | /* compute section to program header mapping */ | ||
| 2340 | file_offset = layout_sections(s1, phdr, phnum, interp, &dyninf, sec_order); | ||
| 2341 | |||
| 2342 | /* Fill remaining program header and finalize relocation related to dynamic | ||
| 2343 | linking. */ | ||
| 2344 | if (phnum > 0) { | ||
| 2345 | fill_unloadable_phdr(phdr, phnum, interp, dynamic); | ||
| 2346 | if (dynamic) { | ||
| 2347 | dyninf.dynamic = dynamic; | ||
| 2348 | dyninf.dynstr = dynstr; | ||
| 2349 | |||
| 2350 | fill_dynamic(s1, &dyninf); | ||
| 2351 | |||
| 2352 | /* put in GOT the dynamic section address and relocate PLT */ | ||
| 2353 | put32(s1->got->data, dynamic->sh_addr); | ||
| 2354 | if (file_type == TCC_OUTPUT_EXE | ||
| 2355 | #if defined(TCC_OUTPUT_DLL_WITH_PLT) | ||
| 2356 | || file_type == TCC_OUTPUT_DLL | ||
| 2357 | #endif | ||
| 2358 | ) | ||
| 2359 | relocate_plt(s1); | ||
| 2360 | |||
| 2361 | /* relocate symbols in .dynsym now that final addresses are known */ | ||
| 2362 | for_each_elem(s1->dynsym, 1, sym, ElfW(Sym)) { | ||
| 2363 | /* relocate to PLT if symbol corresponds to a PLT entry */ | ||
| 2364 | if (sym->st_shndx == SHN_UNDEF) { | ||
| 2365 | if (sym->st_value) | ||
| 2366 | sym->st_value += s1->plt->sh_addr; | ||
| 2367 | } else if (sym->st_shndx < SHN_LORESERVE) { | ||
| 2368 | /* do symbol relocation */ | ||
| 2369 | sym->st_value += s1->sections[sym->st_shndx]->sh_addr; | ||
| 2370 | } | ||
| 2270 | } | 2371 | } |
| 2271 | fwrite(sh, 1, sizeof(ElfW(Shdr)), f); | ||
| 2272 | } | 2372 | } |
| 2273 | } else { | ||
| 2274 | tcc_output_binary(s1, f, section_order); | ||
| 2275 | } | 2373 | } |
| 2276 | fclose(f); | ||
| 2277 | 2374 | ||
| 2278 | ret = 0; | 2375 | /* if building executable or DLL, then relocate each section |
| 2376 | except the GOT which is already relocated */ | ||
| 2377 | if (file_type != TCC_OUTPUT_OBJ) { | ||
| 2378 | ret = final_sections_reloc(s1); | ||
| 2379 | if (ret) | ||
| 2380 | goto the_end; | ||
| 2381 | } | ||
| 2382 | |||
| 2383 | /* Perform relocation to GOT or PLT entries */ | ||
| 2384 | if (file_type == TCC_OUTPUT_EXE && s1->static_link) | ||
| 2385 | fill_got(s1); | ||
| 2386 | |||
| 2387 | /* Create the ELF file with name 'filename' */ | ||
| 2388 | ret = tcc_write_elf_file(s1, filename, phnum, phdr, file_offset, sec_order); | ||
| 2279 | the_end: | 2389 | the_end: |
| 2280 | tcc_free(s1->symtab_to_dynsym); | 2390 | tcc_free(s1->symtab_to_dynsym); |
| 2281 | tcc_free(section_order); | 2391 | tcc_free(sec_order); |
| 2282 | tcc_free(phdr); | 2392 | tcc_free(phdr); |
| 2283 | tcc_free(s1->sym_attrs); | 2393 | tcc_free(s1->sym_attrs); |
| 2284 | return ret; | 2394 | return ret; |
| @@ -2292,9 +2402,7 @@ LIBTCCAPI int tcc_output_file(TCCState *s, const char *filename) · 7 unmodified lines | |||
| 2292 | ret = pe_output_file(s, filename); | 2402 | ret = pe_output_file(s, filename); |
| 2293 | } else | 2403 | } else |
| 2294 | #endif | 2404 | #endif |
| 2295 | { | ||
| 2296 | ret = elf_output_file(s, filename); | 2405 | ret = elf_output_file(s, filename); |
| 2297 | } | ||
| 2298 | return ret; | 2406 | return ret; |
| 2299 | } | 2407 | } |
| 2300 | 2408 | ||
| @@ -2579,8 +2687,8 @@ ST_FUNC int tcc_load_object_file(TCCState *s1, · 278 unmodified lines | |||
| 2579 | handled by converting these instructions into blx | 2687 | handled by converting these instructions into blx |
| 2580 | instructions. Other case of instructions referencing a PLT | 2688 | instructions. Other case of instructions referencing a PLT |
| 2581 | entry require to add a Thumb stub before the PLT entry to | 2689 | entry require to add a Thumb stub before the PLT entry to |
| 2582 | switch to ARM mode. We set bit 0 of the got offset of a | 2690 | switch to ARM mode. We set bit plt_thumb_stub of the |
| 2583 | symbol to indicate such a case. */ | 2691 | attribute of a symbol to indicate such a case. */ |
| 2584 | if (type == R_ARM_THM_JUMP24) | 2692 | if (type == R_ARM_THM_JUMP24) |
| 2585 | alloc_sym_attr(s1, sym_index)->plt_thumb_stub = 1; | 2693 | alloc_sym_attr(s1, sym_index)->plt_thumb_stub = 1; |
| 2586 | #endif | 2694 | #endif |