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