| @@ -58,6 +58,8 @@ ST_FUNC void tccelf_new(TCCState *s) · 57 unmodified lines |
| 58 | 58 | /* create standard sections */ |
| 59 | 59 | text_section = new_section(s, ".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR); |
| 60 | 60 | data_section = new_section(s, ".data", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); |
| 61 | + /* create ro data section (make ro after relocation done with GNU_RELRO) */ |
| 62 | + data_ro_section = new_section(s, ".data.ro", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); |
| 61 | 63 | bss_section = new_section(s, ".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE); |
| 62 | 64 | common_section = new_section(s, ".common", SHT_NOBITS, SHF_PRIVATE); |
| 63 | 65 | common_section->sh_num = SHN_COMMON; |
| @@ -79,11 +81,11 @@ ST_FUNC void tccelf_new(TCCState *s) · 15 unmodified lines |
| 79 | 81 | ST_FUNC void tccelf_bounds_new(TCCState *s) |
| 80 | 82 | { |
| 81 | 83 | TCCState *s1 = s; |
| 82 | | − /* create bounds sections */ |
| 84 | + /* create bounds sections (make ro after relocation done with GNU_RELRO) */ |
| 83 | 85 | bounds_section = new_section(s, ".bounds", |
| 84 | | − SHT_PROGBITS, SHF_ALLOC); |
| 86 | + SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); |
| 85 | 87 | lbounds_section = new_section(s, ".lbounds", |
| 86 | | − SHT_PROGBITS, SHF_ALLOC); |
| 88 | + SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); |
| 87 | 89 | } |
| 88 | 90 | #endif |
| 89 | 91 | |
| @@ -1043,6 +1045,16 @@ static int prepare_dynamic_rel(TCCState *s1, Section *sr) · 953 unmodified lines |
| 1043 | 1045 | case R_386_PC32: |
| 1044 | 1046 | #elif defined(TCC_TARGET_X86_64) |
| 1045 | 1047 | case R_X86_64_PC32: |
| 1048 | + { |
| 1049 | + ElfW(Sym) *sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
| 1050 | + |
| 1051 | + /* support __dso_handle in atexit() */ |
| 1052 | + if (sym->st_shndx != SHN_UNDEF && |
| 1053 | + ELFW(ST_VISIBILITY)(sym->st_other) == STV_HIDDEN) { |
| 1054 | + rel->r_info = ELFW(R_INFO)(sym_index, R_X86_64_PLT32); |
| 1055 | + break; |
| 1056 | + } |
| 1057 | + } |
| 1046 | 1058 | #elif defined(TCC_TARGET_ARM64) |
| 1047 | 1059 | case R_AARCH64_PREL32: |
| 1048 | 1060 | #endif |
| @@ -1828,11 +1840,20 @@ struct dyn_inf { · 779 unmodified lines |
| 1828 | 1840 | addr_t rel_size; |
| 1829 | 1841 | }; |
| 1830 | 1842 | |
| 1843 | +/* Info for GNU_RELRO */ |
| 1844 | +struct ro_inf { |
| 1845 | + addr_t sh_offset; |
| 1846 | + addr_t sh_addr; |
| 1847 | + addr_t sh_size; |
| 1848 | +}; |
| 1849 | + |
| 1831 | 1850 | /* Assign sections to segments and decide how are sections laid out when loaded |
| 1832 | 1851 | in memory. This function also fills corresponding program headers. */ |
| 1833 | | −static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr, int phnum, |
| 1852 | +static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr, |
| 1853 | + int phnum, int phfill, |
| 1834 | 1854 | Section *interp, Section* strsec, |
| 1835 | | − struct dyn_inf *dyninf, int *sec_order) |
| 1855 | + struct dyn_inf *dyninf, struct ro_inf *roinf, |
| 1856 | + int *sec_order) |
| 1836 | 1857 | { |
| 1837 | 1858 | int i, sh_order_index, file_offset; |
| 1838 | 1859 | Section *s; |
| @@ -1883,7 +1904,10 @@ static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr, int phnum, · 44 unmodified lines |
| 1883 | 1904 | /* dynamic relocation table information, for .dynamic section */ |
| 1884 | 1905 | dyninf->rel_addr = dyninf->rel_size = 0; |
| 1885 | 1906 | |
| 1886 | | − for(j = 0; j < (phnum == 6 ? 3 : 2); j++) { |
| 1907 | + /* read only segment mapping for GNU_RELRO */ |
| 1908 | + roinf->sh_offset = roinf->sh_addr = roinf->sh_size = 0; |
| 1909 | + |
| 1910 | + for(j = 0; j < phfill; j++) { |
| 1887 | 1911 | Section *relocplt = s1->got ? s1->got->relocplt : NULL; |
| 1888 | 1912 | |
| 1889 | 1913 | ph->p_type = j == 2 ? PT_TLS : PT_LOAD; |
| @@ -1898,7 +1922,7 @@ static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr, int phnum, · 8 unmodified lines |
| 1898 | 1922 | info about the layout. We do the following ordering: interp, |
| 1899 | 1923 | symbol tables, relocations, progbits, nobits */ |
| 1900 | 1924 | /* XXX: do faster and simpler sorting */ |
| 1901 | | − for(k = 0; k < 6; k++) { |
| 1925 | + for(k = 0; k < 7; k++) { |
| 1902 | 1926 | for(i = 1; i < s1->nb_sections; i++) { |
| 1903 | 1927 | s = s1->sections[i]; |
| 1904 | 1928 | /* compute if section should be included */ |
| @@ -1930,12 +1954,17 @@ static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr, int phnum, · 25 unmodified lines |
| 1930 | 1954 | else if (k != 3 && s == relocplt) |
| 1931 | 1955 | continue; |
| 1932 | 1956 | } else if (s->sh_type == SHT_NOBITS) { |
| 1933 | | − if (k != 5) |
| 1957 | + if (k != 6) |
| 1934 | 1958 | continue; |
| 1935 | | − } else { |
| 1959 | + } else if (s == data_ro_section || |
| 1960 | + s == bounds_section || |
| 1961 | + s == lbounds_section) { |
| 1936 | 1962 | if (k != 4) |
| 1937 | 1963 | continue; |
| 1938 | | − } |
| 1964 | + } else { |
| 1965 | + if (k != 5) |
| 1966 | + continue; |
| 1967 | + } |
| 1939 | 1968 | sec_order[sh_order_index++] = i; |
| 1940 | 1969 | |
| 1941 | 1970 | /* section matches: we align it and add its size */ |
| @@ -1956,8 +1985,17 @@ static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr, int phnum, · 14 unmodified lines |
| 1956 | 1985 | if (s->sh_type == SHT_RELX && s != relocplt) { |
| 1957 | 1986 | if (dyninf->rel_size == 0) |
| 1958 | 1987 | dyninf->rel_addr = addr; |
| 1959 | | − dyninf->rel_size += s->sh_size; |
| 1988 | + dyninf->rel_size = (addr - dyninf->rel_addr) + s->sh_size; |
| 1960 | 1989 | } |
| 1990 | + if (s == data_ro_section || |
| 1991 | + s == bounds_section || |
| 1992 | + s == lbounds_section) { |
| 1993 | + if (roinf->sh_size == 0) { |
| 1994 | + roinf->sh_offset = s->sh_offset; |
| 1995 | + roinf->sh_addr = s->sh_addr; |
| 1996 | + } |
| 1997 | + roinf->sh_size = (addr - roinf->sh_addr) + s->sh_size; |
| 1998 | + } |
| 1961 | 1999 | addr += s->sh_size; |
| 1962 | 2000 | if (s->sh_type != SHT_NOBITS) |
| 1963 | 2001 | file_offset += s->sh_size; |
| @@ -2018,7 +2056,7 @@ static void put_dt(Section *dynamic, int dt, addr_t val) · 54 unmodified lines |
| 2018 | 2056 | } |
| 2019 | 2057 | |
| 2020 | 2058 | static void fill_unloadable_phdr(ElfW(Phdr) *phdr, int phnum, Section *interp, |
| 2021 | | − Section *dynamic, Section *note) |
| 2059 | + Section *dynamic, Section *note, struct ro_inf *roinf) |
| 2022 | 2060 | { |
| 2023 | 2061 | ElfW(Phdr) *ph; |
| 2024 | 2062 | |
| @@ -2046,7 +2084,7 @@ static void fill_unloadable_phdr(ElfW(Phdr) *phdr, int phnum, Section *interp, · 21 unmodified lines |
| 2046 | 2084 | } |
| 2047 | 2085 | |
| 2048 | 2086 | if (note) { |
| 2049 | | − ph = &phdr[phnum - 2]; |
| 2087 | + ph = &phdr[phnum - 2 - (roinf != NULL)]; |
| 2050 | 2088 | |
| 2051 | 2089 | ph->p_type = PT_NOTE; |
| 2052 | 2090 | ph->p_offset = note->sh_offset; |
| @@ -2060,7 +2098,7 @@ static void fill_unloadable_phdr(ElfW(Phdr) *phdr, int phnum, Section *interp, · 7 unmodified lines |
| 2060 | 2098 | |
| 2061 | 2099 | /* if dynamic section, then add corresponding program header */ |
| 2062 | 2100 | if (dynamic) { |
| 2063 | | − ph = &phdr[phnum - 1]; |
| 2101 | + ph = &phdr[phnum - 1 - (roinf != NULL)]; |
| 2064 | 2102 | |
| 2065 | 2103 | ph->p_type = PT_DYNAMIC; |
| 2066 | 2104 | ph->p_offset = dynamic->sh_offset; |
| @@ -2071,6 +2109,19 @@ static void fill_unloadable_phdr(ElfW(Phdr) *phdr, int phnum, Section *interp, · 4 unmodified lines |
| 2071 | 2109 | ph->p_flags = PF_R | PF_W; |
| 2072 | 2110 | ph->p_align = dynamic->sh_addralign; |
| 2073 | 2111 | } |
| 2112 | + |
| 2113 | + if (roinf) { |
| 2114 | + ph = &phdr[phnum - 1]; |
| 2115 | + |
| 2116 | + ph->p_type = PT_GNU_RELRO; |
| 2117 | + ph->p_offset = roinf->sh_offset; |
| 2118 | + ph->p_vaddr = roinf->sh_addr; |
| 2119 | + ph->p_paddr = ph->p_vaddr; |
| 2120 | + ph->p_filesz = roinf->sh_size; |
| 2121 | + ph->p_memsz = roinf->sh_size; |
| 2122 | + ph->p_flags = PF_R; |
| 2123 | + ph->p_align = 1; |
| 2124 | + } |
| 2074 | 2125 | } |
| 2075 | 2126 | |
| 2076 | 2127 | /* Fill the dynamic section with tags describing the address and size of |
| @@ -2440,8 +2491,9 @@ static Section *create_bsd_note_section(TCCState *s1, · 363 unmodified lines |
| 2440 | 2491 | /* XXX: suppress unneeded sections */ |
| 2441 | 2492 | static int elf_output_file(TCCState *s1, const char *filename) |
| 2442 | 2493 | { |
| 2443 | | − int ret, phnum, shnum, file_type, file_offset, *sec_order; |
| 2494 | + int i, ret, phnum, phfill, shnum, file_type, file_offset, *sec_order; |
| 2444 | 2495 | struct dyn_inf dyninf = {0}; |
| 2496 | + struct ro_inf roinf, *roinf_use = NULL; |
| 2445 | 2497 | ElfW(Phdr) *phdr; |
| 2446 | 2498 | Section *strsec, *interp, *dynamic, *dynstr, *note = NULL; |
| 2447 | 2499 | |
| @@ -2489,6 +2541,8 @@ static int elf_output_file(TCCState *s1, const char *filename) · 41 unmodified lines |
| 2489 | 2541 | s1->dynsym = new_symtab(s1, ".dynsym", SHT_DYNSYM, SHF_ALLOC, |
| 2490 | 2542 | ".dynstr", |
| 2491 | 2543 | ".hash", SHF_ALLOC); |
| 2544 | + /* Number of local symbols (readelf complains if not set) */ |
| 2545 | + s1->dynsym->sh_info = 1; |
| 2492 | 2546 | dynstr = s1->dynsym->link; |
| 2493 | 2547 | /* add dynamic section */ |
| 2494 | 2548 | dynamic = new_section(s1, ".dynamic", SHT_DYNAMIC, |
| @@ -2556,22 +2610,31 @@ static int elf_output_file(TCCState *s1, const char *filename) · 61 unmodified lines |
| 2556 | 2610 | } |
| 2557 | 2611 | #endif |
| 2558 | 2612 | |
| 2613 | + for (i = 1; i < s1->nb_sections && |
| 2614 | + !(s1->sections[i]->sh_flags & SHF_TLS); i++); |
| 2615 | + phfill = 2 + (i < s1->nb_sections); |
| 2616 | + |
| 2559 | 2617 | /* compute number of program headers */ |
| 2560 | 2618 | if (file_type == TCC_OUTPUT_OBJ) |
| 2561 | | − phnum = 0; |
| 2619 | + phnum = phfill = 0; |
| 2562 | 2620 | else if (file_type == TCC_OUTPUT_DLL) |
| 2563 | 2621 | phnum = 3; |
| 2564 | 2622 | else if (s1->static_link) |
| 2565 | 2623 | phnum = 2; |
| 2566 | 2624 | else { |
| 2567 | | − int i; |
| 2568 | | − for (i = 1; i < s1->nb_sections && |
| 2569 | | − !(s1->sections[i]->sh_flags & SHF_TLS); i++); |
| 2570 | | − phnum = i < s1->nb_sections ? 6 : 5; |
| 2625 | + phnum = 5 + (i < s1->nb_sections); |
| 2571 | 2626 | } |
| 2572 | 2627 | |
| 2573 | 2628 | phnum += note != NULL; |
| 2574 | 2629 | |
| 2630 | +#if !TARGETOS_FreeBSD && !TARGETOS_NetBSD && !defined(__APPLE__) && !defined(_WIN32) |
| 2631 | + /* GNU_RELRO */ |
| 2632 | + if (file_type != TCC_OUTPUT_OBJ) { |
| 2633 | + phnum++; |
| 2634 | + roinf_use = &roinf; |
| 2635 | + } |
| 2636 | +#endif |
| 2637 | + |
| 2575 | 2638 | /* allocate program segment headers */ |
| 2576 | 2639 | phdr = tcc_mallocz(phnum * sizeof(ElfW(Phdr))); |
| 2577 | 2640 | |
| @@ -2583,14 +2646,14 @@ static int elf_output_file(TCCState *s1, const char *filename) · 5 unmodified lines |
| 2583 | 2646 | sec_order[0] = 0; |
| 2584 | 2647 | |
| 2585 | 2648 | /* compute section to program header mapping */ |
| 2586 | | − file_offset = layout_sections(s1, phdr, phnum, interp, strsec, &dyninf, |
| 2587 | | − sec_order); |
| 2649 | + file_offset = layout_sections(s1, phdr, phnum, phfill, interp, strsec, |
| 2650 | + &dyninf, &roinf, sec_order); |
| 2588 | 2651 | |
| 2589 | 2652 | #ifndef ELF_OBJ_ONLY |
| 2590 | 2653 | /* Fill remaining program header and finalize relocation related to dynamic |
| 2591 | 2654 | linking. */ |
| 2592 | 2655 | if (file_type != TCC_OUTPUT_OBJ) { |
| 2593 | | − fill_unloadable_phdr(phdr, phnum, interp, dynamic, note); |
| 2656 | + fill_unloadable_phdr(phdr, phnum, interp, dynamic, note, roinf_use); |
| 2594 | 2657 | if (dynamic) { |
| 2595 | 2658 | ElfW(Sym) *sym; |
| 2596 | 2659 | dynamic->data_offset = dyninf.data_offset; |