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
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-x86_64-win32:
runs-on: windows-2019
timeout-minutes: 4
test-aarch64-osx:
runs-on: macos-14
timeout-minutes: 2
steps:
- 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
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

View file

@ -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

3
configure vendored
View file

@ -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"

View file

@ -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

3
tcc.c
View file

@ -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"

View file

@ -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:

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);
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;i<s1->nb_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;
}

View file

@ -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;

View file

@ -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;

View file

@ -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")

View file

@ -504,28 +504,21 @@ ST_FUNC int tcc_tool_cross(TCCState *s1, char **argv, int option)
#ifdef _WIN32
#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;
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;

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) {}
#else
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
} 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