History

Split elf_output_file in smaller functions

Thomas Preud'homme committed 12 years ago

Commit 4aec2901 parent 55f751a1 file · +659 −551Browse files

Unified · Split

tccelf.c+659−551
@@ -20,6 +20,7 @@ · 19 unmodified lines
20 20
21#include "tcc.h"21#include "tcc.h"
22 22
23/* XXX: avoid static variable */
23static int new_undef_sym = 0; /* Is there a new undefined sym since last new_undef_sym() */24static int new_undef_sym = 0; /* Is there a new undefined sym since last new_undef_sym() */
24 25
25ST_FUNC int put_elf_str(Section *s, const char *sym)26ST_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 _WIN32435#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#endif506#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 */
508ST_FUNC void relocate_section(TCCState *s1, Section *s)511ST_FUNC void relocate_section(TCCState *s1, Section *s)
509{512{
510 Section *sr = s->reloc;513 Section *sr = s->reloc;
@@ -1422,14 +1425,14 @@ ST_FUNC void tcc_add_linker_symbols(TCCState *s1) · 911 unmodified lines
1422}1425}
1423 1426
1424static void tcc_output_binary(TCCState *s1, FILE *f,1427static 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 */
1497ST_FUNC void fill_got(TCCState *s1)1501ST_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 */
1525static int elf_output_file(TCCState *s1, const char *filename)1531static 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 export1538 /* 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 already1545 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 */
1607static 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));1635static 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, we1641 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 */1671static 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) {1717static 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 unallocated1722 /* 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)));1747struct 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. */
1761static 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#else1882#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#endif1886#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 */1928static 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_EXE1962 if (dynamic) {
2014#if defined(TCC_OUTPUT_DLL_WITH_PLT)1963 ph = &phdr[phnum - 1];
2015 || file_type == TCC_OUTPUT_DLL1964
2016#endif1965 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) {1978static 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_641991#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#else1995#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#else2003#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#endif2007#endif
2095#endif2008#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));2016static 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 section2046/* 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) {2048static 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 are2067 /* 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 else2140 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 */
2165static 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 else2174 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_COFF2186#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 } else2189 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#endif2190#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 }2202static 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 } else2403 } else
2294#endif2404#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 blx2687 handled by converting these instructions into blx
2580 instructions. Other case of instructions referencing a PLT2688 instructions. Other case of instructions referencing a PLT
2581 entry require to add a Thumb stub before the PLT entry to2689 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 a2690 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#endif2694#endif

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