Unified · Split
| @@ -20,6 +20,7 @@ · 19 unmodified lines | ||
| 20 | 20 | |
| 21 | 21 | #include "tcc.h" |
| 22 | 22 | |
| 23 | +/* XXX: avoid static variable */ | |
| 23 | 24 | static int new_undef_sym = 0; /* Is there a new undefined sym since last new_undef_sym() */ |
| 24 | 25 | |
| 25 | 26 | ST_FUNC int put_elf_str(Section *s, const char *sym) |
| @@ -429,6 +430,7 @@ ST_FUNC void relocate_syms(TCCState *s1, int do_resolve) · 403 unmodified lines | ||
| 429 | 430 | sh_num = sym->st_shndx; |
| 430 | 431 | if (sh_num == SHN_UNDEF) { |
| 431 | 432 | name = strtab_section->data + sym->st_name; |
| 433 | + /* Use ld.so to resolve symbol for us (for tcc -run) */ | |
| 432 | 434 | if (do_resolve) { |
| 433 | 435 | #if defined TCC_IS_NATIVE && !defined _WIN32 |
| 434 | 436 | void *addr; |
| @@ -504,7 +506,8 @@ static addr_t add_jmp_table(TCCState *s1, int val) · 69 unmodified lines | ||
| 504 | 506 | #endif |
| 505 | 507 | #endif /* def TCC_HAS_RUNTIME_PLTGOT */ |
| 506 | 508 | |
| 507 | −/* relocate a given section (CPU dependent) */ | |
| 509 | +/* relocate a given section (CPU dependent) by applying the relocations | |
| 510 | + in the associated relocation section */ | |
| 508 | 511 | ST_FUNC void relocate_section(TCCState *s1, Section *s) |
| 509 | 512 | { |
| 510 | 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 | |
| 1424 | 1427 | static void tcc_output_binary(TCCState *s1, FILE *f, |
| 1425 | − const int *section_order) | |
| 1428 | + const int *sec_order) | |
| 1426 | 1429 | { |
| 1427 | 1430 | Section *s; |
| 1428 | 1431 | int i, offset, size; |
| 1429 | 1432 | |
| 1430 | 1433 | offset = 0; |
| 1431 | 1434 | for(i=1;i<s1->nb_sections;i++) { |
| 1432 | − s = s1->sections[section_order[i]]; | |
| 1435 | + s = s1->sections[sec_order[i]]; | |
| 1433 | 1436 | if (s->sh_type != SHT_NOBITS && |
| 1434 | 1437 | (s->sh_flags & SHF_ALLOC)) { |
| 1435 | 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 | 1497 | put32(s1->got->data + offset, sym->st_value & 0xffffffff); |
| 1495 | 1498 | } |
| 1496 | 1499 | |
| 1500 | +/* Perform relocation to GOT or PLT entries */ | |
| 1497 | 1501 | ST_FUNC void fill_got(TCCState *s1) |
| 1498 | 1502 | { |
| 1499 | 1503 | Section *s; |
| @@ -1509,301 +1513,213 @@ ST_FUNC void fill_got(TCCState *s1) · 9 unmodified lines | ||
| 1509 | 1513 | continue; |
| 1510 | 1514 | for_each_elem(s, 0, rel, ElfW_Rel) { |
| 1511 | 1515 | switch (ELFW(R_TYPE) (rel->r_info)) { |
| 1516 | +#ifdef TCC_TARGET_X86_64 | |
| 1512 | 1517 | case R_X86_64_GOT32: |
| 1513 | 1518 | case R_X86_64_GOTPCREL: |
| 1514 | 1519 | case R_X86_64_PLT32: |
| 1515 | 1520 | fill_got_entry(s1, rel); |
| 1516 | 1521 | break; |
| 1522 | +#endif | |
| 1517 | 1523 | } |
| 1518 | 1524 | } |
| 1519 | 1525 | } |
| 1520 | 1526 | } |
| 1521 | 1527 | |
| 1522 | − | |
| 1523 | −/* output an ELF file */ | |
| 1524 | −/* XXX: suppress unneeded sections */ | |
| 1525 | −static int elf_output_file(TCCState *s1, const char *filename) | |
| 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) | |
| 1526 | 1532 | { |
| 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 | |
| 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; | |
| 1533 | + const char *name; | |
| 1534 | + int sym_index, index; | |
| 1535 | + ElfW(Sym) *sym, *esym; | |
| 1536 | + int type; | |
| 1681 | 1537 | |
| 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); | |
| 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; | |
| 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 | 1587 | } else { |
| 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 | − } | |
| 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); | |
| 1737 | 1594 | } |
| 1738 | 1595 | } |
| 1596 | + } else if (s1->rdynamic && ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { | |
| 1597 | + /* if -rdynamic option, then export all non local symbols */ | |
| 1598 | + name = symtab_section->link->data + sym->st_name; | |
| 1599 | + put_elf_sym(s1->dynsym, sym->st_value, sym->st_size, sym->st_info, | |
| 1600 | + 0, sym->st_shndx, name); | |
| 1601 | + } | |
| 1602 | + } | |
| 1603 | +} | |
| 1739 | 1604 | |
| 1740 | − build_got_entries(s1); | |
| 1605 | +/* Bind symbols of libraries: export non local symbols of executable that | |
| 1606 | + resolve undefined symbols of shared libraries */ | |
| 1607 | +static void bind_libs_dynsyms(TCCState *s1) | |
| 1608 | +{ | |
| 1609 | + const char *name; | |
| 1610 | + int sym_index; | |
| 1611 | + ElfW(Sym) *sym, *esym; | |
| 1741 | 1612 | |
| 1742 | − /* add a list of needed dlls */ | |
| 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)); | |
| 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); | |
| 1747 | 1629 | } |
| 1630 | + } | |
| 1631 | + } | |
| 1632 | +} | |
| 1748 | 1633 | |
| 1749 | − if (s1->rpath) | |
| 1750 | − put_dt(dynamic, DT_RPATH, put_elf_str(dynstr, s1->rpath)); | |
| 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; | |
| 1751 | 1640 | |
| 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); | |
| 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; | |
| 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)); | |
| 1773 | − | |
| 1774 | − /* we add a section for symbols */ | |
| 1775 | − strsec = new_section(s1, ".shstrtab", SHT_STRTAB, 0); | |
| 1776 | − put_elf_str(strsec, ""); | |
| 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; | |
| 1777 | 1674 | |
| 1778 | − /* compute number of sections */ | |
| 1779 | − shnum = s1->nb_sections; | |
| 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; | |
| 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 */ | |
| 1782 | − section_order = tcc_malloc(sizeof(int) * shnum); | |
| 1783 | − section_order[0] = 0; | |
| 1784 | − sh_order_index = 1; | |
| 1713 | +/* Allocate strings for section names and decide if an unallocated section | |
| 1714 | + should be output. | |
| 1785 | 1715 | |
| 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 | − } | |
| 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; | |
| 1802 | 1721 | |
| 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 ! */ | |
| 1722 | + /* Allocate strings for section names */ | |
| 1807 | 1723 | for(i = 1; i < s1->nb_sections; i++) { |
| 1808 | 1724 | s = s1->sections[i]; |
| 1809 | 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 | 1741 | s->sh_size = s->data_offset; |
| 1826 | 1742 | } |
| 1827 | 1743 | } |
| 1744 | +} | |
| 1828 | 1745 | |
| 1829 | − /* allocate program segment headers */ | |
| 1830 | − phdr = tcc_mallocz(phnum * sizeof(ElfW(Phdr))); | |
| 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 | + | |
| 1759 | +/* Assign sections to segments and decide how are sections laid out when loaded | |
| 1760 | + in memory. This function also fills corresponding program headers. */ | |
| 1761 | +static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr, int phnum, | |
| 1762 | + Section *interp, struct dyn_inf *dyninf, | |
| 1763 | + int *sec_order) | |
| 1764 | +{ | |
| 1765 | + int i, j, k, file_type, sh_order_index, file_offset; | |
| 1766 | + long long tmp; | |
| 1767 | + addr_t addr; | |
| 1768 | + ElfW(Phdr) *ph; | |
| 1769 | + Section *s; | |
| 1831 | 1770 | |
| 1832 | − if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) { | |
| 1771 | + file_type = s1->output_type; | |
| 1772 | + sh_order_index = 1; | |
| 1773 | + if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) | |
| 1833 | 1774 | file_offset = sizeof(ElfW(Ehdr)) + phnum * sizeof(ElfW(Phdr)); |
| 1834 | − } else { | |
| 1775 | + else | |
| 1835 | 1776 | file_offset = 0; |
| 1836 | − } | |
| 1777 | + | |
| 1837 | 1778 | if (phnum > 0) { |
| 1838 | − /* compute section to program header mapping */ | |
| 1839 | 1779 | if (s1->has_text_addr) { |
| 1840 | 1780 | int a_offset, p_offset; |
| 1841 | 1781 | addr = s1->text_addr; |
| @@ -1855,18 +1795,19 @@ static int elf_output_file(TCCState *s1, const char *filename) · 13 unmodified lines | ||
| 1855 | 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 | 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 | 1802 | if (interp) |
| 1868 | 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 | 1811 | for(j = 0; j < 2; j++) { |
| 1871 | 1812 | ph->p_type = PT_LOAD; |
| 1872 | 1813 | if (j == 0) |
| @@ -1875,8 +1816,10 @@ static int elf_output_file(TCCState *s1, const char *filename) · 2 unmodified lines | ||
| 1875 | 1816 | ph->p_flags = PF_R | PF_W; |
| 1876 | 1817 | ph->p_align = s1->section_align; |
| 1877 | 1818 | |
| 1878 | − /* we do the following ordering: interp, symbol tables, | |
| 1879 | − relocations, progbits, nobits */ | |
| 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 */ | |
| 1880 | 1823 | /* XXX: do faster and simpler sorting */ |
| 1881 | 1824 | for(k = 0; k < 5; k++) { |
| 1882 | 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 | 1852 | if (k != 3) |
| 1910 | 1853 | continue; |
| 1911 | 1854 | } |
| 1912 | − section_order[sh_order_index++] = i; | |
| 1855 | + sec_order[sh_order_index++] = i; | |
| 1913 | 1856 | |
| 1914 | 1857 | /* section matches: we align it and add its size */ |
| 1915 | 1858 | tmp = addr; |
| @@ -1929,17 +1872,17 @@ static int elf_output_file(TCCState *s1, const char *filename) · 13 unmodified lines | ||
| 1929 | 1872 | if (s->sh_type == SHT_RELX) { |
| 1930 | 1873 | #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) |
| 1931 | 1874 | if (!strcmp(strsec->data + s->sh_name, ".rel.got")) { |
| 1932 | − rel_addr = addr; | |
| 1933 | − rel_size += s->sh_size; /* XXX only first rel. */ | |
| 1875 | + dyninf->rel_addr = addr; | |
| 1876 | + dyninf->rel_size += s->sh_size; /* XXX only first rel. */ | |
| 1934 | 1877 | } |
| 1935 | 1878 | if (!strcmp(strsec->data + s->sh_name, ".rel.bss")) { |
| 1936 | − bss_addr = addr; | |
| 1937 | − bss_size = s->sh_size; /* XXX only first rel. */ | |
| 1879 | + dyninf->bss_addr = addr; | |
| 1880 | + dyninf->bss_size = s->sh_size; /* XXX only first rel. */ | |
| 1938 | 1881 | } |
| 1939 | 1882 | #else |
| 1940 | − if (rel_size == 0) | |
| 1941 | − rel_addr = addr; | |
| 1942 | − rel_size += s->sh_size; | |
| 1883 | + if (dyninf->rel_size == 0) | |
| 1884 | + dyninf->rel_addr = addr; | |
| 1885 | + dyninf->rel_size += s->sh_size; | |
| 1943 | 1886 | #endif |
| 1944 | 1887 | } |
| 1945 | 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 */ | |
| 1968 | − if (interp) { | |
| 1969 | − ph = &phdr[0]; | |
| 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; | |
| 1970 | 1917 | |
| 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 | |
| 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 | + } | |
| 1985 | 1924 | |
| 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 | − } | |
| 1925 | + return file_offset; | |
| 1926 | +} | |
| 1995 | 1927 | |
| 1996 | − /* if dynamic section, then add corresponing program header */ | |
| 1997 | − if (dynamic) { | |
| 1998 | − ph = &phdr[phnum - 1]; | |
| 1928 | +static void fill_unloadable_phdr(ElfW(Phdr) *phdr, int phnum, Section *interp, | |
| 1929 | + Section *dynamic) | |
| 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; | |
| 2001 | − ph->p_offset = dynamic->sh_offset; | |
| 2002 | − ph->p_vaddr = dynamic->sh_addr; | |
| 1937 | + if (HAVE_PHDR) | |
| 1938 | + { | |
| 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 | 1944 | ph->p_paddr = ph->p_vaddr; |
| 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; | |
| 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 | + } | |
| 2008 | 1950 | |
| 2009 | − /* put GOT dynamic section address */ | |
| 2010 | − put32(s1->got->data, dynamic->sh_addr); | |
| 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 | + } | |
| 2011 | 1960 | |
| 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; | |
| 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 | +} | |
| 2019 | 1975 | |
| 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 | − } | |
| 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; | |
| 2057 | 1981 | |
| 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 | − } | |
| 1982 | + dynamic = dyninf->dynamic; | |
| 2070 | 1983 | |
| 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))); | |
| 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))); | |
| 2078 | 1991 | #ifdef TCC_TARGET_X86_64 |
| 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)); | |
| 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)); | |
| 2082 | 1995 | #else |
| 2083 | 1996 | #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) |
| 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); | |
| 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); | |
| 2090 | 2003 | #else |
| 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)); | |
| 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)); | |
| 2094 | 2007 | #endif |
| 2095 | 2008 | #endif |
| 2096 | − if (s1->do_debug) | |
| 2097 | − put_dt(dynamic, DT_DEBUG, 0); | |
| 2098 | − put_dt(dynamic, DT_NULL, 0); | |
| 2099 | − } | |
| 2009 | + if (s1->do_debug) | |
| 2010 | + put_dt(dynamic, DT_DEBUG, 0); | |
| 2011 | + put_dt(dynamic, DT_NULL, 0); | |
| 2012 | +} | |
| 2100 | 2013 | |
| 2101 | − ehdr.e_phentsize = sizeof(ElfW(Phdr)); | |
| 2102 | − ehdr.e_phnum = phnum; | |
| 2103 | − ehdr.e_phoff = sizeof(ElfW(Ehdr)); | |
| 2104 | − } | |
| 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; | |
| 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 | 2028 | for(i = 1; i < s1->nb_sections; i++) { |
| 2108 | 2029 | s = s1->sections[i]; |
| 2109 | − if (phnum > 0 && (s->sh_flags & SHF_ALLOC)) | |
| 2110 | − continue; | |
| 2111 | − section_order[sh_order_index++] = i; | |
| 2030 | + if (s->reloc && s != s1->got) | |
| 2031 | + relocate_section(s1, s); | |
| 2032 | + } | |
| 2112 | 2033 | |
| 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; | |
| 2034 | + /* relocate relocation entries if the relocation tables are | |
| 2035 | + allocated in the executable */ | |
| 2036 | + for(i = 1; i < s1->nb_sections; i++) { | |
| 2037 | + s = s1->sections[i]; | |
| 2038 | + if ((s->sh_flags & SHF_ALLOC) && | |
| 2039 | + s->sh_type == SHT_RELX) { | |
| 2040 | + relocate_rel(s1, s); | |
| 2041 | + } | |
| 2118 | 2042 | } |
| 2043 | + return 0; | |
| 2044 | +} | |
| 2119 | 2045 | |
| 2120 | − /* if building executable or DLL, then relocate each section | |
| 2121 | − except the GOT which is already relocated */ | |
| 2122 | − if (file_type != TCC_OUTPUT_OBJ) { | |
| 2123 | − relocate_syms(s1, 0); | |
| 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; | |
| 2124 | 2055 | |
| 2125 | − if (s1->nb_errors != 0) { | |
| 2126 | − fail: | |
| 2127 | − ret = -1; | |
| 2128 | − goto the_end; | |
| 2129 | − } | |
| 2056 | + file_type = s1->output_type; | |
| 2057 | + shnum = s1->nb_sections; | |
| 2130 | 2058 | |
| 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 | − } | |
| 2059 | + memset(&ehdr, 0, sizeof(ehdr)); | |
| 2060 | + | |
| 2061 | + if (phnum > 0) { | |
| 2062 | + ehdr.e_phentsize = sizeof(ElfW(Phdr)); | |
| 2063 | + ehdr.e_phnum = phnum; | |
| 2064 | + ehdr.e_phoff = sizeof(ElfW(Ehdr)); | |
| 2065 | + } | |
| 2138 | 2066 | |
| 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); | |
| 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++; | |
| 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 */ | |
| 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 ? */ | |
| 2137 | + /* output section headers */ | |
| 2138 | + while (offset < ehdr.e_shoff) { | |
| 2139 | + fputc(0, f); | |
| 2140 | + offset++; | |
| 2154 | 2141 | } |
| 2155 | − if (file_type == TCC_OUTPUT_EXE && s1->static_link) | |
| 2156 | − fill_got(s1); | |
| 2157 | 2142 | |
| 2158 | − /* write elf file */ | |
| 2143 | + for(i = 0; i < s1->nb_sections; i++) { | |
| 2144 | + sh = &shdr; | |
| 2145 | + memset(sh, 0, sizeof(ElfW(Shdr))); | |
| 2146 | + s = s1->sections[i]; | |
| 2147 | + if (s) { | |
| 2148 | + sh->sh_name = s->sh_name; | |
| 2149 | + sh->sh_type = s->sh_type; | |
| 2150 | + sh->sh_flags = s->sh_flags; | |
| 2151 | + sh->sh_entsize = s->sh_entsize; | |
| 2152 | + sh->sh_info = s->sh_info; | |
| 2153 | + if (s->link) | |
| 2154 | + sh->sh_link = s->link->sh_num; | |
| 2155 | + sh->sh_addralign = s->sh_addralign; | |
| 2156 | + sh->sh_addr = s->sh_addr; | |
| 2157 | + sh->sh_offset = s->sh_offset; | |
| 2158 | + sh->sh_size = s->sh_size; | |
| 2159 | + } | |
| 2160 | + fwrite(sh, 1, sizeof(ElfW(Shdr)), f); | |
| 2161 | + } | |
| 2162 | +} | |
| 2163 | + | |
| 2164 | +/* Write an elf, coff or "binary" file */ | |
| 2165 | +static int tcc_write_elf_file(TCCState *s1, const char *filename, int phnum, | |
| 2166 | + ElfW(Phdr) *phdr, int file_offset, int *sec_order) | |
| 2167 | +{ | |
| 2168 | + int fd, mode, file_type; | |
| 2169 | + FILE *f; | |
| 2170 | + | |
| 2171 | + file_type = s1->output_type; | |
| 2159 | 2172 | if (file_type == TCC_OUTPUT_OBJ) |
| 2160 | 2173 | mode = 0666; |
| 2161 | 2174 | else |
| @@ -2164,121 +2177,218 @@ static int elf_output_file(TCCState *s1, const char *filename) · 2 unmodified lines | ||
| 2164 | 2177 | fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, mode); |
| 2165 | 2178 | if (fd < 0) { |
| 2166 | 2179 | tcc_error_noabort("could not write '%s'", filename); |
| 2167 | − goto fail; | |
| 2180 | + return -1; | |
| 2168 | 2181 | } |
| 2169 | 2182 | f = fdopen(fd, "wb"); |
| 2170 | 2183 | if (s1->verbose) |
| 2171 | 2184 | printf("<- %s\n", filename); |
| 2172 | 2185 | |
| 2173 | 2186 | #ifdef TCC_TARGET_COFF |
| 2174 | − if (s1->output_format == TCC_OUTPUT_FORMAT_COFF) { | |
| 2187 | + if (s1->output_format == TCC_OUTPUT_FORMAT_COFF) | |
| 2175 | 2188 | tcc_output_coff(s1, f); |
| 2176 | − } 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 | |
| 2189 | + else | |
| 2208 | 2190 | #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++; | |
| 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; | |
| 2241 | 2267 | } |
| 2242 | − size = s->sh_size; | |
| 2243 | − fwrite(s->data, 1, size, f); | |
| 2244 | − offset += size; | |
| 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)); | |
| 2245 | 2280 | } |
| 2246 | − } | |
| 2247 | 2281 | |
| 2248 | − /* output section headers */ | |
| 2249 | − while (offset < ehdr.e_shoff) { | |
| 2250 | − fputc(0, f); | |
| 2251 | − offset++; | |
| 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); | |
| 2252 | 2302 | } |
| 2303 | + } | |
| 2253 | 2304 | |
| 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; | |
| 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); | |
| 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 | 2389 | the_end: |
| 2280 | 2390 | tcc_free(s1->symtab_to_dynsym); |
| 2281 | − tcc_free(section_order); | |
| 2391 | + tcc_free(sec_order); | |
| 2282 | 2392 | tcc_free(phdr); |
| 2283 | 2393 | tcc_free(s1->sym_attrs); |
| 2284 | 2394 | return ret; |
| @@ -2292,9 +2402,7 @@ LIBTCCAPI int tcc_output_file(TCCState *s, const char *filename) · 7 unmodified lines | ||
| 2292 | 2402 | ret = pe_output_file(s, filename); |
| 2293 | 2403 | } else |
| 2294 | 2404 | #endif |
| 2295 | − { | |
| 2296 | 2405 | ret = elf_output_file(s, filename); |
| 2297 | − } | |
| 2298 | 2406 | return ret; |
| 2299 | 2407 | } |
| 2300 | 2408 | |
| @@ -2579,8 +2687,8 @@ ST_FUNC int tcc_load_object_file(TCCState *s1, · 278 unmodified lines | ||
| 2579 | 2687 | handled by converting these instructions into blx |
| 2580 | 2688 | instructions. Other case of instructions referencing a PLT |
| 2581 | 2689 | entry require to add a Thumb stub before the PLT entry to |
| 2582 | − switch to ARM mode. We set bit 0 of the got offset of a | |
| 2583 | − symbol to indicate such a case. */ | |
| 2690 | + switch to ARM mode. We set bit plt_thumb_stub of the | |
| 2691 | + attribute of a symbol to indicate such a case. */ | |
| 2584 | 2692 | if (type == R_ARM_THM_JUMP24) |
| 2585 | 2693 | alloc_sym_attr(s1, sym_index)->plt_thumb_stub = 1; |
| 2586 | 2694 | #endif |