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
|
||||
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
|
||||
|
|
5
Makefile
5
Makefile
|
@ -69,7 +69,10 @@ else
|
|||
ifdef CONFIG_OSX
|
||||
NATIVE_TARGET = $(ARCH)-osx
|
||||
ifneq ($(CC_NAME),tcc)
|
||||
LDFLAGS += -flat_namespace -undefined warning
|
||||
LDFLAGS += -flat_namespace
|
||||
ifneq (1,$(shell expr $(GCC_MAJOR) ">=" 15))
|
||||
LDFLAGS += -undefined warning # depreciated in clang >= 15.0
|
||||
endif
|
||||
endif
|
||||
export MACOSX_DEPLOYMENT_TARGET := 10.6
|
||||
endif
|
||||
|
|
3
configure
vendored
3
configure
vendored
|
@ -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"
|
||||
|
||||
|
|
|
@ -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
3
tcc.c
|
@ -33,8 +33,6 @@ static const char help[] =
|
|||
" -o outfile set output filename\n"
|
||||
" -run run compiled source\n"
|
||||
" -fflag set or reset (with 'no-' prefix) 'flag' (see tcc -hh)\n"
|
||||
" -std=(c99|gnu99) Conform to the ISO 1999 C standard (default).\n"
|
||||
" -std=(c11|gnu11) Conform to the ISO 2011 C standard.\n"
|
||||
" -Wwarning set or reset (with 'no-' prefix) 'warning' (see tcc -hh)\n"
|
||||
" -w disable all warnings\n"
|
||||
" -v --version show version\n"
|
||||
|
@ -69,6 +67,7 @@ static const char help[] =
|
|||
" -bt[N] link with backtrace (stack dump) support [show max N callers]\n"
|
||||
#endif
|
||||
"Misc. options:\n"
|
||||
" -std=version define __STDC_VERSION__ according to version (c11/gnu11)\n"
|
||||
" -x[c|a|b|n] specify type of the next infile (C,ASM,BIN,NONE)\n"
|
||||
" -nostdinc do not use standard system include paths\n"
|
||||
" -nostdlib do not link with standard crt and libraries\n"
|
||||
|
|
18
tccasm.c
18
tccasm.c
|
@ -857,6 +857,7 @@ static void asm_parse_directive(TCCState *s1, int global)
|
|||
{
|
||||
char sname[256];
|
||||
int old_nb_section = s1->nb_sections;
|
||||
int flags = SHF_ALLOC;
|
||||
|
||||
tok1 = tok;
|
||||
/* XXX: support more options */
|
||||
|
@ -870,10 +871,17 @@ static void asm_parse_directive(TCCState *s1, int global)
|
|||
next();
|
||||
}
|
||||
if (tok == ',') {
|
||||
const char *p;
|
||||
/* skip section options */
|
||||
next();
|
||||
if (tok != TOK_STR)
|
||||
expect("string constant");
|
||||
for (p = tokc.str.data; *p; ++p) {
|
||||
if (*p == 'w')
|
||||
flags |= SHF_WRITE;
|
||||
if (*p == 'x')
|
||||
flags |= SHF_EXECINSTR;
|
||||
}
|
||||
next();
|
||||
if (tok == ',') {
|
||||
next();
|
||||
|
@ -883,19 +891,17 @@ static void asm_parse_directive(TCCState *s1, int global)
|
|||
}
|
||||
}
|
||||
last_text_section = cur_text_section;
|
||||
if (tok1 == TOK_ASMDIR_section) {
|
||||
if (tok1 == TOK_ASMDIR_section)
|
||||
use_section(s1, sname);
|
||||
/* The section directive supports flags, but they are unsupported.
|
||||
For now, just assume any section contains code. */
|
||||
cur_text_section->sh_flags |= SHF_EXECINSTR;
|
||||
}
|
||||
else
|
||||
push_section(s1, sname);
|
||||
/* If we just allocated a new section reset its alignment to
|
||||
1. new_section normally acts for GCC compatibility and
|
||||
sets alignment to PTR_SIZE. The assembler behaves different. */
|
||||
if (old_nb_section != s1->nb_sections)
|
||||
if (old_nb_section != s1->nb_sections) {
|
||||
cur_text_section->sh_addralign = 1;
|
||||
cur_text_section->sh_flags = flags;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TOK_ASMDIR_previous:
|
||||
|
|
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);
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
9
tccgen.c
9
tccgen.c
|
@ -5716,6 +5716,12 @@ ST_FUNC void unary(void)
|
|||
vtop--;
|
||||
vpushi(n);
|
||||
break;
|
||||
case TOK_builtin_unreachable:
|
||||
parse_builtin_params(0, ""); /* just skip '()' */
|
||||
type.t = VT_VOID;
|
||||
vpush(&type);
|
||||
CODE_OFF();
|
||||
break;
|
||||
case TOK_builtin_frame_address:
|
||||
case TOK_builtin_return_address:
|
||||
{
|
||||
|
@ -8306,7 +8312,6 @@ static void gen_function(Sym *sym)
|
|||
cur_scope = root_scope = &f;
|
||||
nocode_wanted = 0;
|
||||
|
||||
cur_text_section->sh_flags |= SHF_EXECINSTR;
|
||||
ind = cur_text_section->data_offset;
|
||||
if (sym->a.aligned) {
|
||||
size_t newoff = section_add(cur_text_section, 0,
|
||||
|
@ -8602,6 +8607,8 @@ static int decl(int l)
|
|||
cur_text_section = ad.section;
|
||||
if (!cur_text_section)
|
||||
cur_text_section = text_section;
|
||||
else if (cur_text_section->sh_num > bss_section->sh_num)
|
||||
cur_text_section->sh_flags = text_section->sh_flags;
|
||||
gen_function(sym);
|
||||
}
|
||||
break;
|
||||
|
|
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;
|
||||
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;
|
||||
|
|
1
tcctok.h
1
tcctok.h
|
@ -171,6 +171,7 @@
|
|||
DEF(TOK_builtin_frame_address, "__builtin_frame_address")
|
||||
DEF(TOK_builtin_return_address, "__builtin_return_address")
|
||||
DEF(TOK_builtin_expect, "__builtin_expect")
|
||||
DEF(TOK_builtin_unreachable, "__builtin_unreachable")
|
||||
/*DEF(TOK_builtin_va_list, "__builtin_va_list")*/
|
||||
#if defined TCC_TARGET_PE && defined TCC_TARGET_X86_64
|
||||
DEF(TOK_builtin_va_start, "__builtin_va_start")
|
||||
|
|
38
tcctools.c
38
tcctools.c
|
@ -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;
|
||||
|
|
|
@ -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) {}
|
||||
#else
|
||||
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
|
||||
} 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
|
||||
|
|
Loading…
Reference in a new issue