From 45cff8f03fe58a1ded52864bb6640998ea6775e5 Mon Sep 17 00:00:00 2001 From: grischka Date: Wed, 9 Oct 2024 23:15:05 +0200 Subject: [PATCH] tccelf.c: write section headers before sections also avoid zero lenght PT_LOAD segments (which some musl loaders seem to dislike) Also: - tccasm.c: support .section with flags: .section .xyz,"wx" (fixes e4d874d88a2ef874a9c2fd7c47d3d3a35ae986e2) - tccgen,c: add __builtin_unreachable() - tccdefs.h: #define __has_attribute(x) 0 - tcc.c: tidy help for -std - tcctools.c/execvp_win32: quote strings more correctly - x86_64-gen.c:win32: set unwind begin-address to function-start - github action: add aarch64-osx (M1) & i386-win32 - configure: consider 32-bit build on MSYS64 native --- .github/workflows/build.yml | 30 ++++- Makefile | 5 +- configure | 3 +- include/tccdefs.h | 1 + tcc.c | 3 +- tccasm.c | 18 ++- tccelf.c | 184 +++++++++++++++--------------- tccgen.c | 9 +- tccpe.c | 9 +- tcctok.h | 1 + tcctools.c | 38 +++--- tests/exec_section_in_asm.c | 29 ----- tests/tcctest.c | 2 +- tests/tests2/133_exec_section_in_c.c | 17 --- tests/tests2/133_exec_section_in_c.expect | 1 - x86_64-gen.c | 15 ++- 16 files changed, 170 insertions(+), 195 deletions(-) delete mode 100644 tests/exec_section_in_asm.c delete mode 100644 tests/tests2/133_exec_section_in_c.c delete mode 100644 tests/tests2/133_exec_section_in_c.expect diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 39d8ca31..6624d606 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,7 +10,7 @@ jobs: timeout-minutes: 2 steps: - uses: actions/checkout@v4 - - name: make & test tcc + - name: make & test tcc (x86_64-linux) run: ./configure && make && make test -k test-x86_64-osx: @@ -18,21 +18,36 @@ jobs: timeout-minutes: 2 steps: - uses: actions/checkout@v4 - - name: make & test tcc - run: ./configure --config-codesign=no && make && make test -k + - name: make & test tcc (x86_64-osx) + run: ./configure && make && make test -k + + test-aarch64-osx: + runs-on: macos-14 + timeout-minutes: 2 + steps: + - uses: actions/checkout@v4 + - name: make & test tcc (aarch64-osx) + run: ./configure && make && make test -k - test-x86_64-win32: + test-x86-win32: runs-on: windows-2019 - timeout-minutes: 4 + timeout-minutes: 6 steps: - uses: actions/checkout@v4 - - name: make & test tcc + - name: make & test tcc (x86_64-win32) shell: cmd run: | set MSYS2_PATH_TYPE=inherit set MSYSTEM=MINGW64 set CHERE_INVOKING=yes C:\msys64\usr\bin\bash -l -c "./configure && make && make test -k" + - name: make & test tcc (i386-win32) + shell: cmd + run: | + set MSYS2_PATH_TYPE=inherit + set MSYSTEM=MINGW32 + set CHERE_INVOKING=yes + C:\msys64\usr\bin\bash -l -c "./configure && make clean all && make test -k" test-armv7-linux: runs-on: ubuntu-20.04 @@ -40,6 +55,7 @@ jobs: steps: - uses: actions/checkout@v4 - uses: uraimo/run-on-arch-action@v2 + name: make & test tcc (armv7-linux) with: arch: armv7 distro: ubuntu20.04 @@ -57,6 +73,7 @@ jobs: steps: - uses: actions/checkout@v4 - uses: uraimo/run-on-arch-action@v2 + name: make & test tcc (aarch64-linux) with: arch: aarch64 distro: ubuntu20.04 @@ -74,6 +91,7 @@ jobs: steps: - uses: actions/checkout@v4 - uses: uraimo/run-on-arch-action@v2 + name: make & test tcc (riscv64-linux) with: arch: riscv64 distro: ubuntu20.04 diff --git a/Makefile b/Makefile index 13260d07..5ea21183 100644 --- a/Makefile +++ b/Makefile @@ -69,7 +69,10 @@ else ifdef CONFIG_OSX NATIVE_TARGET = $(ARCH)-osx ifneq ($(CC_NAME),tcc) - LDFLAGS += -flat_namespace -undefined warning + LDFLAGS += -flat_namespace + ifneq (1,$(shell expr $(GCC_MAJOR) ">=" 15)) + LDFLAGS += -undefined warning # depreciated in clang >= 15.0 + endif endif export MACOSX_DEPLOYMENT_TARGET := 10.6 endif diff --git a/configure b/configure index 703ab63f..9aff311e 100755 --- a/configure +++ b/configure @@ -227,10 +227,12 @@ fi # OS specific buildos=$(uname) +cpu_sys=$(uname -m) case $buildos in Windows_NT|MINGW*|MSYS*|CYGWIN*) buildos="WIN32" + test "$MSYSTEM" = "MINGW32" && cpu_sys=i386 ;; Linux) if test "$(uname -o)" = "Android"; then @@ -248,7 +250,6 @@ else default targetos "$buildos" fi -cpu_sys=$(uname -m) default cpu "$cpu_sys" cpu_set="$cpu" diff --git a/include/tccdefs.h b/include/tccdefs.h index 8ec64646..66b8fe8f 100644 --- a/include/tccdefs.h +++ b/include/tccdefs.h @@ -152,6 +152,7 @@ #define __PRETTY_FUNCTION__ __FUNCTION__ #define __has_builtin(x) 0 #define __has_feature(x) 0 + #define __has_atttribute(x) 0 /* C23 Keywords */ #define _Nonnull #define _Nullable diff --git a/tcc.c b/tcc.c index 6fe0cc0d..838f41d9 100644 --- a/tcc.c +++ b/tcc.c @@ -33,8 +33,6 @@ static const char help[] = " -o outfile set output filename\n" " -run run compiled source\n" " -fflag set or reset (with 'no-' prefix) 'flag' (see tcc -hh)\n" - " -std=(c99|gnu99) Conform to the ISO 1999 C standard (default).\n" - " -std=(c11|gnu11) Conform to the ISO 2011 C standard.\n" " -Wwarning set or reset (with 'no-' prefix) 'warning' (see tcc -hh)\n" " -w disable all warnings\n" " -v --version show version\n" @@ -69,6 +67,7 @@ static const char help[] = " -bt[N] link with backtrace (stack dump) support [show max N callers]\n" #endif "Misc. options:\n" + " -std=version define __STDC_VERSION__ according to version (c11/gnu11)\n" " -x[c|a|b|n] specify type of the next infile (C,ASM,BIN,NONE)\n" " -nostdinc do not use standard system include paths\n" " -nostdlib do not link with standard crt and libraries\n" diff --git a/tccasm.c b/tccasm.c index e52872b5..766e1f24 100644 --- a/tccasm.c +++ b/tccasm.c @@ -857,6 +857,7 @@ static void asm_parse_directive(TCCState *s1, int global) { char sname[256]; int old_nb_section = s1->nb_sections; + int flags = SHF_ALLOC; tok1 = tok; /* XXX: support more options */ @@ -870,10 +871,17 @@ static void asm_parse_directive(TCCState *s1, int global) next(); } if (tok == ',') { + const char *p; /* skip section options */ next(); if (tok != TOK_STR) expect("string constant"); + for (p = tokc.str.data; *p; ++p) { + if (*p == 'w') + flags |= SHF_WRITE; + if (*p == 'x') + flags |= SHF_EXECINSTR; + } next(); if (tok == ',') { next(); @@ -883,19 +891,17 @@ static void asm_parse_directive(TCCState *s1, int global) } } last_text_section = cur_text_section; - if (tok1 == TOK_ASMDIR_section) { + if (tok1 == TOK_ASMDIR_section) use_section(s1, sname); - /* The section directive supports flags, but they are unsupported. - For now, just assume any section contains code. */ - cur_text_section->sh_flags |= SHF_EXECINSTR; - } else push_section(s1, sname); /* If we just allocated a new section reset its alignment to 1. new_section normally acts for GCC compatibility and sets alignment to PTR_SIZE. The assembler behaves different. */ - if (old_nb_section != s1->nb_sections) + if (old_nb_section != s1->nb_sections) { cur_text_section->sh_addralign = 1; + cur_text_section->sh_flags = flags; + } } break; case TOK_ASMDIR_previous: diff --git a/tccelf.c b/tccelf.c index c01854ad..76057275 100644 --- a/tccelf.c +++ b/tccelf.c @@ -1488,7 +1488,7 @@ static void add_init_array_defines(TCCState *s1, const char *section_name) s = have_section(s1, section_name); if (!s || !(s->sh_flags & SHF_ALLOC)) { end_offset = 0; - s = data_section; + s = text_section; } else { end_offset = s->data_offset; } @@ -1823,11 +1823,14 @@ static void tcc_add_linker_symbols(TCCState *s1) for(i = 1; i < s1->nb_sections; i++) { s = s1->sections[i]; if ((s->sh_flags & SHF_ALLOC) - && (s->sh_type == SHT_PROGBITS + && (s->sh_type == SHT_PROGBITS || s->sh_type == SHT_NOBITS || s->sh_type == SHT_STRTAB)) { - const char *p; /* check if section name can be expressed in C */ - p = s->name; + const char *p0, *p; + p0 = s->name; + if (*p0 == '.') + ++p0; + p = p0; for(;;) { int c = *p; if (!c) @@ -1836,9 +1839,9 @@ static void tcc_add_linker_symbols(TCCState *s1) goto next_sec; p++; } - snprintf(buf, sizeof(buf), "__start_%s", s->name); + snprintf(buf, sizeof(buf), "__start_%s", p0); set_global_sym(s1, buf, s, 0); - snprintf(buf, sizeof(buf), "__stop_%s", s->name); + snprintf(buf, sizeof(buf), "__stop_%s", p0); set_global_sym(s1, buf, s, -1); } next_sec: ; @@ -2123,6 +2126,7 @@ struct dyn_inf { ElfW(Phdr) *phdr; int phnum; + int shnum; Section *interp; Section *note; Section *gnu_hash; @@ -2135,7 +2139,7 @@ struct dyn_inf { program headers are filled since they contain info about the layout. We do the following ordering: interp, symbol tables, relocations, progbits, nobits */ -static int sort_sections(TCCState *s1, int *sec_order, Section *interp) +static int sort_sections(TCCState *s1, int *sec_order, struct dyn_inf *d) { Section *s; int i, j, k, f, f0, n; @@ -2144,16 +2148,16 @@ static int sort_sections(TCCState *s1, int *sec_order, Section *interp) for (i = 1; i < nb_sections; i++) { s = s1->sections[i]; - if (s->sh_flags & SHF_ALLOC) { + if (0 == s->sh_name) { + j = 0x900; /* no sh_name: won't go to file */ + } else if (s->sh_flags & SHF_ALLOC) { j = 0x100; if (s->sh_flags & SHF_WRITE) j = 0x200; if (s->sh_flags & SHF_TLS) j += 0x200; - } else if (s->sh_name) { - j = 0x700; } else { - j = 0x900; /* no sh_name: won't go to file */ + j = 0x700; } if (s->sh_type == SHT_SYMTAB || s->sh_type == SHT_DYNSYM) { k = 0x10; @@ -2191,7 +2195,7 @@ static int sort_sections(TCCState *s1, int *sec_order, Section *interp) k = 0x70; if (s->sh_type == SHT_NOBITS) k = 0x80; - if (s == interp) + if (s == d->interp) k = 0x00; } k += j; @@ -2201,6 +2205,7 @@ static int sort_sections(TCCState *s1, int *sec_order, Section *interp) sec_cls[n] = k, sec_order[n] = i; } sec_order[0] = 0; + d->shnum = 1; /* count PT_LOAD headers needed */ n = f0 = 0; @@ -2208,21 +2213,25 @@ static int sort_sections(TCCState *s1, int *sec_order, Section *interp) s = s1->sections[sec_order[i]]; k = sec_cls[i]; f = 0; + if (k < 0x900) + ++d->shnum; if (k < 0x700) { f = s->sh_flags & (SHF_ALLOC|SHF_WRITE|SHF_EXECINSTR|SHF_TLS); #if TARGETOS_NetBSD /* NetBSD only supports 2 PT_LOAD sections. See: https://blog.netbsd.org/tnf/entry/the_first_report_on_lld */ - if ((f & SHF_WRITE) == 0) f |= SHF_EXECINSTR; + if ((f & SHF_WRITE) == 0) + f |= SHF_EXECINSTR; #else if ((k & 0xfff0) == 0x240) /* RELRO sections */ f |= 1<<4; #endif - if (f != f0) /* start new header when flags changed or relro */ + /* start new header when flags changed or relro, but avoid zero memsz */ + if (f != f0 && s->sh_size) f0 = f, ++n, f |= 1<<8; } sec_cls[i] = f; - //printf("ph %d sec %02d : %3X %3X %8.2X %04X %s\n", !!f * n, i, f, k, s->sh_type, s->sh_size, s->name); + //printf("ph %d sec %02d : %3X %3X %8.2X %04X %s\n", (f>0) * n, i, f, k, s->sh_type, s->sh_size, s->name); } return n; } @@ -2253,7 +2262,7 @@ static int layout_sections(TCCState *s1, int *sec_order, struct dyn_inf *d) int file_offset; /* compute number of program headers */ - phnum = sort_sections(s1, sec_order, d->interp); + phnum = sort_sections(s1, sec_order, d); phfill = 0; /* set to 1 to have dll's with a PT_PHDR */ if (d->interp) phfill = 2; @@ -2268,8 +2277,10 @@ static int layout_sections(TCCState *s1, int *sec_order, struct dyn_inf *d) d->phdr = tcc_mallocz(phnum * sizeof(ElfW(Phdr))); file_offset = 0; - if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) - file_offset = sizeof(ElfW(Ehdr)) + phnum * sizeof(ElfW(Phdr)); + if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) { + file_offset = (sizeof(ElfW(Ehdr)) + phnum * sizeof(ElfW(Phdr)) + 3) & -4; + file_offset += d->shnum * sizeof (ElfW(Shdr)); + } s_align = ELF_PAGE_SIZE; if (s1->section_align) @@ -2392,7 +2403,7 @@ static int layout_sections(TCCState *s1, int *sec_order, struct dyn_inf *d) ph->p_align = 4; fill_phdr(ph, PT_PHDR, NULL); } - return file_offset; + return 0; } /* put dynamic tag */ @@ -2505,14 +2516,11 @@ static void update_reloc_sections(TCCState *s1, struct dyn_inf *dyninf) } } } - -static int tidy_section_headers(TCCState *s1, int *sec_order); #endif /* ndef ELF_OBJ_ONLY */ /* Create an ELF file on disk. This function handle ELF specific layout requirements */ -static int tcc_output_elf(TCCState *s1, FILE *f, int phnum, ElfW(Phdr) *phdr, - int file_offset, int *sec_order) +static int tcc_output_elf(TCCState *s1, FILE *f, int phnum, ElfW(Phdr) *phdr) { int i, shnum, offset, size, file_type; Section *s; @@ -2523,19 +2531,12 @@ static int tcc_output_elf(TCCState *s1, FILE *f, int phnum, ElfW(Phdr) *phdr, shnum = s1->nb_sections; memset(&ehdr, 0, sizeof(ehdr)); - if (phnum > 0) { ehdr.e_phentsize = sizeof(ElfW(Phdr)); ehdr.e_phnum = phnum; ehdr.e_phoff = sizeof(ElfW(Ehdr)); -#ifndef ELF_OBJ_ONLY - shnum = tidy_section_headers(s1, sec_order); -#endif } - /* align to 4 */ - file_offset = (file_offset + 3) & -4; - /* fill header */ ehdr.e_ident[0] = ELFMAG0; ehdr.e_ident[1] = ELFMAG1; @@ -2577,32 +2578,15 @@ static int tcc_output_elf(TCCState *s1, FILE *f, int phnum, ElfW(Phdr) *phdr, ehdr.e_machine = EM_TCC_TARGET; ehdr.e_version = EV_CURRENT; - ehdr.e_shoff = file_offset; + ehdr.e_shoff = (sizeof(ElfW(Ehdr)) + phnum * sizeof(ElfW(Phdr)) + 3) & -4; ehdr.e_ehsize = sizeof(ElfW(Ehdr)); ehdr.e_shentsize = sizeof(ElfW(Shdr)); ehdr.e_shnum = shnum; ehdr.e_shstrndx = shnum - 1; - fwrite(&ehdr, 1, sizeof(ElfW(Ehdr)), f); + offset = fwrite(&ehdr, 1, sizeof(ElfW(Ehdr)), f); if (phdr) - fwrite(phdr, 1, phnum * sizeof(ElfW(Phdr)), f); - offset = sizeof(ElfW(Ehdr)) + phnum * sizeof(ElfW(Phdr)); - - sort_syms(s1, symtab_section); - - for(i = 1; i < shnum; i++) { - s = s1->sections[sec_order ? sec_order[i] : i]; - if (s->sh_type != SHT_NOBITS) { - while (offset < s->sh_offset) { - fputc(0, f); - offset++; - } - size = s->sh_size; - if (size) - fwrite(s->data, 1, size, f); - offset += size; - } - } + offset += fwrite(phdr, 1, phnum * sizeof(ElfW(Phdr)), f); /* output section headers */ while (offset < ehdr.e_shoff) { @@ -2613,8 +2597,8 @@ static int tcc_output_elf(TCCState *s1, FILE *f, int phnum, ElfW(Phdr) *phdr, for(i = 0; i < shnum; i++) { sh = &shdr; memset(sh, 0, sizeof(ElfW(Shdr))); - s = s1->sections[i]; - if (s) { + if (i) { + s = s1->sections[i]; sh->sh_name = s->sh_name; sh->sh_type = s->sh_type; sh->sh_flags = s->sh_flags; @@ -2627,20 +2611,35 @@ static int tcc_output_elf(TCCState *s1, FILE *f, int phnum, ElfW(Phdr) *phdr, sh->sh_offset = s->sh_offset; sh->sh_size = s->sh_size; } - fwrite(sh, 1, sizeof(ElfW(Shdr)), f); + offset += fwrite(sh, 1, sizeof(ElfW(Shdr)), f); + } + + sort_syms(s1, s1->symtab); + + /* output sections */ + for(i = 1; i < s1->nb_sections; i++) { + s = s1->sections[i]; + if (s->sh_type != SHT_NOBITS) { + while (offset < s->sh_offset) { + fputc(0, f); + offset++; + } + size = s->sh_size; + if (size) + offset += fwrite(s->data, 1, size, f); + } } return 0; } -static int tcc_output_binary(TCCState *s1, FILE *f, - const int *sec_order) +static int tcc_output_binary(TCCState *s1, FILE *f) { Section *s; int i, offset, size; offset = 0; for(i=1;inb_sections;i++) { - s = s1->sections[sec_order[i]]; + s = s1->sections[i]; if (s->sh_type != SHT_NOBITS && (s->sh_flags & SHF_ALLOC)) { while (offset < s->sh_offset) { @@ -2657,7 +2656,7 @@ static int tcc_output_binary(TCCState *s1, FILE *f, /* Write an elf, coff or "binary" file */ static int tcc_write_elf_file(TCCState *s1, const char *filename, int phnum, - ElfW(Phdr) *phdr, int file_offset, int *sec_order) + ElfW(Phdr) *phdr) { int fd, mode, file_type, ret; FILE *f; @@ -2679,59 +2678,50 @@ static int tcc_write_elf_file(TCCState *s1, const char *filename, int phnum, else #endif if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) - ret = tcc_output_elf(s1, f, phnum, phdr, file_offset, sec_order); + ret = tcc_output_elf(s1, f, phnum, phdr); else - ret = tcc_output_binary(s1, f, sec_order); + ret = tcc_output_binary(s1, f); fclose(f); return ret; } #ifndef ELF_OBJ_ONLY -/* Sort section headers by assigned sh_addr, remove sections +/* order sections according to sec_order, remove sections that we aren't going to output. */ -static int tidy_section_headers(TCCState *s1, int *sec_order) +static void reorder_sections(TCCState *s1, int *sec_order) { - int i, nnew, l, *backmap; + int i, nnew, k, *backmap; Section **snew, *s; ElfW(Sym) *sym; - snew = tcc_malloc(s1->nb_sections * sizeof(snew[0])); backmap = tcc_malloc(s1->nb_sections * sizeof(backmap[0])); - for (i = 0, nnew = 0, l = s1->nb_sections; i < s1->nb_sections; i++) { - s = s1->sections[sec_order[i]]; + for (i = 0, nnew = 0, snew = NULL; i < s1->nb_sections; i++) { + k = sec_order[i]; + s = s1->sections[k]; if (!i || s->sh_name) { - backmap[sec_order[i]] = nnew; - snew[nnew] = s; - ++nnew; + backmap[k] = nnew; + dynarray_add(&snew, &nnew, s); } else { - backmap[sec_order[i]] = 0; - snew[--l] = s; + backmap[k] = 0; + /* just remember to free them later */ + dynarray_add(&s1->priv_sections, &s1->nb_priv_sections, s); } } - for (i = 0; i < nnew; i++) { + for (i = 1; i < nnew; i++) { s = snew[i]; - if (s) { - s->sh_num = i; - if (s->sh_type == SHT_RELX) - s->sh_info = backmap[s->sh_info]; - } + s->sh_num = i; + if (s->sh_type == SHT_RELX) + s->sh_info = backmap[s->sh_info]; + else if (s->sh_type == SHT_SYMTAB || s->sh_type == SHT_DYNSYM) + for_each_elem(s, 1, sym, ElfW(Sym)) + if (sym->st_shndx < s1->nb_sections) + sym->st_shndx = backmap[sym->st_shndx]; } - - for_each_elem(symtab_section, 1, sym, ElfW(Sym)) - if (sym->st_shndx != SHN_UNDEF && sym->st_shndx < SHN_LORESERVE) - sym->st_shndx = backmap[sym->st_shndx]; - if ( !s1->static_link ) { - for_each_elem(s1->dynsym, 1, sym, ElfW(Sym)) - if (sym->st_shndx != SHN_UNDEF && sym->st_shndx < SHN_LORESERVE) - sym->st_shndx = backmap[sym->st_shndx]; - } - for (i = 0; i < s1->nb_sections; i++) - sec_order[i] = i; tcc_free(s1->sections); s1->sections = snew; + s1->nb_sections = nnew; tcc_free(backmap); - return nnew; } #ifdef TCC_TARGET_ARM @@ -2797,7 +2787,7 @@ static void alloc_sec_names(TCCState *s1, int is_obj); /* XXX: suppress unneeded sections */ static int elf_output_file(TCCState *s1, const char *filename) { - int i, ret, file_type, file_offset, *sec_order; + int i, ret, file_type, *sec_order; struct dyn_inf dyninf = {0}; Section *interp, *dynstr, *dynamic; int textrel, got_sym, dt_flags_1; @@ -2876,7 +2866,6 @@ static int elf_output_file(TCCState *s1, const char *filename) version_add (s1); textrel = set_sec_sizes(s1); - alloc_sec_names(s1, 0); if (!s1->static_link) { /* add a list of needed dlls */ @@ -2915,10 +2904,12 @@ static int elf_output_file(TCCState *s1, const char *filename) dynstr->sh_size = dynstr->data_offset; } + /* create and fill .shstrtab section */ + alloc_sec_names(s1, 0); /* this array is used to reorder sections in the output file */ sec_order = tcc_malloc(sizeof(int) * 2 * s1->nb_sections); /* compute section to program header mapping */ - file_offset = layout_sections(s1, sec_order, &dyninf); + layout_sections(s1, sec_order, &dyninf); if (dynamic) { /* put in GOT the dynamic section address and relocate PLT */ @@ -2950,8 +2941,10 @@ static int elf_output_file(TCCState *s1, const char *filename) if (dyninf.gnu_hash) update_gnu_hash(s1, dyninf.gnu_hash); + reorder_sections(s1, sec_order); + /* Create the ELF file with name 'filename' */ - ret = tcc_write_elf_file(s1, filename, dyninf.phnum, dyninf.phdr, file_offset, sec_order); + ret = tcc_write_elf_file(s1, filename, dyninf.phnum, dyninf.phdr); the_end: tcc_free(sec_order); tcc_free(dyninf.phdr); @@ -2971,7 +2964,7 @@ static void alloc_sec_names(TCCState *s1, int is_obj) s = s1->sections[i]; if (is_obj) s->sh_size = s->data_offset; - if (s == strsec || s->sh_size || (s->sh_flags & SHF_ALLOC)) + if (s->sh_size || s == strsec || (s->sh_flags & SHF_ALLOC) || is_obj) s->sh_name = put_elf_str(strsec, s->name); } strsec->sh_size = strsec->data_offset; @@ -2985,7 +2978,8 @@ static int elf_output_obj(TCCState *s1, const char *filename) s1->nb_errors = 0; /* Allocate strings for section names */ alloc_sec_names(s1, 1); - file_offset = sizeof (ElfW(Ehdr)); + file_offset = (sizeof (ElfW(Ehdr)) + 3) & -4; + file_offset += s1->nb_sections * sizeof(ElfW(Shdr)); for(i = 1; i < s1->nb_sections; i++) { s = s1->sections[i]; file_offset = (file_offset + 15) & -16; @@ -2994,7 +2988,7 @@ static int elf_output_obj(TCCState *s1, const char *filename) file_offset += s->sh_size; } /* Create the ELF file with name 'filename' */ - ret = tcc_write_elf_file(s1, filename, 0, NULL, file_offset, NULL); + ret = tcc_write_elf_file(s1, filename, 0, NULL); return ret; } diff --git a/tccgen.c b/tccgen.c index 94315823..1cf93304 100644 --- a/tccgen.c +++ b/tccgen.c @@ -5716,6 +5716,12 @@ ST_FUNC void unary(void) vtop--; vpushi(n); break; + case TOK_builtin_unreachable: + parse_builtin_params(0, ""); /* just skip '()' */ + type.t = VT_VOID; + vpush(&type); + CODE_OFF(); + break; case TOK_builtin_frame_address: case TOK_builtin_return_address: { @@ -8306,7 +8312,6 @@ static void gen_function(Sym *sym) cur_scope = root_scope = &f; nocode_wanted = 0; - cur_text_section->sh_flags |= SHF_EXECINSTR; ind = cur_text_section->data_offset; if (sym->a.aligned) { size_t newoff = section_add(cur_text_section, 0, @@ -8602,6 +8607,8 @@ static int decl(int l) cur_text_section = ad.section; if (!cur_text_section) cur_text_section = text_section; + else if (cur_text_section->sh_num > bss_section->sh_num) + cur_text_section->sh_flags = text_section->sh_flags; gen_function(sym); } break; diff --git a/tccpe.c b/tccpe.c index c87814d3..f7bd67ce 100644 --- a/tccpe.c +++ b/tccpe.c @@ -525,7 +525,7 @@ static int pe_put_long_secname(char *secname, const char *name) const char *d = dwarf_secs; do { if (0 == strcmp(d, name)) { - sprintf(secname, "/%d", (int)(d - dwarf_secs + 4)); + snprintf(secname, 8, "/%d", (int)(d - dwarf_secs + 4)); return 1; } d = strchr(d, 0) + 1; @@ -1871,10 +1871,11 @@ static unsigned pe_add_uwwind_info(TCCState *s1) 0x04, // UBYTE Size of prolog 0x02, // UBYTE Count of unwind codes 0x05, // UBYTE: 4 Frame Register (rbp), UBYTE: 4 Frame Register offset (scaled) - // USHORT * n Unwind codes array + // USHORT * n Unwind codes array (descending order) // 0x0b, 0x01, 0xff, 0xff, // stack size - 0x04, 0x03, // set frame ptr (mov rsp -> rbp) - 0x01, 0x50 // push reg (rbp) + // UBYTE offset of end of instr in prolog + 1, UBYTE:4 operation, UBYTE:4 info + 0x04, 0x03, // 3:0 UWOP_SET_FPREG (mov rsp -> rbp) + 0x01, 0x50, // 0:5 UWOP_PUSH_NONVOL (push rbp) }; Section *s = text_section; diff --git a/tcctok.h b/tcctok.h index 08890e1d..f2ebd815 100644 --- a/tcctok.h +++ b/tcctok.h @@ -171,6 +171,7 @@ DEF(TOK_builtin_frame_address, "__builtin_frame_address") DEF(TOK_builtin_return_address, "__builtin_return_address") DEF(TOK_builtin_expect, "__builtin_expect") + DEF(TOK_builtin_unreachable, "__builtin_unreachable") /*DEF(TOK_builtin_va_list, "__builtin_va_list")*/ #if defined TCC_TARGET_PE && defined TCC_TARGET_X86_64 DEF(TOK_builtin_va_start, "__builtin_va_start") diff --git a/tcctools.c b/tcctools.c index 5eb4349d..8e158d55 100644 --- a/tcctools.c +++ b/tcctools.c @@ -504,28 +504,21 @@ ST_FUNC int tcc_tool_cross(TCCState *s1, char **argv, int option) #ifdef _WIN32 #include -static char *str_replace(const char *str, const char *p, const char *r) +/* quote quotes in string and quote string if it contains spaces */ +static char *quote_win32(const char *s0) { - const char *s, *s0; - char *d, *d0; - int sl, pl, rl; - - sl = strlen(str); - pl = strlen(p); - rl = strlen(r); - for (d0 = NULL;; d0 = tcc_malloc(sl + 1)) { - for (d = d0, s = str; s0 = s, s = strstr(s, p), s; s += pl) { - if (d) { - memcpy(d, s0, sl = s - s0), d += sl; - memcpy(d, r, rl), d += rl; - } else - sl += rl - pl; - } - if (d) { - strcpy(d, s0); - return d0; - } - } + const char *s; + char *p, *q; + int a = 0, b = 0, c; + for (s = s0; !!(c = *s); ++s) + a += c == '"', b |= c == ' '; + q = p = tcc_malloc(s - s0 + a + b + b + 1); + *q = '"', q += b; + for (s = s0; !!(c = *s); *q++ = c, ++s) + if (c == '"') + *q++ = '\\'; + *q = '"', q += b, *q = '\0'; + return p; } static int execvp_win32(const char *prog, char **argv) @@ -533,8 +526,7 @@ static int execvp_win32(const char *prog, char **argv) int ret; char **p; /* replace all " by \" */ for (p = argv; *p; ++p) - if (strchr(*p, '"')) - *p = str_replace(*p, "\"", "\\\""); + *p = quote_win32(*p); ret = _spawnvp(P_NOWAIT, prog, (const char *const*)argv); if (-1 == ret) return ret; diff --git a/tests/exec_section_in_asm.c b/tests/exec_section_in_asm.c deleted file mode 100644 index 671b776a..00000000 --- a/tests/exec_section_in_asm.c +++ /dev/null @@ -1,29 +0,0 @@ -/* This test only works on x86-64. */ -/* Previously in TinyCC, ELF sections defined in assembly would always have the -execute bit not set, so you would get segmentation faults when code in these -sections was exectuted. This file is a minimal example of a file that will put -the resulting code in a non-executable section (and invoke it) prior to the fix. -*/ -#include - -void *memset(void *dst, int c, int len); - -__asm__ ( -".section .text.nolibc_memset\n" -".weak memset\n" -"memset:\n" - "xchgl %eax, %esi\n\t" - "movq %rdx, %rcx\n\t" - "pushq %rdi\n\t" - "rep stosb\n\t" - "popq %rax\n\t" - "retq\n" -); - -int main () { - char buf[10]; - memset(&buf[0], 'A', 9); - buf[9] = 0; - puts(buf); - return 0; -} diff --git a/tests/tcctest.c b/tests/tcctest.c index 531bb67f..efc31e26 100644 --- a/tests/tcctest.c +++ b/tests/tcctest.c @@ -3989,7 +3989,7 @@ void builtin_test(void) } } -#if defined _WIN32 +#if defined _WIN32 || (defined __APPLE__ && GCC_MAJOR >= 15) void weak_test(void) {} #else extern int __attribute__((weak)) weak_f1(void); diff --git a/tests/tests2/133_exec_section_in_c.c b/tests/tests2/133_exec_section_in_c.c deleted file mode 100644 index fea8e2f9..00000000 --- a/tests/tests2/133_exec_section_in_c.c +++ /dev/null @@ -1,17 +0,0 @@ -#include - -/* Previously in TinyCC, ELF sections defined in attributes would always have -the execute bit not set, so you would get segmentation faults when code in these -sections was exectuted. This file is a minimal example of a file that will put -the resulting code in a non-executable section (and invoke it) prior to the fix. -*/ -__attribute__((section(".text.wumbo"))) -int wumbo (int arg) { - return arg * 2; -} - -int main () { - wumbo(2); - puts("hi"); - return 0; -} diff --git a/tests/tests2/133_exec_section_in_c.expect b/tests/tests2/133_exec_section_in_c.expect deleted file mode 100644 index 45b983be..00000000 --- a/tests/tests2/133_exec_section_in_c.expect +++ /dev/null @@ -1 +0,0 @@ -hi diff --git a/x86_64-gen.c b/x86_64-gen.c index e1ed7199..a792ba67 100644 --- a/x86_64-gen.c +++ b/x86_64-gen.c @@ -489,7 +489,7 @@ void load(int r, SValue *sv) } #endif } else if (is64_type(ft)) { - if (sv->c.i > UINT32_MAX) { + if (sv->c.i >> 32) { orex(1,r,0, 0xb8 + REG_VALUE(r)); /* movabs $xx, r */ gen_le64(sv->c.i); } else if (sv->c.i > 0) { @@ -1017,7 +1017,7 @@ void gfunc_prolog(Sym *func_sym) /* generate function epilog */ void gfunc_epilog(void) { - int v, saved_ind; + int v, start; /* align local size to word & save local variables */ func_scratch = (func_scratch + 15) & -16; @@ -1037,10 +1037,12 @@ void gfunc_epilog(void) g(func_ret_sub >> 8); } - saved_ind = ind; - ind = func_sub_sp_offset - FUNC_PROLOG_SIZE; v = -loc; + start = func_sub_sp_offset - FUNC_PROLOG_SIZE; + cur_text_section->data_offset = ind; + pe_add_unwind_data(start, ind, v); + ind = start; if (v >= 4096) { Sym *sym = external_helper_sym(TOK___chkstk); oad(0xb8, v); /* mov stacksize, %eax */ @@ -1052,13 +1054,10 @@ void gfunc_epilog(void) o(0xec8148); /* sub rsp, stacksize */ gen_le32(v); } + ind = cur_text_section->data_offset; /* add the "func_scratch" area after each alloca seen */ gsym_addr(func_alloca, -func_scratch); - - cur_text_section->data_offset = saved_ind; - pe_add_unwind_data(ind, saved_ind, v); - ind = cur_text_section->data_offset; } #else -- 2.11.4.GIT