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:
parent
c21576f8a3
commit
45cff8f03f
16 changed files with 171 additions and 196 deletions
32
.github/workflows/build.yml
vendored
32
.github/workflows/build.yml
vendored
|
@ -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
|
||||||
|
|
5
Makefile
5
Makefile
|
@ -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
3
configure
vendored
|
@ -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"
|
||||||
|
|
||||||
|
|
|
@ -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
3
tcc.c
|
@ -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"
|
||||||
|
|
18
tccasm.c
18
tccasm.c
|
@ -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
184
tccelf.c
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
9
tccgen.c
9
tccgen.c
|
@ -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;
|
||||||
|
|
9
tccpe.c
9
tccpe.c
|
@ -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;
|
||||||
|
|
1
tcctok.h
1
tcctok.h
|
@ -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")
|
||||||
|
|
38
tcctools.c
38
tcctools.c
|
@ -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;
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
hi
|
|
15
x86_64-gen.c
15
x86_64-gen.c
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue