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 e4d874d88a)
- 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
This commit is contained in:
grischka 2024-10-09 23:15:05 +02:00
parent c21576f8a3
commit 45cff8f03f
16 changed files with 171 additions and 196 deletions

View file

@ -10,7 +10,7 @@ jobs:
timeout-minutes: 2 timeout-minutes: 2
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: make & test tcc - name: make & test tcc (x86_64-linux)
run: ./configure && make && make test -k run: ./configure && make && make test -k
test-x86_64-osx: test-x86_64-osx:
@ -18,21 +18,36 @@ jobs:
timeout-minutes: 2 timeout-minutes: 2
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: make & test tcc - name: make & test tcc (x86_64-osx)
run: ./configure --config-codesign=no && make && make test -k run: ./configure && make && make test -k
test-x86_64-win32: test-aarch64-osx:
runs-on: windows-2019 runs-on: macos-14
timeout-minutes: 4 timeout-minutes: 2
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: make & test tcc - name: make & test tcc (aarch64-osx)
run: ./configure && make && make test -k
test-x86-win32:
runs-on: windows-2019
timeout-minutes: 6
steps:
- uses: actions/checkout@v4
- name: make & test tcc (x86_64-win32)
shell: cmd shell: cmd
run: | run: |
set MSYS2_PATH_TYPE=inherit set MSYS2_PATH_TYPE=inherit
set MSYSTEM=MINGW64 set MSYSTEM=MINGW64
set CHERE_INVOKING=yes set CHERE_INVOKING=yes
C:\msys64\usr\bin\bash -l -c "./configure && make && make test -k" 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: test-armv7-linux:
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
@ -40,6 +55,7 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: uraimo/run-on-arch-action@v2 - uses: uraimo/run-on-arch-action@v2
name: make & test tcc (armv7-linux)
with: with:
arch: armv7 arch: armv7
distro: ubuntu20.04 distro: ubuntu20.04
@ -57,6 +73,7 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: uraimo/run-on-arch-action@v2 - uses: uraimo/run-on-arch-action@v2
name: make & test tcc (aarch64-linux)
with: with:
arch: aarch64 arch: aarch64
distro: ubuntu20.04 distro: ubuntu20.04
@ -74,6 +91,7 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: uraimo/run-on-arch-action@v2 - uses: uraimo/run-on-arch-action@v2
name: make & test tcc (riscv64-linux)
with: with:
arch: riscv64 arch: riscv64
distro: ubuntu20.04 distro: ubuntu20.04

View file

@ -69,7 +69,10 @@ else
ifdef CONFIG_OSX ifdef CONFIG_OSX
NATIVE_TARGET = $(ARCH)-osx NATIVE_TARGET = $(ARCH)-osx
ifneq ($(CC_NAME),tcc) 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 endif
export MACOSX_DEPLOYMENT_TARGET := 10.6 export MACOSX_DEPLOYMENT_TARGET := 10.6
endif endif

3
configure vendored
View file

@ -227,10 +227,12 @@ fi
# OS specific # OS specific
buildos=$(uname) buildos=$(uname)
cpu_sys=$(uname -m)
case $buildos in case $buildos in
Windows_NT|MINGW*|MSYS*|CYGWIN*) Windows_NT|MINGW*|MSYS*|CYGWIN*)
buildos="WIN32" buildos="WIN32"
test "$MSYSTEM" = "MINGW32" && cpu_sys=i386
;; ;;
Linux) Linux)
if test "$(uname -o)" = "Android"; then if test "$(uname -o)" = "Android"; then
@ -248,7 +250,6 @@ else
default targetos "$buildos" default targetos "$buildos"
fi fi
cpu_sys=$(uname -m)
default cpu "$cpu_sys" default cpu "$cpu_sys"
cpu_set="$cpu" cpu_set="$cpu"

View file

@ -152,6 +152,7 @@
#define __PRETTY_FUNCTION__ __FUNCTION__ #define __PRETTY_FUNCTION__ __FUNCTION__
#define __has_builtin(x) 0 #define __has_builtin(x) 0
#define __has_feature(x) 0 #define __has_feature(x) 0
#define __has_atttribute(x) 0
/* C23 Keywords */ /* C23 Keywords */
#define _Nonnull #define _Nonnull
#define _Nullable #define _Nullable

3
tcc.c
View file

@ -33,8 +33,6 @@ static const char help[] =
" -o outfile set output filename\n" " -o outfile set output filename\n"
" -run run compiled source\n" " -run run compiled source\n"
" -fflag set or reset (with 'no-' prefix) 'flag' (see tcc -hh)\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" " -Wwarning set or reset (with 'no-' prefix) 'warning' (see tcc -hh)\n"
" -w disable all warnings\n" " -w disable all warnings\n"
" -v --version show version\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" " -bt[N] link with backtrace (stack dump) support [show max N callers]\n"
#endif #endif
"Misc. options:\n" "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" " -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" " -nostdinc do not use standard system include paths\n"
" -nostdlib do not link with standard crt and libraries\n" " -nostdlib do not link with standard crt and libraries\n"

View file

@ -857,6 +857,7 @@ static void asm_parse_directive(TCCState *s1, int global)
{ {
char sname[256]; char sname[256];
int old_nb_section = s1->nb_sections; int old_nb_section = s1->nb_sections;
int flags = SHF_ALLOC;
tok1 = tok; tok1 = tok;
/* XXX: support more options */ /* XXX: support more options */
@ -870,10 +871,17 @@ static void asm_parse_directive(TCCState *s1, int global)
next(); next();
} }
if (tok == ',') { if (tok == ',') {
const char *p;
/* skip section options */ /* skip section options */
next(); next();
if (tok != TOK_STR) if (tok != TOK_STR)
expect("string constant"); expect("string constant");
for (p = tokc.str.data; *p; ++p) {
if (*p == 'w')
flags |= SHF_WRITE;
if (*p == 'x')
flags |= SHF_EXECINSTR;
}
next(); next();
if (tok == ',') { if (tok == ',') {
next(); next();
@ -883,19 +891,17 @@ static void asm_parse_directive(TCCState *s1, int global)
} }
} }
last_text_section = cur_text_section; last_text_section = cur_text_section;
if (tok1 == TOK_ASMDIR_section) { if (tok1 == TOK_ASMDIR_section)
use_section(s1, sname); 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 else
push_section(s1, sname); push_section(s1, sname);
/* If we just allocated a new section reset its alignment to /* If we just allocated a new section reset its alignment to
1. new_section normally acts for GCC compatibility and 1. new_section normally acts for GCC compatibility and
sets alignment to PTR_SIZE. The assembler behaves different. */ 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_addralign = 1;
cur_text_section->sh_flags = flags;
}
} }
break; break;
case TOK_ASMDIR_previous: case TOK_ASMDIR_previous:

184
tccelf.c
View file

@ -1488,7 +1488,7 @@ static void add_init_array_defines(TCCState *s1, const char *section_name)
s = have_section(s1, section_name); s = have_section(s1, section_name);
if (!s || !(s->sh_flags & SHF_ALLOC)) { if (!s || !(s->sh_flags & SHF_ALLOC)) {
end_offset = 0; end_offset = 0;
s = data_section; s = text_section;
} else { } else {
end_offset = s->data_offset; 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++) { for(i = 1; i < s1->nb_sections; i++) {
s = s1->sections[i]; s = s1->sections[i];
if ((s->sh_flags & SHF_ALLOC) 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)) { || s->sh_type == SHT_STRTAB)) {
const char *p;
/* check if section name can be expressed in C */ /* 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(;;) { for(;;) {
int c = *p; int c = *p;
if (!c) if (!c)
@ -1836,9 +1839,9 @@ static void tcc_add_linker_symbols(TCCState *s1)
goto next_sec; goto next_sec;
p++; p++;
} }
snprintf(buf, sizeof(buf), "__start_%s", s->name); snprintf(buf, sizeof(buf), "__start_%s", p0);
set_global_sym(s1, buf, s, 0); 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); set_global_sym(s1, buf, s, -1);
} }
next_sec: ; next_sec: ;
@ -2123,6 +2126,7 @@ struct dyn_inf {
ElfW(Phdr) *phdr; ElfW(Phdr) *phdr;
int phnum; int phnum;
int shnum;
Section *interp; Section *interp;
Section *note; Section *note;
Section *gnu_hash; Section *gnu_hash;
@ -2135,7 +2139,7 @@ struct dyn_inf {
program headers are filled since they contain info about the layout. program headers are filled since they contain info about the layout.
We do the following ordering: interp, symbol tables, relocations, progbits, We do the following ordering: interp, symbol tables, relocations, progbits,
nobits */ 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; Section *s;
int i, j, k, f, f0, n; 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++) { for (i = 1; i < nb_sections; i++) {
s = s1->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; j = 0x100;
if (s->sh_flags & SHF_WRITE) if (s->sh_flags & SHF_WRITE)
j = 0x200; j = 0x200;
if (s->sh_flags & SHF_TLS) if (s->sh_flags & SHF_TLS)
j += 0x200; j += 0x200;
} else if (s->sh_name) {
j = 0x700;
} else { } else {
j = 0x900; /* no sh_name: won't go to file */ j = 0x700;
} }
if (s->sh_type == SHT_SYMTAB || s->sh_type == SHT_DYNSYM) { if (s->sh_type == SHT_SYMTAB || s->sh_type == SHT_DYNSYM) {
k = 0x10; k = 0x10;
@ -2191,7 +2195,7 @@ static int sort_sections(TCCState *s1, int *sec_order, Section *interp)
k = 0x70; k = 0x70;
if (s->sh_type == SHT_NOBITS) if (s->sh_type == SHT_NOBITS)
k = 0x80; k = 0x80;
if (s == interp) if (s == d->interp)
k = 0x00; k = 0x00;
} }
k += j; 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_cls[n] = k, sec_order[n] = i;
} }
sec_order[0] = 0; sec_order[0] = 0;
d->shnum = 1;
/* count PT_LOAD headers needed */ /* count PT_LOAD headers needed */
n = f0 = 0; n = f0 = 0;
@ -2208,21 +2213,25 @@ static int sort_sections(TCCState *s1, int *sec_order, Section *interp)
s = s1->sections[sec_order[i]]; s = s1->sections[sec_order[i]];
k = sec_cls[i]; k = sec_cls[i];
f = 0; f = 0;
if (k < 0x900)
++d->shnum;
if (k < 0x700) { if (k < 0x700) {
f = s->sh_flags & (SHF_ALLOC|SHF_WRITE|SHF_EXECINSTR|SHF_TLS); f = s->sh_flags & (SHF_ALLOC|SHF_WRITE|SHF_EXECINSTR|SHF_TLS);
#if TARGETOS_NetBSD #if TARGETOS_NetBSD
/* NetBSD only supports 2 PT_LOAD sections. /* NetBSD only supports 2 PT_LOAD sections.
See: https://blog.netbsd.org/tnf/entry/the_first_report_on_lld */ 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 #else
if ((k & 0xfff0) == 0x240) /* RELRO sections */ if ((k & 0xfff0) == 0x240) /* RELRO sections */
f |= 1<<4; f |= 1<<4;
#endif #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; f0 = f, ++n, f |= 1<<8;
} }
sec_cls[i] = f; 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; return n;
} }
@ -2253,7 +2262,7 @@ static int layout_sections(TCCState *s1, int *sec_order, struct dyn_inf *d)
int file_offset; int file_offset;
/* compute number of program headers */ /* 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 */ phfill = 0; /* set to 1 to have dll's with a PT_PHDR */
if (d->interp) if (d->interp)
phfill = 2; 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))); d->phdr = tcc_mallocz(phnum * sizeof(ElfW(Phdr)));
file_offset = 0; file_offset = 0;
if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) {
file_offset = sizeof(ElfW(Ehdr)) + phnum * sizeof(ElfW(Phdr)); file_offset = (sizeof(ElfW(Ehdr)) + phnum * sizeof(ElfW(Phdr)) + 3) & -4;
file_offset += d->shnum * sizeof (ElfW(Shdr));
}
s_align = ELF_PAGE_SIZE; s_align = ELF_PAGE_SIZE;
if (s1->section_align) 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; ph->p_align = 4;
fill_phdr(ph, PT_PHDR, NULL); fill_phdr(ph, PT_PHDR, NULL);
} }
return file_offset; return 0;
} }
/* put dynamic tag */ /* 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 */ #endif /* ndef ELF_OBJ_ONLY */
/* Create an ELF file on disk. /* Create an ELF file on disk.
This function handle ELF specific layout requirements */ This function handle ELF specific layout requirements */
static int tcc_output_elf(TCCState *s1, FILE *f, int phnum, ElfW(Phdr) *phdr, static int tcc_output_elf(TCCState *s1, FILE *f, int phnum, ElfW(Phdr) *phdr)
int file_offset, int *sec_order)
{ {
int i, shnum, offset, size, file_type; int i, shnum, offset, size, file_type;
Section *s; Section *s;
@ -2523,19 +2531,12 @@ static int tcc_output_elf(TCCState *s1, FILE *f, int phnum, ElfW(Phdr) *phdr,
shnum = s1->nb_sections; shnum = s1->nb_sections;
memset(&ehdr, 0, sizeof(ehdr)); memset(&ehdr, 0, sizeof(ehdr));
if (phnum > 0) { if (phnum > 0) {
ehdr.e_phentsize = sizeof(ElfW(Phdr)); ehdr.e_phentsize = sizeof(ElfW(Phdr));
ehdr.e_phnum = phnum; ehdr.e_phnum = phnum;
ehdr.e_phoff = sizeof(ElfW(Ehdr)); 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 */ /* fill header */
ehdr.e_ident[0] = ELFMAG0; ehdr.e_ident[0] = ELFMAG0;
ehdr.e_ident[1] = ELFMAG1; 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_machine = EM_TCC_TARGET;
ehdr.e_version = EV_CURRENT; 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_ehsize = sizeof(ElfW(Ehdr));
ehdr.e_shentsize = sizeof(ElfW(Shdr)); ehdr.e_shentsize = sizeof(ElfW(Shdr));
ehdr.e_shnum = shnum; ehdr.e_shnum = shnum;
ehdr.e_shstrndx = shnum - 1; ehdr.e_shstrndx = shnum - 1;
fwrite(&ehdr, 1, sizeof(ElfW(Ehdr)), f); offset = fwrite(&ehdr, 1, sizeof(ElfW(Ehdr)), f);
if (phdr) if (phdr)
fwrite(phdr, 1, phnum * sizeof(ElfW(Phdr)), f); offset += 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;
}
}
/* output section headers */ /* output section headers */
while (offset < ehdr.e_shoff) { 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++) { for(i = 0; i < shnum; i++) {
sh = &shdr; sh = &shdr;
memset(sh, 0, sizeof(ElfW(Shdr))); memset(sh, 0, sizeof(ElfW(Shdr)));
s = s1->sections[i]; if (i) {
if (s) { s = s1->sections[i];
sh->sh_name = s->sh_name; sh->sh_name = s->sh_name;
sh->sh_type = s->sh_type; sh->sh_type = s->sh_type;
sh->sh_flags = s->sh_flags; 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_offset = s->sh_offset;
sh->sh_size = s->sh_size; 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; return 0;
} }
static int tcc_output_binary(TCCState *s1, FILE *f, static int tcc_output_binary(TCCState *s1, FILE *f)
const int *sec_order)
{ {
Section *s; Section *s;
int i, offset, size; int i, offset, size;
offset = 0; offset = 0;
for(i=1;i<s1->nb_sections;i++) { for(i=1;i<s1->nb_sections;i++) {
s = s1->sections[sec_order[i]]; s = s1->sections[i];
if (s->sh_type != SHT_NOBITS && if (s->sh_type != SHT_NOBITS &&
(s->sh_flags & SHF_ALLOC)) { (s->sh_flags & SHF_ALLOC)) {
while (offset < s->sh_offset) { 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 */ /* Write an elf, coff or "binary" file */
static int tcc_write_elf_file(TCCState *s1, const char *filename, int phnum, 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; int fd, mode, file_type, ret;
FILE *f; FILE *f;
@ -2679,59 +2678,50 @@ static int tcc_write_elf_file(TCCState *s1, const char *filename, int phnum,
else else
#endif #endif
if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) 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 else
ret = tcc_output_binary(s1, f, sec_order); ret = tcc_output_binary(s1, f);
fclose(f); fclose(f);
return ret; return ret;
} }
#ifndef ELF_OBJ_ONLY #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. */ 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; Section **snew, *s;
ElfW(Sym) *sym; ElfW(Sym) *sym;
snew = tcc_malloc(s1->nb_sections * sizeof(snew[0]));
backmap = tcc_malloc(s1->nb_sections * sizeof(backmap[0])); backmap = tcc_malloc(s1->nb_sections * sizeof(backmap[0]));
for (i = 0, nnew = 0, l = s1->nb_sections; i < s1->nb_sections; i++) { for (i = 0, nnew = 0, snew = NULL; i < s1->nb_sections; i++) {
s = s1->sections[sec_order[i]]; k = sec_order[i];
s = s1->sections[k];
if (!i || s->sh_name) { if (!i || s->sh_name) {
backmap[sec_order[i]] = nnew; backmap[k] = nnew;
snew[nnew] = s; dynarray_add(&snew, &nnew, s);
++nnew;
} else { } else {
backmap[sec_order[i]] = 0; backmap[k] = 0;
snew[--l] = s; /* 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]; s = snew[i];
if (s) { s->sh_num = i;
s->sh_num = i; if (s->sh_type == SHT_RELX)
if (s->sh_type == SHT_RELX) s->sh_info = backmap[s->sh_info];
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); tcc_free(s1->sections);
s1->sections = snew; s1->sections = snew;
s1->nb_sections = nnew;
tcc_free(backmap); tcc_free(backmap);
return nnew;
} }
#ifdef TCC_TARGET_ARM #ifdef TCC_TARGET_ARM
@ -2797,7 +2787,7 @@ static void alloc_sec_names(TCCState *s1, int is_obj);
/* XXX: suppress unneeded sections */ /* XXX: suppress unneeded sections */
static int elf_output_file(TCCState *s1, const char *filename) 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}; struct dyn_inf dyninf = {0};
Section *interp, *dynstr, *dynamic; Section *interp, *dynstr, *dynamic;
int textrel, got_sym, dt_flags_1; int textrel, got_sym, dt_flags_1;
@ -2876,7 +2866,6 @@ static int elf_output_file(TCCState *s1, const char *filename)
version_add (s1); version_add (s1);
textrel = set_sec_sizes(s1); textrel = set_sec_sizes(s1);
alloc_sec_names(s1, 0);
if (!s1->static_link) { if (!s1->static_link) {
/* add a list of needed dlls */ /* 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; 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 */ /* this array is used to reorder sections in the output file */
sec_order = tcc_malloc(sizeof(int) * 2 * s1->nb_sections); sec_order = tcc_malloc(sizeof(int) * 2 * s1->nb_sections);
/* compute section to program header mapping */ /* compute section to program header mapping */
file_offset = layout_sections(s1, sec_order, &dyninf); layout_sections(s1, sec_order, &dyninf);
if (dynamic) { if (dynamic) {
/* put in GOT the dynamic section address and relocate PLT */ /* 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) if (dyninf.gnu_hash)
update_gnu_hash(s1, dyninf.gnu_hash); update_gnu_hash(s1, dyninf.gnu_hash);
reorder_sections(s1, sec_order);
/* Create the ELF file with name 'filename' */ /* 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: the_end:
tcc_free(sec_order); tcc_free(sec_order);
tcc_free(dyninf.phdr); tcc_free(dyninf.phdr);
@ -2971,7 +2964,7 @@ static void alloc_sec_names(TCCState *s1, int is_obj)
s = s1->sections[i]; s = s1->sections[i];
if (is_obj) if (is_obj)
s->sh_size = s->data_offset; 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); s->sh_name = put_elf_str(strsec, s->name);
} }
strsec->sh_size = strsec->data_offset; strsec->sh_size = strsec->data_offset;
@ -2985,7 +2978,8 @@ static int elf_output_obj(TCCState *s1, const char *filename)
s1->nb_errors = 0; s1->nb_errors = 0;
/* Allocate strings for section names */ /* Allocate strings for section names */
alloc_sec_names(s1, 1); 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++) { for(i = 1; i < s1->nb_sections; i++) {
s = s1->sections[i]; s = s1->sections[i];
file_offset = (file_offset + 15) & -16; 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; file_offset += s->sh_size;
} }
/* Create the ELF file with name 'filename' */ /* 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; return ret;
} }

View file

@ -5716,6 +5716,12 @@ ST_FUNC void unary(void)
vtop--; vtop--;
vpushi(n); vpushi(n);
break; 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_frame_address:
case TOK_builtin_return_address: case TOK_builtin_return_address:
{ {
@ -8306,7 +8312,6 @@ static void gen_function(Sym *sym)
cur_scope = root_scope = &f; cur_scope = root_scope = &f;
nocode_wanted = 0; nocode_wanted = 0;
cur_text_section->sh_flags |= SHF_EXECINSTR;
ind = cur_text_section->data_offset; ind = cur_text_section->data_offset;
if (sym->a.aligned) { if (sym->a.aligned) {
size_t newoff = section_add(cur_text_section, 0, size_t newoff = section_add(cur_text_section, 0,
@ -8602,6 +8607,8 @@ static int decl(int l)
cur_text_section = ad.section; cur_text_section = ad.section;
if (!cur_text_section) if (!cur_text_section)
cur_text_section = 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); gen_function(sym);
} }
break; break;

View file

@ -525,7 +525,7 @@ static int pe_put_long_secname(char *secname, const char *name)
const char *d = dwarf_secs; const char *d = dwarf_secs;
do { do {
if (0 == strcmp(d, name)) { if (0 == strcmp(d, name)) {
sprintf(secname, "/%d", (int)(d - dwarf_secs + 4)); snprintf(secname, 8, "/%d", (int)(d - dwarf_secs + 4));
return 1; return 1;
} }
d = strchr(d, 0) + 1; d = strchr(d, 0) + 1;
@ -1871,10 +1871,11 @@ static unsigned pe_add_uwwind_info(TCCState *s1)
0x04, // UBYTE Size of prolog 0x04, // UBYTE Size of prolog
0x02, // UBYTE Count of unwind codes 0x02, // UBYTE Count of unwind codes
0x05, // UBYTE: 4 Frame Register (rbp), UBYTE: 4 Frame Register offset (scaled) 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 // 0x0b, 0x01, 0xff, 0xff, // stack size
0x04, 0x03, // set frame ptr (mov rsp -> rbp) // UBYTE offset of end of instr in prolog + 1, UBYTE:4 operation, UBYTE:4 info
0x01, 0x50 // push reg (rbp) 0x04, 0x03, // 3:0 UWOP_SET_FPREG (mov rsp -> rbp)
0x01, 0x50, // 0:5 UWOP_PUSH_NONVOL (push rbp)
}; };
Section *s = text_section; Section *s = text_section;

View file

@ -171,6 +171,7 @@
DEF(TOK_builtin_frame_address, "__builtin_frame_address") DEF(TOK_builtin_frame_address, "__builtin_frame_address")
DEF(TOK_builtin_return_address, "__builtin_return_address") DEF(TOK_builtin_return_address, "__builtin_return_address")
DEF(TOK_builtin_expect, "__builtin_expect") DEF(TOK_builtin_expect, "__builtin_expect")
DEF(TOK_builtin_unreachable, "__builtin_unreachable")
/*DEF(TOK_builtin_va_list, "__builtin_va_list")*/ /*DEF(TOK_builtin_va_list, "__builtin_va_list")*/
#if defined TCC_TARGET_PE && defined TCC_TARGET_X86_64 #if defined TCC_TARGET_PE && defined TCC_TARGET_X86_64
DEF(TOK_builtin_va_start, "__builtin_va_start") DEF(TOK_builtin_va_start, "__builtin_va_start")

View file

@ -504,28 +504,21 @@ ST_FUNC int tcc_tool_cross(TCCState *s1, char **argv, int option)
#ifdef _WIN32 #ifdef _WIN32
#include <process.h> #include <process.h>
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; const char *s;
char *d, *d0; char *p, *q;
int sl, pl, rl; int a = 0, b = 0, c;
for (s = s0; !!(c = *s); ++s)
sl = strlen(str); a += c == '"', b |= c == ' ';
pl = strlen(p); q = p = tcc_malloc(s - s0 + a + b + b + 1);
rl = strlen(r); *q = '"', q += b;
for (d0 = NULL;; d0 = tcc_malloc(sl + 1)) { for (s = s0; !!(c = *s); *q++ = c, ++s)
for (d = d0, s = str; s0 = s, s = strstr(s, p), s; s += pl) { if (c == '"')
if (d) { *q++ = '\\';
memcpy(d, s0, sl = s - s0), d += sl; *q = '"', q += b, *q = '\0';
memcpy(d, r, rl), d += rl; return p;
} else
sl += rl - pl;
}
if (d) {
strcpy(d, s0);
return d0;
}
}
} }
static int execvp_win32(const char *prog, char **argv) 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; int ret; char **p;
/* replace all " by \" */ /* replace all " by \" */
for (p = argv; *p; ++p) for (p = argv; *p; ++p)
if (strchr(*p, '"')) *p = quote_win32(*p);
*p = str_replace(*p, "\"", "\\\"");
ret = _spawnvp(P_NOWAIT, prog, (const char *const*)argv); ret = _spawnvp(P_NOWAIT, prog, (const char *const*)argv);
if (-1 == ret) if (-1 == ret)
return ret; return ret;

View file

@ -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 <stdio.h>
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;
}

View file

@ -3989,7 +3989,7 @@ void builtin_test(void)
} }
} }
#if defined _WIN32 #if defined _WIN32 || (defined __APPLE__ && GCC_MAJOR >= 15)
void weak_test(void) {} void weak_test(void) {}
#else #else
extern int __attribute__((weak)) weak_f1(void); extern int __attribute__((weak)) weak_f1(void);

View file

@ -1,17 +0,0 @@
#include <stdio.h>
/* 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;
}

View file

@ -1 +0,0 @@
hi

View file

@ -489,7 +489,7 @@ void load(int r, SValue *sv)
} }
#endif #endif
} else if (is64_type(ft)) { } 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 */ orex(1,r,0, 0xb8 + REG_VALUE(r)); /* movabs $xx, r */
gen_le64(sv->c.i); gen_le64(sv->c.i);
} else if (sv->c.i > 0) { } else if (sv->c.i > 0) {
@ -1017,7 +1017,7 @@ void gfunc_prolog(Sym *func_sym)
/* generate function epilog */ /* generate function epilog */
void gfunc_epilog(void) void gfunc_epilog(void)
{ {
int v, saved_ind; int v, start;
/* align local size to word & save local variables */ /* align local size to word & save local variables */
func_scratch = (func_scratch + 15) & -16; func_scratch = (func_scratch + 15) & -16;
@ -1037,10 +1037,12 @@ void gfunc_epilog(void)
g(func_ret_sub >> 8); g(func_ret_sub >> 8);
} }
saved_ind = ind;
ind = func_sub_sp_offset - FUNC_PROLOG_SIZE;
v = -loc; 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) { if (v >= 4096) {
Sym *sym = external_helper_sym(TOK___chkstk); Sym *sym = external_helper_sym(TOK___chkstk);
oad(0xb8, v); /* mov stacksize, %eax */ oad(0xb8, v); /* mov stacksize, %eax */
@ -1052,13 +1054,10 @@ void gfunc_epilog(void)
o(0xec8148); /* sub rsp, stacksize */ o(0xec8148); /* sub rsp, stacksize */
gen_le32(v); gen_le32(v);
} }
ind = cur_text_section->data_offset;
/* add the "func_scratch" area after each alloca seen */ /* add the "func_scratch" area after each alloca seen */
gsym_addr(func_alloca, -func_scratch); 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 #else