Compare commits

..

No commits in common. "a338258d309c888bde96b2d1f206299231a54ddf" and "b39da9f6fa7e32c7c8bf6f0bb093fa6331fa5cbb" have entirely different histories.

84 changed files with 1623 additions and 7993 deletions

View File

@ -34,49 +34,56 @@ jobs:
timeout-minutes: 6
steps:
- uses: actions/checkout@v4
- name: build tcc (x86_64-win32)
- name: make & test tcc (x86_64-win32)
shell: cmd
run: |
echo ::group:: setup msys mingw64-gcc
set MSYS2_PATH_TYPE=inherit
set MSYSTEM=MINGW64
set CHERE_INVOKING=yes
C:\msys64\usr\bin\bash -l -c "pacman -S --noconfirm mingw-w64-x86_64-gcc"
echo ::endgroup::
C:\msys64\usr\bin\bash -l -c "./configure && make && make test -k"
- uses: ilammy/msvc-dev-cmd@v1
with:
arch: amd64
- name: build with MSVC (x86_64-win32)
shell: cmd
run: |
echo ::group:: run build-tcc.bat
cd win32
for /f "delims=" %%i in ('vswhere.exe -latest -property installationPath') do call "%%i\VC\Auxiliary\Build\vcvarsall.bat" amd64
call build-tcc.bat -c cl -t x86_64
- name: test (x86_64-win32)
shell: cmd
run: |
cd tests
call test-win32.bat all -k
call build-tcc.bat -t 64 -c cl
echo ::endgroup::
.\tcc -I.. libtcc.dll -v ../tests/libtcc_test.c -o libtest.exe && .\libtest.exe
.\tcc -I.. libtcc.dll -run ../tests/libtcc_test.c
test-i386-win32:
runs-on: windows-2025
timeout-minutes: 6
steps:
- uses: actions/checkout@v4
- name: build tcc (i386-win32)
- name: make & test tcc (i386-win32)
shell: cmd
run: |
echo ::group:: setup msys mingw32-gcc
set MSYS2_PATH_TYPE=inherit
set MSYSTEM=MINGW32
set CHERE_INVOKING=yes
C:\msys64\usr\bin\bash -l -c "pacman -S --noconfirm mingw-w64-i686-gcc"
echo ::endgroup::
C:\msys64\usr\bin\bash -l -c "./configure && make && make test -k"
- uses: ilammy/msvc-dev-cmd@v1
with:
arch: x86
- name: build with MSVC (i386-win32)
shell: cmd
run: |
echo ::group:: run build-tcc.bat
cd win32
for /f "delims=" %%i in ('vswhere.exe -latest -property installationPath') do call "%%i\VC\Auxiliary\Build\vcvarsall.bat" x86
call build-tcc.bat -c cl -t i386
- name: test (i386-win32)
shell: cmd
run: |
cd tests
call test-win32.bat -p c:\mingw32\bin all -k
test-arm64-win32:
runs-on: windows-11-arm
timeout-minutes: 6
steps:
- uses: actions/checkout@v4
- name: build and test (arm64-win32)
shell: cmd
run: |
cd win32
for /f "delims=" %%i in ('vswhere.exe -latest -property installationPath') do call "%%i\VC\Auxiliary\Build\vcvarsall.bat" amd64_arm64
call build-tcc.bat -c cl -t arm64
set "PATH=C:\Program Files\LLVM\bin;%CD%;%PATH%"
cd ..\tests
call test-win32.bat -c clang all -k
call build-tcc.bat -t 32 -c cl
echo ::endgroup::
.\tcc -I.. libtcc.dll -v ../tests/libtcc_test.c -o libtest.exe && .\libtest.exe
.\tcc -I.. libtcc.dll -run ../tests/libtcc_test.c
test-armv7-linux:
runs-on: ubuntu-22.04
@ -131,13 +138,3 @@ jobs:
run: |
echo "::endgroup::" # flatten 'run container'
./configure && make && make test -k
test-riscv64-linux-native:
runs-on: ubuntu-24.04-riscv
timeout-minutes: 8
steps:
- uses: actions/checkout@v4
- name: make & test tcc (riscv64-linux native)
run: |
uname -m # riscv64
./configure && make && make test -k

1
.gitignore vendored
View File

@ -62,6 +62,7 @@ tests/*-cc*
tests/*-tcc*
tests/libtcc_test
tests/libtcc_test_mt
tests/libtcc_test_xor_rex
tests/asm-c-connect
tests/asm-c-connect-sep
tests/vla_test

View File

@ -31,11 +31,9 @@ ifdef CONFIG_WIN32
LIBTCCDEF = libtcc.def
endif
ifneq ($(CONFIG_debug),yes)
ifneq ($(CC_NAME),clang)
LDFLAGS += -s
endif
LDFLAGS += -s
endif
NATIVE_TARGET = $(if $(findstring arm64,$(ARCH)),arm64-win32,$(ARCH)-win$(if $(findstring arm,$(ARCH)),ce,32))
NATIVE_TARGET = $(ARCH)-win$(if $(findstring arm,$(ARCH)),ce,32)
else
CFG = -unx
LIBS+=-lm
@ -115,7 +113,6 @@ DEF-arm64-osx = $(DEF-arm64) -DTCC_TARGET_MACHO
DEF-arm64-FreeBSD = $(DEF-arm64) -DTARGETOS_FreeBSD
DEF-arm64-NetBSD = $(DEF-arm64) -DTARGETOS_NetBSD
DEF-arm64-OpenBSD = $(DEF-arm64) -DTARGETOS_OpenBSD
DEF-arm64-win32 = $(DEF-arm64) -DTCC_TARGET_PE
DEF-riscv64 = -DTCC_TARGET_RISCV64
DEF-c67 = -DTCC_TARGET_C67 -w # disable warnigs
DEF-x86_64-FreeBSD = $(DEF-x86_64) -DTARGETOS_FreeBSD
@ -133,7 +130,7 @@ TCCDOCS = tcc.1 tcc-doc.html tcc-doc.info
all: $(PROGS) $(TCCLIBS) $(TCCDOCS)
# cross compiler targets to build
TCC_X = i386 x86_64 i386-win32 x86_64-win32 x86_64-osx arm arm64 arm64-win32 arm-wince c67
TCC_X = i386 x86_64 i386-win32 x86_64-win32 x86_64-osx arm arm64 arm-wince c67
TCC_X += riscv64 arm64-osx
# TCC_X += arm-fpa arm-fpa-ld arm-vfp arm-eabi
@ -158,27 +155,10 @@ all : cross
endif
# --------------------------------------------
T = $(or $(CROSS_TARGET),$(NATIVE_TARGET))
T = $(or $(CROSS_TARGET),$(NATIVE_TARGET),unknown)
X = $(if $(CROSS_TARGET),$(CROSS_TARGET)-)
ifneq ($(T),$(NATIVE_TARGET))
$(if $(DEF-$T),,$(error error: unknown target: '$T'))
ifneq ($(CONFIG_WIN32),yes)
DEF-win = -DCONFIG_TCCDIR="\"$(tccdir)/win32\""
endif
# some default config for cross compilers
TRIPLET-i386 = i686-linux-gnu
TRIPLET-x86_64 = x86_64-linux-gnu
TRIPLET-arm = arm-linux-gnueabihf
TRIPLET-arm64 = aarch64-linux-gnu
TRIPLET-riscv64 = riscv64-linux-gnu
ifneq ($(TRIPLET-$T),)
# assume support files in "/usr/<triplet>"
ROOT-$T = /usr/$(TRIPLET-$T)
INC-$T = {B}/include:{R}/include
LIB-$T = {R}/lib:{B}
CRT-$T = {R}/lib
endif
DEFINES += $(DEF-$T)
DEFINES += $(if $(ROOT-$T),-DCONFIG_SYSROOT="\"$(ROOT-$T)\"")
DEFINES += $(if $(CRT-$T),-DCONFIG_TCC_CRTPREFIX="\"$(CRT-$T)\"")
@ -186,17 +166,36 @@ DEFINES += $(if $(LIB-$T),-DCONFIG_TCC_LIBPATHS="\"$(LIB-$T)\"")
DEFINES += $(if $(INC-$T),-DCONFIG_TCC_SYSINCLUDEPATHS="\"$(INC-$T)\"")
DEFINES += $(if $(ELF-$T),-DCONFIG_TCC_ELFINTERP="\"$(ELF-$T)\"")
DEFINES += $(DEF-$(or $(findstring win,$T),unx))
DEFINES += -DCONFIG_TCC_CROSSPREFIX="\"$X\""
ifneq ($(X),)
$(if $(DEF-$T),,$(error error: unknown target: '$T'))
DEF-$(NATIVE_TARGET) =
DEF-$T += -DCONFIG_TCC_CROSSPREFIX="\"$X\""
ifneq ($(CONFIG_WIN32),yes)
DEF-win += -DCONFIG_TCCDIR="\"$(tccdir)/win32\""
endif
else
# using values from config.h
DEF-$(NATIVE_TARGET) =
endif
# include custom configuration (see make help)
-include config-extra.mak
# so one can use: make EXTRA-DEFS=...
DEFINES += $(EXTRA-DEFS)
# find config.h with 'out of tree' builds
DEFINES += -I$(TOP)
ifneq ($(T),$(NATIVE_TARGET))
# assume support files for cross-targets in "/usr/<triplet>" by default
TRIPLET-i386 ?= i686-linux-gnu
TRIPLET-x86_64 ?= x86_64-linux-gnu
TRIPLET-arm ?= arm-linux-gnueabi
TRIPLET-arm64 ?= aarch64-linux-gnu
TRIPLET-riscv64 ?= riscv64-linux-gnu
MARCH-i386 ?= i386-linux-gnu
MARCH-$T ?= $(TRIPLET-$T)
TR = $(if $(TRIPLET-$T),$T,ignored)
CRT-$(TR) ?= /usr/$(TRIPLET-$T)/lib
LIB-$(TR) ?= {B}:/usr/$(TRIPLET-$T)/lib:/usr/lib/$(MARCH-$T)
INC-$(TR) ?= {B}/include:/usr/$(TRIPLET-$T)/include:/usr/include
endif
CORE_FILES = tcc.c tcctools.c libtcc.c tccpp.c tccgen.c tccdbg.c tccelf.c tccasm.c tccrun.c
CORE_FILES += tcc.h config.h libtcc.h tcctok.h
@ -207,14 +206,14 @@ x86_64-win32_FILES = $(x86_64_FILES) tccpe.c
x86_64-osx_FILES = $(x86_64_FILES) tccmacho.c
arm_FILES = $(CORE_FILES) arm-gen.c arm-link.c arm-asm.c arm-tok.h
arm-wince_FILES = $(arm_FILES) tccpe.c
arm-eabihf_FILES = $(arm_FILES)
arm-fpa_FILES = $(arm_FILES)
arm-fpa-ld_FILES = $(arm_FILES)
arm-vfp_FILES = $(arm_FILES)
arm-eabi_FILES = $(arm_FILES)
arm-eabihf_FILES = $(arm_FILES)
arm64_FILES = $(CORE_FILES) arm64-gen.c arm64-link.c arm64-asm.c arm64-tok.h
arm64_FILES = $(CORE_FILES) arm64-gen.c arm64-link.c arm64-asm.c
arm64-osx_FILES = $(arm64_FILES) tccmacho.c
arm64-win32_FILES = $(arm64_FILES) tccpe.c
c67_FILES = $(CORE_FILES) c67-gen.c c67-link.c tcccoff.c
riscv64_FILES = $(CORE_FILES) riscv64-gen.c riscv64-link.c riscv64-asm.c
@ -238,6 +237,7 @@ $(CROSS_TARGET)-tcc.o : DEFINES += -DONE_SOURCE=0
endif
# native tcc always made from tcc.o and libtcc.[so|a]
tcc.o : DEFINES += -DONE_SOURCE=0
DEFINES += -I$(TOP)
GITHASH:=$(shell git rev-parse --abbrev-ref HEAD 2>/dev/null || echo no)
ifneq ($(GITHASH),no)
@ -336,7 +336,7 @@ FORCE:
# some versions of gnu-make do not recognize 'command' as a shell builtin
WHICH = sh -c 'command -v $1'
run-if = $(if $(shell $(call WHICH,$1x)),$S $1 $2,@true||echo "(skipping $@ - no $1)")
run-if = $(if $(shell $(call WHICH,$1)),$S $1 $2)
S = $(if $(findstring yes,$(SILENT)),@$(info * $@))
# --------------------------------------------------------------------------
@ -497,14 +497,14 @@ distclean: clean
help:
@echo "make"
@echo " build native compiler (from separate objects)"
@echo "make cross"
@echo " build cross compilers (from one source)"
@echo "make ONE_SOURCE=no/yes SILENT=no/yes"
@echo " force building from separate/one object(s), less/more silently"
@echo "make cross-TARGET"
@echo " build one specific cross compiler for 'TARGET'. Currently supported:"
@echo " $(wordlist 1,8,$(TCC_X))"
@echo " $(wordlist 9,99,$(TCC_X))"
@echo "make cross"
@echo " build all cross compilers"
@echo "make test"
@echo " run all tests"
@echo "make tests2.all / make tests2.37 / make tests2.37+"

110
arm-gen.c
View File

@ -124,17 +124,16 @@ enum {
#define LDOUBLE_ALIGN 4
#endif
#if LDOUBLE_SIZE == 8
# define TCC_USING_DOUBLE_FOR_LDOUBLE 1
#endif
/* maximum alignment (for aligned attribute support) */
#define MAX_ALIGN 8
#define CHAR_IS_UNSIGNED
#define ARM_SOFTFP_FLOAT 0
#define ARM_HARD_FLOAT 1
#ifdef TCC_ARM_HARDFLOAT
# define ARM_FLOAT_ABI ARM_HARD_FLOAT
#else
# define ARM_FLOAT_ABI ARM_SOFTFP_FLOAT
#endif
/******************************************************/
#else /* ! TARGET_DEFS_ONLY */
@ -157,6 +156,8 @@ ST_DATA const char * const target_machine_defs =
#endif
;
enum float_abi float_abi;
ST_DATA const int reg_classes[NB_REGS] = {
/* r0 */ RC_INT | RC_R0,
/* r1 */ RC_INT | RC_R1,
@ -175,7 +176,6 @@ ST_DATA const int reg_classes[NB_REGS] = {
#endif
};
static int float_abi;
static int func_sub_sp_offset, last_itod_magic;
static int leaffunc;
@ -237,6 +237,16 @@ static int regmask(int r) {
/******************************************************/
#if defined(TCC_ARM_EABI) && !defined(CONFIG_TCC_ELFINTERP)
const char *default_elfinterp(struct TCCState *s)
{
if (s->float_abi == ARM_HARD_FLOAT)
return "/lib/ld-linux-armhf.so.3";
else
return "/lib/ld-linux.so.3";
}
#endif
void o(uint32_t i)
{
/* this is a good place to start adding big-endian support*/
@ -572,7 +582,7 @@ static void load_value(SValue *sv, int r)
void load(int r, SValue *sv)
{
int v, ft, fc, fr, sign;
uint32_t op, base;
uint32_t op;
SValue v1;
fr = sv->r;
@ -588,15 +598,7 @@ void load(int r, SValue *sv)
v = fr & VT_VALMASK;
if (fr & VT_LVAL) {
if ((fr & VT_SYM) && sv->sym->type.t & VT_TLS) {
uint32_t op;
o(0xee1d0fe0); /* mrc p15, 0, lr, c13, c0, 3 */
op = 0xe510e000; /* ldr r, [lr, #0] */
greloca(cur_text_section, sv->sym, ind, R_ARM_TLS_LE32, 0);
o(op | (intr(r) << 12));
return;
}
base = 0xB; // fp
uint32_t base = 0xB; // fp
if(v == VT_LLOCAL) {
v1.type.t = VT_PTR;
v1.r = VT_LOCAL | VT_LVAL;
@ -633,9 +635,12 @@ void load(int r, SValue *sv)
op=0xED100100;
if(!sign)
op|=0x800000;
#if LDOUBLE_SIZE == 8
if ((ft & VT_BTYPE) != VT_FLOAT)
op|=0x8000;
#else
if ((ft & VT_BTYPE) == VT_DOUBLE)
op|=0x8000;
#if LDOUBLE_SIZE != 8
else if ((ft & VT_BTYPE) == VT_LDOUBLE)
op|=0x400000;
#endif
@ -711,7 +716,7 @@ void store(int r, SValue *sv)
{
SValue v1;
int v, ft, fc, fr, sign;
uint32_t op, base;
uint32_t op;
fr = sv->r;
ft = sv->type.t;
@ -726,15 +731,7 @@ void store(int r, SValue *sv)
v = fr & VT_VALMASK;
if (fr & VT_LVAL || fr == VT_LOCAL) {
if ((fr & VT_SYM) && sv->sym->type.t & VT_TLS) {
uint32_t op;
o(0xee1d0fe0); /* mrc p15, 0, lr, c13, c0, 3 */
op = 0xe500e000; /* str r, [lr, #0] */
greloca(cur_text_section, sv->sym, ind, R_ARM_TLS_LE32, 0);
o(op | (intr(r) << 12));
return;
}
base = 0xb; /* fp */
uint32_t base = 0xb; /* fp */
if(v < VT_CONST) {
base=intr(v);
v=VT_LOCAL;
@ -763,10 +760,13 @@ void store(int r, SValue *sv)
op=0xED000100;
if(!sign)
op|=0x800000;
#if LDOUBLE_SIZE == 8
if ((ft & VT_BTYPE) != VT_FLOAT)
op|=0x8000;
#else
if ((ft & VT_BTYPE) == VT_DOUBLE)
op|=0x8000;
#if LDOUBLE_SIZE != 8
else if ((ft & VT_BTYPE) == VT_LDOUBLE)
if ((ft & VT_BTYPE) == VT_LDOUBLE)
op|=0x400000;
#endif
o(op|(fpr(r)<<12)|(fc>>2)|(base<<16));
@ -904,6 +904,15 @@ static void gen_bounds_epilog(void)
}
#endif
static int unalias_ldbl(int btype)
{
#if LDOUBLE_SIZE == 8
if (btype == VT_LDOUBLE)
btype = VT_DOUBLE;
#endif
return btype;
}
/* Return whether a structure is an homogeneous float aggregate or not.
The answer is true if all the elements of the structure are of the same
primitive float type and there is less than 4 elements.
@ -917,10 +926,9 @@ static int is_hgen_float_aggr(CType *type)
ref = type->ref->next;
if (ref) {
btype = ref->type.t & VT_BTYPE;
btype = unalias_ldbl(ref->type.t & VT_BTYPE);
if (btype == VT_FLOAT || btype == VT_DOUBLE) {
for(; ref && btype == (ref->type.t & VT_BTYPE); ref = ref->next, nb_fields++)
;
for(; ref && btype == unalias_ldbl(ref->type.t & VT_BTYPE); ref = ref->next, nb_fields++);
return !ref && nb_fields <= 4;
}
}
@ -1246,6 +1254,7 @@ again:
size = 8;
else
size = LDOUBLE_SIZE;
if (size == 12)
r |= 0x400000;
else if(size == 8)
@ -1937,13 +1946,15 @@ void gen_opf(int op)
vswap();
c2 = is_fconst();
x=0xEE000100;
#if LDOUBLE_SIZE == 8
if ((vtop->type.t & VT_BTYPE) != VT_FLOAT)
x|=0x80;
#else
if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE)
x|=0x80;
#if LDOUBLE_SIZE != 8
else if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE)
x|=0x80000;
#endif
switch(op)
{
case '+':
@ -2179,12 +2190,6 @@ ST_FUNC void gen_cvt_itof(int t)
func=TOK___floatundisf;
else
func=TOK___floatdisf;
} else if((t & VT_BTYPE) == VT_DOUBLE) {
func_type = &func_double_type;
if(vtop->type.t & VT_UNSIGNED)
func=TOK___floatundidf;
else
func=TOK___floatdidf;
#if LDOUBLE_SIZE != 8
} else if((t & VT_BTYPE) == VT_LDOUBLE) {
func_type = &func_ldouble_type;
@ -2192,7 +2197,15 @@ ST_FUNC void gen_cvt_itof(int t)
func=TOK___floatundixf;
else
func=TOK___floatdixf;
} else if((t & VT_BTYPE) == VT_DOUBLE) {
#else
} else if((t & VT_BTYPE) == VT_DOUBLE || (t & VT_BTYPE) == VT_LDOUBLE) {
#endif
func_type = &func_double_type;
if(vtop->type.t & VT_UNSIGNED)
func=TOK___floatundidf;
else
func=TOK___floatdidf;
}
if(func_type) {
vpushsym(func_type, external_helper_sym(func));
@ -2226,12 +2239,14 @@ void gen_cvt_ftoi(int t)
if(u) {
if(r2 == VT_FLOAT)
func=TOK___fixunssfsi;
else if(r2 == VT_DOUBLE)
func=TOK___fixunsdfsi;
#if LDOUBLE_SIZE != 8
else if(r2 == VT_LDOUBLE)
func=TOK___fixunsxfsi;
else if(r2 == VT_DOUBLE)
#else
else if(r2 == VT_LDOUBLE || r2 == VT_DOUBLE)
#endif
func=TOK___fixunsdfsi;
} else {
r=fpr(gv(RC_FLOAT));
r2=intr(vtop->r=get_reg(RC_INT));
@ -2242,12 +2257,14 @@ void gen_cvt_ftoi(int t)
} else if(t == VT_LLONG) { // unsigned handled in gen_cvt_ftoi1
if(r2 == VT_FLOAT)
func=TOK___fixsfdi;
else if(r2 == VT_DOUBLE)
func=TOK___fixdfdi;
#if LDOUBLE_SIZE != 8
else if(r2 == VT_LDOUBLE)
func=TOK___fixxfdi;
else if(r2 == VT_DOUBLE)
#else
else if(r2 == VT_LDOUBLE || r2 == VT_DOUBLE)
#endif
func=TOK___fixdfdi;
}
if(func) {
vpush_helper_func(func);
@ -2266,9 +2283,8 @@ void gen_cvt_ftoi(int t)
void gen_cvt_ftof(int t)
{
#ifdef TCC_ARM_VFP
uint32_t r = gv(RC_FLOAT);
if(((vtop->type.t & VT_BTYPE) == VT_FLOAT) != ((t & VT_BTYPE) == VT_FLOAT)) {
r = vfpr(r);
uint32_t r = vfpr(gv(RC_FLOAT));
o(0xEEB70AC0|(r<<12)|r|T2CPR(vtop->type.t));
}
#else

View File

@ -18,6 +18,11 @@
#define PCRELATIVE_DLLPLT 1
#define RELOCATE_DLLPLT 1
enum float_abi {
ARM_SOFTFP_FLOAT,
ARM_HARD_FLOAT,
};
#else /* !TARGET_DEFS_ONLY */
#include "tcc.h"
@ -44,7 +49,6 @@ ST_FUNC int code_reloc (int reloc_type)
case R_ARM_TARGET1:
case R_ARM_MOVT_PREL:
case R_ARM_MOVW_PREL_NC:
case R_ARM_TLS_LE32:
return 0;
case R_ARM_PC24:
@ -71,7 +75,6 @@ ST_FUNC int gotplt_entry_type (int reloc_type)
case R_ARM_COPY:
case R_ARM_GLOB_DAT:
case R_ARM_JUMP_SLOT:
case R_ARM_TLS_LE32:
return NO_GOTPLT_ENTRY;
case R_ARM_PC24:
@ -432,36 +435,6 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
#endif
/* do nothing */
return;
case R_ARM_TLS_LE32:
{
ElfW(Sym) *sym;
Section *sec;
int32_t x;
addr_t tls_start = 0, tls_end = 0, tls_align = 1;
int i;
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
sec = s1->sections[sym->st_shndx];
for (i = 1; i < s1->nb_sections; i++) {
Section *s = s1->sections[i];
if (s->sh_flags & SHF_TLS && s->sh_size) {
if (!tls_start || s->sh_addr < tls_start)
tls_start = s->sh_addr;
if (s->sh_addr + s->sh_size > tls_end)
tls_end = s->sh_addr + s->sh_size;
if (s->sh_addralign > tls_align)
tls_align = s->sh_addralign;
}
}
if (tls_end > tls_start) {
x = val - tls_start + 8;
} else {
x = val - sec->sh_addr - sec->data_offset + 8;
}
add32le(ptr, x);
}
return;
default:
fprintf(stderr,"FIXME: handle reloc type %d at %x [%p] to %x\n",
type, (unsigned)addr, ptr, (unsigned)val);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -43,8 +43,6 @@ ST_FUNC int code_reloc (int reloc_type)
case R_AARCH64_LDST32_ABS_LO12_NC:
case R_AARCH64_LDST16_ABS_LO12_NC:
case R_AARCH64_LDST8_ABS_LO12_NC:
case R_AARCH64_TLSLE_ADD_TPREL_HI12:
case R_AARCH64_TLSLE_ADD_TPREL_LO12:
case R_AARCH64_GLOB_DAT:
case R_AARCH64_COPY:
return 0;
@ -52,8 +50,6 @@ ST_FUNC int code_reloc (int reloc_type)
case R_AARCH64_JUMP26:
case R_AARCH64_CALL26:
case R_AARCH64_JUMP_SLOT:
case R_AARCH64_CONDBR19:
case R_AARCH64_TSTBR14:
return 1;
}
return -1;
@ -80,10 +76,6 @@ ST_FUNC int gotplt_entry_type (int reloc_type)
case R_AARCH64_GLOB_DAT:
case R_AARCH64_JUMP_SLOT:
case R_AARCH64_COPY:
case R_AARCH64_CONDBR19:
case R_AARCH64_TSTBR14:
case R_AARCH64_TLSLE_ADD_TPREL_HI12:
case R_AARCH64_TLSLE_ADD_TPREL_LO12:
return NO_GOTPLT_ENTRY;
case R_AARCH64_ABS32:
@ -135,18 +127,17 @@ ST_FUNC void relocate_plt(TCCState *s1)
uint64_t off = (got >> 12) - (plt >> 12);
if ((off + ((uint32_t)1 << 20)) >> 21)
tcc_error_noabort("Failed relocating PLT (off=0x%lx, got=0x%lx, plt=0x%lx)", (long)off, (long)got, (long)plt);
write32le(p, ARM64_STP_X_PRE | ARM64_RT(16) | ARM64_RT2(30) |
ARM64_RN(31) | ARM64_IMM7(-2)); // stp x16,x30,[sp,#-16]!
write32le(p + 4, (ARM64_ADRP | ARM64_RD(16) | // adrp x16,...
write32le(p, 0xa9bf7bf0); // stp x16,x30,[sp,#-16]!
write32le(p + 4, (0x90000010 | // adrp x16,...
(off & 0x1ffffc) << 3 | (off & 3) << 29));
write32le(p + 8, (ARM64_LDR_X | ARM64_RT(17) | ARM64_RN(16) | // ldr x17,[x16,#...]
write32le(p + 8, (0xf9400211 | // ldr x17,[x16,#...]
(got & 0xff8) << 7));
write32le(p + 12, (ARM64_ADD_IMM | ARM64_SF(1) | ARM64_RD(16) | ARM64_RN(16) | // add x16,x16,#...
write32le(p + 12, (0x91000210 | // add x16,x16,#...
(got & 0xfff) << 10));
write32le(p + 16, ARM64_BR | ARM64_RN(17)); // br x17
write32le(p + 20, ARM64_NOP); // nop
write32le(p + 24, ARM64_NOP); // nop
write32le(p + 28, ARM64_NOP); // nop
write32le(p + 16, 0xd61f0220); // br x17
write32le(p + 20, 0xd503201f); // nop
write32le(p + 24, 0xd503201f); // nop
write32le(p + 28, 0xd503201f); // nop
p += 32;
got = s1->got->sh_addr;
while (p < p_end) {
@ -155,13 +146,13 @@ ST_FUNC void relocate_plt(TCCState *s1)
uint64_t off = (addr >> 12) - (pc >> 12);
if ((off + ((uint32_t)1 << 20)) >> 21)
tcc_error_noabort("Failed relocating PLT (off=0x%lx, addr=0x%lx, pc=0x%lx)", (long)off, (long)addr, (long)pc);
write32le(p, (ARM64_ADRP | ARM64_RD(16) | // adrp x16,...
write32le(p, (0x90000010 | // adrp x16,...
(off & 0x1ffffc) << 3 | (off & 3) << 29));
write32le(p + 4, (ARM64_LDR_X | ARM64_RT(17) | ARM64_RN(16) | // ldr x17,[x16,#...]
write32le(p + 4, (0xf9400211 | // ldr x17,[x16,#...]
(addr & 0xff8) << 7));
write32le(p + 8, (ARM64_ADD_IMM | ARM64_SF(1) | ARM64_RD(16) | ARM64_RN(16) | // add x16,x16,#...
write32le(p + 8, (0x91000210 | // add x16,x16,#...
(addr & 0xfff) << 10));
write32le(p + 12, ARM64_BR | ARM64_RN(17)); // br x17
write32le(p + 12, 0xd61f0220); // br x17
p += 16;
}
}
@ -247,23 +238,8 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
return;
case R_AARCH64_ADR_PREL_PG_HI21: {
uint64_t off = (val >> 12) - (addr >> 12);
#ifdef TCC_TARGET_PE
/* Weak undefined symbols resolve to address 0 on PE. ADRP cannot
encode that from the default 64-bit image base, so materialize
zero directly and let the paired ADD handle any low addend. */
if ((off + ((uint64_t)1 << 20)) >> 21) {
ElfW(Sym) *sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
if (sym->st_shndx == SHN_UNDEF
&& ELFW(ST_BIND)(sym->st_info) == STB_WEAK) {
write32le(ptr, 0xd2800000 | (read32le(ptr) & 0x1f));
return;
}
tcc_error_noabort("R_AARCH64_ADR_PREL_PG_HI21 relocation failed");
}
#else
if ((off + ((uint64_t)1 << 20)) >> 21)
tcc_error_noabort("R_AARCH64_ADR_PREL_PG_HI21 relocation failed");
#endif
write32le(ptr, ((read32le(ptr) & 0x9f00001f) |
(off & 0x1ffffc) << 3 | (off & 3) << 29));
return;
@ -289,58 +265,19 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
write32le(ptr, ((read32le(ptr) & 0xffc003ff) |
(val & 0xff0) << 6));
return;
case R_AARCH64_CONDBR19:
/* Conditional branch: 19-bit signed offset, bits 23:5 */
#ifdef DEBUG_RELOC
printf ("reloc %d @ 0x%lx: val=0x%lx name=%s\n", type, addr, val,
(char *) symtab_section->link->data + sym->st_name);
#endif
if (((val - addr) + ((uint64_t)1 << 20)) & ~(uint64_t)0x1ffffc)
tcc_error_noabort("R_AARCH64_CONDBR19 relocation failed"
" (val=%lx, addr=%lx)", (long)val, (long)addr);
write32le(ptr, ((read32le(ptr) & 0xff00001f) |
(((val - addr) >> 2 & 0x7ffff) << 5)));
return;
case R_AARCH64_TSTBR14:
/* Test and branch: 14-bit signed offset, bits 20:5 */
#ifdef DEBUG_RELOC
printf ("reloc %d @ 0x%lx: val=0x%lx name=%s\n", type, addr, val,
(char *) symtab_section->link->data + sym->st_name);
#endif
if (((val - addr) + ((uint64_t)1 << 15)) & ~(uint64_t)0xfffc)
tcc_error_noabort("R_AARCH64_TSTBR14 relocation failed"
" (val=%lx, addr=%lx)", (long)val, (long)addr);
write32le(ptr, ((read32le(ptr) & 0xfff8001f) |
(((val - addr) >> 2 & 0x3fff) << 5)));
return;
case R_AARCH64_JUMP26:
case R_AARCH64_CALL26:
{
const char *name;
#ifdef DEBUG_RELOC
printf ("reloc %d @ 0x%lx: val=0x%lx name=%s\n", type, addr, val,
(char *) symtab_section->link->data + sym->st_name);
#endif
if (((val - addr) + ((uint64_t)1 << 27)) & ~(uint64_t)0xffffffc) {
#ifdef TCC_TARGET_PE
ElfW(Sym) *sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
if (sym->st_shndx == SHN_UNDEF
&& ELFW(ST_BIND)(sym->st_info) == STB_WEAK) {
write32le(ptr, ARM64_NOP); /* nop */
return;
}
#endif
name = (char *)symtab_section->link->data +
((ElfW(Sym) *)symtab_section->data)[sym_index].st_name;
if (((val - addr) + ((uint64_t)1 << 27)) & ~(uint64_t)0xffffffc)
tcc_error_noabort("R_AARCH64_(JUMP|CALL)26 relocation failed"
" for '%s' (val=%lx, addr=%lx)",
name, (long)val, (long)addr);
}
" (val=%lx, addr=%lx)", (long)val, (long)addr);
write32le(ptr, (0x14000000 |
(uint32_t)(type == R_AARCH64_CALL26) << 31 |
((val - addr) >> 2 & 0x3ffffff)));
return;
}
case R_AARCH64_ADR_GOT_PAGE: {
uint64_t off =
(((s1->got->sh_addr +
@ -369,27 +306,6 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
#endif
write64le(ptr, val - rel->r_addend);
return;
case R_AARCH64_TLSLE_ADD_TPREL_HI12:
case R_AARCH64_TLSLE_ADD_TPREL_LO12: {
addr_t tls_start = 0;
int i;
for (i = 1; i < s1->nb_sections; i++) {
Section *s = s1->sections[i];
if (s->sh_flags & SHF_TLS && s->sh_size) {
if (!tls_start || s->sh_addr < tls_start)
tls_start = s->sh_addr;
}
}
/* glibc arm64: tp points to tcbhead_t (DTV), TLS data starts after it */
int64_t tp_offset = val - tls_start + 16;
int64_t imm;
if (type == R_AARCH64_TLSLE_ADD_TPREL_HI12)
imm = (tp_offset >> 12) & 0xfff;
else
imm = tp_offset & 0xfff;
write32le(ptr, ((read32le(ptr) & 0xffc003ff) | (imm << 10)));
return;
}
case R_AARCH64_RELATIVE:
#ifdef TCC_TARGET_PE
add32le(ptr, val - s1->pe_imagebase);

View File

@ -1,840 +0,0 @@
/* ------------------------------------------------------------------ */
/* ARM64 (AArch64) assembler token definitions for TCC */
/* General purpose registers - 64-bit */
DEF_ASM(x0)
DEF_ASM(x1)
DEF_ASM(x2)
DEF_ASM(x3)
DEF_ASM(x4)
DEF_ASM(x5)
DEF_ASM(x6)
DEF_ASM(x7)
DEF_ASM(x8)
DEF_ASM(x9)
DEF_ASM(x10)
DEF_ASM(x11)
DEF_ASM(x12)
DEF_ASM(x13)
DEF_ASM(x14)
DEF_ASM(x15)
DEF_ASM(x16)
DEF_ASM(x17)
DEF_ASM(x18)
DEF_ASM(x19)
DEF_ASM(x20)
DEF_ASM(x21)
DEF_ASM(x22)
DEF_ASM(x23)
DEF_ASM(x24)
DEF_ASM(x25)
DEF_ASM(x26)
DEF_ASM(x27)
DEF_ASM(x28)
DEF_ASM(x29)
DEF_ASM(x30)
/* General purpose registers - 32-bit */
DEF_ASM(w0)
DEF_ASM(w1)
DEF_ASM(w2)
DEF_ASM(w3)
DEF_ASM(w4)
DEF_ASM(w5)
DEF_ASM(w6)
DEF_ASM(w7)
DEF_ASM(w8)
DEF_ASM(w9)
DEF_ASM(w10)
DEF_ASM(w11)
DEF_ASM(w12)
DEF_ASM(w13)
DEF_ASM(w14)
DEF_ASM(w15)
DEF_ASM(w16)
DEF_ASM(w17)
DEF_ASM(w18)
DEF_ASM(w19)
DEF_ASM(w20)
DEF_ASM(w21)
DEF_ASM(w22)
DEF_ASM(w23)
DEF_ASM(w24)
DEF_ASM(w25)
DEF_ASM(w26)
DEF_ASM(w27)
DEF_ASM(w28)
DEF_ASM(w29)
DEF_ASM(w30)
/* Special registers */
DEF_ASM(sp)
DEF_ASM(xzr)
DEF_ASM(wzr)
/* SIMD/FP registers - 128-bit views */
DEF_ASM(v0)
DEF_ASM(v1)
DEF_ASM(v2)
DEF_ASM(v3)
DEF_ASM(v4)
DEF_ASM(v5)
DEF_ASM(v6)
DEF_ASM(v7)
DEF_ASM(v8)
DEF_ASM(v9)
DEF_ASM(v10)
DEF_ASM(v11)
DEF_ASM(v12)
DEF_ASM(v13)
DEF_ASM(v14)
DEF_ASM(v15)
DEF_ASM(v16)
DEF_ASM(v17)
DEF_ASM(v18)
DEF_ASM(v19)
DEF_ASM(v20)
DEF_ASM(v21)
DEF_ASM(v22)
DEF_ASM(v23)
DEF_ASM(v24)
DEF_ASM(v25)
DEF_ASM(v26)
DEF_ASM(v27)
DEF_ASM(v28)
DEF_ASM(v29)
DEF_ASM(v30)
DEF_ASM(v31)
/* SIMD/FP registers - 64-bit views (double) */
DEF_ASM(d0)
DEF_ASM(d1)
DEF_ASM(d2)
DEF_ASM(d3)
DEF_ASM(d4)
DEF_ASM(d5)
DEF_ASM(d6)
DEF_ASM(d7)
DEF_ASM(d8)
DEF_ASM(d9)
DEF_ASM(d10)
DEF_ASM(d11)
DEF_ASM(d12)
DEF_ASM(d13)
DEF_ASM(d14)
DEF_ASM(d15)
DEF_ASM(d16)
DEF_ASM(d17)
DEF_ASM(d18)
DEF_ASM(d19)
DEF_ASM(d20)
DEF_ASM(d21)
DEF_ASM(d22)
DEF_ASM(d23)
DEF_ASM(d24)
DEF_ASM(d25)
DEF_ASM(d26)
DEF_ASM(d27)
DEF_ASM(d28)
DEF_ASM(d29)
DEF_ASM(d30)
DEF_ASM(d31)
/* SIMD/FP registers - 32-bit views (single) */
DEF_ASM(s0)
DEF_ASM(s1)
DEF_ASM(s2)
DEF_ASM(s3)
DEF_ASM(s4)
DEF_ASM(s5)
DEF_ASM(s6)
DEF_ASM(s7)
DEF_ASM(s8)
DEF_ASM(s9)
DEF_ASM(s10)
DEF_ASM(s11)
DEF_ASM(s12)
DEF_ASM(s13)
DEF_ASM(s14)
DEF_ASM(s15)
DEF_ASM(s16)
DEF_ASM(s17)
DEF_ASM(s18)
DEF_ASM(s19)
DEF_ASM(s20)
DEF_ASM(s21)
DEF_ASM(s22)
DEF_ASM(s23)
DEF_ASM(s24)
DEF_ASM(s25)
DEF_ASM(s26)
DEF_ASM(s27)
DEF_ASM(s28)
DEF_ASM(s29)
DEF_ASM(s30)
DEF_ASM(s31)
/* SIMD/FP registers - 16-bit views (half) */
DEF_ASM(h0)
DEF_ASM(h1)
DEF_ASM(h2)
DEF_ASM(h3)
DEF_ASM(h4)
DEF_ASM(h5)
DEF_ASM(h6)
DEF_ASM(h7)
DEF_ASM(h8)
DEF_ASM(h9)
DEF_ASM(h10)
DEF_ASM(h11)
DEF_ASM(h12)
DEF_ASM(h13)
DEF_ASM(h14)
DEF_ASM(h15)
DEF_ASM(h16)
DEF_ASM(h17)
DEF_ASM(h18)
DEF_ASM(h19)
DEF_ASM(h20)
DEF_ASM(h21)
DEF_ASM(h22)
DEF_ASM(h23)
DEF_ASM(h24)
DEF_ASM(h25)
DEF_ASM(h26)
DEF_ASM(h27)
DEF_ASM(h28)
DEF_ASM(h29)
DEF_ASM(h30)
DEF_ASM(h31)
/* SIMD/FP registers - 8-bit views (byte) */
DEF_ASM(b0)
DEF_ASM(b1)
DEF_ASM(b2)
DEF_ASM(b3)
DEF_ASM(b4)
DEF_ASM(b5)
DEF_ASM(b6)
DEF_ASM(b7)
DEF_ASM(b8)
DEF_ASM(b9)
DEF_ASM(b10)
DEF_ASM(b11)
DEF_ASM(b12)
DEF_ASM(b13)
DEF_ASM(b14)
DEF_ASM(b15)
DEF_ASM(b16)
DEF_ASM(b17)
DEF_ASM(b18)
DEF_ASM(b19)
DEF_ASM(b20)
DEF_ASM(b21)
DEF_ASM(b22)
DEF_ASM(b23)
DEF_ASM(b24)
DEF_ASM(b25)
DEF_ASM(b26)
DEF_ASM(b27)
DEF_ASM(b28)
DEF_ASM(b29)
DEF_ASM(b30)
DEF_ASM(b31)
/* Condition codes */
DEF_ASM(eq)
DEF_ASM(ne)
DEF_ASM(cs)
DEF_ASM(hs)
DEF_ASM(cc)
DEF_ASM(lo)
DEF_ASM(mi)
DEF_ASM(pl)
DEF_ASM(vs)
DEF_ASM(vc)
DEF_ASM(hi)
DEF_ASM(ls)
DEF_ASM(ge)
DEF_ASM(lt)
DEF_ASM(gt)
DEF_ASM(le)
DEF_ASM(al)
/* Data processing - arithmetic (no condition suffixes for ARM64) */
DEF_ASM(add)
DEF_ASM(adds)
DEF_ASM(sub)
DEF_ASM(subs)
DEF_ASM(cmn)
DEF_ASM(cmp)
DEF_ASM(neg)
DEF_ASM(negs)
DEF_ASM(adc)
DEF_ASM(adcs)
DEF_ASM(sbc)
DEF_ASM(sbcs)
DEF_ASM(ngc)
DEF_ASM(ngcs)
/* Data processing - bitwise */
DEF_ASM(and)
DEF_ASM(ands)
DEF_ASM(bic)
DEF_ASM(bics)
DEF_ASM(orr)
DEF_ASM(orn)
DEF_ASM(eor)
DEF_ASM(eon)
DEF_ASM(mvn)
DEF_ASM(mov)
/* Shifts */
DEF_ASM(lsl)
DEF_ASM(lsr)
DEF_ASM(asr)
DEF_ASM(ror)
/* Multiply/divide */
DEF_ASM(mul)
DEF_ASM(madd)
DEF_ASM(msub)
DEF_ASM(smaddl)
DEF_ASM(smsubl)
DEF_ASM(umaddl)
DEF_ASM(umsubl)
DEF_ASM(smulh)
DEF_ASM(umulh)
DEF_ASM(udiv)
DEF_ASM(sdiv)
/* Moves */
DEF_ASM(movz)
DEF_ASM(movn)
DEF_ASM(movk)
/* Compare/test */
DEF_ASM(tst)
DEF_ASM(teq)
/* Branch instructions */
DEF_ASM(b)
DEF_ASM(bl)
DEF_ASM(br)
DEF_ASM(blr)
DEF_ASM(ret)
DEF_ASM(cbz)
DEF_ASM(cbnz)
DEF_ASM(tbz)
DEF_ASM(tbnz)
/* Conditional branches */
DEF_ASM(beq)
DEF_ASM(bne)
DEF_ASM(bcs)
DEF_ASM(bhs)
DEF_ASM(bcc)
DEF_ASM(blo)
DEF_ASM(bmi)
DEF_ASM(bpl)
DEF_ASM(bvs)
DEF_ASM(bvc)
DEF_ASM(bhi)
DEF_ASM(bls)
DEF_ASM(bge)
DEF_ASM(blt)
DEF_ASM(bgt)
DEF_ASM(ble)
/* Conditional select */
DEF_ASM(csel)
DEF_ASM(csinc)
DEF_ASM(csinv)
DEF_ASM(csneg)
/* Load/Store */
DEF_ASM(ldr)
DEF_ASM(ldrb)
DEF_ASM(ldrh)
DEF_ASM(ldrsb)
DEF_ASM(ldrsh)
DEF_ASM(ldrsw)
DEF_ASM(str)
DEF_ASM(strb)
DEF_ASM(strh)
/* Load/Store - pair */
DEF_ASM(ldp)
DEF_ASM(stp)
DEF_ASM(ldpsw)
/* Address generation */
DEF_ASM(adr)
DEF_ASM(adrp)
/* System instructions */
DEF_ASM(mrs)
DEF_ASM(msr)
DEF_ASM(nop)
DEF_ASM(wfi)
DEF_ASM(wfe)
DEF_ASM(sev)
DEF_ASM(sevl)
DEF_ASM(isb)
DEF_ASM(dsb)
DEF_ASM(dmb)
/* Hints */
DEF_ASM(yield)
DEF_ASM(clrex)
/* Push/pop */
DEF_ASM(push)
DEF_ASM(pop)
/* Floating point */
DEF_ASM(fmov)
DEF_ASM(fadd)
DEF_ASM(fsub)
DEF_ASM(fmul)
DEF_ASM(fnmul)
DEF_ASM(fdiv)
DEF_ASM(fmax)
DEF_ASM(fmin)
DEF_ASM(fmaxnm)
DEF_ASM(fminnm)
DEF_ASM(fsqrt)
DEF_ASM(fabs)
DEF_ASM(fneg)
DEF_ASM(frintn)
DEF_ASM(frintp)
DEF_ASM(frintm)
DEF_ASM(frintz)
DEF_ASM(frinta)
DEF_ASM(frintx)
DEF_ASM(frinti)
DEF_ASM(fcmp)
DEF_ASM(fcmpe)
DEF_ASM(fccmp)
DEF_ASM(fccmpe)
DEF_ASM(fcvts)
DEF_ASM(fcvtd)
DEF_ASM(fcvth)
DEF_ASM(fcvtx)
DEF_ASM(scvtf)
DEF_ASM(ucvtf)
DEF_ASM(fcvtns)
DEF_ASM(fcvtnu)
DEF_ASM(fcvtps)
DEF_ASM(fcvtpu)
/* SIMD instructions */
DEF_ASM(addv)
DEF_ASM(faddp)
DEF_ASM(fmaxp)
DEF_ASM(fminp)
DEF_ASM(fmaxnmp)
DEF_ASM(fminnmp)
DEF_ASM(addp)
DEF_ASM(bif)
DEF_ASM(bit)
DEF_ASM(bsl)
DEF_ASM(dup)
DEF_ASM(ext)
DEF_ASM(ins)
DEF_ASM(movi)
DEF_ASM(mvni)
DEF_ASM(not)
DEF_ASM(shl)
DEF_ASM(shll)
DEF_ASM(shll2)
DEF_ASM(sli)
DEF_ASM(sri)
DEF_ASM(sqshl)
DEF_ASM(sqshlu)
DEF_ASM(srshl)
DEF_ASM(sshll)
DEF_ASM(sshll2)
DEF_ASM(sshr)
DEF_ASM(ushll)
DEF_ASM(ushll2)
DEF_ASM(ushr)
/* Misc */
DEF_ASM(bfm)
DEF_ASM(sbfm)
DEF_ASM(ubfm)
DEF_ASM(extr)
DEF_ASM(crc32b)
DEF_ASM(crc32h)
DEF_ASM(crc32w)
DEF_ASM(crc32x)
DEF_ASM(crc32cb)
DEF_ASM(crc32ch)
DEF_ASM(crc32cw)
DEF_ASM(crc32cx)
DEF_ASM(rev)
DEF_ASM(rev16)
DEF_ASM(rev32)
DEF_ASM(rev64)
DEF_ASM(clz)
DEF_ASM(cls)
DEF_ASM(rbit)
/* Exception generating */
DEF_ASM(svc)
DEF_ASM(hvc)
DEF_ASM(smc)
DEF_ASM(brk)
DEF_ASM(hlt)
DEF_ASM(dcps1)
DEF_ASM(dcps2)
DEF_ASM(dcps3)
/* Conditional branches */
DEF_ASM(b_eq)
DEF_ASM(b_ne)
DEF_ASM(b_cs)
DEF_ASM(b_cc)
DEF_ASM(b_mi)
DEF_ASM(b_pl)
DEF_ASM(b_vs)
DEF_ASM(b_vc)
DEF_ASM(b_hi)
DEF_ASM(b_ls)
DEF_ASM(b_ge)
DEF_ASM(b_lt)
DEF_ASM(b_gt)
DEF_ASM(b_le)
/* LD/ST exclusive */
DEF_ASM(ldxr)
DEF_ASM(ldxrb)
DEF_ASM(ldxrh)
DEF_ASM(stxr)
DEF_ASM(stxrb)
DEF_ASM(stxrh)
DEF_ASM(ldaxr)
DEF_ASM(ldaxrb)
DEF_ASM(ldaxrh)
DEF_ASM(stlxr)
DEF_ASM(stlxrb)
DEF_ASM(stlxrh)
/* LD/ST acquire-release */
DEF_ASM(ldar)
DEF_ASM(ldarb)
DEF_ASM(ldarh)
DEF_ASM(stlr)
DEF_ASM(stlrb)
DEF_ASM(stlrh)
DEF_ASM(ldalr)
DEF_ASM(ldalrb)
DEF_ASM(ldalrh)
DEF_ASM(stllr)
DEF_ASM(stllrb)
DEF_ASM(stllrh)
/* LD/ST unscaled immediate */
DEF_ASM(ldur)
DEF_ASM(ldurb)
DEF_ASM(ldurh)
DEF_ASM(ldursb)
DEF_ASM(ldursh)
DEF_ASM(ldursw)
DEF_ASM(stur)
DEF_ASM(sturb)
DEF_ASM(sturh)
/* Vector load/store */
DEF_ASM(ld1)
DEF_ASM(st1)
DEF_ASM(ld2)
DEF_ASM(st2)
DEF_ASM(ld3)
DEF_ASM(st3)
DEF_ASM(ld4)
DEF_ASM(st4)
/* ------------------------------------------------------------------ */
/* ARM64 instruction opcode constants and encoding helpers */
/* ------------------------------------------------------------------ */
/* Data processing - immediate */
#define ARM64_ADD_IMM 0x11000000U
#define ARM64_ADDS_IMM 0x2B000000U
#define ARM64_SUB_IMM 0x51000000U
#define ARM64_SUBS_IMM 0x6B000000U
/* Data processing - register */
#define ARM64_ADD_REG 0x0B000000U
#define ARM64_ADDS_REG 0x2B000000U
#define ARM64_SUB_REG 0x4B000000U
#define ARM64_SUBS_REG 0x6B000000U
#define ARM64_AND_REG 0x0A000000U
#define ARM64_ANDS_REG 0x6A000000U
#define ARM64_ORR_REG 0x2A000000U
#define ARM64_EOR_REG 0x4A000000U
#define ARM64_MUL_REG 0x1B000000U /* Base opcode, Rm/Rn/Rd must be filled in */
/* Move wide immediate */
#define ARM64_MOVZ 0x52800000U
#define ARM64_MOVN 0x12800000U
#define ARM64_MOVK 0xF2800000U
/* ARM64_MOVI_W/X removed: MOVI is a SIMD&FP instruction, not general-purpose */
/* Use MOVZ/MOVN/MOVK for general-purpose, or SIMD MOVI variants (0x0F000400, etc.) */
/* MOVZ/MOVN 64-bit base opcodes */
#define ARM64_MOVZ64 0xD2800000U /* MOVZ (64-bit), use with ARM64_HW() */
#define ARM64_MOVN64 0x92800000U /* MOVN (64-bit), use with ARM64_HW() */
/* Move wide immediate shift field (LSL #0/16/32/48 encoded as hw*16) */
#define ARM64_HW(v) (((uint32_t)(v) & 3) << 21)
/* Load/store register (unsigned immediate) */
#define ARM64_LDR_X 0xF9400000U
#define ARM64_LDR_W 0xB9400000U
#define ARM64_LDR_B 0x39400000U
#define ARM64_LDR_H 0x79400000U
#define ARM64_LDR_D 0xFD400000U
#define ARM64_LDR_S 0xBD400000U
#define ARM64_STR_X 0xF9000000U
#define ARM64_STR_W 0xB9000000U
#define ARM64_STR_B 0x39000000U
#define ARM64_STR_H 0x79000000U
#define ARM64_STR_D 0xFD000000U
#define ARM64_STR_S 0xBD000000U
/* Load/store register (unscaled immediate) */
#define ARM64_LDUR_X 0xF8400000U
#define ARM64_LDUR_W 0xB8400000U
#define ARM64_LDUR_B 0x38400000U
#define ARM64_LDUR_H 0x78400000U
#define ARM64_STUR_X 0xF8000000U
#define ARM64_STUR_W 0xB8000000U
#define ARM64_STUR_B 0x38000000U
#define ARM64_STUR_H 0x78000000U
/* Load/store register (register offset) */
#define ARM64_LDR_X_REG 0xF8606800U
#define ARM64_LDR_W_REG 0xB8606800U
#define ARM64_LDR_B_REG 0x38606800U
#define ARM64_LDR_H_REG 0x78606800U
#define ARM64_STR_X_REG 0xF8206800U
#define ARM64_STR_W_REG 0xB8206800U
#define ARM64_STR_B_REG 0x38206800U
#define ARM64_STR_H_REG 0x78206800U
/* Load/store (pre/post-indexed) */
#define ARM64_STR_X_PRE 0xF8000000U /* STR X pre-indexed base */
#define ARM64_LDR_X_POST 0xF8400000U /* LDR X post-indexed base */
/* SIMD load/store (unsigned immediate) */
#define ARM64_LDR_SCALAR 0x3D400000U /* Base for scalar load (size built dynamically) */
#define ARM64_LDR_S_VEC 0xBD400000U
#define ARM64_LDR_D_VEC 0xFD400000U
#define ARM64_LDR_Q_VEC 0x3DC00000U
#define ARM64_STR_SCALAR 0x3D000000U /* Base for scalar store (size built dynamically) */
#define ARM64_STR_S_VEC 0xBD000000U
#define ARM64_STR_D_VEC 0xFD000000U
#define ARM64_STR_Q_VEC 0x3D800000U
/* SIMD load/store (unscaled immediate) */
#define ARM64_LDUR_S_SIMD 0xBC400000U
#define ARM64_LDUR_D_SIMD 0xFC400000U
#define ARM64_LDUR_Q_SIMD 0x3C400000U
#define ARM64_STUR_S_SIMD 0xBC000000U
#define ARM64_STUR_D_SIMD 0xFC000000U
#define ARM64_STUR_Q_SIMD 0x3C000000U
/* SIMD load/store (register offset) */
#define ARM64_LDR_S_REG 0xBC606800U
#define ARM64_LDR_D_REG 0xFC606800U
#define ARM64_LDR_Q_REG 0x3C606800U
#define ARM64_STR_S_REG 0xBC206800U
#define ARM64_STR_D_REG 0xFC206800U
#define ARM64_STR_Q_REG 0x3C206800U
/* Load/store pair */
#define ARM64_LDP_X 0xA9400000U
#define ARM64_LDP_X_PRE 0xA9C00000U
#define ARM64_LDP_X_POST 0xA8C00000U
#define ARM64_STP_X 0xA9000000U
#define ARM64_STP_X_PRE 0xA9800000U
#define ARM64_STP_X_POST 0xA8800000U
#define ARM64_LDP_D 0x6D400000U
#define ARM64_LDP_D_PRE 0x6DC00000U
#define ARM64_LDP_D_POST 0x6CC00000U
#define ARM64_STP_D 0x6D000000U
#define ARM64_STP_D_PRE 0x6D800000U
#define ARM64_STP_D_POST 0x6C800000U
/* Branch instructions */
#define ARM64_B 0x14000000U
#define ARM64_BL 0x94000000U
#define ARM64_BR 0xD61F0000U
#define ARM64_BLR 0xD63F0000U
#define ARM64_RET 0xD65F0000U
/* Conditional branch */
#define ARM64_B_COND 0x54000000U
/* Compare and branch */
#define ARM64_CBZ 0x34000000U
#define ARM64_CBNZ 0x35000000U
/* System instructions */
#define ARM64_NOP 0xD503201FU
#define ARM64_ISB 0xD50330DFU
#define ARM64_DSB 0xD503309FU
#define ARM64_DMB 0xD50330BFU
#define ARM64_MRS 0xD5380000U
#define ARM64_MSR 0xD5180000U
#define ARM64_MRS_FPCR 0xD53B4400U
#define ARM64_MRS_FPSR 0xD53B4420U
#define ARM64_MSR_FPCR 0xD51B4400U
#define ARM64_MSR_FPSR 0xD51B4420U
/* Shifts (register) */
#define ARM64_LSL_REG 0x1AC02000U
#define ARM64_LSR_REG 0x1AC02400U
#define ARM64_ASR_REG 0x1AC02800U
#define ARM64_ROR_REG 0x1AC02C00U
/* Shifts (immediate - UBFM/SBFM) */
#define ARM64_LSL_IMM 0xD3400000U
#define ARM64_LSR_IMM 0xD3400000U
#define ARM64_LSR_IMM_32 0x53000000U /* 32-bit LSR base */
#define ARM64_ASR_IMM 0x93400000U
/* Shifted register encoding for ORR/AND/EOR */
#define ARM64_SHIFT_LSL(imm) (((uint32_t)(imm) & 63) << 10)
#define ARM64_SHIFT_LSR(imm) (0x00200000U | (((uint32_t)(imm) & 63) << 10))
#define ARM64_SHIFT_ASR(imm) (0x00400000U | (((uint32_t)(imm) & 63) << 10))
#define ARM64_SHIFT_ROR(imm) (0x00600000U | (((uint32_t)(imm) & 63) << 10))
/* UBFM/SBFM immediate fields (for LSL/LSR/ASR immediate aliases) */
#define ARM64_IMM_R(r) (((uint32_t)(r) & 0x3F) << 16)
#define ARM64_IMM_S(s) (((uint32_t)(s) & 0x3F) << 10)
/* Extended register encoding */
#define ARM64_EXTEND_LSL(lsl) (((uint32_t)(lsl) & 7) << 10)
/* MOV (register) - ORR with zero register */
#define ARM64_MOV_REG 0x2A0003E0U
/* Address generation */
#define ARM64_ADRP 0x90000000U
#define ARM64_ADR 0x10000000U
/* Logical immediate */
#define ARM64_AND_IMM 0x12000000U
#define ARM64_ORR_IMM_BASE 0x32000000U
#define ARM64_EOR_IMM 0x52000000U
#define ARM64_ANDS_IMM 0x72000000U
#define ARM64_ORR_IMM 0x320003E0U /* ORR immediate alias with Rn = XZR/WZR */
/* ------------------------------------------------------------------ */
/* ARM64 instruction encoding helper macros */
/* ------------------------------------------------------------------ */
/* Register field encodings */
#define ARM64_RD(r) ((uint32_t)(r) & 0x1FU)
#define ARM64_RN(r) (((uint32_t)(r) & 0x1FU) << 5)
#define ARM64_RM(r) (((uint32_t)(r) & 0x1FU) << 16)
#define ARM64_RT(r) ((uint32_t)(r) & 0x1FU)
#define ARM64_RT2(r) (((uint32_t)(r) & 0x1FU) << 10)
/* Immediate field encodings */
#define ARM64_IMM12(v) (((uint32_t)(v) & 0xFFFU) << 10)
#define ARM64_IMM7(v) (((uint32_t)(v) & 0x7FU) << 15)
#define ARM64_IMM14(v) (((uint32_t)(v) & 0x3FFFU) << 5)
#define ARM64_IMM16(v) (((uint32_t)(v) & 0xFFFFU) << 5)
#define ARM64_IMM_HW(v, hw) (((uint32_t)(v) & 0xFFFFU) << 5 | (((hw) & 3) << 21))
/* Shift and size encodings */
#define ARM64_SIZE(s) (((uint32_t)(s) & 3) << 30)
#define ARM64_SF(s) (((uint32_t)(s) & 1) << 31)
#define ARM64_S(v) (((uint32_t)(v) & 1) << 29)
#define ARM64_N(v) (((uint32_t)(v) & 1) << 22)
#define ARM64_SH(v) (((uint32_t)(v) & 1) << 22)
/* Condition code encoding */
#define ARM64_COND(c) ((uint32_t)(c) & 0xFU)
/* Branch offset encoding */
#define ARM64_OFFSET26(v) (((uint32_t)(v) >> 2) & 0x3FFFFFFU)
#define ARM64_OFFSET19(v) (((uint32_t)(v) >> 2) & 0x7FFFFU)
#define ARM64_OFFSET14(v) (((uint32_t)(v) >> 2) & 0x3FFFU)
/* Special register field (for MRS/MSR) */
#undef ARM64_SYSREG
#define ARM64_SYSREG(op0, op1, crn, crm, op2) \
((((op0) & 3) << 19) | (((op1) & 7) << 16) | \
(((crn) & 15) << 12) | (((crm) & 15) << 8) | (((op2) & 7) << 5))
/* Barrier option encoding */
#define ARM64_ISB_OPTION(opt) (((uint32_t)(opt) & 0xFU) << 8)
#define ARM64_DSB_OPTION(opt) (((uint32_t)(opt) & 0xFU) << 8)
#define ARM64_DMB_OPTION(opt) (((uint32_t)(opt) & 0xFU) << 8)
/* Additional opcodes for code generator - VERIFIED */
/* Note: Many of these are specific instances, not general templates */
/* Floating-point move - VERIFIED */
#define ARM64_FMOV_D_S 0x1E604000U /* FMOV Dd,Dn (scalar) */
#define ARM64_FMOV_X_D 0x9E660000U /* FMOV Xd,Dn (general to FP) */
#define ARM64_FMOV_W_S 0x1E260000U /* FMOV Wd,Sn (general to FP) */
/* ARM64_FMOV_S_D removed: 0x4EA01C00 is SIMD vector, not scalar FMOV */
/* Use 0x1E204000 for FMOV Sd,Sn or 0x1E604000 variant for cross-size */
/* FMOV variants for code generator */
#define ARM64_FMOV_SCALAR 0x1E604000U /* FMOV Dd, Dn (scalar FP) */
#define ARM64_FMOV_XD 0x9E660000U /* FMOV Xd, Dn (FP to GP 64-bit) */
#define ARM64_FMOV_WS 0x1E260000U /* FMOV Wd, Sn (FP to GP 32-bit) */
/* MOV vector (ORR vector register alias) */
#define ARM64_MOV_V16B 0x4EA01C00U /* MOV Vd.16B, Vn.16B (ORR vector, Rm=Rn alias) */
/* Load/Store SIMD&FP - Base opcodes (register fields must be filled in) */
#define ARM64_STR_Q_PRE 0x3C800000U /* STR Q pre-index base */
#define ARM64_LDR_Q_POST 0x3CC00000U /* LDR Q post-index base */
/* LDPSW - Base opcode (register fields must be filled in) */
/* Use gen_ldst_pair() with appropriate mode for LDPSW */
/* Base encodings: 0x68C00000 (post), 0x69400000 (offset), 0x69C00000 (pre) */
/* ARM64_LDR_S_SIMD removed: 0x0D00801C is not a standard encoding */
/* Use ARM64_LDR_S (0xBD400000) for scalar S or ARM64_LDR_S_VEC for SIMD */
/* MOV between SIMD and general - Use UMOV/SMOV instead */
/* ARM64_MOV_V_D removed: 0x4E083C00 is UMOV/SMOV encoding */
/* Use appropriate UMOV/SMOV base: 0x0E002C00/0x0E003C00 (32-bit) */
/* or 0x4E002C00/0x4E003C00 (64-bit) */
/* Verified from previous section */
#define ARM64_FCMP 0x1E202008U /* FCMP with zero */
#define ARM64_SDIV 0x1AC00C00U /* SDIV (32-bit) */
/* EXTR (Extract) */
#define ARM64_EXTR 0x13800000U /* EXTR Wd, Wn, Wm, #imm (32-bit) */
#define ARM64_EXTR64 0x93C00000U /* EXTR Xd, Xn, Xm, #imm (64-bit) */
/* ARM64_MUL removed - use ARM64_MUL_REG with gen_dp_reg() */
/* ORR shifted - Base opcodes (register fields must be filled in) */
#define ARM64_ORR_REG_LSL 0x2A000000U /* ORR (shifted register) base */
/* ARM64_ORR_REG_LSL32 removed: use ARM64_ORR_REG_LSL with SF=1 */
/* ARM64_ORR_REG_MOV is duplicate of ARM64_MOV_REG */
/* LSR immediate - These are UBFM encodings, use gen_shift() instead */
/* Base UBFM encodings: 0x53000000 (W), 0xD3400000 (X) */
/* gen_shift() handles immr/imms encoding for LSR/LSL/ASR */
/* ARM64_LSR_W_8, ARM64_LSR_X_8, ARM64_LSR_X_16, ARM64_LSR_X_24 removed */
/* They are specific instances, not templates */
/* SUB shifted - Base opcode (use gen_sub_reg or asm handler) */
#define ARM64_SUB_REG_LSL 0xCB000000U /* SUB (shifted register) base */
/* Duplicates removed: ARM64_LDP_X, ARM64_B, ARM64_BL, ARM64_BR, ARM64_NOP */
/* These are already defined in their respective sections above */

29
configure vendored
View File

@ -35,11 +35,13 @@ mingw32="no"
LIBSUF=".a"
EXESUF=""
DLLSUF=".so"
tcc_usrinclude=""
tcc_sysincludepaths=""
tcc_libpaths=""
tcc_crtprefix=""
tcc_elfinterp=""
triplet=
tcc_lddir=
confvars=
suggest="yes"
gcc_major=0
@ -51,7 +53,6 @@ cpuver=
dwarf=
targetos=
build_cross=
quiet=
# use CC/AR from environment when set
test -n "$CC" && cc="$CC"
@ -159,6 +160,8 @@ for opt do
;;
--debug) confvars_set debug
;;
--with-libgcc) confvars_set libgcc
;;
--with-selinux) confvars_set selinux
;;
--tcc-switches=*) assign_opt "$opt" tcc_switches
@ -171,8 +174,6 @@ for opt do
;;
--help|-h) show_help="yes"
;;
-q) quiet=yes
;;
*) echo "configure: WARNING: unrecognized option $opt"
;;
esac
@ -196,7 +197,6 @@ Standard options:
--docdir=DIR documentation in DIR [SHAREDIR/doc/tcc]
--mandir=DIR man documentation in DIR [SHAREDIR/man]
--infodir=DIR info documentation in DIR [SHAREDIR/info]
-q be quiet
Advanced options (experts only):
--source-path=PATH path of source code [$source_path]
@ -210,8 +210,9 @@ Advanced options (experts only):
--disable-static make libtcc.so instead of libtcc.a
--enable-static make libtcc.a instead of libtcc.dll (win32)
--disable-rpath disable use of -rpath with libtcc.so
--with-libgcc use libgcc_s.so.1 instead of libtcc1.a
--with-selinux use mmap for executable memory (tcc -run)
--enable-cross build all cross compilers (see also 'make help')
--enable-cross build cross compilers (see also 'make help')
--sysincludepaths=... specify system include paths, colon separated
--libpaths=... specify system library paths, colon separated
@ -265,11 +266,7 @@ default os_release "$(uname -r)"
case $buildos in
Windows_NT|MINGW*|MSYS*|CYGWIN*)
buildos="WIN32"
case "$MSYSTEM" in
MINGW32) cpu_sys=i386 ;;
MINGW64) cpu_sys=x86_64 ;;
CLANGARM64|MINGW_ARM64) cpu_sys=arm64 ;;
esac
test "$MSYSTEM" = "MINGW32" && cpu_sys=i386
;;
Linux)
if test "$(uname -o)" = "Android"; then
@ -366,7 +363,6 @@ case $targetos in
cc=`command -v cc`
cc=`readlink $cc || echo clang`
tcc_usrinclude="`xcrun --show-sdk-path`/usr/include"
default tcc_sysincludepaths "{B}/include:$tcc_usrinclude"
if test "${confvars%new_macho*}" = "${confvars}"; then
# if new_macho was not specified and (known) ver <= 10, use old (=no)
osxver=$(sw_vers -productVersion 2>/dev/null) # X.Y.Z
@ -478,8 +474,7 @@ if test -z "$build_cross"; then
if test -z "$triplet"; then
case $cpu in x86_64|arm64|riscv64)
if test -f "/usr/lib64/crti.o" ; then
default tcc_libpaths "{B}:/usr/lib64"
default tcc_crtprefix "/usr/lib64"
tcc_lddir="lib64"
fi
esac
fi
@ -553,7 +548,6 @@ fi
fcho() { if test -n "$2"; then echo "$1$2"; fi }
if test -z "$quiet"; then
fcho "Binary directory " "$bindir"
fcho "TinyCC directory " "$tccdir"
fcho "Library directory " "$libdir"
@ -562,6 +556,7 @@ fcho "Manual directory " "$mandir"
fcho "Info directory " "$infodir"
fcho "Doc directory " "$docdir"
fcho "Target root prefix " "$sysroot"
fcho "/usr/include dir " "$tcc_usrinclude"
echo "Source path $source_path"
echo "Build OS $(uname -m -s)"
echo "C compiler $cc ($gcc_major.$gcc_minor)"
@ -575,7 +570,6 @@ fcho "Elfinterp " "$tcc_elfinterp"
fcho "Switches " "$tcc_switches"
fcho "Config " "${confvars# }"
echo "Creating config.mak and config.h"
fi
version=$(head "$source_path/VERSION")
@ -693,6 +687,7 @@ for v in $cpu $confvars ; do
esac
;;
# other
CONFIG_libgcc=yes) print_num CONFIG_USE_LIBGCC 1 ;;
CONFIG_selinux=yes) print_num CONFIG_SELINUX 1 ;;
CONFIG_pie=yes) print_num CONFIG_TCC_PIE 1 ;;
CONFIG_pic=yes) print_num CONFIG_TCC_PIC 1 ;;
@ -707,11 +702,13 @@ for v in $cpu $confvars ; do
esac
done
print_str CONFIG_USR_INCLUDE "$tcc_usrinclude"
print_str CONFIG_TCC_SYSINCLUDEPATHS "$tcc_sysincludepaths"
print_str CONFIG_TCC_LIBPATHS "$tcc_libpaths"
print_str CONFIG_TCC_CRTPREFIX "$tcc_crtprefix"
print_str CONFIG_TCC_ELFINTERP "$tcc_elfinterp"
print_str CONFIG_TCC_SWITCHES "$tcc_switches"
print_str CONFIG_LDDIR "$tcc_lddir"
print_str CONFIG_TRIPLET "$triplet"
print_str CONFIG_OS_RELEASE "$os_release"
echo "#endif" >> $TMPH && echo >> $TMPH
@ -723,7 +720,7 @@ print_num CONFIG_TCC_PREDEFS "$predefs"
diff $TMPH config.h >/dev/null 2>&1
if test $? -ne 0 ; then
mv -f $TMPH config.h
elif test -z "$quiet"; then
else
echo "config.h is unchanged"
fi

3
elf.h
View File

@ -2336,8 +2336,7 @@ typedef Elf32_Addr Elf32_Conflict;
/* Processor specific values for the Shdr sh_type field. */
#define SHT_ARM_EXIDX (SHT_LOPROC + 1) /* ARM unwind section. */
#define SHT_ARM_PREEMPTMAP (SHT_LOPROC + 2) /* Preemption details. */
#define SHT_ARM_ATTRIBUTES (SHT_LOPROC + 3) /* ARM attributes section. */
#define SHT_RISCV_ATTRIBUTES 0x70000003
#define SHT_ARM_ATTRIBUTES (SHT_LOPROC + 3) /* ARM attributes section. */
/* AArch64 relocs. */

View File

@ -494,6 +494,13 @@ ST_FUNC void gen_expr32(ExprValue *pe)
gen_addr32(pe->sym ? VT_SYM : 0, pe->sym, pe->v);
}
#ifdef TCC_TARGET_X86_64
ST_FUNC void gen_expr64(ExprValue *pe)
{
gen_addr64(pe->sym ? VT_SYM : 0, pe->sym, pe->v);
}
#endif
/* XXX: unify with C code output ? */
static void gen_disp32(ExprValue *pe)
{

View File

@ -271,7 +271,7 @@ static void gen_modrm(int opc, int op_r2, int r, Sym *sym, int c)
} else if ((r & VT_VALMASK) == VT_LOCAL) {
o(opc);
/* currently, we use only ebp as base */
if (c == (signed char)c) {
if (c == (char)c) {
/* short reference */
o(0x45 | op_reg);
g(c);
@ -313,16 +313,6 @@ ST_FUNC void load(int r, SValue *sv)
#endif
if (fr & VT_LVAL) {
if ((fr & VT_SYM) && sv->sym->type.t & VT_TLS) {
int dst_reg = REG_VALUE(r);
o(0x65); /* gs segment prefix */
o(0x8b); /* mov r/m, r */
o(0x04 | (dst_reg << 3)); /* modrm: [sib] | destreg */
o(0x25); /* sib: disp32 */
greloca(cur_text_section, sv->sym, ind, R_386_TLS_LE, fc);
gen_le32(0);
return;
}
if (v == VT_LLOCAL) {
v1.type.t = VT_INT;
v1.r = VT_LOCAL | VT_LVAL;
@ -439,16 +429,6 @@ ST_FUNC void store(int r, SValue *v)
} else
#endif
if ((fr & VT_SYM) && v->sym->type.t & VT_TLS) {
o(0x65); /* gs segment prefix */
o(opc);
o(0x04 | (REG_VALUE(r) << 3)); /* modrm: [sib] | srcreg */
o(0x25); /* sib: disp32 */
greloca(cur_text_section, v->sym, ind, R_386_TLS_LE, fc);
gen_le32(0);
return;
}
if (fr == VT_CONST || fr == VT_LOCAL || (v->r & VT_LVAL)) {
gen_modrm(opc, r, v->r, v->sym, fc);
} else if (fr != r) {
@ -459,7 +439,7 @@ ST_FUNC void store(int r, SValue *v)
static void gadd_sp(int val)
{
if (val == (signed char)val) {
if (val == (char)val) {
o(0xc483);
g(val);
} else {
@ -794,7 +774,7 @@ ST_FUNC void gjmp_addr(int a)
{
int r;
r = a - ind - 2;
if (r == (signed char)r) {
if (r == (char)r) {
g(0xeb);
g(r);
} else {
@ -807,7 +787,7 @@ ST_FUNC void gjmp_addr(int a)
ST_FUNC void gjmp_cond_addr(int a, int op)
{
int r = a - ind - 2;
if (r == (signed char)r)
if (r == (char)r)
g(op - 32), g(r);
else
g(0x0f), gjmp2(op - 16, r - 4);
@ -850,7 +830,7 @@ ST_FUNC void gen_opi(int op)
r = gv(RC_INT);
vswap();
c = vtop->c.i;
if (c == (signed char)c) {
if (c == (char)c) {
/* generate inc and dec for smaller code */
if ((c == 1 || c == -1) && (op == '+' || op == '-')) {
opc = (c == 1) ^ (op == '+');

View File

@ -305,6 +305,7 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
}
return;
case R_386_TLS_LDO_32:
case R_386_TLS_LE:
{
ElfW(Sym) *sym;
Section *sec;
@ -316,38 +317,6 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
add32le(ptr, x);
}
return;
case R_386_TLS_LE:
{
ElfW(Sym) *sym;
Section *sec;
int32_t x;
addr_t tls_start = 0, tls_end = 0, tls_align = 1;
int i;
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
sec = s1->sections[sym->st_shndx];
for (i = 1; i < s1->nb_sections; i++) {
Section *s = s1->sections[i];
if (s->sh_flags & SHF_TLS && s->sh_size) {
if (!tls_start || s->sh_addr < tls_start)
tls_start = s->sh_addr;
if (s->sh_addr + s->sh_size > tls_end)
tls_end = s->sh_addr + s->sh_size;
if (s->sh_addralign > tls_align)
tls_align = s->sh_addralign;
}
}
if (tls_end > tls_start) {
addr_t tls_size = tls_end - tls_start;
addr_t aligned_size = (tls_size + tls_align - 1) & ~(tls_align - 1);
x = val - (tls_start + aligned_size);
} else {
x = val - sec->sh_addr - sec->data_offset;
}
add32le(ptr, x);
}
return;
case R_386_NONE:
return;
default:

View File

@ -90,6 +90,8 @@
#define __NO_TLS 1
#define __RUNETYPE_INTERNAL 1
# if __SIZEOF_POINTER__ == 8
/* FIXME, __int128_t is used by setjump */
#define __int128_t struct { unsigned char _dummy[16] __attribute((aligned(16))); }
#define __SIZEOF_SIZE_T__ 8
#define __SIZEOF_PTRDIFF_T__ 8
#else
@ -140,6 +142,12 @@
#endif
#define __INT32_TYPE__ int
#if defined __aarch64__
/* GCC's __uint128_t appears in some Linux/OSX header files. Make it a
synonym for long double to get the size and alignment right. */
#define __uint128_t long double
#endif
#if !defined _WIN32
/* glibc defines. We do not support __USER_NAME_PREFIX__ */
#define __REDIRECT(name, proto, alias) name proto __asm__ (#alias)
@ -179,17 +187,14 @@
# endif
#endif
/* GCC's __uint128_t appears in some Linux/OSX header files.
Just make it some type with same size and alignment. */
struct __uint128__ { char x[16]; } __attribute((__aligned__(16)));
#define __int128_t struct __uint128__
#define __uint128_t struct __uint128__
/* __builtin_va_list */
#if defined __x86_64__
#if !defined _WIN32
/* GCC compatible definition of va_list. */
/* This should be in sync with the declaration in our lib/va_list.c */
enum __va_arg_type {
__va_gen_reg, __va_float_reg, __va_stack
};
typedef struct {
unsigned gp_offset, fp_offset;
union {
@ -199,7 +204,43 @@
char *reg_save_area;
} __builtin_va_list[1];
void *__va_arg(__builtin_va_list ap, int arg_type, int size, int align);
static inline void *__va_arg(__builtin_va_list ap, int arg_type,
int size, int align)
{
size = (size + 7) & ~7;
align = (align + 7) & ~7;
switch ((enum __va_arg_type)arg_type) {
case __va_gen_reg:
if (ap->gp_offset + size <= 48) {
ap->gp_offset += size;
return ap->reg_save_area + ap->gp_offset - size;
}
goto use_overflow_area;
case __va_float_reg:
if (ap->fp_offset < 128 + 48) {
ap->fp_offset += 16;
if (size == 8)
return ap->reg_save_area + ap->fp_offset - 16;
if (ap->fp_offset < 128 + 48) {
double *p = (double *)(ap->reg_save_area + ap->fp_offset);
p[-1] = p[0];
ap->fp_offset += 16;
return ap->reg_save_area + ap->fp_offset - 32;
}
}
goto use_overflow_area;
case __va_stack:
use_overflow_area:
ap->overflow_arg_area += size;
ap->overflow_arg_area =
(char*)((long long)(ap->overflow_arg_area + align - 1) & -align);
return ap->overflow_arg_area - size;
default: /* should never happen */
char *a = (char *)0; *a = 0; // abort
return 0;
}
}
#define __builtin_va_start(ap, last) \
(*(ap) = *(__builtin_va_list)((char*)__builtin_frame_address(0) - 24))
#define __builtin_va_arg(ap, t) \
@ -222,9 +263,7 @@
&~3), *(type *)(ap - ((sizeof(type)+3)&~3)))
#elif defined __aarch64__
#if defined _WIN32
typedef char *__builtin_va_list;
#elif defined __APPLE__
#if defined __APPLE__
typedef struct {
void *__stack;
} __builtin_va_list;

View File

@ -41,7 +41,7 @@ ARM_O = libtcc1.o armeabi.o armflush.o $(COMMON_O)
ARM64_O = lib-arm64.o $(COMMON_O)
RISCV64_O = lib-arm64.o $(COMMON_O)
COMMON_O = stdatomic.o atomic.o builtin.o alloca.o alloca-bt.o
WIN_O = crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o winex.o
WIN_O = crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o
LIN_O = dsohandle.o
OSX_O =
@ -59,13 +59,12 @@ $(Cbc)COMMON_O += bcheck.o
EXTRA_O = runmain.o bt-exe.o bt-dll.o bt-log.o bcheck.o
OBJ-i386 = $(I386_O) pic86.o $(LIN_O)
OBJ-x86_64 = $(X86_64_O) va_list.o $(LIN_O)
OBJ-x86_64-osx = $(X86_64_O) va_list.o $(OSX_O)
OBJ-x86_64 = $(X86_64_O) $(LIN_O)
OBJ-x86_64-osx = $(X86_64_O) $(OSX_O)
OBJ-i386-win32 = $(I386_O) chkstk.o $(WIN_O)
OBJ-x86_64-win32 = $(X86_64_O) chkstk.o $(WIN_O)
OBJ-arm64 = $(ARM64_O) armflush.o $(LIN_O)
OBJ-arm64 = $(ARM64_O) $(LIN_O)
OBJ-arm64-osx = $(ARM64_O) $(OSX_O)
OBJ-arm64-win32 = $(ARM64_O) chkstk.o $(WIN_O)
OBJ-arm = $(ARM_O) $(LIN_O)
OBJ-arm-fpa = $(OBJ-arm)
OBJ-arm-fpa-ld = $(OBJ-arm)
@ -73,7 +72,7 @@ OBJ-arm-vfp = $(OBJ-arm)
OBJ-arm-eabi = $(OBJ-arm)
OBJ-arm-eabihf = $(OBJ-arm)
OBJ-arm-wince = $(ARM_O) $(WIN_O)
OBJ-riscv64 = $(RISCV64_O) lib-riscv.o $(LIN_O)
OBJ-riscv64 = $(RISCV64_O) $(LIN_O)
OBJ-extra = $(filter $(EXTRA_O),$(OBJ-$T))
OBJ-libtcc1 = $(addprefix $(X),$(filter-out $(OBJ-extra),$(OBJ-$T)))

View File

@ -4,9 +4,6 @@
intrinsic with gcc. However tcc in order to compile
itself needs this function */
/* ------------------------------------------------------------- */
#if defined __arm__
#ifdef __TINYC__
/* syscall wrapper */
@ -52,13 +49,3 @@ void __clear_cache(void *beginning, void *end)
* However, there is no ARM asm parser in tcc so we use it for now */
syscall(__ARM_NR_cacheflush, beginning, end, 0);
}
/* ------------------------------------------------------------- */
#elif defined __aarch64__
void __clear_cache(void *beg, void *end)
{
__arm64_clear_cache(beg, end);
}
/* ------------------------------------------------------------- */
#endif

View File

@ -34,11 +34,7 @@
REDIR(__bound_strncmp) \
REDIR(__bound_strcat) \
REDIR(__bound_strchr) \
REDIR(__bound_strdup) \
REDIR(__bound_strncat) \
REDIR(__bound_strrchr) \
REDIR(__bound_setjmp) \
REDIR(__bound_longjmp)
REDIR(__bound_strdup)
#ifdef __leading_underscore
#define _(s) "_"#s
@ -49,28 +45,11 @@
#define REDIR(s) void *s;
static struct { REDIR_ALL } all_ptrs;
#undef REDIR
#define REDIR(s) #s"\0"
static const char all_names[] = REDIR_ALL;
#undef REDIR
#if __aarch64__
# define REDIR(s) \
__asm__(".global "_(s)";"_(s)":"); \
__asm__(".int 0x58000090"); /* ldr x16, [pc, #16] */ \
__asm__(".int 0xf9400210"); /* ldr x16, [x16] */ \
__asm__(".int 0xd61f0200"); /* br x16 */ \
__asm__(".int 0xd503201f"); /* nop for alignment */ \
__asm__(".quad all_ptrs + (. - all_jmps - 16) / 24 * 8"); \
__asm__(".type "_(s)",function\n.size "_(s)",.-"_(s));
__asm__(".text\n.align 8\nall_jmps:");
REDIR_ALL
#else
# define REDIR(s) \
__asm__(".global "_(s)";"_(s)":"); goto *all_ptrs.s;
static void all_jmps() { REDIR_ALL }
#endif
#define REDIR(s) __asm__(".global " _(s) ";" _(s) ": jmp *%0" : : "m" (all_ptrs.s) );
static void all_jmps() { REDIR_ALL }
#undef REDIR
void __bt_init_dll(int bcheck)

View File

@ -11,21 +11,6 @@
# define __declspec(n)
#endif
#ifdef _WIN64
static void bt_init_pe_prog_base(rt_context *p)
{
MEMORY_BASIC_INFORMATION mbi;
addr_t imagebase;
if (!p->prog_base)
return;
if (!VirtualQuery(p, &mbi, sizeof(mbi)) || !mbi.AllocationBase)
return;
imagebase = (addr_t)mbi.AllocationBase - p->prog_base;
p->prog_base = (addr_t)mbi.AllocationBase - (imagebase & 0xffffffffu);
}
#endif
__declspec(dllexport)
void __bt_init(rt_context *p, int is_exe)
{
@ -39,10 +24,6 @@ void __bt_init(rt_context *p, int is_exe)
if (p->bounds_start)
__bound_init(p->bounds_start, -1);
#ifdef _WIN64
bt_init_pe_prog_base(p);
#endif
/* add to chain */
rt_wait_sem();
p->next = g_rc, g_rc = p;

View File

@ -18,40 +18,49 @@ typedef int int32_t;
typedef unsigned uint32_t;
typedef long long int64_t;
typedef unsigned long long uint64_t;
static void *memcpy(void* d, void* s, __SIZE_TYPE__ c) {
char *d_, *s_;
d_ = d; s_ = s;
for (__SIZE_TYPE__ i = 0; i < c; ++i) {
d_[i] = s_[i];
}
return d;
}
#else
#include <stdint.h>
#include <string.h>
#endif
typedef union {
struct { uint64_t x0, x1; };
long double f;
#if !defined __riscv && !defined __APPLE__
void __clear_cache(void *beg, void *end)
{
__arm64_clear_cache(beg, end);
}
#endif
typedef struct {
uint64_t x0, x1;
} u128_t;
typedef union {
uint64_t x;
double f;
} u64_t;
typedef union {
uint32_t x;
float f;
} u32_t;
static long double f3_zero(int sgn)
{
long double f;
u128_t x = { 0, (uint64_t)sgn << 63 };
return x.f;
memcpy(&f, &x, 16);
return f;
}
static long double f3_infinity(int sgn)
{
long double f;
u128_t x = { 0, (uint64_t)sgn << 63 | 0x7fff000000000000 };
return x.f;
memcpy(&f, &x, 16);
return f;
}
static long double f3_NaN(void)
{
long double f;
#if 0
// ARM's default NaN usually has just the top fraction bit set:
u128_t x = { 0, 0x7fff800000000000 };
@ -59,31 +68,28 @@ static long double f3_NaN(void)
// GCC's library sets all fraction bits:
u128_t x = { -1, 0x7fffffffffffffff };
#endif
return x.f;
memcpy(&f, &x, 16);
return f;
}
static int fp3_convert_NaN(long double *f, int sgn, u128_t *mnt)
static int fp3_convert_NaN(long double *f, int sgn, u128_t mnt)
{
u128_t x = { mnt->x0,
mnt->x1 | 0x7fff800000000000 | (uint64_t)sgn << 63 };
*f = x.f;
u128_t x = { mnt.x0,
mnt.x1 | 0x7fff800000000000 | (uint64_t)sgn << 63 };
memcpy(f, &x, 16);
return 1;
#define fp3_convert_NaN(a,b,c) fp3_convert_NaN(a,b,&c)
}
static int fp3_detect_NaNs(long double *f,
int a_sgn, int a_exp, u128_t *a,
int b_sgn, int b_exp, u128_t *b)
#define a (*a)
#define b (*b)
int a_sgn, int a_exp, u128_t a,
int b_sgn, int b_exp, u128_t b)
{
#if 0
// Detect signalling NaNs:
if (a_exp == 32767 && (a.x0 | a.x1 << 16) && !(a.x1 >> 47 & 1))
return fp3_convert_NaN(f, a_sgn, a);
if (b_exp == 32767 && (b.x0 | b.x1 << 16) && !(b.x1 >> 47 & 1))
return fp3_convert_NaN(f, b_sgn, b);
#endif
// Detect quiet NaNs:
if (a_exp == 32767 && (a.x0 | a.x1 << 16))
return fp3_convert_NaN(f, a_sgn, a);
@ -91,16 +97,12 @@ static int fp3_detect_NaNs(long double *f,
return fp3_convert_NaN(f, b_sgn, b);
return 0;
#undef a
#undef b
#define fp3_detect_NaNs(a,b,c,d,e,f,g) fp3_detect_NaNs(a,b,c,&d,e,f,&g)
}
static void f3_unpack(int *sgn, int32_t *exp, u128_t *mnt, long double f)
{
u128_t x;
x.f = f;
memcpy(&x, &f, 16);
*sgn = x.x1 >> 63;
*exp = x.x1 >> 48 & 32767;
x.x1 = x.x1 << 16 >> 16;
@ -108,7 +110,7 @@ static void f3_unpack(int *sgn, int32_t *exp, u128_t *mnt, long double f)
x.x1 |= (uint64_t)1 << 48;
else
*exp = 1;
mnt->f = x.f;
memcpy(mnt, &x, 16);
}
static void f3_normalise(int32_t *exp, u128_t *mnt)
@ -182,7 +184,8 @@ static long double f3_round(int sgn, int32_t exp, u128_t *x)
return f3_infinity(sgn);
x->x1 = x->x1 << 16 >> 16 | (uint64_t)exp << 48 | (uint64_t)sgn << 63;
return x->f;
memcpy(&f, x, 16);
return f;
}
static long double f3_add(long double fa, long double fb, int neg)
@ -377,20 +380,23 @@ long double __divtf3(long double fa, long double fb)
long double __negtf2(long double f)
{
((u128_t*)&f)->x1 ^= 1UL << 63;
u128_t a;
memcpy(&a, &f, 16);
a.x1 ^= 1UL << 63;
memcpy(&f, &a, 16);
return f;
}
long double __extendsftf2(float f)
{
long double fx;
u128_t x;
u32_t u;
uint32_t a;
uint64_t aa;
u.f = f, a = u.x;
memcpy(&a, &f, 4);
aa = a;
x.x0 = 0;
if (!(a << 1))
x.x1 = aa << 32;
@ -405,17 +411,16 @@ long double __extendsftf2(float f)
} else
x.x1 = (aa >> 31 << 63 | ((aa >> 23 & 255) + 16256) << 48 |
aa << 41 >> 16);
return x.f;
memcpy(&fx, &x, 16);
return fx;
}
long double __extenddftf2(double f)
{
long double fx;
u128_t x;
u64_t u;
uint64_t a;
u.f = f, a = u.x;
memcpy(&a, &f, 8);
x.x0 = a << 60;
if (!(a << 1))
x.x1 = a;
@ -430,7 +435,8 @@ long double __extenddftf2(double f)
x.x1 = a >> 63 << 63 | (15360 - adj + 1) << 48 | a << adj << 12 >> 16;
} else
x.x1 = a >> 63 << 63 | ((a >> 52 & 2047) + 15360) << 48 | a << 12 >> 16;
return x.f;
memcpy(&fx, &x, 16);
return fx;
}
float __trunctfsf2(long double f)
@ -438,10 +444,11 @@ float __trunctfsf2(long double f)
u128_t mnt;
int32_t exp;
int sgn;
u32_t x;
#define x x.x
uint32_t x;
float fx;
f3_unpack(&sgn, &exp, &mnt, f);
if (exp == 32767 && (mnt.x0 | mnt.x1 << 16))
x = 0x7fc00000 | (uint32_t)sgn << 31 | (mnt.x1 >> 25 & 0x007fffff);
else if (exp > 16510)
@ -459,8 +466,8 @@ float __trunctfsf2(long double f)
x += 4;
x = ((x >> 2) + (exp << 23)) | (uint32_t)sgn << 31;
}
#undef x
return x.f;
memcpy(&fx, &x, 4);
return fx;
}
double __trunctfdf2(long double f)
@ -468,10 +475,11 @@ double __trunctfdf2(long double f)
u128_t mnt;
int32_t exp;
int sgn;
u64_t x;
#define x x.x
uint64_t x;
double fx;
f3_unpack(&sgn, &exp, &mnt, f);
if (exp == 32767 && (mnt.x0 | mnt.x1 << 16))
x = (0x7ff8000000000000 | (uint64_t)sgn << 63 |
mnt.x1 << 16 >> 12 | mnt.x0 >> 60);
@ -490,8 +498,8 @@ double __trunctfdf2(long double f)
x += 4;
x = ((x >> 2) + ((uint64_t)exp << 52)) | (uint64_t)sgn << 63;
}
#undef x
return x.f;
memcpy(&fx, &x, 8);
return fx;
}
int32_t __fixtfsi(long double fa)
@ -556,6 +564,7 @@ long double __floatsitf(int32_t a)
int exp = 16414;
uint32_t mnt = a;
u128_t x = { 0, 0 };
long double f;
int i;
if (a) {
if (a < 0) {
@ -570,7 +579,8 @@ long double __floatsitf(int32_t a)
x.x1 = ((uint64_t)sgn << 63 | (uint64_t)exp << 48 |
(uint64_t)(mnt << 1) << 16);
}
return x.f;
memcpy(&f, &x, 16);
return f;
}
long double __floatditf(int64_t a)
@ -579,6 +589,7 @@ long double __floatditf(int64_t a)
int exp = 16446;
uint64_t mnt = a;
u128_t x = { 0, 0 };
long double f;
int i;
if (a) {
if (a < 0) {
@ -593,7 +604,8 @@ long double __floatditf(int64_t a)
x.x0 = mnt << 49;
x.x1 = (uint64_t)sgn << 63 | (uint64_t)exp << 48 | mnt << 1 >> 16;
}
return x.f;
memcpy(&f, &x, 16);
return f;
}
long double __floatunsitf(uint32_t a)
@ -601,6 +613,7 @@ long double __floatunsitf(uint32_t a)
int exp = 16414;
uint32_t mnt = a;
u128_t x = { 0, 0 };
long double f;
int i;
if (a) {
for (i = 16; i; i >>= 1)
@ -610,7 +623,8 @@ long double __floatunsitf(uint32_t a)
}
x.x1 = (uint64_t)exp << 48 | (uint64_t)(mnt << 1) << 16;
}
return x.f;
memcpy(&f, &x, 16);
return f;
}
long double __floatunditf(uint64_t a)
@ -629,14 +643,15 @@ long double __floatunditf(uint64_t a)
x.x0 = mnt << 49;
x.x1 = (uint64_t)exp << 48 | mnt << 1 >> 16;
}
return x.f;
memcpy(&f, &x, 16);
return f;
}
static int f3_cmp(long double fa, long double fb)
{
u128_t a, b;
a.f = fa;
b.f = fb;
memcpy(&a, &fa, 16);
memcpy(&b, &fb, 16);
return (!(a.x0 | a.x1 << 1 | b.x0 | b.x1 << 1) ? 0 :
((a.x1 << 1 >> 49 == 0x7fff && (a.x0 | a.x1 << 16)) ||
(b.x1 << 1 >> 49 == 0x7fff && (b.x0 | b.x1 << 16))) ? 2 :

View File

@ -1,20 +0,0 @@
/*
* TCC runtime library for riscv64.
*
* Copyright (c) 2026
*
* Copying and distribution of this file, with or without modification,
* are permitted in any medium without royalty provided the copyright
* notice and this notice are preserved. This file is offered as-is,
* without any warranty.
*/
/* ------------------------------------------------------------- */
/* __clear_cache is used in tccrun.c. It is a built-in
intrinsic with gcc. However tcc in order to compile
itself needs this function */
void __clear_cache(void *beg, void *end)
{
__riscv64_clear_cache(beg, end);
}

View File

@ -107,9 +107,10 @@ union float_long {
};
/* XXX: we don't support several builtin supports for now */
#if defined __i386__
#if !defined __x86_64__ && !defined __arm__ && !defined __riscv && !defined __aarch64__
/* XXX: use gcc/tcc intrinsic ? */
#if defined __i386__
#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
__asm__ ("subl %5,%1\n\tsbbl %3,%0" \
: "=r" ((USItype) (sh)), \
@ -138,6 +139,9 @@ union float_long {
: "=r" (__cbtmp) : "rm" ((USItype) (x))); \
(count) = __cbtmp ^ 31; \
} while (0)
#else
#error unsupported CPU type
#endif
/* most of this code is taken from libgcc2.c from gcc */
@ -474,7 +478,7 @@ long long __ashldi3(long long a, int b)
#endif
}
#endif /* __i386__ */
#endif /* !__x86_64__ */
/* XXX: fix tcc's code generator to do this instead */
float __floatundisf(unsigned long long a)
@ -621,3 +625,11 @@ long long __fixxfdi (long double a1)
return s ? ret : -ret;
}
#endif /* !ARM */
#if defined _WIN64
/* MSVC x64 intrinsic */
void __faststorefence(void)
{
__asm__("lock; orl $0,(%rsp)");
}
#endif

View File

@ -1,67 +0,0 @@
/* va_list.c - tinycc support for va_list on X86_64 */
#if defined __x86_64__
/* Avoid include files, they may not be available when cross compiling */
extern void abort(void);
/* This should be in sync with our include/stdarg.h */
enum __va_arg_type {
__va_gen_reg, __va_float_reg, __va_stack
};
/* GCC compatible definition of va_list. */
/*predefined by TCC (tcc_predefs.h):
typedef struct {
unsigned int gp_offset;
unsigned int fp_offset;
union {
unsigned int overflow_offset;
char *overflow_arg_area;
};
char *reg_save_area;
} __builtin_va_list[1];
*/
extern void *memcpy(void *dest, const void *src, unsigned long n);
void *__va_arg(__builtin_va_list ap,
int arg_type,
int size, int align)
{
size = (size + 7) & ~7;
align = (align + 7) & ~7;
switch ((enum __va_arg_type)arg_type) {
case __va_gen_reg:
if (ap->gp_offset + size <= 48) {
ap->gp_offset += size;
return ap->reg_save_area + ap->gp_offset - size;
}
goto use_overflow_area;
case __va_float_reg:
if (ap->fp_offset < 128 + 48) {
ap->fp_offset += 16;
if (size == 8)
return ap->reg_save_area + ap->fp_offset - 16;
if (ap->fp_offset < 128 + 48) {
memcpy(ap->reg_save_area + ap->fp_offset - 8,
ap->reg_save_area + ap->fp_offset, 8);
ap->fp_offset += 16;
return ap->reg_save_area + ap->fp_offset - 32;
}
}
goto use_overflow_area;
case __va_stack:
use_overflow_area:
ap->overflow_arg_area += size;
ap->overflow_arg_area = (char*)((long long)(ap->overflow_arg_area + align - 1) & -align);
return ap->overflow_arg_area - size;
default: /* should never happen */
abort();
return 0;
}
}
#endif

163
libtcc.c
View File

@ -124,15 +124,8 @@ static void tcc_add_systemdir(TCCState *s)
tcc_add_library_path(s, normalize_slashes(buf));
}
#endif
/* for tcc -E : On windows (depending on compiler) a FILE*
must be created by the same module where it is used. */
PUB_FUNC FILE *tcc_fopen(const char *f, const char *m) {
return fopen(f, m);
}
PUB_FUNC int tcc_fclose(FILE *f) {
return fclose(f);
}
#endif
/********************************************************/
PUB_FUNC void tcc_enter_state(TCCState *s1)
@ -252,7 +245,7 @@ static void *default_reallocator(void *ptr, unsigned long size)
else {
ptr1 = realloc(ptr, size);
if (!ptr1) {
fprintf(stderr, "tcc: memory full\n");
fprintf(stderr, "memory full\n");
exit (1);
}
}
@ -798,7 +791,7 @@ ST_FUNC int tcc_open(TCCState *s1, const char *filename)
}
/* compile the file opened in 'file'. Return non zero if errors. */
static int tcc_compile(TCCState *s1, int filetype, const char *str, int fd)
static int tcc_compile(TCCState *s1, int filetype, const char *str, int fd, const char *filename)
{
/* Here we enter the code section where we use the global variables for
parsing and code generation (tccpp.c, tccgen.c, <target>-gen.c).
@ -814,8 +807,16 @@ static int tcc_compile(TCCState *s1, int filetype, const char *str, int fd)
if (fd == -1) {
int len = strlen(str);
tcc_open_bf(s1, "<string>", len);
tcc_open_bf(s1, filename ? filename : "<string>", len);
memcpy(file->buffer, str, len);
if (s1->do_debug && filename) {
FILE *fp = fopen(filename, "w");
if (fp) {
fputs(str, fp);
fclose(fp);
}
}
} else {
tcc_open_bf(s1, str, 0);
file->fd = fd;
@ -845,7 +846,12 @@ static int tcc_compile(TCCState *s1, int filetype, const char *str, int fd)
LIBTCCAPI int tcc_compile_string(TCCState *s, const char *str)
{
return tcc_compile(s, s->filetype, str, -1);
return tcc_compile(s, s->filetype, str, -1, NULL);
}
LIBTCCAPI int tcc_compile_string_file(TCCState *s, const char *str, const char *filename)
{
return tcc_compile(s, s->filetype, str, -1, filename);
}
/* define a preprocessor symbol. value can be NULL, sym can be "sym=val" */
@ -896,8 +902,8 @@ LIBTCCAPI TCCState *tcc_new(void)
#if defined TCC_TARGET_MACHO /* || defined TCC_TARGET_PE */
s->leading_underscore = 1;
#endif
#ifdef TCC_ARM_HARDFLOAT
s->float_abi = ARM_HARD_FLOAT;
#ifdef TCC_TARGET_ARM
s->float_abi = ARM_FLOAT_ABI;
#endif
#ifdef CONFIG_NEW_DTAGS
s->enable_new_dtags = 1;
@ -995,19 +1001,17 @@ LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type)
/* allow linking with system dll's directly */
tcc_add_systemdir(s);
# endif
#elif defined TCC_TARGET_MACHO
# ifdef TCC_IS_NATIVE
tcc_add_macos_sdkpath(s);
# endif
#else
/* paths for crt objects */
tcc_split_path(s, &s->crt_paths, &s->nb_crt_paths, CONFIG_TCC_CRTPREFIX);
if (output_type != TCC_OUTPUT_MEMORY && !s->nostdlib)
tccelf_add_crtbegin(s); /* may produce errors */
tccelf_add_crtbegin(s);
#endif
return s->nb_errors ? -1 : 0;
return 0;
}
LIBTCCAPI int tcc_add_include_path(TCCState *s, const char *pathname)
@ -1242,7 +1246,7 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
return tcc_add_binary(s1, flags, filename, fd);
dynarray_add(&s1->target_deps, &s1->nb_target_deps, tcc_strdup(filename));
return tcc_compile(s1, flags, filename, fd);
return tcc_compile(s1, flags, filename, fd, NULL);
}
LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename)
@ -1364,11 +1368,10 @@ struct lopt {
/* match linker option */
static int link_option(struct lopt *o, const char *q)
{
const char *p;
const char *p = o->opt;
int c;
redo:
/* there should be 1 or 2 dashes */
p = o->opt;
if (*p++ != '-')
return 0;
if (*p == '-')
@ -1381,22 +1384,16 @@ redo:
goto succ; /* -Wl,-opt=arg */
++q;
}
if (*p == '\0') {
if (c == '|')
goto succ;
if (c == '=' || c == ':') {
if (c == '=' || c == ':') {
if (*p == '\0') {
if (o->s->link_optind + 1 < o->s->link_argc) {
p = o->s->link_argv[++o->s->link_optind];
goto succ; /* -Wl,-opt,arg */
}
o->match = 1; /* -Wl,-opt -Wl,arg */
return 0;
}
} else if (c == ':')
goto succ; /* -Wl,-Iarg */
while (*q)
if (*q++ == '|')
goto redo;
} else if (c == ':')
goto succ; /* -Wl,-Iarg */
}
return 0;
succ:
o->arg = p;
@ -1406,20 +1403,6 @@ succ:
static void args_parser_add_file(TCCState *s, const char* filename, int filetype);
#ifdef TCC_TARGET_PE
static void tcc_pe_set_dll_characteristics(TCCState *s, unsigned flags)
{
s->pe_dll_characteristics |= flags;
s->pe_dll_characteristics_clear &= ~flags;
}
static void tcc_pe_clear_dll_characteristics(TCCState *s, unsigned flags)
{
s->pe_dll_characteristics &= ~flags;
s->pe_dll_characteristics_clear |= flags;
}
#endif
/* set linker options */
static int tcc_set_linker(TCCState *s, const char *optarg)
{
@ -1438,9 +1421,9 @@ static int tcc_set_linker(TCCState *s, const char *optarg)
s->symbolic = 1;
} else if (link_option(&o, "nostdlib")) {
s->nostdlib_paths = 1;
} else if (link_option(&o, "e=|entry=")) {
} else if (link_option(&o, "e=") || link_option(&o, "entry=")) {
tcc_set_str(&s->elf_entryname, o.arg);
} else if (link_option(&o, "image-base=|Ttext=")) {
} else if (link_option(&o, "image-base=") || link_option(&o, "Ttext=")) {
s->text_addr = strtoull(o.arg, &end, 16);
s->has_text_addr = 1;
} else if (link_option(&o, "init=")) {
@ -1469,17 +1452,18 @@ static int tcc_set_linker(TCCState *s, const char *optarg)
#endif
else
goto err;
} else if (link_option(&o, "export-all-symbols|export-dynamic|E")) {
} else if (link_option(&o, "export-all-symbols")
|| link_option(&o, "export-dynamic")) {
s->rdynamic = 1;
} else if (link_option(&o, "rpath=")) {
tcc_concat_str(&s->rpath, o.arg, ':');
} else if (link_option(&o, "dynamic-linker=|I:")) {
} else if (link_option(&o, "dynamic-linker=") || link_option(&o, "I:")) {
tcc_set_str(&s->elfint, o.arg);
} else if (link_option(&o, "enable-new-dtags")) {
s->enable_new_dtags = 1;
} else if (link_option(&o, "section-alignment=")) {
s->section_align = strtoul(o.arg, &end, 16);
} else if (link_option(&o, "soname=|install_name=")) {
} else if (link_option(&o, "soname=") || link_option(&o, "install_name=")) {
tcc_set_str(&s->soname, o.arg);
} else if (link_option(&o, "whole-archive")) {
s->filetype |= AFF_WHOLE_ARCHIVE;
@ -1489,31 +1473,7 @@ static int tcc_set_linker(TCCState *s, const char *optarg)
s->znodelete = 1;
#ifdef TCC_TARGET_PE
} else if (link_option(&o, "large-address-aware")) {
s->pe_characteristics |= PE_IMAGE_FILE_LARGE_ADDRESS_AWARE;
} else if (link_option(&o, "dynamicbase")) {
tcc_pe_set_dll_characteristics(s, PE_DLLCHARACTERISTICS_DYNAMIC_BASE);
} else if (link_option(&o, "disable-dynamicbase|no-dynamicbase")) {
tcc_pe_clear_dll_characteristics(s,
PE_DLLCHARACTERISTICS_DYNAMIC_BASE |
PE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA);
} else if (link_option(&o, "nxcompat")) {
tcc_pe_set_dll_characteristics(s, PE_DLLCHARACTERISTICS_NX_COMPAT);
} else if (link_option(&o, "disable-nxcompat|no-nxcompat")) {
tcc_pe_clear_dll_characteristics(s, PE_DLLCHARACTERISTICS_NX_COMPAT);
} else if (link_option(&o, "high-entropy-va")) {
# if defined(TCC_TARGET_X86_64) || defined(TCC_TARGET_ARM64)
tcc_pe_set_dll_characteristics(s,
PE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA |
PE_DLLCHARACTERISTICS_DYNAMIC_BASE);
# else
goto err;
# endif
} else if (link_option(&o, "disable-high-entropy-va|no-high-entropy-va")) {
tcc_pe_clear_dll_characteristics(s, PE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA);
} else if (link_option(&o, "tsaware")) {
tcc_pe_set_dll_characteristics(s, PE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE);
} else if (link_option(&o, "disable-tsaware|no-tsaware")) {
tcc_pe_clear_dll_characteristics(s, PE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE);
s->pe_characteristics |= 0x20;
} else if (link_option(&o, "file-alignment=")) {
s->pe_file_align = strtoul(o.arg, &end, 16);
} else if (link_option(&o, "stack=")) {
@ -1625,6 +1585,30 @@ enum {
#define TCC_OPTION_HAS_ARG 0x0001
#define TCC_OPTION_NOSEP 0x0002 /* cannot have space before option and arg */
/*
* in tcc_options, if opt-string A is a prefix of opt-string B,
* it's un-ambiguous if and only if option A is without TCC_OPTION_HAS_ARG.
* otherwise (A with HAS_ARG), if, for instance, A is FOO and B is FOOBAR,
* then "-FOOBAR" is either A with arg BAR, or B (-FOOBARX too, if B HAS_ARG).
*
* tcc_parse_args searches tcc_options in order, so if ambiguous:
* - if the shorter (A) is earlier: the longer (B) is completely unreachable.
* - else B wins, and A can't be used with adjacent arg if it also matches B.
*
* there are few clashes currently, and the longer is always earlier/reachable.
* when it's ambiguous, shorter-concat-arg is not useful currently.
* the sh(1) script 'optclash' can identifiy clashes (tcc root dir, try "-h").
* at the time of writing, running './optclash' prints this:
-Wl,... (1642) overrides -W... (1644)
-Wp,... (1643) overrides -W... (1644)
-dumpmachine (1630) overrides -d... (1632)
-dumpversion (1631) overrides -d... (1632)
-dynamiclib (1623) overrides -d... (1632)
-flat_namespace (1624) overrides -f... (1650)
-mfloat-abi... (1647) overrides -m... (1649)
*/
static const TCCOption tcc_options[] = {
{ "h", TCC_OPTION_HELP, 0 },
{ "-help", TCC_OPTION_HELP, 0 },
@ -1864,6 +1848,27 @@ static void args_parser_add_file(TCCState *s, const char* filename, int filetype
++s->nb_libraries;
}
/* parsing is between getopt(3) and getopt_long(3), and permuting-like:
* - an option is 1 or more chars.
* - at most 1 option per arg in argv.
* - an option in argv is "-OPT[...]" (few are --OPT, if OPT is "-...").
* - optarg is next arg, or adjacent non-empty (no '='. -std=.. is arg "=..").
* - supports also adjacent-only optarg (typically optional).
* - supports mixed options and operands ("--" is ignored, except with -run).
* - -OPT[...] can be ambiguous, which is resolved using tcc_options's order.
* (see tcc_options for details)
*
* specifically, per arg of argv, in order:
* - if arg begins with '@' and is not exactly "@": process as @listfile.
* - elif arg is exactly "-" or doesn't begin with '-': process as input file.
* - if -run... is already set: also stop, arg... become argv of run_main.
* - elif arg is "--":
* - if -run... is already set: stop, arg... become argv of run_main.
* - else ignore it.
* - else ("-STRING") try to apply it as option, maybe with next (opt)arg.
*
* after all args, if -run... but no "stop": run_main gets our argv (tcc ...)
*/
/* using * to argc/argv to let "tcc -ar" benefit from @listfile expansion */
PUB_FUNC int tcc_parse_args(TCCState *s, int *pargc, char ***pargv)
{
@ -2070,7 +2075,7 @@ PUB_FUNC int tcc_parse_args(TCCState *s, int *pargc, char ***pargv)
s->float_abi = ARM_HARD_FLOAT;
else
return tcc_error_noabort("unsupported float abi '%s'", optarg);
continue;
break;
#endif
case TCC_OPTION_m:
if (set_flag(s, options_m, optarg) < 0) {
@ -2212,7 +2217,7 @@ unsupported_option:
if (run) {
if (*run && tcc_set_options(s, run) < 0)
return -1;
x = 0, r = 0;
x = 0;
goto extra_action;
}
if (!empty)

View File

@ -105,6 +105,18 @@ LIBTCCAPI void tcc_list_symbols(TCCState *s, void *ctx,
LIBTCCAPI void *_tcc_setjmp(TCCState *s1, void *jmp_buf, void *top_func, void *longjmp);
#define tcc_setjmp(s1,jb,f) setjmp(_tcc_setjmp(s1, jb, f, longjmp))
/* debugging */
/* For debugging to work you have to enable it with tcc_set_options */
/* compile a string containing a C source. Return -1 if error.
Write the string to file filename if debug is set. */
LIBTCCAPI int tcc_compile_string_file(TCCState *s, const char *buf, const char *filename);
/* Output object file. This must be done after tcc_relocate.
It only generates the file if debug is set.
The filename can be loaded with gdb command add-symbol-file */
LIBTCCAPI int elf_output_obj(TCCState *s1, const char *filename);
/* custom error printer for runtime exceptions. Returning 0 stops backtrace */
typedef int TCCBtFunc(void *udata, void *pc, const char *file, int line, const char* func, const char *msg);
LIBTCCAPI void tcc_set_backtrace_func(TCCState *s1, void* userdata, TCCBtFunc*);

38
optclash Executable file
View File

@ -0,0 +1,38 @@
#!/bin/sh
export LC_ALL=C
defname=libtcc.c
# $1 is the line number, $2... is the actual source line
extract_opts() { awk '/tcc_options\[\]/ {x=1}; x; x && $2~/^}/ {exit}'; }
case $1 in -h|--help)
echo "Usage: $0 [INFILE]"
echo "Detect tcc_options[] clashes in $defname-like INFILE."
echo "If INFILE is missing, use $defname at the same dir as this script."
echo "Clashes are reported as longer-overrides, or longer-unreachable."
exit
esac
f=${1-$(dirname "$0")/$defname}
[ -r "$f" ] || { >&2 echo "$0: can't read -- $f"; exit 1; }
nl -b a <"$f" | extract_opts | tr \" ' ' | awk '$2=="{"' | sort -b -k 3 |
# "<line-num> { <unquoted-opt> <rest-of-line>" sorted-up by opt
# unavoidable O(N^2). the sort simplifies the awk code - only test prior opts.
awk '
{
n=$1; opt=$3; h=/HAS_ARG/
for (pn in prevs) { # pn: line-num
po = prevs[pn] # po: opt-with-has-arg
if (index(opt,po) == 1) {
clash=1
printf("-%s%s (%d) %s -%s... (%s)\n", opt,h?"...":"",n,
n>pn? "is not reachable! by":"overrides", po,pn)
}
}
}
h {prevs[n] = opt}
END {if (clash) exit 1; print "no clashes"}
'

View File

@ -247,9 +247,11 @@ static void parse_branch_offset_operand(TCCState *s1, Operand *op){
if ((int) op->e.v >= -0x1000 && (int) op->e.v < 0x1000)
op->type = OP_IM12S;
} else if (op->e.sym->type.t & (VT_EXTERN | VT_STATIC)) {
/* For extern/static symbols, always use far-branch expansion
since linker relaxation (R_RISCV_RELAX) is not implemented. */
op->type = OP_IM32;
greloca(cur_text_section, op->e.sym, ind, R_RISCV_BRANCH, 0);
/* XXX: Implement far branches */
op->type = OP_IM12S;
op->e.v = 0;
} else {
expect("operand");
@ -676,37 +678,15 @@ static void asm_binary_opcode(TCCState* s1, int token)
asm_emit_i(token, (0x4 << 2) | 3 | (4 << 12), &ops[0], &ops[1], &imm);
return;
case TOK_ASM_neg:
/* sub rd, x0, rs2 */
asm_emit_r(token, (0xC << 2) | 3 | (32 << 25), &ops[0], &zero, &ops[1]);
/* sub rd, x0, rs */
imm.e.v = 1;
asm_emit_i(token, (0x4 << 2) | 3 | (4 << 12), &ops[0], &zero, &imm);
return;
case TOK_ASM_negw:
/* subw rd, x0, rs2 */
asm_emit_r(token, (0xE << 2) | 3 | (32 << 25), &ops[0], &zero, &ops[1]);
/* sub rd, x0, rs */
imm.e.v = 1;
asm_emit_i(token, (0x4 << 2) | 3 | (4 << 12), &ops[0], &zero, &imm);
return;
case TOK_ASM_sext_w:
/* addiw rd, rs, 0 */
asm_emit_i(token, 0x1b, &ops[0], &ops[1], &zimm);
return;
case TOK_ASM_fneg_s:
/* fsgnjn.s rd, rs, rs */
asm_emit_f(token, 0x53 | (1 << 12) | (0 << 25) | (4 << 27), &ops[0], &ops[1], &ops[1]);
return;
case TOK_ASM_fneg_d:
/* fsgnjn.d rd, rs, rs */
asm_emit_f(token, 0x53 | (1 << 12) | (1 << 25) | (4 << 27), &ops[0], &ops[1], &ops[1]);
return;
case TOK_ASM_fmv_s:
/* fsgnj.s rd, rs, rs */
asm_emit_f(token, 0x53 | (0 << 12) | (0 << 25) | (4 << 27), &ops[0], &ops[1], &ops[1]);
return;
case TOK_ASM_fmv_d:
/* fsgnj.d rd, rs, rs */
asm_emit_f(token, 0x53 | (0 << 12) | (1 << 25) | (4 << 27), &ops[0], &ops[1], &ops[1]);
return;
/* FCVT instructions now handled by asm_fcvt_opcode() with
optional rounding mode operand (GNU as syntax:
fcvt.w.s rd, rs1 [, rtz/rne/...) */
case TOK_ASM_jump:
/* auipc x5, 0 */
asm_emit_opcode(3 | (5 << 2) | ENCODE_RD(5));
@ -742,15 +722,6 @@ static void asm_binary_opcode(TCCState* s1, int token)
asm_emit_f(token, 0x53 | (4 << 27) | (0 << 25) | (2 << 12), &ops[0], &ops[1], &ops[1]);
return;
/* CSR pseudo-instructions */
case TOK_ASM_csrr:
/* csrrs rd, csr, x0 */
asm_emit_opcode(0x73 | (2 << 12) | (ops[1].e.v << 20) | ENCODE_RD(ops[0].reg));
return;
case TOK_ASM_csrw:
/* csrrw x0, csr, rs */
asm_emit_opcode(0x73 | (1 << 12) | (ops[0].e.v << 20) | ENCODE_RS1(ops[1].reg));
return;
case TOK_ASM_csrs:
/* csrrs x0, csr, rs */
asm_emit_opcode(0x73 | (2 << 12) | (ops[0].e.v << 20) | ENCODE_RS1(ops[1].reg));
@ -767,18 +738,6 @@ static void asm_binary_opcode(TCCState* s1, int token)
/* csrrw rd, fcsr, rs */
asm_emit_opcode(0x73 | (1 << 12) | (3 << 20) | ENCODE_RD(ops[0].reg) | ENCODE_RS1(ops[1].reg));
return;
case TOK_ASM_csrwi:
/* csrrwi x0, csr, uimm */
asm_emit_opcode(0x73 | (5 << 12) | (ops[0].e.v << 20) | ENCODE_RS1(ops[1].e.v));
return;
case TOK_ASM_csrsi:
/* csrrsi x0, csr, uimm */
asm_emit_opcode(0x73 | (6 << 12) | (ops[0].e.v << 20) | ENCODE_RS1(ops[1].e.v));
return;
case TOK_ASM_csrci:
/* csrrci x0, csr, uimm */
asm_emit_opcode(0x73 | (7 << 12) | (ops[0].e.v << 20) | ENCODE_RS1(ops[1].e.v));
return;
default:
expect("binary instruction");
}
@ -1254,30 +1213,6 @@ static void asm_ternary_opcode(TCCState *s1, int token)
return;
/* F/D extension */
case TOK_ASM_fadd_d:
asm_emit_f(token, 0x53 | (0 << 27) | (1 << 25) | (7 << 12), ops, ops + 1, ops + 2);
return;
case TOK_ASM_fadd_s:
asm_emit_f(token, 0x53 | (0 << 27) | (0 << 25) | (7 << 12), ops, ops + 1, ops + 2);
return;
case TOK_ASM_fsub_d:
asm_emit_f(token, 0x53 | (1 << 27) | (1 << 25) | (7 << 12), ops, ops + 1, ops + 2);
return;
case TOK_ASM_fsub_s:
asm_emit_f(token, 0x53 | (1 << 27) | (0 << 25) | (7 << 12), ops, ops + 1, ops + 2);
return;
case TOK_ASM_fmul_d:
asm_emit_f(token, 0x53 | (2 << 27) | (1 << 25) | (7 << 12), ops, ops + 1, ops + 2);
return;
case TOK_ASM_fmul_s:
asm_emit_f(token, 0x53 | (2 << 27) | (0 << 25) | (7 << 12), ops, ops + 1, ops + 2);
return;
case TOK_ASM_fdiv_d:
asm_emit_f(token, 0x53 | (3 << 27) | (1 << 25) | (7 << 12), ops, ops + 1, ops + 2);
return;
case TOK_ASM_fdiv_s:
asm_emit_f(token, 0x53 | (3 << 27) | (0 << 25) | (7 << 12), ops, ops + 1, ops + 2);
return;
case TOK_ASM_fsgnj_d:
asm_emit_f(token, 0x53 | (4 << 27) | (1 << 25) | (0 << 12), ops, ops + 1, ops + 2);
return;
@ -1297,26 +1232,6 @@ static void asm_ternary_opcode(TCCState *s1, int token)
asm_emit_f(token, 0x53 | (5 << 27) | (0 << 25) | (0 << 12), ops, ops + 1, ops + 2);
return;
/* F/D comparison: produce integer result, encode manually */
case TOK_ASM_feq_s:
asm_emit_opcode(0x53 | (0x14 << 27) | (0 << 25) | (2 << 12) | ENCODE_RD(ops[0].reg) | ENCODE_RS1(ops[1].reg) | ENCODE_RS2(ops[2].reg));
return;
case TOK_ASM_feq_d:
asm_emit_opcode(0x53 | (0x14 << 27) | (1 << 25) | (2 << 12) | ENCODE_RD(ops[0].reg) | ENCODE_RS1(ops[1].reg) | ENCODE_RS2(ops[2].reg));
return;
case TOK_ASM_flt_s:
asm_emit_opcode(0x53 | (0x14 << 27) | (0 << 25) | (1 << 12) | ENCODE_RD(ops[0].reg) | ENCODE_RS1(ops[1].reg) | ENCODE_RS2(ops[2].reg));
return;
case TOK_ASM_flt_d:
asm_emit_opcode(0x53 | (0x14 << 27) | (1 << 25) | (1 << 12) | ENCODE_RD(ops[0].reg) | ENCODE_RS1(ops[1].reg) | ENCODE_RS2(ops[2].reg));
return;
case TOK_ASM_fle_s:
asm_emit_opcode(0x53 | (0x14 << 27) | (0 << 25) | (0 << 12) | ENCODE_RD(ops[0].reg) | ENCODE_RS1(ops[1].reg) | ENCODE_RS2(ops[2].reg));
return;
case TOK_ASM_fle_d:
asm_emit_opcode(0x53 | (0x14 << 27) | (1 << 25) | (0 << 12) | ENCODE_RD(ops[0].reg) | ENCODE_RS1(ops[1].reg) | ENCODE_RS2(ops[2].reg));
return;
default:
expect("ternary instruction");
}
@ -1360,205 +1275,56 @@ static void asm_atomic_opcode(TCCState *s1, int token)
switch(token){
case TOK_ASM_lr_w:
asm_emit_a(token, 0x2F | 0x2<<12 | 0xC<<27, &ops[0], &ops[1], &ops[2], 0, 0);
asm_emit_a(token, 0x2F | 0x2<<12 | 0x2<<27, &ops[0], &ops[1], &ops[2], 0, 0);
break;
case TOK_ASM_lr_w_aq:
asm_emit_a(token, 0x2F | 0x2<<12 | 0xC<<27, &ops[0], &ops[1], &ops[2], 1, 0);
asm_emit_a(token, 0x2F | 0x2<<12 | 0x2<<27, &ops[0], &ops[1], &ops[2], 1, 0);
break;
case TOK_ASM_lr_w_rl:
asm_emit_a(token, 0x2F | 0x2<<12 | 0xC<<27, &ops[0], &ops[1], &ops[2], 0, 1);
asm_emit_a(token, 0x2F | 0x2<<12 | 0x2<<27, &ops[0], &ops[1], &ops[2], 0, 1);
break;
case TOK_ASM_lr_w_aqrl:
asm_emit_a(token, 0x2F | 0x2<<12 | 0xC<<27, &ops[0], &ops[1], &ops[2], 1, 1);
asm_emit_a(token, 0x2F | 0x2<<12 | 0x2<<27, &ops[0], &ops[1], &ops[2], 1, 1);
break;
case TOK_ASM_lr_d:
asm_emit_a(token, 0x2F | 0x3<<12 | 0xC<<27, &ops[0], &ops[1], &ops[2], 0, 0);
asm_emit_a(token, 0x2F | 0x3<<12 | 0x2<<27, &ops[0], &ops[1], &ops[2], 0, 0);
break;
case TOK_ASM_lr_d_aq:
asm_emit_a(token, 0x2F | 0x3<<12 | 0xC<<27, &ops[0], &ops[1], &ops[2], 1, 0);
asm_emit_a(token, 0x2F | 0x3<<12 | 0x2<<27, &ops[0], &ops[1], &ops[2], 1, 0);
break;
case TOK_ASM_lr_d_rl:
asm_emit_a(token, 0x2F | 0x3<<12 | 0xC<<27, &ops[0], &ops[1], &ops[2], 0, 1);
asm_emit_a(token, 0x2F | 0x3<<12 | 0x2<<27, &ops[0], &ops[1], &ops[2], 0, 1);
break;
case TOK_ASM_lr_d_aqrl:
asm_emit_a(token, 0x2F | 0x3<<12 | 0xC<<27, &ops[0], &ops[1], &ops[2], 1, 1);
asm_emit_a(token, 0x2F | 0x3<<12 | 0x2<<27, &ops[0], &ops[1], &ops[2], 1, 1);
break;
case TOK_ASM_sc_w:
asm_emit_a(token, 0x2F | 0x2<<12 | 0x18<<27, &ops[0], &ops[1], &ops[2], 0, 0);
asm_emit_a(token, 0x2F | 0x2<<12 | 0x3<<27, &ops[0], &ops[1], &ops[2], 0, 0);
break;
case TOK_ASM_sc_w_aq:
asm_emit_a(token, 0x2F | 0x2<<12 | 0x18<<27, &ops[0], &ops[1], &ops[2], 1, 0);
asm_emit_a(token, 0x2F | 0x2<<12 | 0x3<<27, &ops[0], &ops[1], &ops[2], 1, 0);
break;
case TOK_ASM_sc_w_rl:
asm_emit_a(token, 0x2F | 0x2<<12 | 0x18<<27, &ops[0], &ops[1], &ops[2], 0, 1);
asm_emit_a(token, 0x2F | 0x2<<12 | 0x3<<27, &ops[0], &ops[1], &ops[2], 0, 1);
break;
case TOK_ASM_sc_w_aqrl:
asm_emit_a(token, 0x2F | 0x2<<12 | 0x18<<27, &ops[0], &ops[1], &ops[2], 1, 1);
asm_emit_a(token, 0x2F | 0x2<<12 | 0x3<<27, &ops[0], &ops[1], &ops[2], 1, 1);
break;
case TOK_ASM_sc_d:
asm_emit_a(token, 0x2F | 0x3<<12 | 0x18<<27, &ops[0], &ops[1], &ops[2], 0, 0);
asm_emit_a(token, 0x2F | 0x3<<12 | 0x3<<27, &ops[0], &ops[1], &ops[2], 0, 0);
break;
case TOK_ASM_sc_d_aq:
asm_emit_a(token, 0x2F | 0x3<<12 | 0x18<<27, &ops[0], &ops[1], &ops[2], 1, 0);
asm_emit_a(token, 0x2F | 0x3<<12 | 0x3<<27, &ops[0], &ops[1], &ops[2], 1, 0);
break;
case TOK_ASM_sc_d_rl:
asm_emit_a(token, 0x2F | 0x3<<12 | 0x18<<27, &ops[0], &ops[1], &ops[2], 0, 1);
asm_emit_a(token, 0x2F | 0x3<<12 | 0x3<<27, &ops[0], &ops[1], &ops[2], 0, 1);
break;
case TOK_ASM_sc_d_aqrl:
asm_emit_a(token, 0x2F | 0x3<<12 | 0x18<<27, &ops[0], &ops[1], &ops[2], 1, 1);
asm_emit_a(token, 0x2F | 0x3<<12 | 0x3<<27, &ops[0], &ops[1], &ops[2], 1, 1);
break;
/* AMO instructions (base, aq=0 rl=0) */
case TOK_ASM_amoadd_w:
asm_emit_a(token, 0x2F | 0x2<<12 | 0x0<<27, &ops[0], &ops[1], &ops[2], 0, 0); break;
case TOK_ASM_amoadd_d:
asm_emit_a(token, 0x2F | 0x3<<12 | 0x0<<27, &ops[0], &ops[1], &ops[2], 0, 0); break;
case TOK_ASM_amoswap_w:
asm_emit_a(token, 0x2F | 0x2<<12 | 0x1<<27, &ops[0], &ops[1], &ops[2], 0, 0); break;
case TOK_ASM_amoswap_d:
asm_emit_a(token, 0x2F | 0x3<<12 | 0x1<<27, &ops[0], &ops[1], &ops[2], 0, 0); break;
case TOK_ASM_amoand_w:
asm_emit_a(token, 0x2F | 0x2<<12 | 0xC<<27, &ops[0], &ops[1], &ops[2], 0, 0); break;
case TOK_ASM_amoand_d:
asm_emit_a(token, 0x2F | 0x3<<12 | 0xC<<27, &ops[0], &ops[1], &ops[2], 0, 0); break;
case TOK_ASM_amoor_w:
asm_emit_a(token, 0x2F | 0x2<<12 | 0x18<<27, &ops[0], &ops[1], &ops[2], 0, 0); break;
case TOK_ASM_amoor_d:
asm_emit_a(token, 0x2F | 0x3<<12 | 0x18<<27, &ops[0], &ops[1], &ops[2], 0, 0); break;
case TOK_ASM_amoxor_w:
asm_emit_a(token, 0x2F | 0x2<<12 | 0x4<<27, &ops[0], &ops[1], &ops[2], 0, 0); break;
case TOK_ASM_amoxor_d:
asm_emit_a(token, 0x2F | 0x3<<12 | 0x4<<27, &ops[0], &ops[1], &ops[2], 0, 0); break;
case TOK_ASM_amomax_w:
asm_emit_a(token, 0x2F | 0x2<<12 | 0x14<<27, &ops[0], &ops[1], &ops[2], 0, 0); break;
case TOK_ASM_amomax_d:
asm_emit_a(token, 0x2F | 0x3<<12 | 0x14<<27, &ops[0], &ops[1], &ops[2], 0, 0); break;
case TOK_ASM_amomaxu_w:
asm_emit_a(token, 0x2F | 0x2<<12 | 0x1C<<27, &ops[0], &ops[1], &ops[2], 0, 0); break;
case TOK_ASM_amomaxu_d:
asm_emit_a(token, 0x2F | 0x3<<12 | 0x1C<<27, &ops[0], &ops[1], &ops[2], 0, 0); break;
case TOK_ASM_amomin_w:
asm_emit_a(token, 0x2F | 0x2<<12 | 0x10<<27, &ops[0], &ops[1], &ops[2], 0, 0); break;
case TOK_ASM_amomin_d:
asm_emit_a(token, 0x2F | 0x3<<12 | 0x10<<27, &ops[0], &ops[1], &ops[2], 0, 0); break;
case TOK_ASM_amominu_w:
asm_emit_a(token, 0x2F | 0x2<<12 | 0x18<<27, &ops[0], &ops[1], &ops[2], 0, 0); break;
case TOK_ASM_amominu_d:
asm_emit_a(token, 0x2F | 0x3<<12 | 0x18<<27, &ops[0], &ops[1], &ops[2], 0, 0); break;
/* AMO aq/rl variants */
case TOK_ASM_amoadd_w_aq:
asm_emit_a(token, 0x2F | 0x2<<12 | 0x0<<27, &ops[0], &ops[1], &ops[2], 1, 0); break;
case TOK_ASM_amoadd_w_rl:
asm_emit_a(token, 0x2F | 0x2<<12 | 0x0<<27, &ops[0], &ops[1], &ops[2], 0, 1); break;
case TOK_ASM_amoadd_w_aqrl:
asm_emit_a(token, 0x2F | 0x2<<12 | 0x0<<27, &ops[0], &ops[1], &ops[2], 1, 1); break;
case TOK_ASM_amoadd_d_aq:
asm_emit_a(token, 0x2F | 0x3<<12 | 0x0<<27, &ops[0], &ops[1], &ops[2], 1, 0); break;
case TOK_ASM_amoadd_d_rl:
asm_emit_a(token, 0x2F | 0x3<<12 | 0x0<<27, &ops[0], &ops[1], &ops[2], 0, 1); break;
case TOK_ASM_amoadd_d_aqrl:
asm_emit_a(token, 0x2F | 0x3<<12 | 0x0<<27, &ops[0], &ops[1], &ops[2], 1, 1); break;
case TOK_ASM_amoswap_w_aq:
asm_emit_a(token, 0x2F | 2<<12 | 0x1<<27, &ops[0], &ops[1], &ops[2], 1, 0); break;
case TOK_ASM_amoswap_w_rl:
asm_emit_a(token, 0x2F | 2<<12 | 0x1<<27, &ops[0], &ops[1], &ops[2], 0, 1); break;
case TOK_ASM_amoswap_w_aqrl:
asm_emit_a(token, 0x2F | 2<<12 | 0x1<<27, &ops[0], &ops[1], &ops[2], 1, 1); break;
case TOK_ASM_amoswap_d_aq:
asm_emit_a(token, 0x2F | 3<<12 | 0x1<<27, &ops[0], &ops[1], &ops[2], 1, 0); break;
case TOK_ASM_amoswap_d_rl:
asm_emit_a(token, 0x2F | 3<<12 | 0x1<<27, &ops[0], &ops[1], &ops[2], 0, 1); break;
case TOK_ASM_amoswap_d_aqrl:
asm_emit_a(token, 0x2F | 3<<12 | 0x1<<27, &ops[0], &ops[1], &ops[2], 1, 1); break;
case TOK_ASM_amoand_w_aq:
asm_emit_a(token, 0x2F | 2<<12 | 0xc<<27, &ops[0], &ops[1], &ops[2], 1, 0); break;
case TOK_ASM_amoand_w_rl:
asm_emit_a(token, 0x2F | 2<<12 | 0xc<<27, &ops[0], &ops[1], &ops[2], 0, 1); break;
case TOK_ASM_amoand_w_aqrl:
asm_emit_a(token, 0x2F | 2<<12 | 0xc<<27, &ops[0], &ops[1], &ops[2], 1, 1); break;
case TOK_ASM_amoand_d_aq:
asm_emit_a(token, 0x2F | 3<<12 | 0xc<<27, &ops[0], &ops[1], &ops[2], 1, 0); break;
case TOK_ASM_amoand_d_rl:
asm_emit_a(token, 0x2F | 3<<12 | 0xc<<27, &ops[0], &ops[1], &ops[2], 0, 1); break;
case TOK_ASM_amoand_d_aqrl:
asm_emit_a(token, 0x2F | 3<<12 | 0xc<<27, &ops[0], &ops[1], &ops[2], 1, 1); break;
case TOK_ASM_amoor_w_aq:
asm_emit_a(token, 0x2F | 2<<12 | 0x8<<27, &ops[0], &ops[1], &ops[2], 1, 0); break;
case TOK_ASM_amoor_w_rl:
asm_emit_a(token, 0x2F | 2<<12 | 0x8<<27, &ops[0], &ops[1], &ops[2], 0, 1); break;
case TOK_ASM_amoor_w_aqrl:
asm_emit_a(token, 0x2F | 2<<12 | 0x8<<27, &ops[0], &ops[1], &ops[2], 1, 1); break;
case TOK_ASM_amoor_d_aq:
asm_emit_a(token, 0x2F | 3<<12 | 0x8<<27, &ops[0], &ops[1], &ops[2], 1, 0); break;
case TOK_ASM_amoor_d_rl:
asm_emit_a(token, 0x2F | 3<<12 | 0x8<<27, &ops[0], &ops[1], &ops[2], 0, 1); break;
case TOK_ASM_amoor_d_aqrl:
asm_emit_a(token, 0x2F | 3<<12 | 0x8<<27, &ops[0], &ops[1], &ops[2], 1, 1); break;
case TOK_ASM_amoxor_w_aq:
asm_emit_a(token, 0x2F | 2<<12 | 0x4<<27, &ops[0], &ops[1], &ops[2], 1, 0); break;
case TOK_ASM_amoxor_w_rl:
asm_emit_a(token, 0x2F | 2<<12 | 0x4<<27, &ops[0], &ops[1], &ops[2], 0, 1); break;
case TOK_ASM_amoxor_w_aqrl:
asm_emit_a(token, 0x2F | 2<<12 | 0x4<<27, &ops[0], &ops[1], &ops[2], 1, 1); break;
case TOK_ASM_amoxor_d_aq:
asm_emit_a(token, 0x2F | 3<<12 | 0x4<<27, &ops[0], &ops[1], &ops[2], 1, 0); break;
case TOK_ASM_amoxor_d_rl:
asm_emit_a(token, 0x2F | 3<<12 | 0x4<<27, &ops[0], &ops[1], &ops[2], 0, 1); break;
case TOK_ASM_amoxor_d_aqrl:
asm_emit_a(token, 0x2F | 3<<12 | 0x4<<27, &ops[0], &ops[1], &ops[2], 1, 1); break;
case TOK_ASM_amomax_w_aq:
asm_emit_a(token, 0x2F | 2<<12 | 0x14<<27, &ops[0], &ops[1], &ops[2], 1, 0); break;
case TOK_ASM_amomax_w_rl:
asm_emit_a(token, 0x2F | 2<<12 | 0x14<<27, &ops[0], &ops[1], &ops[2], 0, 1); break;
case TOK_ASM_amomax_w_aqrl:
asm_emit_a(token, 0x2F | 2<<12 | 0x14<<27, &ops[0], &ops[1], &ops[2], 1, 1); break;
case TOK_ASM_amomax_d_aq:
asm_emit_a(token, 0x2F | 3<<12 | 0x14<<27, &ops[0], &ops[1], &ops[2], 1, 0); break;
case TOK_ASM_amomax_d_rl:
asm_emit_a(token, 0x2F | 3<<12 | 0x14<<27, &ops[0], &ops[1], &ops[2], 0, 1); break;
case TOK_ASM_amomax_d_aqrl:
asm_emit_a(token, 0x2F | 3<<12 | 0x14<<27, &ops[0], &ops[1], &ops[2], 1, 1); break;
case TOK_ASM_amomaxu_w_aq:
asm_emit_a(token, 0x2F | 2<<12 | 0x1c<<27, &ops[0], &ops[1], &ops[2], 1, 0); break;
case TOK_ASM_amomaxu_w_rl:
asm_emit_a(token, 0x2F | 2<<12 | 0x1c<<27, &ops[0], &ops[1], &ops[2], 0, 1); break;
case TOK_ASM_amomaxu_w_aqrl:
asm_emit_a(token, 0x2F | 2<<12 | 0x1c<<27, &ops[0], &ops[1], &ops[2], 1, 1); break;
case TOK_ASM_amomaxu_d_aq:
asm_emit_a(token, 0x2F | 3<<12 | 0x1c<<27, &ops[0], &ops[1], &ops[2], 1, 0); break;
case TOK_ASM_amomaxu_d_rl:
asm_emit_a(token, 0x2F | 3<<12 | 0x1c<<27, &ops[0], &ops[1], &ops[2], 0, 1); break;
case TOK_ASM_amomaxu_d_aqrl:
asm_emit_a(token, 0x2F | 3<<12 | 0x1c<<27, &ops[0], &ops[1], &ops[2], 1, 1); break;
case TOK_ASM_amomin_w_aq:
asm_emit_a(token, 0x2F | 2<<12 | 0x10<<27, &ops[0], &ops[1], &ops[2], 1, 0); break;
case TOK_ASM_amomin_w_rl:
asm_emit_a(token, 0x2F | 2<<12 | 0x10<<27, &ops[0], &ops[1], &ops[2], 0, 1); break;
case TOK_ASM_amomin_w_aqrl:
asm_emit_a(token, 0x2F | 2<<12 | 0x10<<27, &ops[0], &ops[1], &ops[2], 1, 1); break;
case TOK_ASM_amomin_d_aq:
asm_emit_a(token, 0x2F | 3<<12 | 0x10<<27, &ops[0], &ops[1], &ops[2], 1, 0); break;
case TOK_ASM_amomin_d_rl:
asm_emit_a(token, 0x2F | 3<<12 | 0x10<<27, &ops[0], &ops[1], &ops[2], 0, 1); break;
case TOK_ASM_amomin_d_aqrl:
asm_emit_a(token, 0x2F | 3<<12 | 0x10<<27, &ops[0], &ops[1], &ops[2], 1, 1); break;
case TOK_ASM_amominu_w_aq:
asm_emit_a(token, 0x2F | 2<<12 | 0x18<<27, &ops[0], &ops[1], &ops[2], 1, 0); break;
case TOK_ASM_amominu_w_rl:
asm_emit_a(token, 0x2F | 2<<12 | 0x18<<27, &ops[0], &ops[1], &ops[2], 0, 1); break;
case TOK_ASM_amominu_w_aqrl:
asm_emit_a(token, 0x2F | 2<<12 | 0x18<<27, &ops[0], &ops[1], &ops[2], 1, 1); break;
case TOK_ASM_amominu_d_aq:
asm_emit_a(token, 0x2F | 3<<12 | 0x18<<27, &ops[0], &ops[1], &ops[2], 1, 0); break;
case TOK_ASM_amominu_d_rl:
asm_emit_a(token, 0x2F | 3<<12 | 0x18<<27, &ops[0], &ops[1], &ops[2], 0, 1); break;
case TOK_ASM_amominu_d_aqrl:
asm_emit_a(token, 0x2F | 3<<12 | 0x18<<27, &ops[0], &ops[1], &ops[2], 1, 1); break;
}
}
@ -1620,26 +1386,6 @@ static void asm_emit_b(int token, uint32_t opcode, const Operand *rs1, const Ope
if (rs2->type != OP_REG) {
tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
}
if (imm->type == OP_IM32 && imm->e.sym) {
/* far branch: expand to inverted short branch + auipc + jalr */
int b_ofs = ind;
uint32_t inv_func3 = ((opcode >> 12) & 7) ^ 1;
uint32_t inv_opcode = (opcode & ~(7 << 12)) | (inv_func3 << 12);
/* b<inverse> .+8 */
asm_emit_opcode(inv_opcode | ENCODE_RS1(rs1->reg)
| ENCODE_RS2(rs2->reg) | (1 << 8));
/* auipc t0, 0 */
greloca(cur_text_section, imm->e.sym, ind, R_RISCV_CALL, 0);
asm_emit_opcode(0x17 | ENCODE_RD(5));
/* jalr x0, 0(t0) */
write32le(cur_text_section->data + b_ofs,
read32le(cur_text_section->data + b_ofs)
| (((ind - b_ofs) >> 1) & 0xf) << 8
| (((ind - b_ofs) >> 5) & 0x3f) << 25
| (((ind - b_ofs) >> 11) & 1) << 7
| (((ind - b_ofs) >> 12) & 1) << 31);
return;
}
if (imm->type != OP_IM12S) {
tcc_error("'%s': Expected second source operand that is an immediate value between 0 and 8191", get_tok_str(token, NULL));
}
@ -1658,62 +1404,6 @@ static void asm_emit_b(int token, uint32_t opcode, const Operand *rs1, const Ope
asm_emit_opcode(opcode | ENCODE_RS1(rs1->reg) | ENCODE_RS2(rs2->reg) | (((offset >> 1) & 0xF) << 8) | (((offset >> 5) & 0x1f) << 25) | (((offset >> 11) & 1) << 7) | (((offset >> 12) & 1) << 31));
}
/* FCVT helper: parse optional rounding mode operand (GNU as syntax:
fcvt.w.s rd, rs1 [, rtz/rne/rdn/rup/rmm]) */
static int asm_fcvt_rm(TCCState *s1)
{
int rm = 7; /* dynamic */
if (tok == ',') {
next();
switch (tok) {
case TOK_ASM_rne: rm = 0; next(); break;
case TOK_ASM_rtz: rm = 1; next(); break;
case TOK_ASM_rdn: rm = 2; next(); break;
case TOK_ASM_rup: rm = 3; next(); break;
case TOK_ASM_rmm: rm = 4; next(); break;
default: expect("rounding mode"); break;
}
}
return rm;
}
/* fcvt + fclass handler (all are binary with optional rounding operand) */
static void asm_fcvt_opcode(TCCState *s1, int token)
{
Operand ops[2];
int rm;
uint32_t enc = 0;
parse_operand(s1, &ops[0]);
skip(',');
parse_operand(s1, &ops[1]);
switch (token) {
case TOK_ASM_fcvt_w_s: rm = asm_fcvt_rm(s1); enc = 0x53 | (0x60 << 25) | (rm << 12); break;
case TOK_ASM_fcvt_wu_s: rm = asm_fcvt_rm(s1); enc = 0x53 | (0x60 << 25) | (rm << 12) | (1 << 20); break;
case TOK_ASM_fcvt_l_s: rm = asm_fcvt_rm(s1); enc = 0x53 | (0x60 << 25) | (rm << 12) | (2 << 20); break;
case TOK_ASM_fcvt_lu_s: rm = asm_fcvt_rm(s1); enc = 0x53 | (0x60 << 25) | (rm << 12) | (3 << 20); break;
case TOK_ASM_fcvt_s_w: enc = 0x53 | (0x68 << 25) | (7 << 12); break;
case TOK_ASM_fcvt_s_wu: enc = 0x53 | (0x68 << 25) | (7 << 12) | (1 << 20); break;
case TOK_ASM_fcvt_s_l: enc = 0x53 | (0x68 << 25) | (7 << 12) | (2 << 20); break;
case TOK_ASM_fcvt_s_lu: enc = 0x53 | (0x68 << 25) | (7 << 12) | (3 << 20); break;
case TOK_ASM_fcvt_w_d: rm = asm_fcvt_rm(s1); enc = 0x53 | (0x61 << 25) | (rm << 12); break;
case TOK_ASM_fcvt_wu_d: rm = asm_fcvt_rm(s1); enc = 0x53 | (0x61 << 25) | (rm << 12) | (1 << 20); break;
case TOK_ASM_fcvt_l_d: rm = asm_fcvt_rm(s1); enc = 0x53 | (0x61 << 25) | (rm << 12) | (2 << 20); break;
case TOK_ASM_fcvt_lu_d: rm = asm_fcvt_rm(s1); enc = 0x53 | (0x61 << 25) | (rm << 12) | (3 << 20); break;
case TOK_ASM_fcvt_d_w: enc = 0x53 | (0x69 << 25) | (7 << 12); break;
case TOK_ASM_fcvt_d_wu: enc = 0x53 | (0x69 << 25) | (7 << 12) | (1 << 20); break;
case TOK_ASM_fcvt_d_l: enc = 0x53 | (0x69 << 25) | (7 << 12) | (2 << 20); break;
case TOK_ASM_fcvt_d_lu: enc = 0x53 | (0x69 << 25) | (7 << 12) | (3 << 20); break;
case TOK_ASM_fcvt_s_d: enc = 0x53 | (0x20 << 25) | (7 << 12) | (1 << 20); break;
case TOK_ASM_fcvt_d_s: enc = 0x53 | (0x21 << 25) | (7 << 12); break;
case TOK_ASM_fclass_s: enc = 0x53 | (0x70 << 25) | (1 << 12); break;
case TOK_ASM_fclass_d: enc = 0x53 | (0x71 << 25) | (1 << 12); break;
default: expect("fcvt/fclass instruction"); return;
}
asm_emit_opcode(enc | ENCODE_RD(ops[0].reg) | ENCODE_RS1(ops[1].reg));
}
ST_FUNC void asm_opcode(TCCState *s1, int token)
{
switch (token) {
@ -1747,30 +1437,6 @@ ST_FUNC void asm_opcode(TCCState *s1, int token)
asm_binary_opcode(s1, token);
return;
/* fcvt/fclass — separate handler for optional rounding operand */
case TOK_ASM_fcvt_w_s:
case TOK_ASM_fcvt_wu_s:
case TOK_ASM_fcvt_l_s:
case TOK_ASM_fcvt_lu_s:
case TOK_ASM_fcvt_s_w:
case TOK_ASM_fcvt_s_wu:
case TOK_ASM_fcvt_s_l:
case TOK_ASM_fcvt_s_lu:
case TOK_ASM_fcvt_w_d:
case TOK_ASM_fcvt_wu_d:
case TOK_ASM_fcvt_l_d:
case TOK_ASM_fcvt_lu_d:
case TOK_ASM_fcvt_d_w:
case TOK_ASM_fcvt_d_wu:
case TOK_ASM_fcvt_d_l:
case TOK_ASM_fcvt_d_lu:
case TOK_ASM_fcvt_s_d:
case TOK_ASM_fcvt_d_s:
case TOK_ASM_fclass_s:
case TOK_ASM_fclass_d:
asm_fcvt_opcode(s1, token);
return;
case TOK_ASM_lb:
case TOK_ASM_lh:
case TOK_ASM_lw:
@ -1847,26 +1513,12 @@ ST_FUNC void asm_opcode(TCCState *s1, int token)
case TOK_ASM_csrrw:
case TOK_ASM_csrrwi:
/* F/D extension */
case TOK_ASM_fadd_s:
case TOK_ASM_fadd_d:
case TOK_ASM_fsub_s:
case TOK_ASM_fsub_d:
case TOK_ASM_fmul_s:
case TOK_ASM_fmul_d:
case TOK_ASM_fdiv_s:
case TOK_ASM_fdiv_d:
case TOK_ASM_fsgnj_d:
case TOK_ASM_fsgnj_s:
case TOK_ASM_fmax_s:
case TOK_ASM_fmax_d:
case TOK_ASM_fmin_s:
case TOK_ASM_fmin_d:
case TOK_ASM_feq_s:
case TOK_ASM_feq_d:
case TOK_ASM_flt_s:
case TOK_ASM_flt_d:
case TOK_ASM_fle_s:
case TOK_ASM_fle_d:
asm_ternary_opcode(s1, token);
return;
case TOK_ASM_fmadd_d:
@ -1966,20 +1618,10 @@ ST_FUNC void asm_opcode(TCCState *s1, int token)
case TOK_ASM_not:
case TOK_ASM_neg:
case TOK_ASM_negw:
case TOK_ASM_sext_w:
case TOK_ASM_fabs_s:
case TOK_ASM_fabs_d:
case TOK_ASM_fmv_s:
case TOK_ASM_fmv_d:
case TOK_ASM_fneg_s:
case TOK_ASM_fneg_d:
case TOK_ASM_csrc:
case TOK_ASM_csrs:
case TOK_ASM_csrr:
case TOK_ASM_csrw:
case TOK_ASM_csrwi:
case TOK_ASM_csrsi:
case TOK_ASM_csrci:
case TOK_ASM_fsrm:
case TOK_ASM_fscsr:
asm_binary_opcode(s1, token);
@ -2018,83 +1660,7 @@ ST_FUNC void asm_opcode(TCCState *s1, int token)
case TOK_ASM_sc_d_aq:
case TOK_ASM_sc_d_rl:
case TOK_ASM_sc_d_aqrl:
/* AMO instructions */
case TOK_ASM_amoadd_w:
case TOK_ASM_amoadd_d:
case TOK_ASM_amoswap_w:
case TOK_ASM_amoswap_d:
case TOK_ASM_amoand_w:
case TOK_ASM_amoand_d:
case TOK_ASM_amoor_w:
case TOK_ASM_amoor_d:
case TOK_ASM_amoxor_w:
case TOK_ASM_amoxor_d:
case TOK_ASM_amomax_w:
case TOK_ASM_amomax_d:
case TOK_ASM_amomaxu_w:
case TOK_ASM_amomaxu_d:
case TOK_ASM_amomin_w:
case TOK_ASM_amomin_d:
case TOK_ASM_amominu_w:
case TOK_ASM_amominu_d:
/* AMO aq/rl */
case TOK_ASM_amoadd_w_aq:
case TOK_ASM_amoadd_w_rl:
case TOK_ASM_amoadd_w_aqrl:
case TOK_ASM_amoadd_d_aq:
case TOK_ASM_amoadd_d_rl:
case TOK_ASM_amoadd_d_aqrl:
/* AMO aq/rl (all ops) */
case TOK_ASM_amoswap_w_aq:
case TOK_ASM_amoswap_w_rl:
case TOK_ASM_amoswap_w_aqrl:
case TOK_ASM_amoswap_d_aq:
case TOK_ASM_amoswap_d_rl:
case TOK_ASM_amoswap_d_aqrl:
case TOK_ASM_amoand_w_aq:
case TOK_ASM_amoand_w_rl:
case TOK_ASM_amoand_w_aqrl:
case TOK_ASM_amoand_d_aq:
case TOK_ASM_amoand_d_rl:
case TOK_ASM_amoand_d_aqrl:
case TOK_ASM_amoor_w_aq:
case TOK_ASM_amoor_w_rl:
case TOK_ASM_amoor_w_aqrl:
case TOK_ASM_amoor_d_aq:
case TOK_ASM_amoor_d_rl:
case TOK_ASM_amoor_d_aqrl:
case TOK_ASM_amoxor_w_aq:
case TOK_ASM_amoxor_w_rl:
case TOK_ASM_amoxor_w_aqrl:
case TOK_ASM_amoxor_d_aq:
case TOK_ASM_amoxor_d_rl:
case TOK_ASM_amoxor_d_aqrl:
case TOK_ASM_amomax_w_aq:
case TOK_ASM_amomax_w_rl:
case TOK_ASM_amomax_w_aqrl:
case TOK_ASM_amomax_d_aq:
case TOK_ASM_amomax_d_rl:
case TOK_ASM_amomax_d_aqrl:
case TOK_ASM_amomaxu_w_aq:
case TOK_ASM_amomaxu_w_rl:
case TOK_ASM_amomaxu_w_aqrl:
case TOK_ASM_amomaxu_d_aq:
case TOK_ASM_amomaxu_d_rl:
case TOK_ASM_amomaxu_d_aqrl:
case TOK_ASM_amomin_w_aq:
case TOK_ASM_amomin_w_rl:
case TOK_ASM_amomin_w_aqrl:
case TOK_ASM_amomin_d_aq:
case TOK_ASM_amomin_d_rl:
case TOK_ASM_amomin_d_aqrl:
case TOK_ASM_amominu_w_aq:
case TOK_ASM_amominu_w_rl:
case TOK_ASM_amominu_w_aqrl:
case TOK_ASM_amominu_d_aq:
case TOK_ASM_amominu_d_rl:
case TOK_ASM_amominu_d_aqrl:
asm_atomic_opcode(s1, token);
asm_atomic_opcode(s1, token);
break;
default:
@ -2273,8 +1839,9 @@ ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands,
} else {
load(tcc_ireg(op->reg), op->vt);
}
/* RV64: long long fits in a single 64-bit register;
the load/store above already handles it correctly */
if (op->is_llong) {
tcc_error("long long not implemented");
}
}
}
}
@ -2302,7 +1869,9 @@ ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands,
} else {
store(tcc_ireg(op->reg), op->vt);
}
/* RV64: long long fits in a single 64-bit register */
if (op->is_llong) {
tcc_error("long long not implemented");
}
}
}
}

View File

@ -30,10 +30,6 @@
#define CHAR_IS_UNSIGNED
/* define if return values need to be extended explicitely
at caller side (for interfacing with non-TCC compilers) */
#define PROMOTE_RET
#else
#define USING_GLOBALS
#include "tcc.h"
@ -179,19 +175,6 @@ static int load_symofs(int r, SValue *sv, int forstore, int *new_fc)
if (sv->r & VT_SYM) {
Sym label = {0};
assert(v == VT_CONST);
if (sv->sym->type.t & VT_TLS) {
/* TLS Local Exec model: lui + addi + add tp */
rr = is_ireg(r) ? ireg(r) : 5;
greloca(cur_text_section, sv->sym, ind,
R_RISCV_TPREL_HI20, sv->c.i);
o(0x37 | (rr << 7)); // lui RR, 0 %tprel_hi(sym)
greloca(cur_text_section, sv->sym, ind,
R_RISCV_TPREL_LO12_I, 0);
EI(0x13, 0, rr, rr, 0); // addi RR, RR, 0 %tprel_lo(sym)
ER(0x33, 0, rr, rr, 4, 0); // add RR, RR, tp
*new_fc = 0;
return rr;
}
if (sv->sym->type.t & VT_STATIC) { // XXX do this per linker relax
greloca(cur_text_section, sv->sym, ind,
R_RISCV_PCREL_HI20, sv->c.i);
@ -294,29 +277,13 @@ ST_FUNC void load(int r, SValue *sv)
EI(opcode, func3, rr, br, fc); // l[bhwd][u] / fl[wd] RR, fc(BR)
} else if (v == VT_CONST) {
int rb = 0, do32bit = 8, zext = 0;
if (is_float(sv->type.t) && bt != VT_LDOUBLE) {
/* load float/double constant: move bit pattern from int reg */
uint64_t val = sv->c.i;
int is_dbl = bt == VT_DOUBLE;
if (val == 0) {
o(0x53 | (rr << 7) | ((unsigned)(0x78 | is_dbl) << 25));
return;
}
if (is_dbl) {
load_large_constant(6, (int)val, (int)(val >> 32));
} else {
if (LOW_OVERFLOW(fc))
o(0x37 | (6 << 7) | UPPER(fc)); // lui t1, upper
EI(0x13 | 8, 0, 6, LOW_OVERFLOW(fc) ? 6 : 0, SIGN11(fc)); // addiw t1,...
}
o(0x53 | (rr << 7) | (6 << 15) | ((unsigned)(0x78 | is_dbl) << 25));
return;
}
assert(is_ireg(r) || bt == VT_LDOUBLE);
assert((!is_float(sv->type.t) && is_ireg(r)) || bt == VT_LDOUBLE);
if (fr & VT_SYM) {
rb = load_symofs(r, sv, 0, &fc);
do32bit = 0;
}
if (is_float(sv->type.t) && bt != VT_LDOUBLE)
tcc_error("unimp: load(float)");
if (do32bit && fc != sv->c.i) {
int64_t si = sv->c.i;
si >>= 32;
@ -1274,31 +1241,10 @@ ST_FUNC void gen_opf(int op)
}
}
ST_FUNC void gen_cvt_csti(int t)
{
int r = ireg(gv(RC_INT));
if ((t & VT_BTYPE) == VT_SHORT) {
if (t & VT_UNSIGNED) {
EI(0x13, 1, r, r, 48); // slli r, r, 48
EI(0x13, 5, r, r, 48); // srli r, r, 48
} else {
EI(0x13, 1, r, r, 48); // slli r, r, 48
EIu(0x13, 5, r, r, 0x400 | 48); // srai r, r, 48
}
} else {
if (t & VT_UNSIGNED) {
EI(0x13, 7, r, r, 0xff); // andi r, r, 0xff
} else {
EI(0x13, 1, r, r, 56); // slli r, r, 56
EIu(0x13, 5, r, r, 0x400 | 56); // srai r, r, 56
}
}
}
ST_FUNC void gen_cvt_sxtw(void)
{
int r = ireg(gv(RC_INT));
EI(0x1b, 0, r, r, 0); // addiw r, r, 0
/* XXX on risc-v the registers are usually sign-extended already.
Let's try to not do anything here. */
}
ST_FUNC void gen_cvt_itof(int t)
@ -1485,12 +1431,4 @@ ST_FUNC void gen_vla_alloc(CType *type, int align)
}
#endif
}
ST_FUNC void gen_clear_cache(void)
{
/* Zifencei extension: fence + fence.i for I/D synchronization.
Required by RISC-V Linux ABI, present on all Linux-capable cores. */
o(0x0ff0000f); // fence iorw, iorw
o(0x0000100f); // fence.i
}
#endif

View File

@ -53,8 +53,6 @@ ST_FUNC int code_reloc (int reloc_type)
case R_RISCV_64:
case R_RISCV_SET_ULEB128:
case R_RISCV_SUB_ULEB128:
case R_RISCV_TPREL_HI20:
case R_RISCV_TPREL_LO12_I:
return 0;
case R_RISCV_CALL_PLT:
@ -103,10 +101,6 @@ ST_FUNC int gotplt_entry_type (int reloc_type)
case R_RISCV_GOT_HI20:
return ALWAYS_GOTPLT_ENTRY;
case R_RISCV_TPREL_HI20:
case R_RISCV_TPREL_LO12_I:
return NO_GOTPLT_ENTRY;
}
return -1;
}
@ -181,23 +175,37 @@ ST_FUNC void relocate_plt(TCCState *s1)
static void riscv64_record_pcrel_hi(TCCState *s1, addr_t addr, addr_t val)
{
struct pcrel_hi *entry = tcc_malloc(sizeof *entry);
entry->addr = addr;
entry->val = val;
dynarray_add(&s1->pcrel_hi_entries, &s1->nb_pcrel_hi_entries, entry);
int n = s1->nb_pcrel_hi_entries;
if (n >= s1->alloc_pcrel_hi_entries) {
int new_alloc = s1->alloc_pcrel_hi_entries ? s1->alloc_pcrel_hi_entries * 2 : 64;
s1->pcrel_hi_entries = tcc_realloc(s1->pcrel_hi_entries,
new_alloc * sizeof(*s1->pcrel_hi_entries));
s1->alloc_pcrel_hi_entries = new_alloc;
}
s1->pcrel_hi_entries[n].addr = addr;
s1->pcrel_hi_entries[n].val = val;
s1->nb_pcrel_hi_entries = n + 1;
last_hi.addr = addr;
last_hi.val = val;
}
static int riscv64_lookup_pcrel_hi(TCCState *s1, addr_t hi_addr, addr_t *hi_val)
{
int i;
for (i = s1->nb_pcrel_hi_entries; i > 0; ) {
struct pcrel_hi *entry = s1->pcrel_hi_entries[--i];
struct pcrel_hi *entry;
if (s1->nb_pcrel_hi_entries && hi_addr == last_hi.addr) {
*hi_val = last_hi.val;
return 1;
}
for (i = s1->nb_pcrel_hi_entries - 1; i >= 0; --i) {
entry = &s1->pcrel_hi_entries[i];
if (entry->addr == hi_addr) {
last_hi = *entry;
*hi_val = entry->val;
return 0;
return 1;
}
}
return tcc_error_noabort("unsupported hi/lo pcrel reloc scheme");
return 0;
}
ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
@ -271,13 +279,15 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
printf("PCREL_LO12_I: val=%lx addr=%lx\n", (long)val, (long)addr);
#endif
addr = val;
riscv64_lookup_pcrel_hi(s1, addr, &val);
if (!riscv64_lookup_pcrel_hi(s1, addr, &val))
tcc_error_noabort("unsupported hi/lo pcrel reloc scheme");
write32le(ptr, (read32le(ptr) & 0xfffff)
| (((val - addr) & 0xfff) << 20));
return;
case R_RISCV_PCREL_LO12_S:
addr = val;
riscv64_lookup_pcrel_hi(s1, addr, &val);
if (!riscv64_lookup_pcrel_hi(s1, addr, &val))
tcc_error_noabort("unsupported hi/lo pcrel reloc scheme");
off32 = val - addr;
write32le(ptr, (read32le(ptr) & ~0xfe000f80)
| ((off32 & 0xfe0) << 20)
@ -399,37 +409,6 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
case R_RISCV_COPY:
/* XXX */
return;
case R_RISCV_RELATIVE:
/* R_RISCV_RELATIVE value is already applied in R_RISCV_32/64
dynamic output paths, but we need this case for incoming
RELATIVE relocations from object files. */
return;
case R_RISCV_TPREL_HI20:
case R_RISCV_TPREL_LO12_I: {
addr_t tls_start = 0;
int64_t tp_offset;
int i;
for (i = 1; i < s1->nb_sections; i++) {
Section *s = s1->sections[i];
if (s->sh_flags & SHF_TLS && s->sh_size) {
if (!tls_start || s->sh_addr < tls_start)
tls_start = s->sh_addr;
}
}
tp_offset = val - tls_start;
if (type == R_RISCV_TPREL_HI20) {
off64 = (int64_t)(tp_offset + 0x800) >> 12;
if ((off64 + ((uint64_t)1 << 20)) >> 21)
tcc_error_noabort("R_RISCV_TPREL_HI20 relocation failed");
write32le(ptr, (read32le(ptr) & 0xfff)
| ((off64 & 0xfffff) << 12));
} else {
write32le(ptr, (read32le(ptr) & 0xfffff)
| (((tp_offset) & 0xfff) << 20));
}
return;
}
default:
fprintf(stderr, "FIXME: handle reloc type %x at %x [%p] to %x\n",

View File

@ -270,14 +270,6 @@
/* enough implemented for musl */
DEF_ASM_WITH_SUFFIX(fsgnj, s)
DEF_ASM_WITH_SUFFIX(fsgnj, d)
DEF_ASM_WITH_SUFFIX(fadd, s)
DEF_ASM_WITH_SUFFIX(fadd, d)
DEF_ASM_WITH_SUFFIX(fsub, s)
DEF_ASM_WITH_SUFFIX(fsub, d)
DEF_ASM_WITH_SUFFIX(fmul, s)
DEF_ASM_WITH_SUFFIX(fmul, d)
DEF_ASM_WITH_SUFFIX(fdiv, s)
DEF_ASM_WITH_SUFFIX(fdiv, d)
DEF_ASM_WITH_SUFFIX(fmadd, s)
DEF_ASM_WITH_SUFFIX(fmadd, d)
DEF_ASM_WITH_SUFFIX(fmax, s)
@ -287,35 +279,7 @@
DEF_ASM_WITH_SUFFIX(fsqrt, s)
DEF_ASM_WITH_SUFFIX(fsqrt, d)
/* F/D comparison and conversion (not needed by musl, added for completeness) */
DEF_ASM_WITH_SUFFIX(feq, s)
DEF_ASM_WITH_SUFFIX(feq, d)
DEF_ASM_WITH_SUFFIX(flt, s)
DEF_ASM_WITH_SUFFIX(flt, d)
DEF_ASM_WITH_SUFFIX(fle, s)
DEF_ASM_WITH_SUFFIX(fle, d)
DEF_ASM_WITH_SUFFIX(fclass, s)
DEF_ASM_WITH_SUFFIX(fclass, d)
DEF_ASM_WITH_SUFFIXES(fcvt, w, s)
DEF_ASM_WITH_SUFFIXES(fcvt, wu, s)
DEF_ASM_WITH_SUFFIXES(fcvt, l, s)
DEF_ASM_WITH_SUFFIXES(fcvt, lu, s)
DEF_ASM_WITH_SUFFIXES(fcvt, s, w)
DEF_ASM_WITH_SUFFIXES(fcvt, s, wu)
DEF_ASM_WITH_SUFFIXES(fcvt, s, l)
DEF_ASM_WITH_SUFFIXES(fcvt, s, lu)
DEF_ASM_WITH_SUFFIXES(fcvt, w, d)
DEF_ASM_WITH_SUFFIXES(fcvt, wu, d)
DEF_ASM_WITH_SUFFIXES(fcvt, l, d)
DEF_ASM_WITH_SUFFIXES(fcvt, lu, d)
DEF_ASM_WITH_SUFFIXES(fcvt, d, w)
DEF_ASM_WITH_SUFFIXES(fcvt, d, wu)
DEF_ASM_WITH_SUFFIXES(fcvt, d, l)
DEF_ASM_WITH_SUFFIXES(fcvt, d, lu)
DEF_ASM_WITH_SUFFIXES(fcvt, s, d)
DEF_ASM_WITH_SUFFIXES(fcvt, d, s)
/* "C" Extension for Compressed Instructions, V2.0 */
/* "C" Extension for Compressed Instructions, V2.0 */
DEF_ASM_WITH_SUFFIX(c, nop)
/* Loads */
DEF_ASM_WITH_SUFFIX(c, li)
@ -500,93 +464,7 @@
DEF_ASM_WITH_SUFFIXES(sc, d, rl)
DEF_ASM_WITH_SUFFIXES(sc, d, aqrl)
/* "A" Extension for Atomic Operations, V2.1 (base, no aq/rl suffixes) */
DEF_ASM_WITH_SUFFIX(amoadd, w)
DEF_ASM_WITH_SUFFIX(amoadd, d)
DEF_ASM_WITH_SUFFIX(amoswap, w)
DEF_ASM_WITH_SUFFIX(amoswap, d)
DEF_ASM_WITH_SUFFIX(amoand, w)
DEF_ASM_WITH_SUFFIX(amoand, d)
DEF_ASM_WITH_SUFFIX(amoor, w)
DEF_ASM_WITH_SUFFIX(amoor, d)
DEF_ASM_WITH_SUFFIX(amoxor, w)
DEF_ASM_WITH_SUFFIX(amoxor, d)
DEF_ASM_WITH_SUFFIX(amomax, w)
DEF_ASM_WITH_SUFFIX(amomax, d)
DEF_ASM_WITH_SUFFIX(amomaxu, w)
DEF_ASM_WITH_SUFFIX(amomaxu, d)
DEF_ASM_WITH_SUFFIX(amomin, w)
DEF_ASM_WITH_SUFFIX(amomin, d)
DEF_ASM_WITH_SUFFIX(amominu, w)
DEF_ASM_WITH_SUFFIX(amominu, d)
/* AMO aq/rl ordering suffixes */
DEF_ASM_WITH_SUFFIXES(amoadd, w, aq)
DEF_ASM_WITH_SUFFIXES(amoadd, w, rl)
DEF_ASM_WITH_SUFFIXES(amoadd, w, aqrl)
DEF_ASM_WITH_SUFFIXES(amoadd, d, aq)
DEF_ASM_WITH_SUFFIXES(amoadd, d, rl)
DEF_ASM_WITH_SUFFIXES(amoadd, d, aqrl)
/* Complete AMO aq/rl ordering suffixes (all ops) */
DEF_ASM_WITH_SUFFIXES(amoswap, w, aq)
DEF_ASM_WITH_SUFFIXES(amoswap, w, rl)
DEF_ASM_WITH_SUFFIXES(amoswap, w, aqrl)
DEF_ASM_WITH_SUFFIXES(amoswap, d, aq)
DEF_ASM_WITH_SUFFIXES(amoswap, d, rl)
DEF_ASM_WITH_SUFFIXES(amoswap, d, aqrl)
DEF_ASM_WITH_SUFFIXES(amoand, w, aq)
DEF_ASM_WITH_SUFFIXES(amoand, w, rl)
DEF_ASM_WITH_SUFFIXES(amoand, w, aqrl)
DEF_ASM_WITH_SUFFIXES(amoand, d, aq)
DEF_ASM_WITH_SUFFIXES(amoand, d, rl)
DEF_ASM_WITH_SUFFIXES(amoand, d, aqrl)
DEF_ASM_WITH_SUFFIXES(amoor, w, aq)
DEF_ASM_WITH_SUFFIXES(amoor, w, rl)
DEF_ASM_WITH_SUFFIXES(amoor, w, aqrl)
DEF_ASM_WITH_SUFFIXES(amoor, d, aq)
DEF_ASM_WITH_SUFFIXES(amoor, d, rl)
DEF_ASM_WITH_SUFFIXES(amoor, d, aqrl)
DEF_ASM_WITH_SUFFIXES(amoxor, w, aq)
DEF_ASM_WITH_SUFFIXES(amoxor, w, rl)
DEF_ASM_WITH_SUFFIXES(amoxor, w, aqrl)
DEF_ASM_WITH_SUFFIXES(amoxor, d, aq)
DEF_ASM_WITH_SUFFIXES(amoxor, d, rl)
DEF_ASM_WITH_SUFFIXES(amoxor, d, aqrl)
DEF_ASM_WITH_SUFFIXES(amomax, w, aq)
DEF_ASM_WITH_SUFFIXES(amomax, w, rl)
DEF_ASM_WITH_SUFFIXES(amomax, w, aqrl)
DEF_ASM_WITH_SUFFIXES(amomax, d, aq)
DEF_ASM_WITH_SUFFIXES(amomax, d, rl)
DEF_ASM_WITH_SUFFIXES(amomax, d, aqrl)
DEF_ASM_WITH_SUFFIXES(amomaxu, w, aq)
DEF_ASM_WITH_SUFFIXES(amomaxu, w, rl)
DEF_ASM_WITH_SUFFIXES(amomaxu, w, aqrl)
DEF_ASM_WITH_SUFFIXES(amomaxu, d, aq)
DEF_ASM_WITH_SUFFIXES(amomaxu, d, rl)
DEF_ASM_WITH_SUFFIXES(amomaxu, d, aqrl)
DEF_ASM_WITH_SUFFIXES(amomin, w, aq)
DEF_ASM_WITH_SUFFIXES(amomin, w, rl)
DEF_ASM_WITH_SUFFIXES(amomin, w, aqrl)
DEF_ASM_WITH_SUFFIXES(amomin, d, aq)
DEF_ASM_WITH_SUFFIXES(amomin, d, rl)
DEF_ASM_WITH_SUFFIXES(amomin, d, aqrl)
DEF_ASM_WITH_SUFFIXES(amominu, w, aq)
DEF_ASM_WITH_SUFFIXES(amominu, w, rl)
DEF_ASM_WITH_SUFFIXES(amominu, w, aqrl)
DEF_ASM_WITH_SUFFIXES(amominu, d, aq)
DEF_ASM_WITH_SUFFIXES(amominu, d, rl)
DEF_ASM_WITH_SUFFIXES(amominu, d, aqrl)
/* rounding mode keywords (used as fcvt operand: fcvt.w.s rd, rs1, rtz) */
DEF_ASM(rne)
DEF_ASM(rtz)
DEF_ASM(rdn)
DEF_ASM(rup)
DEF_ASM(rmm)
/* `fence` arguments */
/* `fence` arguments */
/* NOTE: Order is important */
DEF_ASM_FENCE(w)
DEF_ASM_FENCE(r)

View File

@ -386,15 +386,6 @@ Set type for PE (Windows) executables.
@item -Wl,-[Ttext=# | section-alignment=# | file-alignment=# | image-base=# | stack=#]
Modify executable layout.
@item -Wl,-[dynamicbase | nxcompat | high-entropy-va | tsaware]
@item -Wl,-[no-dynamicbase | no-nxcompat | no-high-entropy-va | no-tsaware]
@item -Wl,-[disable-dynamicbase | disable-nxcompat | disable-high-entropy-va | disable-tsaware]
Set or clear PE (Windows) executable header hardening flags. The
@option{-Wl,-high-entropy-va} option is supported on x86-64 and ARM64 PE
targets and implies @option{-Wl,-dynamicbase}. Clearing dynamicbase also
clears high-entropy-va. When @option{-Wl,-dynamicbase} is used for an
executable, TCC also enables base relocation emission for Windows ASLR.
@item -Wl,-Bsymbolic
Set DT_SYMBOLIC tag.

28
tcc.c
View File

@ -35,7 +35,7 @@ static const char help[] =
"General options:\n"
" -c compile only - generate an object file\n"
" -o outfile set output filename\n"
" -run run compiled source\n"
" -run run compiled source [with custom stdin: -rstdin FILE]\n"
" -fflag set or reset (with 'no-' prefix) 'flag' (see tcc -hh)\n"
" -Wwarning set or reset (with 'no-' prefix) 'warning' (see tcc -hh)\n"
" -w disable all warnings\n"
@ -105,7 +105,6 @@ static const char help2[] =
" -static link to static libraries (not recommended)\n"
" -dumpversion print version\n"
" -print-search-dirs print search paths\n"
" -rstdin file with -run: use 'file' as custom stdin\n"
" -dt with -run/-E: auto-define 'test_...' macros\n"
"Ignored options:\n"
" -arch -C --param -pedantic -pipe -s -traditional\n"
@ -226,7 +225,7 @@ static void print_search_dirs(TCCState *s)
printf("libtcc1:\n %s/%s\n", s->library_paths[0], CONFIG_TCC_CROSSPREFIX TCC_LIBTCC1);
#ifdef TCC_TARGET_UNIX
print_dirs("crt", s->crt_paths, s->nb_crt_paths);
printf("elfinterp:\n %s\n", s->elfint);
printf("elfinterp:\n %s\n", DEFAULT_ELFINTERP(s));
#endif
}
@ -294,7 +293,7 @@ int main(int argc, char **argv)
const char *first_file;
int argc0 = argc;
char **argv0 = argv;
FILE *ppfp = NULL;
FILE *ppfp = stdout;
redo:
argc = argc0, argv = argv0;
@ -336,7 +335,7 @@ redo:
tcc_error_noabort("no input files");
} else if (s->output_type == TCC_OUTPUT_PREPROCESS) {
if (s->outfile && 0!=strcmp("-",s->outfile)) {
ppfp = tcc_fopen(s->outfile, "wb");
ppfp = fopen(s->outfile, "wb");
if (!ppfp)
tcc_error_noabort("could not write '%s'", s->outfile);
}
@ -355,9 +354,8 @@ redo:
set_environment(s);
if (s->output_type == 0)
s->output_type = TCC_OUTPUT_EXE;
ret = tcc_set_output_type(s, s->output_type);
if (ppfp)
s->ppfp = ppfp;
tcc_set_output_type(s, s->output_type);
s->ppfp = ppfp;
if ((s->output_type == TCC_OUTPUT_MEMORY
|| s->output_type == TCC_OUTPUT_PREPROCESS)
@ -371,7 +369,7 @@ redo:
/* compile or add each files or library */
first_file = NULL;
while (0 == ret) {
do {
struct filespec *f = s->files[n];
s->filetype = f->type;
if (f->type & AFF_TYPE_LIB) {
@ -383,11 +381,9 @@ redo:
first_file = f->name;
ret = tcc_add_file(s, f->name);
}
if (++n == s->nb_files)
break;
if (s->output_type == TCC_OUTPUT_OBJ && !s->option_r)
break;
}
} while (++n < s->nb_files
&& 0 == ret
&& (s->output_type != TCC_OUTPUT_OBJ || s->option_r));
if (s->do_bench)
end_time = getclock_ms();
@ -426,7 +422,7 @@ redo:
tcc_delete(s);
if (!done)
goto redo;
if (ppfp)
tcc_fclose(ppfp);
if (ppfp && ppfp != stdout)
fclose(ppfp);
return ret;
}

117
tcc.h
View File

@ -52,9 +52,6 @@ extern long double strtold (const char *__nptr, char **__endptr);
#ifdef _WIN32
# define WIN32_LEAN_AND_MEAN 1
# ifndef _WIN32_WINNT
# define _WIN32_WINNT 0x502 /* AddVectoredExceptionHandler */
# endif
# include <windows.h>
# include <io.h> /* open, close etc. */
# include <direct.h> /* getcwd */
@ -89,9 +86,6 @@ extern long double strtold (const char *__nptr, char **__endptr);
# define __x86_64__ 1
# endif
# endif
# if defined(_M_ARM64) && !defined(__aarch64__)
# define __aarch64__ 1
# endif
# ifndef va_copy
# define va_copy(a,b) a = b
# endif
@ -234,7 +228,8 @@ extern long double strtold (const char *__nptr, char **__endptr);
/* No ten-byte long doubles on window and macos except in
cross-compilers made by a mingw-GCC */
#if defined TCC_TARGET_PE \
|| (defined TCC_TARGET_MACHO && defined TCC_TARGET_ARM64)
|| (defined TCC_TARGET_MACHO && defined TCC_TARGET_ARM64) \
|| (defined _WIN32 && !defined __GNUC__)
# define TCC_USING_DOUBLE_FOR_LDOUBLE 1
#endif
@ -252,14 +247,15 @@ extern long double strtold (const char *__nptr, char **__endptr);
#ifndef CONFIG_SYSROOT
# define CONFIG_SYSROOT ""
#endif
#if !defined CONFIG_TCCDIR && !defined _WIN32
# define CONFIG_TCCDIR "/usr/local/lib/tcc"
#endif
#ifndef CONFIG_LDDIR
# define CONFIG_LDDIR "lib"
#endif
#ifdef CONFIG_TRIPLET
# define USE_TRIPLET(s) s "/" CONFIG_TRIPLET
# define ALSO_TRIPLET(s) USE_TRIPLET(s) PATHSEP s
# define ALSO_TRIPLET(s) USE_TRIPLET(s) ":" s
#else
# define USE_TRIPLET(s) s
# define ALSO_TRIPLET(s) s
@ -267,8 +263,11 @@ extern long double strtold (const char *__nptr, char **__endptr);
/* path to find crt1.o, crti.o and crtn.o */
#ifndef CONFIG_TCC_CRTPREFIX
# define CONFIG_TCC_CRTPREFIX \
USE_TRIPLET(CONFIG_SYSROOT "/usr/lib")
# define CONFIG_TCC_CRTPREFIX USE_TRIPLET(CONFIG_SYSROOT "/usr/" CONFIG_LDDIR)
#endif
#ifndef CONFIG_USR_INCLUDE
# define CONFIG_USR_INCLUDE "/usr/include"
#endif
/* Below: {B} is substituted by CONFIG_TCCDIR (rsp. -B option) */
@ -276,22 +275,25 @@ extern long double strtold (const char *__nptr, char **__endptr);
/* system include paths */
#ifndef CONFIG_TCC_SYSINCLUDEPATHS
# if defined TCC_TARGET_PE || defined _WIN32
# define CONFIG_TCC_SYSINCLUDEPATHS \
"{B}/include" PATHSEP "{B}/include/winapi"
# define CONFIG_TCC_SYSINCLUDEPATHS "{B}/include"PATHSEP"{B}/include/winapi"
# else
# define CONFIG_TCC_SYSINCLUDEPATHS \
"{B}/include" PATHSEP ALSO_TRIPLET(CONFIG_SYSROOT "/usr/include")
"{B}/include" \
":" ALSO_TRIPLET(CONFIG_SYSROOT "/usr/local/include") \
":" ALSO_TRIPLET(CONFIG_SYSROOT CONFIG_USR_INCLUDE)
# endif
#endif
/* library search paths */
#ifndef CONFIG_TCC_LIBPATHS
# if defined TCC_TARGET_PE || defined _WIN32
# define CONFIG_TCC_LIBPATHS \
"{B}/lib"
# define CONFIG_TCC_LIBPATHS "{B}/lib"
# else
# define CONFIG_TCC_LIBPATHS \
"{B}" PATHSEP ALSO_TRIPLET(CONFIG_SYSROOT "/usr/lib")
"{B}" \
":" ALSO_TRIPLET(CONFIG_SYSROOT "/usr/" CONFIG_LDDIR) \
":" ALSO_TRIPLET(CONFIG_SYSROOT "/" CONFIG_LDDIR) \
":" ALSO_TRIPLET(CONFIG_SYSROOT "/usr/local/" CONFIG_LDDIR)
# endif
#endif
@ -307,19 +309,28 @@ extern long double strtold (const char *__nptr, char **__endptr);
# define CONFIG_TCC_ELFINTERP "/lib64/ld-linux-x86-64.so.2"
# elif defined(TCC_TARGET_RISCV64)
# define CONFIG_TCC_ELFINTERP "/lib/ld-linux-riscv64-lp64d.so.1"
# elif defined(TCC_TARGET_ARM)
# define CONFIG_TCC_ELFINTERP "/lib/ld-linux.so.3"
# define CONFIG_TCC_ELFINTERP_ARMHF "/lib/ld-linux-armhf.so.3"
# elif defined(TCC_ARM_EABI)
# define DEFAULT_ELFINTERP(s) default_elfinterp(s)
# else
# define CONFIG_TCC_ELFINTERP "/lib/ld-linux.so.2"
# endif
#endif
/* var elf_interp dans *-gen.c */
#ifndef DEFAULT_ELFINTERP
# define DEFAULT_ELFINTERP(s) CONFIG_TCC_ELFINTERP
#endif
/* (target specific) libtcc1.a */
#ifndef TCC_LIBTCC1
# define TCC_LIBTCC1 "libtcc1.a"
#endif
/* library to use with CONFIG_USE_LIBGCC instead of libtcc1.a */
#if defined CONFIG_USE_LIBGCC && !defined TCC_LIBGCC
#define TCC_LIBGCC USE_TRIPLET(CONFIG_SYSROOT "/" CONFIG_LDDIR) "/libgcc_s.so.1"
#endif
/* <cross-prefix-to->libtcc1.a */
#ifndef CONFIG_TCC_CROSSPREFIX
# define CONFIG_TCC_CROSSPREFIX ""
@ -459,9 +470,6 @@ typedef struct CType {
struct Sym *ref;
} CType;
/* long double words on host(!) platform */
#define LDOUBLE_WORDS ((sizeof(long double)+3)/4)
/* constant value */
typedef union CValue {
long double ld;
@ -472,7 +480,7 @@ typedef union CValue {
char *data;
int size;
} str;
int tab[LDOUBLE_WORDS];
int tab[LDOUBLE_SIZE/4];
} CValue;
/* value on stack */
@ -727,15 +735,6 @@ struct sym_attr {
#endif
};
#ifdef TCC_TARGET_PE
#define PE_IMAGE_FILE_RELOCS_STRIPPED 0x0001
#define PE_IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020
#define PE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA 0x0020
#define PE_DLLCHARACTERISTICS_DYNAMIC_BASE 0x0040
#define PE_DLLCHARACTERISTICS_NX_COMPAT 0x0100
#define PE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 0x8000
#endif
struct TCCState {
unsigned char verbose; /* if true, display some information during compilation */
unsigned char nostdinc; /* if true, no standard headers are added */
@ -898,7 +897,6 @@ struct TCCState {
/* predefined sections */
Section *text_section, *data_section, *rodata_section, *bss_section;
Section *tdata_section, *tbss_section;
Section *common_section;
Section *cur_text_section; /* current section where function code is generated */
#ifdef CONFIG_TCC_BCHECK
@ -940,23 +938,23 @@ struct TCCState {
#define qrel s1->qrel
#ifdef TCC_TARGET_RISCV64
struct pcrel_hi { addr_t addr, val; } **pcrel_hi_entries;
struct pcrel_hi { addr_t addr, val; } last_hi;
struct pcrel_hi *pcrel_hi_entries;
int nb_pcrel_hi_entries;
int alloc_pcrel_hi_entries;
#define last_hi s1->last_hi
#endif
#ifdef TCC_TARGET_PE
/* PE info */
int pe_subsystem;
unsigned pe_characteristics;
unsigned pe_dll_characteristics;
unsigned pe_dll_characteristics_clear;
unsigned pe_file_align;
unsigned pe_stack_size;
addr_t pe_imagebase;
# if defined(TCC_TARGET_X86_64) || defined(TCC_TARGET_ARM64)
# ifdef TCC_TARGET_X86_64
Section *uw_pdata;
int uw_sym;
int uw_xsym;
unsigned uw_offs;
# endif
#endif
@ -1075,8 +1073,7 @@ struct filespec {
#define VT_STATIC 0x00002000 /* static variable */
#define VT_TYPEDEF 0x00004000 /* typedef definition */
#define VT_INLINE 0x00008000 /* inline definition */
#define VT_TLS 0x00010000 /* thread-local storage */
/* currently unused: 0x000[248]0000 */
/* currently unused: 0x000[1248]0000 */
#define VT_STRUCT_SHIFT 20 /* shift for bitfield shift values (32 - 2*6) */
#define VT_STRUCT_MASK (((1U << (6+6)) - 1) << VT_STRUCT_SHIFT | VT_BITFIELD)
@ -1094,7 +1091,7 @@ struct filespec {
#define VT_ATOMIC VT_VOLATILE
/* type mask (except storage) */
#define VT_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE | VT_TLS)
#define VT_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE)
#define VT_TYPE (~(VT_STORAGE|VT_STRUCT_MASK))
/* symbol was created by tccasm.c first */
@ -1317,11 +1314,6 @@ PUB_FUNC void tcc_print_stats(TCCState *s, unsigned total_time);
PUB_FUNC int tcc_parse_args(TCCState *s, int *argc, char ***argv);
#ifdef _WIN32
ST_FUNC char *normalize_slashes(char *path);
PUB_FUNC FILE *tcc_fopen(const char *f, const char *m);
PUB_FUNC int tcc_fclose(FILE *f);
#else
# define tcc_fopen fopen
# define tcc_fclose fclose
#endif
ST_FUNC DLLReference *tcc_add_dllref(TCCState *s1, const char *dllname, int level);
ST_FUNC char *tcc_load_text(int fd);
@ -1446,8 +1438,8 @@ ST_DATA int nocode_wanted; /* true if no code generation wanted for an expressio
ST_DATA int global_expr; /* true if compound literals must be allocated globally (used during initializers parsing */
ST_DATA CType func_vt; /* current function return type (used by return instruction) */
ST_DATA int func_var; /* true if current function is variadic */
ST_DATA int func_vc; /* stack address for implicit struct return storage */
ST_DATA int func_ind; /* function start address */
ST_DATA int func_vc;
ST_DATA int func_ind;
ST_DATA const char *funcname;
ST_FUNC void tccgen_init(TCCState *s1);
@ -1693,6 +1685,7 @@ ST_FUNC void gen_increment_tcov (SValue *sv);
/* ------------ x86_64-gen.c ------------ */
#ifdef TCC_TARGET_X86_64
ST_FUNC void gen_addr64(int r, Sym *sym, int64_t c);
ST_FUNC void gen_opl(int op);
#ifdef TCC_TARGET_PE
ST_FUNC void gen_vla_result(int addr);
@ -1725,12 +1718,11 @@ ST_FUNC void gen_increment_tcov (SValue *sv);
/* ------------ riscv64-gen.c ------------ */
#ifdef TCC_TARGET_RISCV64
ST_FUNC void gen_opl(int op);
//ST_FUNC void gfunc_return(CType *func_type);
ST_FUNC void gen_va_start(void);
ST_FUNC void arch_transfer_ret_regs(int);
ST_FUNC void gen_cvt_sxtw(void);
ST_FUNC void gen_cvt_csti(int t);
ST_FUNC void gen_increment_tcov (SValue *sv);
ST_FUNC void gen_clear_cache(void);
#endif
/* ------------ c67-gen.c ------------ */
@ -1752,11 +1744,11 @@ ST_FUNC int find_constraint(ASMOperand *operands, int nb_operands, const char *n
ST_FUNC Sym* get_asm_sym(int name, Sym *csym);
ST_FUNC void asm_expr(TCCState *s1, ExprValue *pe);
ST_FUNC int asm_int_expr(TCCState *s1);
#if PTR_SIZE == 8
ST_FUNC void gen_expr64(ExprValue *pe);
#endif
/* ------------ i386-asm.c ------------ */
ST_FUNC void gen_expr32(ExprValue *pe);
#ifdef TCC_TARGET_X86_64
ST_FUNC void gen_expr64(ExprValue *pe);
#endif
ST_FUNC void asm_opcode(TCCState *s1, int opcode);
ST_FUNC int asm_parse_regvar(int t);
ST_FUNC void asm_compute_constraints(ASMOperand *operands, int nb_operands, int nb_outputs, const uint8_t *clobber_regs, int *pout_reg);
@ -1773,7 +1765,7 @@ ST_FUNC int pe_putimport(TCCState *s1, int dllindex, const char *name, addr_t va
ST_FUNC int pe_setsubsy(TCCState *s1, const char *arg);
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
#endif
#if defined(TCC_TARGET_X86_64) || defined(TCC_TARGET_ARM64)
#ifdef TCC_TARGET_X86_64
ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack);
#endif
PUB_FUNC int tcc_get_dllexports(const char *filename, char **pp);
@ -1930,15 +1922,10 @@ dwarf_read_sleb128(unsigned char **ln, unsigned char *end)
/********************************************************/
#if CONFIG_TCC_SEMLOCK
#if defined _WIN32
typedef struct { volatile LONG init; CRITICAL_SECTION cs; } TCCSem;
typedef struct { int init; CRITICAL_SECTION cs; } TCCSem;
static inline void wait_sem(TCCSem *p) {
if (InterlockedCompareExchange(&p->init, 1, 0) == 0) {
InitializeCriticalSection(&p->cs);
InterlockedExchange(&p->init, 2);
} else {
while (InterlockedCompareExchange(&p->init, 2, 2) != 2)
Sleep(0);
}
if (!p->init)
InitializeCriticalSection(&p->cs), p->init = 1;
EnterCriticalSection(&p->cs);
}
static inline void post_sem(TCCSem *p) {
@ -1989,8 +1976,6 @@ static inline void post_sem(TCCSem *p) {
#define data_section TCC_STATE_VAR(data_section)
#define rodata_section TCC_STATE_VAR(rodata_section)
#define bss_section TCC_STATE_VAR(bss_section)
#define tdata_section TCC_STATE_VAR(tdata_section)
#define tbss_section TCC_STATE_VAR(tbss_section)
#define common_section TCC_STATE_VAR(common_section)
#define cur_text_section TCC_STATE_VAR(cur_text_section)
#define bounds_section TCC_STATE_VAR(bounds_section)

105
tccasm.c
View File

@ -25,26 +25,6 @@
static Section *last_text_section; /* to handle .previous asm directive */
static int asmgoto_n;
static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global);
static Sym* asm_new_label(TCCState *s1, int label, int is_local);
static Sym* asm_new_label1(TCCState *s1, int label, int is_local, int sh_num, int value);
#if PTR_SIZE == 8
/* output constant with relocation if 'r & VT_SYM' is true */
ST_FUNC void gen_addr64(int r, Sym *sym, int64_t c)
{
if (r & VT_SYM)
greloca(cur_text_section, sym, ind, R_DATA_PTR, c), c=0;
gen_le32(c);
gen_le32(c>>32);
}
ST_FUNC void gen_expr64(ExprValue *pe)
{
gen_addr64(pe->sym ? VT_SYM : 0, pe->sym, pe->v);
}
#endif
static int asm_get_prefix_name(TCCState *s1, const char *prefix, unsigned int n)
{
char buf[64];
@ -57,6 +37,10 @@ ST_FUNC int asm_get_local_label_name(TCCState *s1, unsigned int n)
return asm_get_prefix_name(s1, "L..", n);
}
static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global);
static Sym* asm_new_label(TCCState *s1, int label, int is_local);
static Sym* asm_new_label1(TCCState *s1, int label, int is_local, int sh_num, int value);
/* If a C name has an _ prepended then only asm labels that start
with _ are representable in C, by removing the first _. ASM names
without _ at the beginning don't correspond to C names, but we use
@ -344,12 +328,12 @@ static inline void asm_expr_sum(TCCState *s1, ExprValue *pe)
if (esym1 && esym1->st_shndx == esym2->st_shndx
&& esym1->st_shndx != SHN_UNDEF) {
/* we also accept defined symbols in the same section */
pe->v += (int)(esym1->st_value - esym2->st_value);
pe->v += esym1->st_value - esym2->st_value;
pe->sym = NULL;
} else if (esym2->st_shndx == cur_text_section->sh_num) {
/* When subtracting a defined symbol in current section
this actually makes the value PC-relative. */
pe->v += (int)(0 - esym2->st_value);
pe->v += 0 - esym2->st_value;
pe->pcrel = 1;
e2.sym = NULL;
} else {
@ -510,7 +494,7 @@ static void pop_section(TCCState *s1)
static void asm_parse_directive(TCCState *s1, int global)
{
int n, offset, v, size, tok1, c;
int n, offset, v, size, tok1;
Section *sec;
uint8_t *ptr;
@ -540,25 +524,18 @@ static void asm_parse_directive(TCCState *s1, int global)
/* the section must have a compatible alignment */
if (sec->sh_addralign < n)
sec->sh_addralign = n;
c = sec->sh_flags & SHF_EXECINSTR;
} else {
if (n < 0)
n = 0;
size = n, c = 0;
size = n;
}
v = 0;
if (tok == ',') {
next();
v = asm_int_expr(s1), c = 0;
v = asm_int_expr(s1);
}
zero_pad:
if ((uint64_t)ind + size >= 1<<30)
tcc_error("too much data");
if (sec->sh_type != SHT_NOBITS) {
if (c) {
gen_fill_nops(size);
break;
}
sec->data_offset = ind;
ptr = section_ptr_add(sec, size);
memset(ptr, v, size);
@ -566,7 +543,7 @@ static void asm_parse_directive(TCCState *s1, int global)
ind += size;
break;
case TOK_ASMDIR_quad:
#if PTR_SIZE == 8
#ifdef TCC_TARGET_X86_64
size = 8;
goto asm_data;
#else
@ -615,7 +592,7 @@ static void asm_parse_directive(TCCState *s1, int global)
if (sec->sh_type != SHT_NOBITS) {
if (size == 4) {
gen_expr32(&e);
#if PTR_SIZE == 8
#ifdef TCC_TARGET_X86_64
} else if (size == 8) {
gen_expr64(&e);
#endif
@ -713,9 +690,11 @@ static void asm_parse_directive(TCCState *s1, int global)
expect("constant or same-section symbol");
n += esym->st_value;
}
if (n < 0 || n > 0x100000)
tcc_error(".org out of range");
if (n < ind)
tcc_error("attempt to .org backwards");
v = c = 0;
v = 0;
size = n - ind;
goto zero_pad;
}
@ -833,7 +812,6 @@ static void asm_parse_directive(TCCState *s1, int global)
case TOK_ASMDIR_size:
{
Sym *sym;
ElfSym *esym;
next();
if (tok < TOK_IDENT)
@ -845,10 +823,8 @@ static void asm_parse_directive(TCCState *s1, int global)
tcc_warning_c(warn_unsupported)("ignoring .size %s,*", get_tok_str(tok, NULL));
next();
skip(',');
n = asm_int_expr(s1);
esym = elfsym(sym);
if (esym) {
esym->st_size = n;
while (tok != TOK_LINEFEED && tok != ';' && tok != CH_EOF) {
next();
}
}
break;
@ -976,7 +952,7 @@ static void asm_parse_directive(TCCState *s1, int global)
}
break;
#endif
#if PTR_SIZE == 8
#ifdef TCC_TARGET_X86_64
/* added for compatibility with GAS */
case TOK_ASMDIR_code64:
next();
@ -1019,41 +995,17 @@ static void asm_parse_directive(TCCState *s1, int global)
case TOK_ASMDIR_reloc:
{
ExprValue e;
const char *reloc_name;
int reloc_type = -1;
next();
asm_expr(s1, &e);
skip(',');
reloc_name = get_tok_str(tok, NULL);
#if defined(TCC_TARGET_ARM64)
if (!strcmp(reloc_name, "R_AARCH64_CALL26"))
reloc_type = R_AARCH64_CALL26;
#elif defined(TCC_TARGET_RISCV64)
if (!strcmp(reloc_name, "R_RISCV_CALL") || !strcmp(reloc_name, "R_RISCV_CALL_PLT"))
reloc_type = R_RISCV_CALL;
else if (!strcmp(reloc_name, "R_RISCV_BRANCH"))
reloc_type = R_RISCV_BRANCH;
else if (!strcmp(reloc_name, "R_RISCV_JAL"))
reloc_type = R_RISCV_JAL;
else if (!strcmp(reloc_name, "R_RISCV_PCREL_HI20"))
reloc_type = R_RISCV_PCREL_HI20;
else if (!strcmp(reloc_name, "R_RISCV_PCREL_LO12_I"))
reloc_type = R_RISCV_PCREL_LO12_I;
else if (!strcmp(reloc_name, "R_RISCV_PCREL_LO12_S"))
reloc_type = R_RISCV_PCREL_LO12_S;
else if (!strcmp(reloc_name, "R_RISCV_32_PCREL"))
reloc_type = R_RISCV_32_PCREL;
else if (!strcmp(reloc_name, "R_RISCV_32"))
reloc_type = R_RISCV_32;
else if (!strcmp(reloc_name, "R_RISCV_64"))
reloc_type = R_RISCV_64;
if (strcmp(get_tok_str(tok, NULL), "R_AARCH64_CALL26"))
#endif
if (reloc_type < 0)
tcc_error("unimp: reloc '%s' unknown", reloc_name);
tcc_error("unimp: reloc '%s' unknown", get_tok_str(tok, NULL));
next();
skip(',');
greloca(cur_text_section, get_asm_sym(tok, NULL), e.v, reloc_type, 0);
greloca(cur_text_section, get_asm_sym(tok, NULL), e.v, R_AARCH64_CALL26, 0);
next();
}
break;
@ -1080,14 +1032,11 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global)
tcc_debug_line(s1);
parse_flags |= PARSE_FLAG_LINEFEED; /* XXX: suppress that hack */
redo:
#if !defined(TCC_TARGET_ARM64)
if (tok == '#') {
/* horrible gas comment */
while (tok != TOK_LINEFEED)
next();
} else
#endif
if (tok >= TOK_ASMDIR_FIRST && tok <= TOK_ASMDIR_LAST) {
} else if (tok >= TOK_ASMDIR_FIRST && tok <= TOK_ASMDIR_LAST) {
asm_parse_directive(s1, global);
} else if (tok == TOK_PPNUM) {
const char *p;
@ -1227,9 +1176,6 @@ static void subst_asm_operands(ASMOperand *operands, int nb_operands,
if (*str == 'c' || *str == 'n' ||
*str == 'b' || *str == 'w' || *str == 'h' || *str == 'k' ||
*str == 'q' || *str == 'l' ||
#ifdef TCC_TARGET_ARM64
*str == 'x' || *str == 's' || *str == 'd' || *str == 'Z' ||
#endif
#ifdef TCC_TARGET_RISCV64
*str == 'z' ||
#endif
@ -1250,7 +1196,7 @@ static void subst_asm_operands(ASMOperand *operands, int nb_operands,
sv = *op->vt;
if (op->reg >= 0) {
sv.r = op->reg;
if (op->is_memory)
if ((op->vt->r & VT_VALMASK) == VT_LLOCAL && op->is_memory)
sv.r |= VT_LVAL;
}
subst_asm_operand(out_str, &sv, modifier);
@ -1302,12 +1248,7 @@ static void parse_asm_operands(ASMOperand *operands, int *nb_operands_ptr,
if ((vtop->r & VT_LVAL) &&
((vtop->r & VT_VALMASK) == VT_LLOCAL ||
(vtop->r & VT_VALMASK) < VT_CONST) &&
!strchr(op->constraint, 'm')
#ifdef TCC_TARGET_ARM64
&& !strchr(op->constraint, 'Q')
&& !strstr(op->constraint, "Ump")
#endif
) {
!strchr(op->constraint, 'm')) {
gv(RC_INT);
}
}

120
tccelf.c
View File

@ -70,8 +70,6 @@ ST_FUNC void tccelf_new(TCCState *s)
/* create ro data section (make ro after relocation done with GNU_RELRO) */
rodata_section = new_section(s, rdata, SHT_PROGBITS, shf_RELRO);
bss_section = new_section(s, ".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE);
tdata_section = new_section(s, ".tdata", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE | SHF_TLS);
tbss_section = new_section(s, ".tbss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE | SHF_TLS);
common_section = new_section(s, ".common", SHT_NOBITS, SHF_PRIVATE);
common_section->sh_num = SHN_COMMON;
@ -112,21 +110,6 @@ ST_FUNC void tccelf_new(TCCState *s)
if (s->elf_entryname)
set_global_sym(s, s->elf_entryname, NULL, 0); /* SHN_UNDEF */
#endif
#ifndef ELF_OBJ_ONLY
if (NULL == s->elfint && s1->output_type != TCC_OUTPUT_OBJ) {
const char *p = CONFIG_TCC_ELFINTERP;
#if defined TCC_TARGET_ARM && defined CONFIG_TCC_ELFINTERP_ARMHF
if (s->float_abi == ARM_HARD_FLOAT)
p = CONFIG_TCC_ELFINTERP_ARMHF;
#endif
#if defined TCC_IS_NATIVE && defined TARGETOS_BSD
/* see commit 55cb2170cd5ce77a7d76dcaf462fad2707281605 */
{ const char *e = getenv("LD_SO"); if (e) p = e; }
#endif
s->elfint = tcc_strdup(p);
}
#endif /* ndef ELF_OBJ_ONLY */
}
ST_FUNC void free_section(Section *s)
@ -162,6 +145,9 @@ ST_FUNC void tccelf_delete(TCCState *s1)
dynarray_reset(&s1->priv_sections, &s1->nb_priv_sections);
tcc_free(s1->sym_attrs);
#ifdef TCC_TARGET_RISCV64
tcc_free(s1->pcrel_hi_entries);
#endif
symtab_section = NULL; /* for tccrun.c:rt_printline() */
}
@ -1123,7 +1109,7 @@ ST_FUNC void relocate_syms(TCCState *s1, Section *symtab, int do_resolve)
if (sym_bind == STB_WEAK)
sym->st_value = 0;
else
tcc_error_noabort("unresolved reference to '%s'", name);
tcc_error_noabort("undefined symbol '%s'", name);
} else if (sh_num < SHN_LORESERVE) {
/* add section base */
@ -1144,6 +1130,10 @@ static void relocate_section(TCCState *s1, Section *s, Section *sr)
addr_t tgt, addr;
int is_dwarf = s->sh_num >= s1->dwlo && s->sh_num < s1->dwhi;
#ifdef TCC_TARGET_RISCV64
s1->nb_pcrel_hi_entries = 0;
#endif
qrel = (ElfW_Rel *)sr->data;
for_each_elem(sr, 0, rel, ElfW_Rel) {
if (s->data == NULL) /* bss */
@ -1165,7 +1155,6 @@ static void relocate_section(TCCState *s1, Section *s, Section *sr)
addr = s->sh_addr + rel->r_offset;
relocate(s1, rel, type, ptr, addr, tgt);
}
#ifndef ELF_OBJ_ONLY
/* if the relocation is allocated, we change its symbol table */
if (sr->sh_flags & SHF_ALLOC) {
@ -1183,10 +1172,6 @@ static void relocate_section(TCCState *s1, Section *s, Section *sr)
}
}
#endif
#ifdef TCC_TARGET_RISCV64
dynarray_reset(&s1->pcrel_hi_entries, &s1->nb_pcrel_hi_entries);
#endif
}
/* relocate all sections */
@ -2091,7 +2076,7 @@ static void bind_exe_dynsyms(TCCState *s1, int is_PIE)
if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK ||
!strcmp(name, "_fp_hw")) {
} else {
tcc_error_noabort("unresolved reference to '%s'", name);
tcc_error_noabort("undefined symbol '%s'", name);
}
}
}
@ -2122,7 +2107,7 @@ static void bind_libs_dynsyms(TCCState *s1)
if (esym->st_shndx == SHN_UNDEF) {
/* weak symbols can stay undefined */
if (ELFW(ST_BIND)(esym->st_info) != STB_WEAK)
tcc_warning("unresolved dynamic reference to '%s'", name);
tcc_warning("undefined dynamic symbol '%s'", name);
}
}
}
@ -2296,7 +2281,7 @@ static int sort_sections(TCCState *s1, int *sec_order, struct dyn_inf *d)
if (k < 0x900)
++d->shnum;
if (k < 0x700) {
f = s->sh_flags & (SHF_ALLOC|SHF_WRITE|SHF_EXECINSTR);
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 */
@ -2355,18 +2340,6 @@ static int layout_sections(TCCState *s1, int *sec_order, struct dyn_inf *d)
++phnum;
if (d->roinf)
++phnum;
{
int has_tls = 0;
for (i = 1; i < s1->nb_sections; i++) {
s = s1->sections[i];
if (s->sh_flags & SHF_TLS) {
has_tls = 1;
break;
}
}
if (has_tls)
++phnum;
}
d->phnum = phnum;
d->phdr = tcc_mallocz(phnum * sizeof(ElfW(Phdr)));
@ -2443,6 +2416,10 @@ static int layout_sections(TCCState *s1, int *sec_order, struct dyn_inf *d)
ph->p_flags |= PF_W;
if (f & SHF_EXECINSTR)
ph->p_flags |= PF_X;
if (f & SHF_TLS) {
ph->p_type = PT_TLS;
ph->p_align = align + 1;
}
ph->p_offset = file_offset;
ph->p_vaddr = addr;
@ -2487,34 +2464,6 @@ static int layout_sections(TCCState *s1, int *sec_order, struct dyn_inf *d)
fill_phdr(++ph, PT_GNU_EH_FRAME, eh_frame_hdr_section);
if (d->roinf)
fill_phdr(++ph, PT_GNU_RELRO, d->roinf)->p_flags |= PF_W;
{
/* Create PT_TLS segment covering all TLS sections */
Section *tls_start_sec = NULL;
addr_t tls_start = 0, tls_end = 0;
for (i = 1; i < s1->nb_sections; i++) {
s = s1->sections[i];
if (s->sh_flags & SHF_TLS && s->sh_size) {
if (!tls_start_sec) {
tls_start_sec = s;
tls_start = s->sh_addr;
tls_end = s->sh_addr + s->sh_size;
} else {
if (s->sh_addr < tls_start)
tls_start = s->sh_addr;
if (s->sh_addr + s->sh_size > tls_end)
tls_end = s->sh_addr + s->sh_size;
}
}
}
if (tls_start_sec) {
ph = fill_phdr(++ph, PT_TLS, tls_start_sec);
ph->p_vaddr = tls_start;
ph->p_paddr = tls_start;
ph->p_filesz = tls_end - tls_start;
ph->p_memsz = ph->p_filesz;
ph->p_align = tls_start_sec->sh_addralign;
}
}
if (d->interp)
fill_phdr(&d->phdr[1], PT_INTERP, d->interp);
if (phfill) {
@ -2890,28 +2839,6 @@ static void create_arm_attribute_section(TCCState *s1)
}
#endif
#ifdef TCC_TARGET_RISCV64
static void create_riscv_attribute_section(TCCState *s1)
{
static const unsigned char riscv_attr[] = {
0x41, /* 'A' */
0x49, 0x00, 0x00, 0x00, /* total_len = 73 */
'r', 'i', 's', 'c', 'v', 0x00, /* "riscv\0" */
0x3a, 0x00, 0x00, 0x00, /* file_len = 58 */
0x05, /* Tag_RISCV_arch */
0x35, 0x00, 0x00, 0x00, /* isa_len = 53 */
'r','v','6','4','i','2','p','1','_','m','2','p','0','_',
'a','2','p','1','_','f','2','p','2','_','d','2','p','2','_',
'c','2','p','0','_','z','i','c','s','r','2','p','0','_',
'z','i','f','e','n','c','e','i','2','p','0', 0x00,
};
Section *attr = new_section(s1, ".riscv.attributes", SHT_RISCV_ATTRIBUTES, 0);
unsigned char *ptr = section_ptr_add(attr, sizeof(riscv_attr));
attr->sh_addralign = 1;
memcpy(ptr, riscv_attr, sizeof(riscv_attr));
}
#endif
#if TARGETOS_OpenBSD || TARGETOS_NetBSD || TARGETOS_FreeBSD
static void fill_bsd_note(Section *s, int type,
@ -3014,10 +2941,18 @@ static int elf_output_file(TCCState *s1, const char *filename)
if (!s1->static_link) {
if (file_type & TCC_OUTPUT_EXE) {
char *ptr;
/* allow override the dynamic loader */
const char *elfint = s1->elfint;
if (elfint == NULL)
elfint = getenv("LD_SO");
if (elfint == NULL)
elfint = DEFAULT_ELFINTERP(s1);
/* add interpreter section only if executable */
interp = new_section(s1, ".interp", SHT_PROGBITS, SHF_ALLOC);
interp->sh_addralign = 1;
put_elf_str(interp, s1->elfint);
ptr = section_ptr_add(interp, 1 + strlen(elfint));
strcpy(ptr, elfint);
dyninf.interp = interp;
}
@ -3168,13 +3103,10 @@ static void alloc_sec_names(TCCState *s1, int is_obj)
}
/* Output an elf .o file */
static int elf_output_obj(TCCState *s1, const char *filename)
LIBTCCAPI int elf_output_obj(TCCState *s1, const char *filename)
{
Section *s;
int i, ret, file_offset;
#ifdef TCC_TARGET_RISCV64
create_riscv_attribute_section(s1);
#endif
/* Allocate strings for section names */
alloc_sec_names(s1, 1);
file_offset = (sizeof (ElfW(Ehdr)) + 3) & -4;
@ -3371,8 +3303,6 @@ invalid:
continue;
if (sh->sh_type != s->sh_type
&& strcmp (s->name, ".eh_frame")
/* some crt1.o seem to have two ".note.GNU-stack" (SHT_NOTE & SHT_PROGBITS) */
&& strcmp (s->name, ".note.GNU-stack")
) {
tcc_error_noabort("section type conflict: %s %02x <> %02x", s->name, sh->sh_type, s->sh_type);
goto the_end;

241
tccgen.c
View File

@ -70,9 +70,8 @@ ST_DATA int nocode_wanted; /* no code generation wanted */
ST_DATA int global_expr; /* true if compound literals must be allocated globally (used during initializers parsing */
ST_DATA CType func_vt; /* current function return type (used by return instruction) */
ST_DATA int func_var; /* true if current function is variadic (used by return instruction) */
ST_DATA int func_vc; /* stack address for implicit struct return storage */
ST_DATA int func_ind; /* function start address */
static int func_old;
ST_DATA int func_vc;
ST_DATA int func_ind;
ST_DATA const char *funcname;
ST_DATA CType int_type, func_old_type, char_type, char_pointer_type;
static CString initstr;
@ -323,6 +322,12 @@ ST_FUNC int ieee_finite(double d)
return ((unsigned)((p[1] | 0x800fffff) + 1)) >> 31;
}
/* compiling intel long double natively */
#if (defined __i386__ || defined __x86_64__) \
&& (defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64)
# define TCC_IS_NATIVE_387
#endif
ST_FUNC void test_lvalue(void)
{
if (!(vtop->r & VT_LVAL))
@ -526,8 +531,6 @@ ST_FUNC void put_extern_sym2(Sym *sym, int sh_num,
sym_type = STT_NOTYPE;
if (IS_ASM_FUNC(t))
sym_type = STT_FUNC;
} else if (t & VT_TLS) {
sym_type = STT_TLS;
} else {
sym_type = STT_OBJECT;
}
@ -1382,7 +1385,7 @@ static Sym *external_sym(int v, CType *type, int r, AttributeDef *ad)
/* make sure that type->ref is on global stack */
move_ref_to_global(s);
/* put into local scope */
sym_copy(s, &local_stack);
s = sym_copy(s, &local_stack);
}
return s;
}
@ -1903,8 +1906,6 @@ ST_FUNC int gv(int rc)
#endif
bt = vtop->type.t & VT_BTYPE;
if (bt == VT_VOID || bt == VT_STRUCT) /* should not happen */
return vtop->r;
#ifdef TCC_TARGET_RISCV64
/* XXX mega hack */
@ -2520,17 +2521,11 @@ void gen_negf(int op)
operation. We implement this with bit manipulation and have
to do some type reinterpretation for this, which TCC can do
only via memory. */
int align, size, bt;
size = type_size(&vtop->type, &align);
bt = vtop->type.t & VT_BTYPE;
#if defined TCC_TARGET_X86_64 || defined TCC_TARGET_I386
/* sizeof long double is 12 or 16 here, but it's really the 80bit
extended float format. */
if (bt == VT_LDOUBLE)
size = 10;
#endif
if (nocode_wanted) /* save_reg() wont work */
goto gv2;
save_reg(gv(RC_TYPE(bt)));
vdup();
incr_bf_adr(size - 1);
@ -2539,8 +2534,6 @@ void gen_negf(int op)
gen_op('^');
vstore();
vpop();
gv2:
gv(RC_TYPE(bt)); /* -n is not a lvalue */
}
#endif
@ -2926,8 +2919,7 @@ static int combine_types(CType *dest, SValue *op1, SValue *op2, int op)
type.ref = NULL;
if (bt1 == VT_VOID || bt2 == VT_VOID) {
if (op != '?')
tcc_error("operation on void value");
ret = op == '?' ? 1 : 0;
/* NOTE: as an extension, we accept void on only one side */
type.t = VT_VOID;
} else if (bt1 == VT_PTR || bt2 == VT_PTR) {
@ -3105,7 +3097,9 @@ op_err:
#endif
type1 = vtop[-1].type;
vpush_type_size(pointed_type(&vtop[-1].type), &align);
vtop->type.t &= ~VT_UNSIGNED;
if (!(vtop[-1].type.t & VT_UNSIGNED)) {
gen_cast_s(VT_PTRDIFF_T);
}
gen_op('*');
#ifdef CONFIG_TCC_BCHECK
if (tcc_state->do_bounds_check && !CONST_WANTED) {
@ -3174,7 +3168,7 @@ op_err:
}
// Make sure that we have converted to an rvalue:
if (vtop->r & VT_LVAL)
gv(RC_TYPE(vtop->type.t));
gv(is_float(vtop->type.t & VT_BTYPE) ? RC_FLOAT : RC_INT);
}
#if defined TCC_TARGET_ARM64 || defined TCC_TARGET_RISCV64 || defined TCC_TARGET_ARM
@ -3279,15 +3273,20 @@ again:
df = is_float(dbt);
dbt_bt = dbt & VT_BTYPE;
sbt_bt = sbt & VT_BTYPE;
if (dbt_bt == VT_VOID) {
if (dbt_bt == VT_VOID)
goto done;
}
if (sbt_bt == VT_VOID) {
error:
cast_error(&vtop->type, type);
}
c = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST;
#if !defined TCC_IS_NATIVE && !defined TCC_IS_NATIVE_387
/* don't try to convert to ldouble when cross-compiling
(except when it's '0' which is needed for arm:gen_negf()) */
if (dbt_bt == VT_LDOUBLE && !nocode_wanted && (sf || vtop->c.i != 0))
c = 0;
#endif
if (c) {
/* constant case: we can do it now */
/* XXX: in ISOC, cannot do it if error in convert */
@ -3354,11 +3353,8 @@ error:
}
/* cannot generate code for global or static initializers */
if (nocode_wanted & DATA_ONLY_WANTED) {
if (df)
vtop->r = get_reg(RC_FLOAT); /* don't confuse backends */
if (nocode_wanted & DATA_ONLY_WANTED)
goto done;
}
/* non constant case: generate code */
if (dbt == VT_BOOL) {
@ -3467,11 +3463,11 @@ error:
if (ds >= ss)
goto done;
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 || defined TCC_TARGET_ARM64 || defined TCC_TARGET_RISCV64
if (ss == 4) {
gen_cvt_csti(dbt);
goto done;
}
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 || defined TCC_TARGET_ARM64
if (ss == 4) {
gen_cvt_csti(dbt);
goto done;
}
#endif
bits = (ss - ds) * 8;
/* for unsigned, gen_op will convert SAR to SHR */
@ -4749,8 +4745,6 @@ static int parse_btype(CType *type, AttributeDef *ad, int ignore_label)
} else {
if (bt != -1 || (st != -1 && u != VT_INT))
goto tmbt;
if ((t & VT_DEFSIGN) && (u == VT_VOID || u > VT_LLONG))
goto tmbt;
bt = u;
}
if (u != VT_INT)
@ -4933,12 +4927,7 @@ static int parse_btype(CType *type, AttributeDef *ad, int ignore_label)
}
goto basic_type2;
case TOK_THREAD_LOCAL:
case TOK___thread:
if (t & VT_TLS)
tcc_error("multiple thread-local storage specifiers");
t |= VT_TLS;
next();
break;
tcc_error("_Thread_local is not implemented");
default:
if (typespec_found)
goto the_end;
@ -5638,7 +5627,6 @@ ST_FUNC void unary(void)
case TOK_CLDOUBLE:
#ifdef TCC_USING_DOUBLE_FOR_LDOUBLE
t = VT_DOUBLE | VT_LONG;
tokc.d = tokc.ld;
#else
t = VT_LDOUBLE;
#endif
@ -5953,8 +5941,6 @@ ST_FUNC void unary(void)
vtop->type = type;
break;
}
#endif
#ifdef TCC_TARGET_ARM64
case TOK___arm64_clear_cache: {
parse_builtin_params(0, "ee");
gen_clear_cache();
@ -5963,17 +5949,6 @@ ST_FUNC void unary(void)
break;
}
#endif
#ifdef TCC_TARGET_RISCV64
case TOK___riscv64_clear_cache: {
parse_builtin_params(0, "ee");
vpop();
vpop();
gen_clear_cache();
vpushi(0);
vtop->type.t = VT_VOID;
break;
}
#endif
/* atomic operations */
case TOK___atomic_store:
@ -6129,7 +6104,6 @@ special_math_val:
tcc_error("'%s' undeclared", name);
/* for simple function calls, we tolerate undeclared
external reference to int() function */
if (!func_old)
tcc_warning_c(warn_implicit_function_declaration)(
"implicit declaration of function '%s'", name);
s = external_global_sym(t, &func_old_type);
@ -6184,8 +6158,7 @@ special_math_val:
gen_op('+');
/* change type to field type, and set to lvalue */
vtop->type = s->type;
if (qualifiers)
parse_btype_qualify(&vtop->type, qualifiers);
vtop->type.t |= qualifiers;
/* an array is never an lvalue */
if (!(vtop->type.t & VT_ARRAY)) {
vtop->r |= VT_LVAL;
@ -6679,7 +6652,7 @@ static void expr_cond(void)
/* keep structs lvalue by transforming `(expr ? a : b)` to `*(expr ? &a : &b)` so
that `(expr ? a : b).mem` does not error with "lvalue expected" */
islv = VT_STRUCT == (type.t & VT_BTYPE);
islv = (vtop->r & VT_LVAL) && (sv.r & VT_LVAL) && VT_STRUCT == (type.t & VT_BTYPE);
/* now we convert second operand */
if (c != 1) {
@ -6687,7 +6660,8 @@ static void expr_cond(void)
if (islv) {
mk_pointer(&vtop->type);
gaddrof();
}
} else if (VT_STRUCT == (vtop->type.t & VT_BTYPE))
gaddrof();
}
rc = RC_TYPE(type.t);
@ -6698,8 +6672,7 @@ static void expr_cond(void)
tt = r2 = 0;
if (c < 0) {
if (type.t != VT_VOID)
r2 = gv(rc);
r2 = gv(rc);
tt = gjmp(0);
}
gsym(u);
@ -6714,15 +6687,14 @@ static void expr_cond(void)
if (islv) {
mk_pointer(&vtop->type);
gaddrof();
}
} else if (VT_STRUCT == (vtop->type.t & VT_BTYPE))
gaddrof();
}
if (c < 0) {
if (type.t != VT_VOID) {
r1 = gv(rc);
move_reg(r2, r1, islv ? VT_PTR : type.t);
vtop->r = r2;
}
r1 = gv(rc);
move_reg(r2, r1, islv ? VT_PTR : type.t);
vtop->r = r2;
gsym(tt);
}
@ -6765,8 +6737,7 @@ ST_FUNC void gexpr(void)
/* make builtin_constant_p((1,2)) return 0 (like on gcc) */
if ((vtop->r & VT_VALMASK) == VT_CONST && nocode_wanted && !CONST_WANTED)
if (vtop->type.t != VT_VOID && (vtop->type.t & VT_BTYPE) != VT_STRUCT)
gv(RC_TYPE(vtop->type.t));
gv(RC_TYPE(vtop->type.t));
}
}
@ -6876,10 +6847,11 @@ static void check_func_return(void)
{
if ((func_vt.t & VT_BTYPE) == VT_VOID)
return;
if ((!strcmp(funcname, "main") || func_old)
if (!strcmp (funcname, "main")
&& (func_vt.t & VT_BTYPE) == VT_INT) {
/* main returns 0 by default */
vpushi(0);
gen_assign_cast(&func_vt);
gfunc_return(&func_vt);
} else {
tcc_warning("function might return no value: '%s'", funcname);
@ -7262,8 +7234,6 @@ again:
tcc_warning("void function returns a value");
vtop--;
}
} else if (b && func_old && (func_vt.t & VT_BTYPE) == VT_INT) {
vpushi(0);
} else if (b) {
tcc_warning("'return' with no value");
b = 0;
@ -7788,71 +7758,6 @@ static int decl_designator(init_params *p, CType *type, unsigned long c,
return al;
}
static void write_ldouble(unsigned char *d, void *s)
{
//printf("long double %Lf\n", *(long double*)s);
#ifdef TCC_CROSS_TEST
if (LDOUBLE_SIZE >= 10) {
double b = *(long double*)s;
s = &b;
#else
if (sizeof (long double) == 8 && LDOUBLE_SIZE >= 10) {
#endif
/* our 'long double' is a double really (_WIN32, __APPLE__) */
uint64_t m = *(uint64_t*)s;
int e = m >> 48;
int f = e >> 4 & 0x7FF;
m <<= 11;
if (0 == f) {
if (0 == m)
goto set;
for (f = 1; !(m & 1ULL<<63); --f)
m <<= 1;
}
if (f == 0x7ff)
f = 0x43FF;
e = (e & 0x8000) | (f + 0x3C00);
m |= 1ULL<<63;
set:
#if (defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64)
/* double -> extended */
write64le(d, m);
write16le(d+8, e);
#elif LDOUBLE_SIZE == 16
/* double -> quad */
write64le(d+6, m << 1);
write16le(d+14, e);
#endif
;
} else {
#if LDOUBLE_SIZE == 8
/* long double -> double */
double b = *(long double*)s;
memcpy(d, &b, 8);
#elif (__i386__ || __x86_64__) && (defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64)
/* extended -> extended */
memcpy(d, s, 10);
#elif (__i386__ || __x86_64__) && (defined TCC_TARGET_ARM64 || defined TCC_TARGET_RISCV64)
/* extended -> quad */
uint64_t m = *(uint64_t*)s;
int e = *(uint16_t*)((char*)s + 8);
write64le(d+6, m << 1);
write16le(d+14, e);
#elif (__aarch64__ || __riscv) && (defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64)
/* quad -> extended */
uint64_t m = read64le((char*)s + 6);
int e = read16le((char*)s + 14);
(e & 0x7fff) && (m & 1) && 0 == ++m && ++e;
write64le(d, m >> 1 | ((e & 0x7fff) ? 1ULL<<63 : 0));
write16le(d+8, e);
#else
/* unknown */
if (sizeof (long double) == LDOUBLE_SIZE)
memcpy(d, s, LDOUBLE_SIZE);
#endif
}
}
/* store a value or an expression directly in global data or in local array */
static void init_putv(init_params *p, CType *type, unsigned long c)
{
@ -7893,12 +7798,21 @@ static void init_putv(init_params *p, CType *type, unsigned long c)
ptr = sec->data + c;
val = vtop->c.i;
if ((vtop->r & (VT_SYM|VT_CONST)) == (VT_SYM|VT_CONST)
&& vtop->sym->v >= SYM_FIRST_ANOM
&& ((vtop->r & VT_LVAL) /* compound literal */
|| bt == VT_STRUCT /* designator */
)) {
/* memcpy stuff over. */
/* XXX: make code faster ? */
if ((vtop->r & (VT_SYM|VT_CONST)) == (VT_SYM|VT_CONST) &&
vtop->sym->v >= SYM_FIRST_ANOM &&
/* XXX This rejects compound literals like
'(void *){ptr}'. The problem is that '&sym' is
represented the same way, which would be ruled out
by the SYM_FIRST_ANOM check above, but also '"string"'
in 'char *p = "string"' is represented the same
with the type being VT_PTR and the symbol being an
anonymous one. That is, there's no difference in vtop
between '(void *){x}' and '&(void *){x}'. Ignore
pointer typed entities here. Hopefully no real code
will ever use compound literals with scalar type. */
(vtop->type.t & VT_BTYPE) != VT_PTR) {
/* These come from compound literals, memcpy stuff over. */
Section *ssec;
ElfSym *esym;
ElfW_Rel *rel;
@ -7965,7 +7879,34 @@ static void init_putv(init_params *p, CType *type, unsigned long c)
write64le(ptr, val);
break;
case VT_LDOUBLE:
write_ldouble(ptr, &vtop->c.ld);
#if defined TCC_IS_NATIVE_387
/* Host and target platform may be different but both have x87.
On windows, tcc does not use VT_LDOUBLE, except when it is a
cross compiler. In this case a mingw gcc as host compiler
comes here with 10-byte long doubles, while msvc or tcc won't.
tcc itself can still translate by asm.
In any case we avoid possibly random bytes 11 and 12.
*/
if (sizeof (long double) >= 10)
memcpy(ptr, &vtop->c.ld, 10);
#ifdef __TINYC__
else if (sizeof (long double) == sizeof (double))
__asm__("fldl %1\nfstpt %0\n" : "=m" (*ptr) : "m" (vtop->c.ld));
#endif
else
#endif
/* For other platforms it should work natively, but may not work
for cross compilers */
if (sizeof(long double) == LDOUBLE_SIZE)
memcpy(ptr, &vtop->c.ld, LDOUBLE_SIZE);
else if (sizeof(double) == LDOUBLE_SIZE)
*(double*)ptr = (double)vtop->c.ld;
else if (0 == memcmp(ptr, &vtop->c.ld, LDOUBLE_SIZE))
; /* nothing to do for 0.0 */
#ifndef TCC_CROSS_TEST
else
tcc_error("can't cross compile long double constants");
#endif
break;
#if PTR_SIZE == 8
@ -8123,8 +8064,6 @@ static void decl_initializer(init_params *p, CType *type, unsigned long c, int f
}
}
}
if (tok == ',' && !no_oblock) /* static const char s[] = { "123", }; */
next();
} else {
do_init_array:
@ -8397,12 +8336,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
CType *tp = type;
while ((tp->t & (VT_BTYPE|VT_ARRAY)) == (VT_PTR|VT_ARRAY))
tp = &tp->ref->type;
if (type->t & VT_TLS) {
if (has_init)
sec = tdata_section;
else
sec = tbss_section;
} else if (tp->t & VT_CONSTANT) {
if (tp->t & VT_CONSTANT) {
sec = rodata_section;
} else if (has_init) {
sec = data_section;
@ -8586,7 +8520,6 @@ static void gen_function(Sym *sym)
func_ind = ind;
func_vt = sym->type.ref->type;
func_var = sym->type.ref->f.func_type == FUNC_ELLIPSIS;
func_old = sym->type.ref->f.func_type == FUNC_OLD;
/* NOTE: we patch the symbol size later */
put_extern_sym(sym, cur_text_section, ind, 0);

View File

@ -19,7 +19,6 @@ int atoi(const char *nptr);
long int strtol(const char *nptr, char **endptr, int base);
unsigned long int strtoul(const char *nptr, char **endptr, int base);
void exit(int);
void *alloca(size_t);
/* stdio.h */
typedef struct __FILE FILE;
@ -40,7 +39,6 @@ int getchar(void);
char *gets(char *s);
int ungetc(int c, FILE *stream);
int fflush(FILE *stream);
int puts(const char *s);
int putchar (int c);
int printf(const char *format, ...);

View File

@ -702,7 +702,7 @@ static void check_relocs(TCCState *s1, struct macho *mo)
goti = tcc_realloc(goti, (mo->n_got + 1) * sizeof(*goti));
if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) {
if (sym->st_shndx == SHN_UNDEF)
tcc_error("unresolved local reference to '%s'",
tcc_error("undefined local symbo: '%s'",
(char *) symtab_section->link->data + sym->st_name);
goti[mo->n_got++] = INDIRECT_SYMBOL_LOCAL;
} else {
@ -859,7 +859,7 @@ static void check_relocs(TCCState *s1, struct macho *mo)
goti = tcc_realloc(goti, (mo->n_got + 1) * sizeof(*goti));
if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) {
if (sym->st_shndx == SHN_UNDEF)
tcc_error("unresolved local reference to '%s'",
tcc_error("undefined local symbo: '%s'",
(char *) symtab_section->link->data + sym->st_name);
goti[mo->n_got++] = INDIRECT_SYMBOL_LOCAL;
} else {
@ -1042,7 +1042,7 @@ static int check_symbols(TCCState *s1, struct macho *mo)
sym->st_shndx = SHN_FROMDLL;
continue;
}
tcc_error_noabort("unresolved reference to '%s'", name);
tcc_error_noabort("undefined symbol '%s'", name);
ret = -1;
}
}
@ -1058,7 +1058,6 @@ static void convert_symbol(TCCState *s1, struct macho *mo, struct nlist_64 *pn)
case STT_NOTYPE:
case STT_OBJECT:
case STT_FUNC:
case STT_TLS:
case STT_SECTION:
n.n_type = N_SECT;
break;

247
tccpe.c
View File

@ -27,8 +27,6 @@
#define stricmp strcasecmp
#define strnicmp strncasecmp
#include <sys/stat.h> /* chmod() */
#else
#include <process.h>
#endif
#ifdef TCC_TARGET_X86_64
@ -52,16 +50,6 @@
# define IMAGE_FILE_MACHINE 0x01C0
# define RSRC_RELTYPE 7 /* ??? (not tested) */
#elif defined TCC_TARGET_ARM64
# define ADDR3264 ULONGLONG
# define PE_IMAGE_REL IMAGE_REL_BASED_DIR64
# define REL_TYPE_DIRECT R_AARCH64_ABS64
# define R_XXX_THUNKFIX R_AARCH64_ABS64
# define R_XXX_RELATIVE R_AARCH64_RELATIVE
# define R_XXX_FUNCCALL R_AARCH64_CALL26
# define IMAGE_FILE_MACHINE 0xAA64
# define RSRC_RELTYPE 3
#elif defined TCC_TARGET_I386
# define ADDR3264 DWORD
# define PE_IMAGE_REL IMAGE_REL_BASED_HIGHLOW
@ -138,7 +126,7 @@ typedef struct _IMAGE_OPTIONAL_HEADER {
DWORD SizeOfUninitializedData;
DWORD AddressOfEntryPoint;
DWORD BaseOfCode;
#if !defined(TCC_TARGET_X86_64) && !defined(TCC_TARGET_ARM64)
#ifndef TCC_TARGET_X86_64
DWORD BaseOfData;
#endif
/* NT additional fields. */
@ -237,19 +225,6 @@ typedef struct _IMAGE_BASE_RELOCATION {
#define IMAGE_SIZEOF_BASE_RELOCATION 8
#ifndef IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA
#define IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA PE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA
#endif
#ifndef IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
#define IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE PE_DLLCHARACTERISTICS_DYNAMIC_BASE
#endif
#ifndef IMAGE_DLLCHARACTERISTICS_NX_COMPAT
#define IMAGE_DLLCHARACTERISTICS_NX_COMPAT PE_DLLCHARACTERISTICS_NX_COMPAT
#endif
#ifndef IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE
#define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE PE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE
#endif
#define IMAGE_REL_BASED_ABSOLUTE 0
#define IMAGE_REL_BASED_HIGH 1
#define IMAGE_REL_BASED_LOW 2
@ -275,24 +250,6 @@ typedef struct _IMAGE_BASE_RELOCATION {
#endif /* ndef IMAGE_NT_SIGNATURE */
/* ----------------------------------------------------------- */
static WORD pe_get_dll_characteristics(TCCState *s1)
{
unsigned v = 0;
#ifdef TCC_TARGET_ARM64
v = PE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA |
PE_DLLCHARACTERISTICS_DYNAMIC_BASE |
PE_DLLCHARACTERISTICS_NX_COMPAT |
PE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE;
#endif
v |= s1->pe_dll_characteristics;
v &= ~s1->pe_dll_characteristics_clear;
return v;
}
#ifndef IMAGE_FILE_MACHINE_ARM64
#define IMAGE_FILE_MACHINE_ARM64 0xAA64
#endif
#ifndef IMAGE_REL_BASED_DIR64
# define IMAGE_REL_BASED_DIR64 10
#endif
@ -304,7 +261,7 @@ struct pe_header
BYTE dosstub[0x40];
DWORD nt_sig;
IMAGE_FILE_HEADER filehdr;
#if defined(TCC_TARGET_X86_64) || defined(TCC_TARGET_ARM64)
#ifdef TCC_TARGET_X86_64
IMAGE_OPTIONAL_HEADER64 opthdr;
#else
#ifdef _WIN64
@ -580,55 +537,17 @@ static void pe_add_coffsym(struct pe_info *pe)
/* Run cv2pdb, available at https://github.com/rainers/cv2pdb. It reads
and strips the dwarf info and creates a <exename>.pdb file instead */
#ifndef _WIN32
static void pe_shell_quote(CString *cmd, const char *arg)
{
cstr_cat(cmd, "'", 1);
while (*arg) {
if (*arg == '\'')
cstr_cat(cmd, "'\\''", 4);
else
cstr_cat(cmd, arg, 1);
++arg;
}
cstr_cat(cmd, "'", 1);
}
#endif
static intptr_t pe_run_cv2pdb(const char *exename)
{
#ifdef _WIN32
const char *argv[] = { "cv2pdb.exe", exename, NULL };
return _spawnvp(_P_WAIT, "cv2pdb.exe", argv);
#else
CString cmd;
intptr_t ret;
cstr_new(&cmd);
cstr_cat(&cmd, "cv2pdb.exe ", -1);
pe_shell_quote(&cmd, exename);
cstr_ccat(&cmd, 0);
ret = system(cmd.data);
cstr_free(&cmd);
return ret;
#endif
}
static void pe_create_pdb(TCCState *s1, const char *exename)
{
size_t len = strlen(exename);
char *pdbfile = tcc_malloc(len + sizeof(".pdb"));
intptr_t r;
strcpy(pdbfile, exename);
strcpy(tcc_fileextension(pdbfile), ".pdb");
r = pe_run_cv2pdb(exename);
char buf[300]; int r;
snprintf(buf, sizeof buf, "cv2pdb.exe %s", exename);
r = system(buf);
strcpy(tcc_fileextension(strcpy(buf, exename)), ".pdb");
if (r) {
tcc_error_noabort("could not create '%s'\n(need working cv2pdb from https://github.com/rainers/cv2pdb)", pdbfile);
tcc_error_noabort("could not create '%s'\n(need working cv2pdb from https://github.com/rainers/cv2pdb)", buf);
} else if (s1->verbose) {
printf("<- %s\n", pdbfile);
printf("<- %s\n", buf);
}
tcc_free(pdbfile);
}
/*----------------------------------------------------------------------------*/
@ -686,15 +605,11 @@ static int pe_write(struct pe_info *pe)
0x00E0, /*WORD SizeOfOptionalHeader; */
0x010F, /*WORD Characteristics; */
#define CHARACTERISTICS_DLL 0x230F
#elif defined(TCC_TARGET_ARM64)
0x00F0, /*WORD SizeOfOptionalHeader; */
0x0022 /*WORD Characteristics; */
#define CHARACTERISTICS_DLL 0x2022
#endif
},{
/* IMAGE_OPTIONAL_HEADER opthdr */
/* Standard fields. */
#if defined(TCC_TARGET_X86_64) || defined(TCC_TARGET_ARM64)
#ifdef TCC_TARGET_X86_64
0x020B, /*WORD Magic; */
#else
0x010B, /*WORD Magic; */
@ -706,35 +621,23 @@ static int pe_write(struct pe_info *pe)
0x00000000, /*DWORD SizeOfUninitializedData; */
0x00000000, /*DWORD AddressOfEntryPoint; */
0x00000000, /*DWORD BaseOfCode; */
#if !defined(TCC_TARGET_X86_64) && !defined(TCC_TARGET_ARM64)
#ifndef TCC_TARGET_X86_64
0x00000000, /*DWORD BaseOfData; */
#endif
/* NT additional fields. */
#if defined(TCC_TARGET_ARM)
0x00100000, /*DWORD ImageBase; */
#elif defined(TCC_TARGET_ARM64)
0x140000000ULL, /*ULONGLONG ImageBase; */
#else
0x00400000, /*DWORD ImageBase; */
#endif
0x00001000, /*DWORD SectionAlignment; */
0x00000200, /*DWORD FileAlignment; */
#if defined(TCC_TARGET_ARM64)
0x0006, /*WORD MajorOperatingSystemVersion; */
0x0002, /*WORD MinorOperatingSystemVersion; */
#else
0x0004, /*WORD MajorOperatingSystemVersion; */
0x0000, /*WORD MinorOperatingSystemVersion; */
#endif
0x0000, /*WORD MajorImageVersion; */
0x0000, /*WORD MinorImageVersion; */
#if defined(TCC_TARGET_ARM64)
0x0006, /*WORD MajorSubsystemVersion; */
0x0002, /*WORD MinorSubsystemVersion; */
#else
0x0004, /*WORD MajorSubsystemVersion; */
0x0000, /*WORD MinorSubsystemVersion; */
#endif
0x00000000, /*DWORD Win32VersionValue; */
0x00000000, /*DWORD SizeOfImage; */
0x00000200, /*DWORD SizeOfHeaders; */
@ -799,7 +702,7 @@ static int pe_write(struct pe_info *pe)
break;
case sec_data:
#if !defined(TCC_TARGET_X86_64) && !defined(TCC_TARGET_ARM64)
#ifndef TCC_TARGET_X86_64
if (!pe_header.opthdr.BaseOfData)
pe_header.opthdr.BaseOfData = addr;
#endif
@ -861,14 +764,11 @@ static int pe_write(struct pe_info *pe)
pe_header.opthdr.SizeOfHeaders = pe->sizeofheaders;
pe_header.opthdr.ImageBase = pe->imagebase;
pe_header.opthdr.Subsystem = pe->subsystem;
pe_header.opthdr.DllCharacteristics = pe_get_dll_characteristics(s1);
if (s1->pe_stack_size)
pe_header.opthdr.SizeOfStackReserve = s1->pe_stack_size;
if (PE_DLL == pe->type)
pe_header.filehdr.Characteristics = CHARACTERISTICS_DLL;
pe_header.filehdr.Characteristics |= s1->pe_characteristics;
if (pe->reloc)
pe_header.filehdr.Characteristics &= ~PE_IMAGE_FILE_RELOCS_STRIPPED;
if (pe->coffsym) {
pe_add_coffsym(pe);
@ -1291,8 +1191,7 @@ static int pe_assign_addresses (struct pe_info *pe)
Section *s;
TCCState *s1 = pe->s1;
if (PE_DLL == pe->type ||
(pe_get_dll_characteristics(s1) & PE_DLLCHARACTERISTICS_DYNAMIC_BASE))
if (PE_DLL == pe->type)
pe->reloc = new_section(s1, ".reloc", SHT_PROGBITS, 0);
//pe->thunk = new_section(s1, ".iedat", SHT_PROGBITS, SHF_ALLOC);
@ -1481,18 +1380,6 @@ static int pe_check_symbols(struct pe_info *pe)
write32le(p + 4, 0xE59CF000); // arm code ldr pc, [ip]
put_elf_reloc(symtab_section, text_section,
offset + 8, R_XXX_THUNKFIX, is->iat_index); // offset to IAT position
#elif defined(TCC_TARGET_ARM64)
p = section_ptr_add(text_section, 24);
/* ldr x16, [pc, #16] */
write32le(p + 0, 0x58000090);
/* ldr x16, [x16] */
write32le(p + 4, 0xf9400210);
/* br x16 */
write32le(p + 8, 0xd61f0200);
/* nop for 8-byte literal alignment */
write32le(p + 12, 0xd503201f);
put_elf_reloc(symtab_section, text_section,
offset + 16, R_XXX_THUNKFIX, is->iat_index);
#else
p = section_ptr_add(text_section, 8);
write16le(p, 0x25FF);
@ -1724,7 +1611,7 @@ static int get_dllexports(int fd, char **pp)
if (IMAGE_DIRECTORY_ENTRY_EXPORT >= oh.NumberOfRvaAndSizes)
goto the_end_0;
addr = oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
} else if (ih.Machine == 0x8664 || ih.Machine == IMAGE_FILE_MACHINE_ARM64) {
} else if (ih.Machine == 0x8664) {
IMAGE_OPTIONAL_HEADER64 oh;
sec_hdroffset = opt_hdroffset + sizeof oh;
if (!read_mem(fd, opt_hdroffset, &oh, sizeof oh))
@ -1947,7 +1834,7 @@ PUB_FUNC int tcc_get_dllexports(const char *filename, char **pp)
/* ------------------------------------------------------------- */
#ifdef TCC_TARGET_X86_64
static unsigned pe_add_unwind_info(TCCState *s1)
static unsigned pe_add_uwwind_info(TCCState *s1)
{
if (NULL == s1->uw_pdata) {
s1->uw_pdata = find_section(s1, ".pdata");
@ -1992,7 +1879,7 @@ ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack)
DWORD UnwindData;
} *p;
d = pe_add_unwind_info(s1);
d = pe_add_uwwind_info(s1);
pd = s1->uw_pdata;
o = pd->data_offset;
p = section_ptr_add(pd, sizeof *p);
@ -2006,85 +1893,9 @@ ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack)
for (n = o + sizeof *p; o < n; o += sizeof p->BeginAddress)
put_elf_reloc(symtab_section, pd, o, R_XXX_RELATIVE, s1->uw_sym);
}
#elif defined(TCC_TARGET_ARM64)
/* ARM64 unwind codes:
save_fplr_x: 10iiiiii - stp x29,lr,[sp,#-(i+1)*8]!
set_fp: 11100001 - mov x29,sp
alloc_s: 000iiiii - sub sp,sp,#i*16 (up to 496 bytes)
alloc_m: 11000iii xxxxxxxx - sub sp,sp,#X*16 (up to 32KB)
end: 11100100 - end of unwind codes
*/
static Section *pe_add_unwind_info(TCCState *s1)
{
Section *s;
if (NULL == s1->uw_pdata) {
s1->uw_pdata = find_section(s1, ".pdata");
s1->uw_pdata->sh_addralign = 4;
}
s = find_section(s1, ".xdata");
s->sh_addralign = 4;
if (0 == s1->uw_sym)
s1->uw_sym = put_elf_sym(symtab_section, 0, 0, 0, 0,
text_section->sh_num, ".uw_text_base");
if (0 == s1->uw_xsym)
s1->uw_xsym = put_elf_sym(symtab_section, 0, 0, 0, 0,
s->sh_num, ".uw_base");
return s;
}
ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack)
{
TCCState *s1 = tcc_state;
Section *pd, *xd;
unsigned o, d, code_bytes, func_len;
unsigned char *q;
uint32_t header;
struct /* _RUNTIME_FUNCTION */ {
DWORD BeginAddress;
DWORD UnwindData;
} *p;
int epilog;
xd = pe_add_unwind_info(s1);
pd = s1->uw_pdata;
func_len = (end - start) >> 2;
code_bytes = 0;
epilog = code_bytes;
code_bytes += 3; /* set_fp, save_fplr_x, end */
code_bytes = (code_bytes + 3) & ~3;
section_ptr_add(xd, -xd->data_offset & 3);
d = xd->data_offset;
q = section_ptr_add(xd, 4 + code_bytes);
/* Full ARM64 xdata header: E=1 with one epilog and no exception handler. */
header = (func_len & 0x3ffff)
| 1 << 21
| (epilog & 0x1F) << 22
| (code_bytes >> 2) << 27
;
write32le(q, header);
q += 4;
*q++ = 0xE1; /* set_fp */
*q++ = 0x9B; /* save_fplr_x: stp x29,lr,[sp,#-224]! */
*q++ = 0xE4; /* end */
while ((unsigned)(q - (xd->data + d + 4)) < code_bytes)
*q++ = 0xE3; /* nop padding */
o = pd->data_offset;
p = section_ptr_add(pd, sizeof *p);
p->BeginAddress = start;
p->UnwindData = d;
put_elf_reloc(symtab_section, pd, o, R_XXX_RELATIVE, s1->uw_sym);
put_elf_reloc(symtab_section, pd, o + 4, R_XXX_RELATIVE, s1->uw_xsym);
}
#endif
/* ------------------------------------------------------------- */
#if defined(TCC_TARGET_X86_64) || defined(TCC_TARGET_ARM64)
#ifdef TCC_TARGET_X86_64
#define PE_STDSYM(n,s) n
#else
#define PE_STDSYM(n,s) "_" n s
@ -2180,7 +1991,7 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
ST_FUNC int pe_setsubsy(TCCState *s1, const char *arg)
{
static const struct subsy { const char* p; int v; } x[] = {
#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64) || defined(TCC_TARGET_ARM64)
#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64)
{ "native", 1 },
{ "gui", 2 },
{ "windows", 2 },
@ -2209,16 +2020,10 @@ static void pe_set_options(TCCState * s1, struct pe_info *pe)
{
if (PE_DLL == pe->type) {
/* XXX: check if is correct for arm-pe target */
#if defined(TCC_TARGET_ARM64)
pe->imagebase = 0x180000000ULL;
#else
pe->imagebase = 0x10000000;
#endif
} else {
#if defined(TCC_TARGET_ARM)
pe->imagebase = 0x00010000;
#elif defined(TCC_TARGET_ARM64)
pe->imagebase = 0x140000000ULL;
#else
pe->imagebase = 0x00400000;
#endif
@ -2275,33 +2080,29 @@ ST_FUNC int pe_output_file(TCCState *s1, const char *filename)
resolve_common_syms(s1);
pe_set_options(s1, &pe);
pe_check_symbols(&pe);
if (s1->nb_errors)
goto done;
if (filename) {
;
else if (filename) {
pe_assign_addresses(&pe);
relocate_syms(s1, s1->symtab, 0);
if (s1->nb_errors)
goto done;
s1->pe_imagebase = pe.imagebase;
relocate_sections(s1);
pe.start_addr = (DWORD)
(get_sym_addr(s1, pe.start_symbol, 1, 1) - pe.imagebase);
if (s1->nb_errors)
goto done;
pe_write(&pe);
if (0 == s1->nb_errors)
pe_write(&pe);
dynarray_reset(&pe.sec_info, &pe.sec_count);
} else {
/* -run */
#ifdef TCC_IS_NATIVE
pe.thunk = data_section;
pe_build_imports(&pe);
s1->run_main = pe.start_symbol;
#if defined(TCC_TARGET_X86_64) || defined(TCC_TARGET_ARM64)
#ifdef TCC_TARGET_X86_64
s1->uw_pdata = find_section(s1, ".pdata");
#endif
#endif
}
done:
dynarray_reset(&pe.sec_info, &pe.sec_count);
pe_free_imports(&pe);
#if PE_PRINT_SECTIONS
if (g_debug & 8)

95
tccpp.c
View File

@ -942,11 +942,11 @@ redo_start:
else if (parse_flags & PARSE_FLAG_ASM_FILE)
p = parse_line_comment(p - 1);
}
#if !defined(TCC_TARGET_ARM) && !defined(TCC_TARGET_ARM64)
#if !defined(TCC_TARGET_ARM)
else if (parse_flags & PARSE_FLAG_ASM_FILE)
p = parse_line_comment(p - 1);
#else
/* ARM/ARM64 assembly uses '#' for constants */
/* ARM assembly uses '#' for constants */
#endif
break;
_default:
@ -987,7 +987,11 @@ static inline int tok_size(const int *p)
case TOK_CULLONG:
return 1 + 2;
case TOK_CLDOUBLE:
return 1 + LDOUBLE_WORDS;
#ifdef TCC_USING_DOUBLE_FOR_LDOUBLE
return 1 + 8 / 4;
#else
return 1 + LDOUBLE_SIZE / 4;
#endif
default:
return 1 + 0;
}
@ -1126,12 +1130,22 @@ static void tok_str_add2(TokenString *s, int t, CValue *cv)
str[len++] = cv->tab[1];
break;
case TOK_CLDOUBLE:
#if LDOUBLE_SIZE == 8 || defined TCC_USING_DOUBLE_FOR_LDOUBLE
str[len++] = cv->tab[0];
str[len++] = cv->tab[1];
#elif LDOUBLE_SIZE == 12
str[len++] = cv->tab[0];
str[len++] = cv->tab[1];
str[len++] = cv->tab[2];
#elif LDOUBLE_SIZE == 16
str[len++] = cv->tab[0];
str[len++] = cv->tab[1];
if (LDOUBLE_WORDS >= 3)
str[len++] = cv->tab[2];
if (LDOUBLE_WORDS >= 4)
str[len++] = cv->tab[3];
#else
#error add long double size support
#endif
break;
default:
break;
}
@ -1205,7 +1219,15 @@ static inline void tok_get(int *t, const int **pp, CValue *cv)
n = 2;
goto copy;
case TOK_CLDOUBLE:
n = LDOUBLE_WORDS;
#if LDOUBLE_SIZE == 8 || defined TCC_USING_DOUBLE_FOR_LDOUBLE
n = 2;
#elif LDOUBLE_SIZE == 12
n = 3;
#elif LDOUBLE_SIZE == 16
n = 4;
#else
# error add long double size support
#endif
copy:
do
*tab++ = *p++;
@ -2212,8 +2234,13 @@ static void parse_string(const char *s, int len)
}
}
#ifdef TCC_USING_DOUBLE_FOR_LDOUBLE
/* we use 64 bit (52 needed) numbers */
#define BN_SIZE 2
#else
/* we use 128 bit (64/112 needed) numbers */
#define BN_SIZE 4
#endif
/* bn = (bn << shift) | or_val */
static int bn_lshift(unsigned int *bn, int shift, int or_val)
@ -2245,7 +2272,11 @@ static void parse_number(const char *p)
int b, t, shift, frac_bits, s, exp_val, ch;
char *q;
unsigned int bn[BN_SIZE];
#ifdef TCC_USING_DOUBLE_FOR_LDOUBLE
double d;
#else
long double d;
#endif
/* number */
q = token_buf;
@ -2357,14 +2388,19 @@ static void parse_number(const char *p)
ch = *p++;
}
exp_val = exp_val * s;
/* now we can generate the number */
/* XXX: should patch directly float number */
#ifdef TCC_USING_DOUBLE_FOR_LDOUBLE
d = (double)bn[1] * 4294967296.0 + (double)bn[0];
d = ldexp(d, exp_val - frac_bits);
#else
d = (long double)bn[3] * 79228162514264337593543950336.0L +
(long double)bn[2] * 18446744073709551616.0L +
(long double)bn[1] * 4294967296.0L +
(long double)bn[0];
d = ldexpl(d, exp_val - frac_bits);
#endif
t = toup(ch);
if (t == 'F') {
ch = *p++;
@ -2374,7 +2410,11 @@ static void parse_number(const char *p)
} else if (t == 'L') {
ch = *p++;
tok = TOK_CLDOUBLE;
#ifdef TCC_USING_DOUBLE_FOR_LDOUBLE
tokc.d = d;
#else
tokc.ld = d;
#endif
} else {
tok = TOK_CDOUBLE;
tokc.d = (double)d;
@ -2424,14 +2464,18 @@ static void parse_number(const char *p)
} else if (t == 'L') {
ch = *p++;
tok = TOK_CLDOUBLE;
#ifdef TCC_USING_DOUBLE_FOR_LDOUBLE
tokc.d = strtod(token_buf, NULL);
#else
tokc.ld = strtold(token_buf, NULL);
#endif
} else {
tok = TOK_CDOUBLE;
tokc.d = strtod(token_buf, NULL);
}
}
} else {
unsigned long long n, n1;
unsigned long long n = 0, n1 = 0;
int lcount, ucount, ov = 0;
const char *p1;
@ -2442,7 +2486,6 @@ static void parse_number(const char *p)
b = 8;
q++;
}
n = 0;
while(1) {
t = *q++;
/* no need for checks except for base 10 / 8 errors */
@ -2456,11 +2499,14 @@ static void parse_number(const char *p)
t = t - '0';
if (t >= b)
tcc_error("invalid digit");
n1 = n;
n = n * b + t;
/* detect overflow */
if (n1 >= 0x1000000000000000ULL && n / b != n1)
ov = 1;
if (!ov) {
/* detect overflow */
if (n1 >= 0x1000000000000000ULL && n / b != n1)
ov = 1;
else
n1 = n;
}
}
/* Determine the characteristics (unsigned and/or 64bit) the type of
@ -2510,7 +2556,26 @@ static void parse_number(const char *p)
}
if (ov)
tcc_warning("integer constant overflow");
/* Give a warning with values in case of an overflow. This helps to
spot the 0 too much in 0x8000'0000'0000'0000'0. It may even be
better to use a 0x8000'0000'0000'0000 from n1 instead of a 0 from
n after the overflow. This is at least undefined behavior.
The C99 to C23 standards state:
"Each constant shall have a type and the value of a constant
shall be in the range of representable values for its type."
"If an integer constant cannot be represented by any type ...,
then the integer constant has no type."
The C++ standards state:
"A program is ill-formed if one of its translation units contains
an integer-literal that cannot be represented by any of the
allowed types." */
tcc_warning(
b == 8
? "integer constant overflow, using %#llo; did you mean %#llo?"
: b == 10
? "integer constant overflow, using %llu, did you mean %llu?"
: "integer constant overflow, using %#llx; did you mean %#llx?",
n, n1);
tok = TOK_CINT;
if (lcount) {
@ -2634,7 +2699,7 @@ maybe_newline:
p++;
tok = TOK_TWOSHARPS;
} else {
#if !defined(TCC_TARGET_ARM) && !defined(TCC_TARGET_ARM64)
#if !defined(TCC_TARGET_ARM)
if (parse_flags & PARSE_FLAG_ASM_FILE) {
p = parse_line_comment(p - 1);
goto redo_no_start;

View File

@ -130,15 +130,8 @@ static int rt_mem(TCCState *s1, int size)
//printf("map %p %p %p\n", ptr, prw, (void*)ptr_diff);
size *= 2;
#else
# ifdef _WIN32
/* Generated code is page-protected below; avoid changing CRT heap pages. */
ptr = VirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
# else
ptr = tcc_malloc(size += PAGESIZE); /* one extra page to align malloc memory */
# endif
#endif
if (!ptr)
return tcc_error_noabort("tccrun: could not allocate memory");
s1->run_ptr = ptr;
s1->run_size = size;
return ptr_diff;
@ -195,20 +188,12 @@ ST_FUNC void tcc_run_free(TCCState *s1)
#ifdef CONFIG_SELINUX
munmap(ptr, size);
#else
# ifdef _WIN32
(void)size;
# ifdef _WIN64
win64_del_function_table(s1->run_function_table);
# endif
VirtualFree(ptr, 0, MEM_RELEASE);
# else
/* unprotect memory to make it usable for malloc again */
protect_pages((void*)PAGEALIGN(ptr), size - PAGESIZE, 2 /*rw*/);
# ifdef _WIN64
win64_del_function_table(s1->run_function_table);
# endif
tcc_free(ptr);
# endif
#endif
}
@ -302,7 +287,7 @@ static void cleanup_sections(TCCState *s1)
do {
for (i = --f; i < p->nb_secs; i++) {
Section *s = p->secs[i];
if (s == s1->symtab || s == s1->symtab->link || s == s1->symtab->hash) {
if (s1->do_debug || s == s1->symtab || s == s1->symtab->link || s == s1->symtab->hash) {
s->data = tcc_realloc(s->data, s->data_allocated = s->data_offset);
} else {
free_section(s), tcc_free(s), p->secs[i] = NULL;
@ -314,10 +299,11 @@ static void cleanup_sections(TCCState *s1)
/* ------------------------------------------------------------- */
/* 0 = .text rwx other rw (memory >= 2 pages a 4096 bytes) */
/* 1 = .text rx other rw (memory >= 3 pages) */
/* 2 = .text rx .rdata ro .data/.bss rw (memory >= 4 pages) */
/* 2 = .debug .debug ro (optional) */
/* 3 = .text rx .rdata ro .data/.bss rw (memory >= 4 pages) */
/* Some targets implement secutiry options that do not allow write in
executable code. These targets need CONFIG_RUNMEM_RO=1.
executable code. These targets need CONFIG_RUNMEM_RO=2.
The disadvantage of this is that it requires a little bit more memory. */
#ifndef CONFIG_RUNMEM_RO
@ -358,12 +344,13 @@ redo:
if (copy == 3)
return 0;
for (k = 0; k < 3; ++k) { /* 0:rx, 1:ro, 2:rw sections */
for (k = 0; k < 4; ++k) { /* 0:rx, 1:ro, 2:ro debug , 3:rw sections */
n = 0; addr = 0;
for(i = 1; i < s1->nb_sections; i++) {
static const char shf[] = {
SHF_ALLOC|SHF_EXECINSTR, SHF_ALLOC, SHF_ALLOC|SHF_WRITE
SHF_ALLOC|SHF_EXECINSTR, SHF_ALLOC, 0, SHF_ALLOC|SHF_WRITE
};
if (k == 2 && s1->do_debug == 0) continue;
s = s1->sections[i];
if (shf[k] != (s->sh_flags & (SHF_ALLOC|SHF_WRITE|SHF_EXECINSTR)))
continue;
@ -427,11 +414,7 @@ redo:
}
if (protect_pages((void*)addr, n, f) < 0)
return tcc_error_noabort(
#ifdef _WIN32
"VirtualProtect failed");
#else
"mprotect failed (did you mean to configure --with-selinux?)");
#endif
}
}
@ -453,8 +436,6 @@ redo:
/* relocate symbols */
relocate_syms(s1, s1->symtab, 1);
if (s1->nb_errors)
goto redo;
/* relocate sections */
#ifdef TCC_TARGET_PE
s1->pe_imagebase = mem;
@ -490,7 +471,7 @@ static int protect_pages(void *ptr, unsigned long length, int mode)
if (mprotect(ptr, length, protect[mode]))
return -1;
/* XXX: BSD sometimes dump core with bad system call */
# if (defined TCC_TARGET_ARM && !TARGETOS_BSD) || defined TCC_TARGET_ARM64 || defined TCC_TARGET_RISCV64
# if (defined TCC_TARGET_ARM && !TARGETOS_BSD) || defined TCC_TARGET_ARM64
if (mode == 0 || mode == 3) {
void __clear_cache(void *beginning, void *end);
__clear_cache(ptr, (char *)ptr + length);
@ -506,14 +487,11 @@ static void *win64_add_function_table(TCCState *s1)
void *p = NULL;
if (s1->uw_pdata) {
p = (void*)s1->uw_pdata->sh_addr;
if (!RtlAddFunctionTable(
RtlAddFunctionTable(
(RUNTIME_FUNCTION*)p,
s1->uw_pdata->data_offset / sizeof (RUNTIME_FUNCTION),
s1->pe_imagebase
)) {
tcc_error_noabort("RtlAddFunctionTable failed");
p = NULL;
}
);
s1->uw_pdata = NULL;
}
return p;
@ -1223,11 +1201,7 @@ static int rt_error(rt_frame *f, const char *fmt, ...)
/* translate from ucontext_t* to internal rt_context * */
static void rt_getcontext(ucontext_t *uc, rt_frame *rc)
{
#if defined _WIN64 && defined __aarch64__
rc->ip = uc->Pc; /* Program Counter */
rc->fp = uc->Fp; /* Frame Pointer (X29) */
rc->sp = uc->Sp; /* Stack Pointer (X30 is LR, but SP is separate) */
#elif defined _WIN64
#if defined _WIN64
rc->ip = uc->Rip;
rc->fp = uc->Rbp;
rc->sp = uc->Rsp;
@ -1426,11 +1400,7 @@ static long __stdcall cpu_exception_handler(EXCEPTION_POINTERS *ex_info)
/* Generate a stack backtrace when a CPU exception occurs. */
static void set_exception_handler(void)
{
#ifdef _WIN64
AddVectoredExceptionHandler(1, cpu_exception_handler);
#else
SetUnhandledExceptionFilter(cpu_exception_handler);
#endif
}
#endif

View File

@ -39,7 +39,6 @@
DEF(TOK_RESTRICT3, "__restrict__")
DEF(TOK_EXTENSION, "__extension__") /* gcc keyword */
DEF(TOK_THREAD_LOCAL, "_Thread_local") /* C11 thread-local storage */
DEF(TOK___thread, "__thread") /* GCC thread-local storage extension */
DEF(TOK_GENERIC, "_Generic")
DEF(TOK_STATIC_ASSERT, "_Static_assert")
@ -307,13 +306,8 @@
#if defined TCC_TARGET_PE
DEF(TOK___chkstk, "__chkstk")
#endif
#ifdef TCC_TARGET_ARM64
DEF(TOK___arm64_clear_cache, "__arm64_clear_cache")
#endif
#ifdef TCC_TARGET_RISCV64
DEF(TOK___riscv64_clear_cache, "__riscv64_clear_cache")
#endif
#if defined TCC_TARGET_ARM64 || defined TCC_TARGET_RISCV64
DEF(TOK___arm64_clear_cache, "__arm64_clear_cache")
DEF(TOK___addtf3, "__addtf3")
DEF(TOK___subtf3, "__subtf3")
DEF(TOK___multf3, "__multf3")
@ -408,13 +402,12 @@
DEF_ASMDIR(endr)
DEF_ASMDIR(org)
DEF_ASMDIR(quad)
#if PTR_SIZE == 4
#if defined(TCC_TARGET_I386)
DEF_ASMDIR(code16)
DEF_ASMDIR(code32)
#else
#elif defined(TCC_TARGET_X86_64)
DEF_ASMDIR(code64)
#endif
#if defined(TCC_TARGET_RISCV64)
#elif defined(TCC_TARGET_RISCV64)
DEF_ASMDIR(option)
#endif
DEF_ASMDIR(short)
@ -428,14 +421,10 @@
#include "i386-tok.h"
#endif
#if defined TCC_TARGET_ARM
#if defined TCC_TARGET_ARM || defined TCC_TARGET_ARM64
#include "arm-tok.h"
#endif
#if defined TCC_TARGET_ARM64
#include "arm64-tok.h"
#endif
#if defined TCC_TARGET_RISCV64
#include "riscv64-tok.h"
#endif

View File

@ -13,6 +13,7 @@ TESTS = \
hello-run \
libtest \
libtest_mt \
libtest_xor_rex \
test3 \
abitest \
asm-c-connect-test \
@ -40,6 +41,9 @@ endif
ifeq (,$(filter i386 x86_64,$(ARCH)))
TESTS := $(filter-out asm-c-connect-test,$(TESTS))
endif
ifeq (,$(filter x86_64,$(ARCH)))
TESTS := $(filter-out libtest_xor_rex,$(TESTS))
endif
ifeq ($(OS),Windows_NT) # for libtcc_test to find libtcc.dll
PATH := $(CURDIR)/$(TOP)$(if $(findstring ;,$(PATH)),;,:)$(PATH)
endif
@ -72,9 +76,9 @@ endif
RUN_TCC = -run $(TOPSRC)/tcc.c $(TCCFLAGS)
DISAS = objdump -d
ifdef CONFIG_OSX
DUMPTCC = (set -x; $(TCC_LOCAL) -vv; otool -L $(TCC_LOCAL); exit 1)
DUMPTCC = (set -x; $(TOP)/tcc -vv; otool -L $(TOP)/tcc; exit 1)
else
DUMPTCC = (set -x; $(TCC_LOCAL) -vv; ldd $(TCC_LOCAL); exit 1)
DUMPTCC = (set -x; $(TOP)/tcc -vv; ldd $(TOP)/tcc; exit 1)
endif
all test :
@ -82,7 +86,6 @@ all test :
@$(TCC_LOCAL) -v
@$(MAKE) --no-print-directory -s clean
@$(MAKE) --no-print-directory -s -r _all
@echo ------- ALL TESTS PASSED --------
_all : $(TESTS)
@ -104,14 +107,17 @@ libtcc_test$(EXESUF): libtcc_test.c
libtcc_test_mt$(EXESUF): libtcc_test_mt.c
$(CC) -o $@ $< $(CFLAGS) $(-LTCC) $(LIBS)
libtcc_test_xor_rex$(EXESUF): libtcc_test_xor_rex.c
$(CC) -o $@ $< $(CFLAGS) $(-LTCC) $(LIBS)
%-dir:
@echo ------------ $@ ------------
$(MAKE) -k -C $*
# test.ref - generate using cc
test.ref: tcctest.c
$(CC) -o tcctest.gcc$(EXESUF) $< $(CFLAGS) -w -O0 -std=gnu99 -fno-omit-frame-pointer
./tcctest.gcc$(EXESUF) > $@
$(CC) -o tcctest.gcc $< $(CFLAGS) -w -O0 -std=gnu99 -fno-omit-frame-pointer
./tcctest.gcc > $@
# auto test
test1 test1b: tcctest.c test.ref
@ -310,7 +316,6 @@ CROSS-TGTS = \
arm-NetBSD \
arm-wince \
arm64 \
arm64-win32 \
arm64-osx \
arm64-FreeBSD \
arm64-NetBSD \

58
tests/libtcc_debug.c Normal file
View File

@ -0,0 +1,58 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "libtcc.h"
static const char program[] =
"#include <stdio.h>\n"
"int fib(int n)\n"
"{\n"
" if (n <= 2)\n"
" return 1;\n"
" else\n"
" return fib(n-1) + fib(n-2);\n"
"}\n"
"int tst(void)\n"
"{\n"
" int i;\n"
" for (i = 2; i < 20; i++)\n"
" printf(\"%d \", fib(i));\n"
" printf(\"\\n\");\n"
" return 0;\n"
"}\n";
void handle_error(void *opaque, const char *msg)
{
fprintf(opaque, "%s\n", msg);
}
int
main(void)
{
int (*func)(void);
TCCState *s = tcc_new();
if (!s) {
fprintf(stderr, __FILE__ ": could not create tcc state\n");
return 1;
}
#if 1
/* If -g option is not set the debugging files tst.c en tst.o will
not be created. */
tcc_set_options(s, "-g");
#endif
tcc_set_error_func(s, stdout, handle_error);
tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
if (tcc_compile_string_file(s, program, "tst.c") == -1)
return 1;
if (tcc_relocate(s) < 0)
return 1;
elf_output_obj(s, "tst.o");
/* set breakpoint on next line. and load symbol file with
gdb command add-symbol-file.
Then set breakpoint on tst and continue. */
if ((func = tcc_get_symbol(s, "tst")))
func();
tcc_delete(s);
return 0;
}

View File

@ -162,7 +162,6 @@ void *reloc_state(TCCState *s, const char *entry)
{
void *func;
tcc_add_symbol(s, "add", add);
tcc_add_symbol(s, "printf", printf);
if (tcc_relocate(s) < 0) {
fprintf(stderr, __FILE__ ": could not relocate tcc state.\n");
return NULL;
@ -338,16 +337,8 @@ int main(int argc, char **argv)
#else
#include <tcclib.h>
#ifdef _WIN32
# ifndef _WIN64
__declspec(stdcall)
# endif
void Sleep(unsigned);
# define sleep_ms Sleep
#else
int usleep(unsigned long);
# define sleep_ms(x) usleep((x)*1000);
#endif
unsigned int sleep(unsigned int seconds);
int fib(n)
{
@ -356,7 +347,7 @@ int fib(n)
int main(int argc, char **argv)
{
sleep_ms(333);
sleep(1);
printf(" %d", fib(atoi(argv[1])));
return 0;
}

128
tests/libtcc_test_xor_rex.c Normal file
View File

@ -0,0 +1,128 @@
/*
* Test for x86_64 xor REX prefix bug in load() -- x86_64-gen.c
*
* Bug: when loading a 64-bit zero constant into registers r8-r15,
* load() emits:
*
* o(0xc031 + REG_VALUE(r) * 0x900); // xor r, r
*
* REG_VALUE(r) masks to (r & 7), losing bit 3, and no orex() call
* emits the REX prefix needed for extended registers.
*
* Result: r=TREG_R11(11) -> REG_VALUE=3 -> emits 31 db (xor ebx,ebx)
* Correct: should emit 45 31 db (REX.RB xor r11d,r11d)
*
* Fix:
* orex(0, r, r, 0x31);
* o(0xc0 + REG_VALUE(r) * 9);
*
* Trigger: an indirect call through a compile-time null function pointer,
* e.g. ((void(*)(void))0)(), causes gcall_or_jmp() to fall into the
* "indirect call" path which does load(TREG_R11, <constant 0>).
*
* This test compiles such code via the libtcc API, then inspects the
* generated machine code for the incorrect encoding.
*/
#if !defined __x86_64__
#include <stdio.h>
int main(void) { printf("SKIP (x86_64 only)\n"); return 0; }
#else
#include <stdio.h>
#include "libtcc.h"
static void handle_error(void *opaque, const char *msg)
{
fprintf(opaque, "%s\n", msg);
}
/*
* Compiled via libtcc. The cast-to-null indirect call forces
* gcall_or_jmp() into its "else" branch (no VT_SYM, so the
* condition on line ~650 fails), which does:
*
* r = TREG_R11;
* load(r, vtop); // <-- buggy xor lands here
* o(0x41); o(0xff); // call/jmp *r
* o(0xd0 + REG_VALUE(r)); // r11 -> 0xd3
*
* We never execute the function (it would crash); we only
* inspect the generated bytes.
*/
static const char test_code[] =
"void test(void) {\n"
" ((void(*)(void))0)();\n"
"}\n";
int main(int argc, char **argv)
{
TCCState *s;
unsigned char *code;
int i;
int ret = 0;
s = tcc_new();
if (!s) {
fprintf(stderr, "tcc_new() failed\n");
return 2;
}
tcc_set_error_func(s, stderr, handle_error);
for (i = 1; i < argc; ++i) {
char *a = argv[i];
if (a[0] == '-') {
if (a[1] == 'B')
tcc_set_lib_path(s, a + 2);
else if (a[1] == 'I')
tcc_add_include_path(s, a + 2);
else if (a[1] == 'L')
tcc_add_library_path(s, a + 2);
}
}
tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
if (tcc_compile_string(s, test_code) == -1)
return 2;
if (tcc_relocate(s) < 0)
return 2;
code = (unsigned char *)tcc_get_symbol(s, "test");
if (!code) {
fprintf(stderr, "symbol 'test' not found\n");
return 2;
}
/*
* Scan for the 'call *%r11' instruction: 41 ff d3
* Then inspect the bytes immediately before it.
*
* Correct: 45 31 db 41 ff d3 (xor %r11d,%r11d ; call *%r11)
* Buggy: 31 db 41 ff d3 (xor %ebx,%ebx ; call *%r11)
*/
for (i = 3; i < 128; i++) {
if (code[i] == 0x41 && code[i+1] == 0xff && code[i+2] == 0xd3) {
if (i >= 3 && code[i-3] == 0x45
&& code[i-2] == 0x31
&& code[i-1] == 0xdb) {
printf("xor_rex: OK\n");
} else if (i >= 2 && code[i-2] == 0x31 && code[i-1] == 0xdb) {
printf("xor_rex: FAIL - xor %%ebx,%%ebx (31 db) emitted"
" instead of xor %%r11d,%%r11d (45 31 db)\n");
ret = 1;
} else {
printf("xor_rex: FAIL - unexpected bytes before"
" call *%%r11: %02x %02x %02x %02x\n",
code[i-4], code[i-3], code[i-2], code[i-1]);
ret = 1;
}
goto done;
}
}
printf("xor_rex: SKIP - call *%%r11 not found in generated code\n");
done:
tcc_delete(s);
return ret;
}
#endif

View File

@ -1,164 +0,0 @@
/* ------------------------------------------------------------- */
/* minimal startup with runtime linker to msvcrt */
#if 0
#define REDIR_ALL \
REDIR(__set_app_type)\
REDIR(__getmainargs)\
REDIR(_controlfp)\
REDIR(_vsnprintf)\
REDIR(exit)\
\
REDIR(puts)\
REDIR(printf)\
REDIR(putchar)\
REDIR(strtod)\
REDIR(memset)\
REDIR(strcpy)\
REDIR(strlen)\
REDIR(malloc)\
REDIR(free)\
#if defined __i386__ && !defined __TINYC__
# define __leading_underscore 1
#endif
#ifdef __leading_underscore
# define _(s) "_"#s
#else
# define _(s) #s
#endif
#define REDIR(s) void *s;
static struct { REDIR_ALL } all_ptrs;
#undef REDIR
#define REDIR(s) #s"\0"
static const char all_names[] = REDIR_ALL;
#undef REDIR
#if __aarch64__
#if defined __TINYC__
# define ALIGN ".align 8"
#else
# define ALIGN ".align 3" /* .align is power of 2 on non-ELF platforms */
#endif
# define REDIR(s) \
__asm__("\n"_(s)":"); \
__asm__(".int 0x58000090"); /* ldr x16, [pc, #16] */ \
__asm__(".int 0xf9400210"); /* ldr x16, [x16] */ \
__asm__(".int 0xd61f0200"); /* br x16 */ \
__asm__(".int 0xd503201f"); /* nop for alignment */ \
__asm__(".quad all_ptrs + (. - all_jmps - 16) / 24 * 8"); \
__asm__(".global "_(s));
__asm__("\t.text\n\t"ALIGN"\nall_jmps:");
REDIR_ALL
#else
# define REDIR(s) \
__asm__("\n"_(s)":");\
__asm__("jmp *%0"::"m"(all_ptrs.s));\
__asm__(".global "_(s));
static void all_jmps() { REDIR_ALL }
#endif
#undef REDIR
#if 0
# include <windows.h>
#else
# if __i386__
# define STDCALL __declspec(stdcall)
# else
# define STDCALL
# endif
# define DWORD long unsigned
# define HMODULE void*
# define HANDLE void*
S TDCALL HMODULE LoadLibraryA(const char *);
S TDCALL HMODULE GetProcAddress(HMODULE , char*);
S TDCALL void ExitProcess(int);
S TDCALL int WriteFile(HANDLE, const void*, DWORD, DWORD*, void*);
S TDCALL HANDLE GetStdHandle(DWORD);
S TDCALL int FlushFileBuffers(HANDLE);
# define STD_ERROR_HANDLE -12
#endif
static void eput(const char *s)
{
DWORD n_out;
int n = 0;
while (s[n])
++n;
WriteFile(GetStdHandle(STD_ERROR_HANDLE), s, n, &n_out, 0);
}
static void rt_reloc()
{
const char *s = all_names;
void **p = (void**)&all_ptrs;
void *dll = LoadLibraryA("msvcrt.dll");
do {
char buf[100], *d = buf;
*p = (void*)GetProcAddress(dll, (char*)s);
*d++ = '_'; do *d++ = *s; while (*s++);
if (0 == *p)
*p = (void*)GetProcAddress(dll, buf);
if (0 == *p) {
eput("MSVCRT_START.C: RUNTIME RELOCATION ERROR: '");
eput(buf+1);
eput("'\n");
ExitProcess(-1);
}
++p;
} while (*s);
}
#else
# define rt_reloc()
#endif
int main(int argc, char **argv, char **env);
void exit(int);
void __set_app_type(int apptype);
typedef struct { int newmode; } _startupinfo;
int __getmainargs(int *pargc, char ***pargv, char ***penv, int globb, _startupinfo*);
void _controlfp(unsigned a, unsigned b);
#define _MCW_PC 0x00030000 // Precision Control
#define _PC_53 0x00010000 // 53 bits
int __argc;
char **__argv;
char **environ;
_startupinfo start_info = {0};
void mainCRTStartup(void)
{
rt_reloc();
#if defined __i386__ || defined __x86_64__
_controlfp(_PC_53, _MCW_PC);
#endif
__set_app_type(1);
__getmainargs(&__argc, &__argv, &environ, 0, &start_info);
exit(main(__argc, __argv, environ));
}
#include <stdarg.h>
#define size_t __SIZE_TYPE__
int printf(const char *, ...);
int _vsnprintf(char *, size_t, const char *, va_list);
/* undefined on windows-11-arm64 */
int vprintf(const char *format, va_list ap)
{
char buf[1000];
_vsnprintf(buf, sizeof buf, format, ap);
return printf("%s", buf);
}
void __main() {} /* for gcc */
void _pei386_runtime_relocator(void) {} /* for gcc */
void __chkstk(unsigned n) {} /* for clang */

155
tests/nostdlib_test.c Executable file
View File

@ -0,0 +1,155 @@
#!/usr/local/bin/tcc -run -nostdlib
// Not working on windows and apple because of different API.
#include <unistd.h>
#include <sys/syscall.h>
#if defined __x86_64__
__asm__ ("syscall:\n\t"
"mov %rdi,%rax\n\t"
"mov %rsi,%rdi\n\t"
"mov %rdx,%rsi\n\t"
"mov %rcx,%rdx\n\t"
"mov %r8,%r10\n\t"
"mov %r9,%r8\n\t"
"mov 0x8(%rsp),%r9\n\t"
"syscall\n\t"
"ret");
__asm__ (".global _start\n\t"
"_start:\n\t"
"mov 0(%rsp), %rdi\n\t"
"lea 8(%rsp), %rsi\n\t"
"jmp print");
#elif defined __i386__
__asm__ ("syscall:\n\t"
"push %ebp\n\t"
"push %edi\n\t"
"push %esi\n\t"
"push %ebx\n\t"
"mov 0x2c(%esp),%ebp\n\t"
"mov 0x28(%esp),%edi\n\t"
"mov 0x24(%esp),%esi\n\t"
"mov 0x20(%esp),%edx\n\t"
"mov 0x1c(%esp),%ecx\n\t"
"mov 0x18(%esp),%ebx\n\t"
"mov 0x14(%esp),%eax\n\t"
// "call *%gs:0x10\n\t"
".byte 0x65,0xff,0x15,0x10,0x00,0x00,0x00\n\t"
"pop %ebx\n\t"
"pop %esi\n\t"
"pop %edi\n\t"
"pop %ebp\n\t"
"ret");
__asm__ (".global _start\n\t"
"_start:\n\t"
"pop %esi\n\t"
"mov %esp, %ecx\n\t"
"and $0xfffffff0,%esp\n\t"
"push %ecx\n\t"
"push %esi\n\t"
"call print");
#elif defined __arm__
__asm__ ("syscall:\n\t"
"mov r12, sp\n\t"
"push {r4, r5, r6, r7}\n\t"
"mov r7, r0\n\t"
"mov r0, r1\n\t"
"mov r1, r2\n\t"
"mov r2, r3\n\t"
"ldm r12, {r3, r4, r5, r6}\n\t"
"svc 0x00000000\n\t"
"pop {r4, r5, r6, r7}\n\t"
"mov pc, lr");
__asm__ (".global _start\n\t"
"_start:\n\t"
"pop {r0}\n\t"
"mov r1, sp\n\t"
"bl print");
#elif defined __aarch64__
__asm__ ("syscall:\n\t"
".int 0x2a0003e8\n\t" // mov w8, w0
".int 0xaa0103e0\n\t" // x0, x1
".int 0xaa0203e1\n\t" // mov x1, x2
".int 0xaa0303e2\n\t" // mov x2, x3
".int 0xaa0403e3\n\t" // mov x3, x4
".int 0xaa0503e4\n\t" // mov x4, x5
".int 0xaa0603e5\n\t" // mov x5, x6
".int 0xaa0703e6\n\t" // mov x6, x7
".int 0xd4000001\n\t" // svc #0x0
".int 0xd65f03c0"); // ret
__asm__ (".global _start\n\t"
"_start:\n\t"
".int 0xf94003e0\n\t" // ldr x0, [sp]
".int 0x910023e1\n\t" // add x1, sp, #08
".reloc .,R_AARCH64_CALL26,print\n\t"
".int 0x94000000"); // bl print
#elif defined __riscv
__asm__ ("syscall:\n\t"
"mv t1,a0\n\t"
"mv a0,a1\n\t"
"mv a1,a2\n\t"
"mv a2,a3\n\t"
"mv a3,a4\n\t"
"mv a4,a5\n\t"
"mv a5,a6\n\t"
"mv a6,a7\n\t"
"mv a7,t1\n\t"
"ecall\n\t"
"ret");
__asm__ (".global _start\n\t"
"_start:\n\t"
"ld a0,0(sp)\n\t"
"addi a1,sp,8\n\t"
"jal print");
#endif
unsigned long strlen(const char *s)
{
unsigned long len = 0;
while (*s++)
len++;
return len;
}
static void pr_num(int num)
{
char val[20], *p = &val[20];
*--p = '\0';
do {
int a = num, b = 0;
while (a >= 10) {
a -= 10;
b++;
}
*--p = a + '0';
num = b;
} while (num);
syscall(SYS_write, 1, p, strlen(p));
}
static void pr_str(int n, char *s)
{
pr_num(n);
syscall(SYS_write, 1, ": ", 2);
syscall(SYS_write, 1, s, strlen(s));
syscall(SYS_write, 1, "\n", 1);
}
void print(int argc, char **argv) {
int i;
char **envp = &argv[argc + 1];
syscall(SYS_write, 1, "argc: ", 6);
pr_num(argc);
syscall(SYS_write, 1, "\n", 1);
syscall(SYS_write, 1, "argv[]\n", 7);
for (i = 0; i < argc; i++)
pr_str(i, argv[i]);
syscall(SYS_write, 1, "envp[]\n", 7);
i = 0;
while (*envp)
pr_str(i++, *envp++);
syscall(SYS_exit, 0);
}

View File

@ -46,7 +46,6 @@ clean:
rm -f *.output
02.test : DIFF_OPTS += -w
16.test : DIFF_OPTS += -B
# 15.test : DIFF_OPTS += -I"^XXX:"
# diff options:

View File

@ -32,9 +32,8 @@
#define XLONG_LONG_FORMAT "%Lx"
#endif
/* MinGW has 80-bit rather than 64-bit long double which isn't
compatible with printf in msvcrt */
#if defined(_WIN32)
// MinGW has 80-bit rather than 64-bit long double which isn't compatible with TCC or MSVC
#if defined(_WIN32) && defined(__GNUC__)
#define LONG_DOUBLE double
#define LONG_DOUBLE_LITERAL(x) x
#else
@ -82,6 +81,9 @@ typedef __SIZE_TYPE__ uintptr_t;
#include incname
#include stringify(funnyname)
int puts(const char *s);
void *alloca(size_t size);
int fib(int n);
void num(int n);
void forward_ref(void);
@ -285,7 +287,6 @@ comment
printf("basefromheader %s\n", get_basefile_from_header());
printf("base %s\n", __BASE_FILE__);
#if !(defined _WIN32 && CC_NAME == CC_clang)
{
/* Some compilers (clang) prepend './' to __FILE__ from included
files. */
@ -294,8 +295,6 @@ comment
fn += 2;
printf("filefromheader %s\n", fn);
}
#endif
printf("file %s\n", __FILE__);
/* Check that funnily named include was in fact included */
@ -1096,10 +1095,8 @@ void struct_test()
sizeof(struct aligntest2), __alignof__(struct aligntest2));
printf("aligntest3 sizeof=%d alignof=%d\n",
sizeof(struct aligntest3), __alignof__(struct aligntest3));
#if !(defined _WIN32 && CC_NAME == CC_clang)
printf("aligntest4 sizeof=%d alignof=%d\n",
sizeof(struct aligntest4), __alignof__(struct aligntest4));
#endif
printf("aligntest5 sizeof=%d alignof=%d\n",
sizeof(struct aligntest5), __alignof__(struct aligntest5));
printf("aligntest6 sizeof=%d alignof=%d\n",
@ -1108,10 +1105,8 @@ void struct_test()
sizeof(struct aligntest7), __alignof__(struct aligntest7));
printf("aligntest8 sizeof=%d alignof=%d\n",
sizeof(struct aligntest8), __alignof__(struct aligntest8));
#if !(defined _WIN32 && CC_NAME == CC_clang)
printf("aligntest9 sizeof=%d alignof=%d\n",
sizeof(struct aligntest9), __alignof__(struct aligntest9));
#endif
printf("aligntest10 sizeof=%d alignof=%d\n",
sizeof(struct aligntest10), __alignof__(struct aligntest10));
printf("altest5 sizeof=%d alignof=%d\n",
@ -1122,9 +1117,7 @@ void struct_test()
sizeof(altest7), __alignof__(altest7));
/* empty structures (GCC extension) */
#if !(defined _WIN32 && CC_NAME == CC_clang)
printf("sizeof(struct empty) = %d\n", sizeof(struct empty));
#endif
printf("alignof(struct empty) = %d\n", __alignof__(struct empty));
printf("Large: sizeof=%d\n", sizeof(ls));
@ -1175,7 +1168,7 @@ void char_short_test()
var4 = 0x11223344aa998877ULL;
printf("promote char/short assign VA %d %d\n", var3 = var1 + 1, var3 = var4 + 1);
printf("promote char/short cast VA %d %d\n", (signed char)(var1 + 1), (signed char)(var4 + 1));
#if !defined __arm__ && !defined __riscv
#if !defined(__arm__)
/* We can't really express GCC behaviour of return type promotion in
the presence of undefined behaviour (like __csf is). */
var1 = csf(unsigned char,0x89898989);
@ -1466,37 +1459,17 @@ static int tab_reinit[10];
static int tentative_ar[];
static int tentative_ar[] = {1,2,3};
int cinit1; /* a global variable can be defined several times without error ! */
//int cinit1; /* a global variable can be defined several times without error ! */
int cinit1;
int cinit1;
int cinit1 = 0;
int *cinit2 = (int []){3, 2, 1};
uintptr_t cinit3 = (uintptr_t)"AA";
char const * const cinit8[] = { [0 ... 1] = "BB", [2 ... 4] = "CC" };
void *cinit52 = &(void*){ (void*) 52 };
#if __TINYC__ || __GNUC__ >= 6
int cinit4 = (int){44};
void *cinit51 = (void*){ (void*) 51 };
struct _c6 { int a,b; } cinit6 = (struct _c6){61,62}, *cinit7 = &(struct _c6){71,72};
#else
int cinit4 = 44;
void *cinit51 = (void*)51;
struct _c6 { int a,b; } cinit6 = { 61,62 }, cinit70 = {71,72}, *cinit7 = &cinit70;
#endif
void compound_literal_test(void)
{
int *p, i;
char *q, *q3;
printf("cinit3 : %s\n", cinit3);
printf("cinit4 : %d\n", cinit4);
printf("cinit51 : %d\n", (int)cinit51);
printf("cinit52 : %d\n", *(int*)cinit52);
printf("cinit6 : %d %d\n", cinit6.a, cinit6.b);
printf("cinit7 : %d %d\n", cinit7->a, cinit7->b);
printf("cinit8 : %s %s %s %s %s\n", cinit8[0], cinit8[1], cinit8[2], cinit8[3], cinit8[4]);
p = (int []){1, 2, 3};
for(i=0;i<3;i++)
printf(" %d", p[i]);
@ -2203,6 +2176,15 @@ float strtof(const char *nptr, char **endptr);
LONG_DOUBLE strtold(const char *nptr, char **endptr);
#endif
#if CC_NAME == CC_clang
/* In clang 0.0/0.0 is nan and not -nan.
Also some older clang version do v=-v
as v = -0 - v */
static char enable_nan_test = 0;
#else
static char enable_nan_test = 1;
#endif
#define FTEST(prefix, typename, type, fmt)\
void prefix ## cmp(type a, type b)\
{\
@ -2258,7 +2240,7 @@ void prefix ## fcast(type a)\
b = llia;\
printf("lltof: " fmt "\n", b);\
b = llua;\
if (CC_NAME != CC_clang) printf("ulltof: " fmt "\n", b);\
printf("ulltof: " fmt "\n", b);\
}\
\
float prefix ## retf(type a) { return a; }\
@ -2318,7 +2300,7 @@ void prefix ## test(void)\
prefix ## fcast(-2334.6);\
prefix ## call();\
prefix ## signed_zeros();\
if (CC_NAME != CC_clang) prefix ## nan();\
if (enable_nan_test) prefix ## nan();\
}
FTEST(f, float, float, "%f")
@ -2574,8 +2556,8 @@ void longlong_test(void)
a = ia;
b = ua;
printf(LONG_LONG_FORMAT " " LONG_LONG_FORMAT "\n", a, b);
printf(LONG_LONG_FORMAT " " LONG_LONG_FORMAT " " LONG_LONG_FORMAT " "XLONG_LONG_FORMAT"\n",
(long long)1,
printf(LONG_LONG_FORMAT " " LONG_LONG_FORMAT " " LONG_LONG_FORMAT " %Lx\n",
(long long)1,
(long long)-2,
1LL,
0x1234567812345679);
@ -2885,14 +2867,12 @@ void stdarg_test(void)
stdarg_for_struct(bob, bob2, bob3, bob4, bob, bob, bob.profile);
stdarg_for_libc("stdarg_for_libc: %s %.2f %d\n", "string", 1.23, 456);
stdarg_syntax(1, 17);
#if !(defined _WIN32 && CC_NAME == CC_clang) /* broken clang */
stdarg_double_struct(6,-1,pts[0],pts[1],pts[2],pts[3],pts[4],pts[5]);
stdarg_double_struct(7,1,pts[0],-1.0,pts[1],pts[2],pts[3],pts[4],pts[5]);
stdarg_double_struct(7,2,pts[0],pts[1],-1.0,pts[2],pts[3],pts[4],pts[5]);
stdarg_double_struct(7,3,pts[0],pts[1],pts[2],-1.0,pts[3],pts[4],pts[5]);
stdarg_double_struct(7,4,pts[0],pts[1],pts[2],pts[3],-1.0,pts[4],pts[5]);
stdarg_double_struct(7,5,pts[0],pts[1],pts[2],pts[3],pts[4],-1.0,pts[5]);
#endif
}
int reltab[3] = { 1, 2, 3 };
@ -3309,7 +3289,7 @@ void local_label_test(void)
}
/* inline assembler test */
#if (defined(__i386__) || defined(__x86_64__)) && !(defined _WIN32 && CC_NAME == CC_clang)
#if defined(__i386__) || defined(__x86_64__)
typedef __SIZE_TYPE__ word;
@ -3571,8 +3551,8 @@ void asm_local_label_diff (void)
{
printf ("asm_local_label_diff: %d %d\n", alld_stuff[0], alld_stuff[1]);
}
#endif //!__APPLE__
#endif //!_WIN32
#endif
#endif
/* This checks that static local variables are available from assembler. */
void asm_local_statics (void)

View File

@ -1,74 +0,0 @@
@echo off
setlocal
set CC=gcc
set TESTS=
if "%1"=="/?" goto :usage
goto :p0
:usage
echo usage: test-win32.bat [options...] [tests...]
echo options:
echo -c compiler reference compiler (gcc or clang)
echo -p path prepend path to PATH
echo tests tests to run (default all)
echo requires: make, gcc/clang, and sh in the PATH
exit /B 1
:p2
shift
:p1
shift
:p0
if "%1"=="-c" set CC=%2&&goto p2
if "%1"=="-p" set PATH=%2;%PATH%&&goto p2
if not "%1"=="" set TESTS=%TESTS% %1&&goto p1
if "%TESTS%"=="" set TESTS=all -k
set PATH=%CD%\..\win32;%PATH%
for /f "delims=-" %%a in ('tcc.exe -dumpmachine') do set ARCH=%%a
set ARCH=%ARCH:aarch=arm%
set MACH=%ARCH:i386=x86%
set MACH=%MACH:x86_64=amd64%
rem echo ARCH:%ARCH% MACHINE:%MACH%
set CRTLIB=c:/windows/system32/msvcrt.dll
set LIBTCC=libtcc.dll
set LGCC=-lgcc
if %CC%==gcc goto :c2
set CRTLIB=msvcrt.lib
set LIBTCC=libtcc.lib
set LGCC=
if exist %CRTLIB% goto :c3
tcc -impdef msvcrt.dll
lib >nul /def:msvcrt.def /out:%CRTLIB% /machine:%MACH%
:c2
if not exist %CRTLIB% echo test-win32.bat: error: %CRTLIB% not found&&exit /b 1
:c3
set REF_LINK=-nostdlib msvcrt_start.c %LGCC% -lkernel32 %CRTLIB%
set CFG_MAK=..\config.mak
set CFG_H=..\config.h
echo>>%CFG_H% #define CC_NAME CC_%CC%
echo>>%CFG_H% #define GCC_MAJOR 15
if exist %CFG_MAK% del %CFG_MAK%
echo>>%CFG_MAK% CC = %CC%.exe
echo>>%CFG_MAK% CC_NAME = %CC%
echo>>%CFG_MAK% ARCH = %ARCH%
echo>>%CFG_MAK% CFLAGS = -Wall -O0
echo>>%CFG_MAK% LDFLAGS =
echo>>%CFG_MAK% LIBSUF = .lib
echo>>%CFG_MAK% prefix = $(TOP)/bin
echo>>%CFG_MAK% EXESUF = .exe
echo>>%CFG_MAK% DLLSUF = .dll
echo>>%CFG_MAK% TARGETOS = WIN32
echo>>%CFG_MAK% CONFIG_WIN32 = yes
echo>>%CFG_MAK% TOPSRC = $(TOP)
echo>>%CFG_MAK% SHELL = sh
echo>>%CFG_MAK% test.ref: CFLAGS += %REF_LINK%
set GMAKE=make
%GMAKE% TCC_LOCAL=tcc.exe LIBTCC=win32/%LIBTCC% %TESTS%

View File

@ -1,280 +0,0 @@
/* ARM64 instruction encoding verification test.
Exercises shift-by-immediate, load/store addressing modes,
conditional branches, and system register access. */
#include <stdio.h>
#include <stdint.h>
/* ---- shift-by-immediate helpers ---- */
static uint32_t lsl32(uint32_t x, int n) { return x << n; }
static uint32_t lsr32(uint32_t x, int n) { return x >> n; }
static int32_t asr32(int32_t x, int n) { return x >> n; }
static uint64_t lsl64(uint64_t x, int n) { return x << n; }
static uint64_t lsr64(uint64_t x, int n) { return x >> n; }
static int64_t asr64(int64_t x, int n) { return x >> n; }
static void test_shifts(void)
{
printf("shift-imm:\n");
printf("%x\n", lsl32(1, 0));
printf("%x\n", lsl32(1, 15));
printf("%x\n", lsl32(1, 31));
printf("%x\n", lsr32(0x80000000U, 31));
printf("%x\n", lsr32(0x80000000U, 16));
printf("%x\n", asr32(-1, 1));
printf("%x\n", asr32(-256, 4));
printf("%llx\n", (unsigned long long)lsl64(1ULL, 0));
printf("%llx\n", (unsigned long long)lsl64(1ULL, 32));
printf("%llx\n", (unsigned long long)lsl64(1ULL, 63));
printf("%llx\n", (unsigned long long)lsr64(0x8000000000000000ULL, 63));
printf("%llx\n", (unsigned long long)asr64(-1LL, 1));
printf("%llx\n", (unsigned long long)asr64(-256LL, 4));
}
/* ---- load/store with various addressing modes ---- */
static void test_ldr_str(void)
{
int64_t buf[4] = { 0x1122334455667788LL, 0x99AABBCCDDEEFF00LL,
0x0F1E2D3C4B5A6978LL, 0x0000000000000001LL };
int64_t val;
int32_t wval;
int64_t *p;
printf("ldr-str:\n");
/* LDR X, [Xn, #offset] */
val = buf[0];
printf("%llx\n", (unsigned long long)val);
val = buf[1];
printf("%llx\n", (unsigned long long)val);
/* LDR W, [Xn, #offset] (32-bit load) */
wval = *(int32_t*)&buf[0];
printf("%x\n", (unsigned)wval);
/* Pre-indexed: store pointer, modify */
p = &buf[0];
val = *(p + 2);
printf("%llx\n", (unsigned long long)val);
/* Post-indexed simulation via pointer arithmetic */
p = &buf[0];
val = *p;
p++;
printf("%llx %llx\n", (unsigned long long)val,
(unsigned long long)*p);
}
/* ---- STP/LDP (store/load pair) ---- */
static void test_ldp_stp(void)
{
int64_t src[2] = { 0xAAAABBBBCCCCDDDDLL, 0x1111222233334444LL };
int64_t dst[2];
/* The compiler should use stp/ldp for this */
dst[0] = src[0];
dst[1] = src[1];
printf("ldp-stp:\n");
printf("%llx %llx\n",
(unsigned long long)dst[0],
(unsigned long long)dst[1]);
}
/* ---- CBZ / CBNZ via C patterns ---- */
static const char *cbz_test(int x)
{
if (x == 0)
return "zero";
return "nonzero";
}
static const char *cbnz_test(int x)
{
if (x != 0)
return "nonzero";
return "zero";
}
static void test_cond_branches(void)
{
printf("cbz-cbnz:\n");
printf("%s\n", cbz_test(0));
printf("%s\n", cbz_test(42));
printf("%s\n", cbnz_test(0));
printf("%s\n", cbnz_test(42));
}
/* ---- conditional compare patterns (CCMP/CCMN) ---- */
static int cond_select(int a, int b)
{
/* TCC should generate csel or equivalent */
return a > b ? a : b;
}
static void test_cond_select(void)
{
printf("csel:\n");
printf("%d\n", cond_select(5, 10));
printf("%d\n", cond_select(10, 5));
printf("%d\n", cond_select(0, 0));
printf("%d\n", cond_select(-1, 1));
}
/* ---- MRS/MSR system registers (FPCR/FPSR) ---- */
static void test_sysregs(void)
{
unsigned int fpcr, fpsr;
printf("sysregs:\n");
/* Read FPCR */
__asm__ volatile ("mrs %0, fpcr" : "=r"(fpcr));
printf("%u\n", fpcr & 0x0F);
/* Read FPSR */
__asm__ volatile ("mrs %0, fpsr" : "=r"(fpsr));
printf("%u\n", fpsr);
/* Write/restore FPCR (should be same value) */
__asm__ volatile ("msr fpcr, %0" : : "r"(fpcr));
/* Read back and verify */
{
unsigned int check;
__asm__ volatile ("mrs %0, fpcr" : "=r"(check));
printf("%s\n", check == fpcr ? "ok" : "fail");
}
}
/* ---- NOP encoding (should not crash) ---- */
static void test_nop(void)
{
printf("nop:\n");
__asm__ volatile ("nop");
__asm__ volatile ("nop");
__asm__ volatile ("nop");
printf("ok\n");
}
/* ---- barrier instructions ---- */
static void test_barriers(void)
{
printf("barriers:\n");
__asm__ volatile ("dmb sy");
__asm__ volatile ("dsb sy");
__asm__ volatile ("isb");
printf("ok\n");
}
/* ---- MOV (register) patterns ---- */
static int64_t mov_x0_x1(int64_t x)
{
register int64_t r __asm__("x0") = x;
__asm__ volatile ("" : "=r"(r) : "0"(r));
return r;
}
static void test_mov_reg(void)
{
printf("mov-reg:\n");
printf("%lld\n", (long long)mov_x0_x1(42));
printf("%lld\n", (long long)mov_x0_x1(-1));
}
/* ---- large struct passing (reference semantics) ---- */
struct large { int64_t a, b, c, d; };
static int64_t sum_large(struct large s)
{
return s.a + s.b + s.c + s.d;
}
static struct large make_large(int64_t a, int64_t b, int64_t c, int64_t d)
{
struct large s = { a, b, c, d };
return s;
}
static void test_large_structs(void)
{
struct large s = { 1, 2, 3, 4 };
struct large t;
printf("large-struct:\n");
printf("%lld\n", (long long)sum_large(s));
t = make_large(10, 20, 30, 40);
printf("%lld %lld %lld %lld\n",
(long long)t.a, (long long)t.b,
(long long)t.c, (long long)t.d);
}
/* ---- boundary-sized structs ---- */
struct s18 { char x[18]; };
struct s24 { char x[24]; };
struct s32 { char x[32]; };
static void print_s18(struct s18 s) { printf("%.18s\n", s.x); }
static void print_s24(struct s24 s) { printf("%.24s\n", s.x); }
static void print_s32(struct s32 s) { printf("%.32s\n", s.x); }
static struct s18 ret_s18(void)
{
struct s18 s = { "123456789012345678" };
return s;
}
static struct s24 ret_s24(void)
{
struct s24 s = { "123456789012345678901234" };
return s;
}
static struct s32 ret_s32(void)
{
struct s32 s = { "12345678901234567890123456789012" };
return s;
}
static void test_boundary_structs(void)
{
struct s18 a;
struct s24 b;
struct s32 c;
printf("boundary-structs:\n");
a = ret_s18();
printf("%.18s\n", a.x);
b = ret_s24();
printf("%.24s\n", b.x);
c = ret_s32();
printf("%.32s\n", c.x);
}
int main(void)
{
test_shifts();
test_ldr_str();
test_ldp_stp();
test_cond_branches();
test_cond_select();
test_sysregs();
test_nop();
test_barriers();
test_mov_reg();
test_large_structs();
test_boundary_structs();
return 0;
}

View File

@ -1,50 +0,0 @@
shift-imm:
1
8000
80000000
1
8000
ffffffff
fffffff0
1
100000000
8000000000000000
1
ffffffffffffffff
fffffffffffffff0
ldr-str:
1122334455667788
99aabbccddeeff00
55667788
f1e2d3c4b5a6978
1122334455667788 99aabbccddeeff00
ldp-stp:
aaaabbbbccccdddd 1111222233334444
cbz-cbnz:
zero
nonzero
zero
nonzero
csel:
10
10
0
1
sysregs:
0
0
ok
nop:
ok
barriers:
ok
mov-reg:
42
-1
large-struct:
10
10 20 30 40
boundary-structs:
123456789012345678
123456789012345678901234
12345678901234567890123456789012

View File

@ -1,91 +0,0 @@
/* ARM64 inline assembly error tests.
Verify that invalid assembly produces proper error messages.
Run with -dt; skipped on non-arm64 architectures. */
#include <stdio.h>
#if defined test_unknown_instruction
int main(void)
{
__asm__("fubar x0, x1, x2");
return 0;
}
#elif defined test_shift_imm_range_32
int main(void)
{
/* LSL by 32 is out of range for 32-bit operand */
__asm__("lsl w0, w1, #32");
return 0;
}
#elif defined test_shift_imm_range_64
int main(void)
{
/* LSL by 64 is out of range for 64-bit operand */
__asm__("lsl x0, x1, #64");
return 0;
}
#elif defined test_invalid_sysreg
int main(void)
{
/* Bogus system register name */
__asm__("mrs x0, bogusreg");
return 0;
}
#elif defined test_invalid_barrier_option
int main(void)
{
/* Invalid barrier scope name */
__asm__("dmb xyz");
return 0;
}
#elif defined test_missing_third_operand
int main(void)
{
__asm__("add x0, x1");
return 0;
}
#elif defined test_movz_imm_range
int main(void)
{
__asm__("movz x0, #0x10000");
return 0;
}
#elif defined test_movz_shift_range
int main(void)
{
__asm__("movz x0, #1, lsl #8");
return 0;
}
#elif defined test_invalid_muls
int main(void)
{
__asm__("muls x0, x1, x2");
return 0;
}
#elif defined test_extended_inline_asm
int main(void)
{
int x = 1;
/* Invalid operand reference in extended inline asm */
__asm__("add %0, %1, #1" : "=r"(x) : "2"(x));
return 0;
}
#elif defined test_extended_inline_clobber
int main(void)
{
/* Invalid clobber register name */
__asm__ volatile ("nop" : : : "bogus");
return 0;
}
#endif

View File

@ -1,32 +0,0 @@
[test_unknown_instruction]
139_arm64_errors.c:10: error: ARM64 instruction 'fubar' not implemented
[test_shift_imm_range_32]
139_arm64_errors.c:17: error: shift immediate out of range
[test_shift_imm_range_64]
139_arm64_errors.c:25: error: shift immediate out of range
[test_invalid_sysreg]
139_arm64_errors.c:34: error: unsupported system register
[test_invalid_barrier_option]
139_arm64_errors.c:42: error: invalid operand 'xyz'
[test_missing_third_operand]
139_arm64_errors.c:48: error: missing third operand
[test_movz_imm_range]
139_arm64_errors.c:55: error: move wide immediate out of range
[test_movz_shift_range]
139_arm64_errors.c:62: error: move wide shift out of range
[test_invalid_muls]
139_arm64_errors.c:70: error: ARM64 instruction 'muls' not implemented
[test_extended_inline_asm]
139_arm64_errors.c:79: error: invalid reference in constraint 1 ('2')
[test_extended_inline_clobber]
139_arm64_errors.c:87: error: invalid clobber register 'bogus'

View File

@ -1,451 +0,0 @@
/*
* ARM64 Extended Inline Assembly Tests
* Tests for GCC-style extended inline assembly with operands, constraints, and clobbers
*/
#include <stdio.h>
#include <stdint.h>
#include <assert.h>
struct pair64 {
uint64_t a;
uint64_t b;
};
static int arm64_symbol_target(void)
{
return 7;
}
static void test_symbolic_address_constraint_compile_only(void)
{
asm volatile("" : : "S"(arm64_symbol_target));
}
/* Test 1: Basic output operand */
void test_basic_output(void)
{
int x;
asm("mov %0, #42" : "=r"(x));
assert(x == 42);
printf("Test 1 (basic output): PASSED\n");
}
/* Test 2: Input operand */
void test_input_operand(void)
{
int x = 10;
int y;
asm("add %0, %1, #5" : "=r"(y) : "r"(x));
assert(y == 15);
printf("Test 2 (input operand): PASSED\n");
}
/* Test 3: Read-write operand */
void test_read_write_operand(void)
{
int x = 10;
asm("add %0, %0, #1" : "+r"(x));
assert(x == 11);
printf("Test 3 (read-write operand): PASSED\n");
}
/* Test 4: Memory operand - load */
void test_memory_load(void)
{
int x = 42;
int y;
asm("ldr %w0, [%1]" : "=r"(y) : "r"(&x));
assert(y == 42);
printf("Test 4 (memory load): PASSED\n");
}
/* Test 5: Memory operand - store */
void test_memory_store(void)
{
int x;
int val = 123;
asm("str %w1, [%0]" : : "r"(&x), "r"(val));
assert(x == 123);
printf("Test 5 (memory store): PASSED\n");
}
/* Test 5a: Stack memory operand with frame-relative offset */
void test_stack_memory_operand(void)
{
long x = 0;
long val = 321;
asm volatile("str %0, %1" : : "r"(val), "m"(x));
assert(x == 321);
printf("Test 5a (stack memory operand): PASSED\n");
}
/* Test 5b: Symbol memory operand */
static long arm64_symbol_mem;
void test_symbol_memory_operand(void)
{
long val = 654;
arm64_symbol_mem = 0;
asm volatile("str %0, %1" : : "r"(val), "m"(arm64_symbol_mem));
assert(arm64_symbol_mem == 654);
printf("Test 5b (symbol memory operand): PASSED\n");
}
/* Test 6: Clobber list */
void test_clobber_list(void)
{
int x = 10;
int y = 20;
int result;
asm("add %0, %1, %2"
: "=r"(result)
: "r"(x), "r"(y)
: "cc");
assert(result == 30);
printf("Test 6 (clobber list): PASSED\n");
}
/* Test 7: Multiple outputs */
void test_multiple_outputs(void)
{
int a, b;
asm("mov %0, #1; mov %1, #2"
: "=r"(a), "=r"(b));
assert(a == 1 && b == 2);
printf("Test 7 (multiple outputs): PASSED\n");
}
/* Test 8: Constraint reference */
void test_constraint_reference(void)
{
int x = 10;
int y;
asm("add %0, %1, #5" : "=r"(y) : "0"(x));
assert(y == 15);
printf("Test 8 (constraint reference): PASSED\n");
}
/* Test 9: Early clobber */
void test_early_clobber(void)
{
int x = 10;
int y;
asm("mov %0, #42" : "=&r"(y) : "r"(x));
assert(y == 42);
printf("Test 9 (early clobber): PASSED\n");
}
/* Test 10: 32-bit register modifier */
void test_w_register(void)
{
uint32_t x = 100;
uint32_t y;
asm("add %w0, %w1, #50" : "=r"(y) : "r"(x));
assert(y == 150);
printf("Test 10 (w register modifier): PASSED\n");
}
/* Test 11: Immediate constraint 'I' (12-bit immediate) */
void test_immediate_i_constraint(void)
{
int x = 100;
int y;
asm("add %0, %1, #200" : "=r"(y) : "r"(x), "I"(200));
assert(y == 300);
printf("Test 11 (immediate I constraint): PASSED\n");
}
/* Test 12: Register constraint */
void test_general_operand_constraint(void)
{
int x = 50;
int y;
asm("add %0, %1, #10" : "=r"(y) : "r"(x));
assert(y == 60);
printf("Test 12 (general operand constraint): PASSED\n");
}
/* Test 13: Multiple inputs and outputs */
void test_multiple_io(void)
{
int a = 10, b = 20;
int sum, diff;
asm("add %0, %1, %2" : "=r"(sum) : "r"(a), "r"(b));
asm("sub %0, %1, %2" : "=r"(diff) : "r"(a), "r"(b));
assert(sum == 30 && diff == -10);
printf("Test 13 (multiple IO): PASSED\n");
}
/* Test 14: Register variable preservation */
void test_regvar_preservation(void)
{
register uint64_t keep asm("x19") = 0x123456789abcdef0ULL;
uint64_t out;
asm volatile("mov x19, #7; add %0, x19, #1"
: "=r"(out)
:
: "x19");
assert(keep == 0x123456789abcdef0ULL);
assert(out == 8);
printf("Test 14 (regvar preservation): PASSED\n");
}
/* Test 15: Complex arithmetic */
void test_complex_arithmetic(void)
{
int a = 100, b = 50, c = 25;
int result;
asm("add %0, %1, %2; sub %0, %0, %3"
: "=&r"(result)
: "r"(a), "r"(b), "r"(c));
assert(result == 125);
printf("Test 15 (complex arithmetic): PASSED\n");
}
/* Test 16: Named operand (GCC extension) */
void test_named_operand(void)
{
int input = 10;
int output;
asm("add %[out], %[in], #5"
: [out] "=r"(output)
: [in] "r"(input));
assert(output == 15);
printf("Test 16 (named operand): PASSED\n");
}
/* Test 17: Memory clobber */
void test_memory_clobber(void)
{
int x = 10;
asm volatile("" : : : "memory");
assert(x == 10);
printf("Test 17 (memory clobber): PASSED\n");
}
/* Test 18: Condition flags clobber */
void test_cc_clobber(void)
{
int x = 100;
int y;
asm("adds %0, %1, #0" : "=r"(y) : "r"(x) : "cc");
assert(y == 100);
printf("Test 18 (cc clobber): PASSED\n");
}
/* Test 19: Large immediate with movz/movk */
void test_large_immediate(void)
{
uint64_t val;
asm("movz %0, #0x1234, lsl #16; movk %0, #0x5678" : "=r"(val));
assert(val == 0x12345678ULL);
printf("Test 19 (large immediate): PASSED\n");
}
/* Test 20: Bitwise operations */
void test_bitwise_ops(void)
{
uint64_t a = 0xf0f0f0f00f0f0f0fULL;
uint64_t b = 0x3333ffff0000ccccULL;
uint64_t andv;
uint64_t orv;
uint64_t xorv;
uint64_t imm_and;
asm("and %0, %1, %2" : "=r"(andv) : "r"(a), "r"(b));
asm("orr %0, %1, %2" : "=r"(orv) : "r"(a), "r"(b));
asm("eor %0, %1, %2" : "=r"(xorv) : "r"(a), "r"(b));
asm("and %0, %1, %2" : "=r"(imm_and)
: "r"(~0ULL), "L"(0xff00ff00ff00ff00ULL));
assert(andv == (a & b));
assert(orv == (a | b));
assert(xorv == (a ^ b));
assert(imm_and == 0xff00ff00ff00ff00ULL);
printf("Test 20 (bitwise ops): PASSED\n");
}
/* Test 21: Register shift operands */
void test_register_shift_operands(void)
{
uint64_t val = 3;
uint64_t amount = 4;
uint64_t shifted;
uint64_t rotated;
asm("lsl %0, %1, %2" : "=r"(shifted) : "r"(val), "r"(amount));
asm("ror %0, %1, %2" : "=r"(rotated)
: "r"(0x0123456789abcdefULL), "r"(8ULL));
assert(shifted == 48);
assert(rotated == 0xef0123456789abcdULL);
printf("Test 21 (register shifts): PASSED\n");
}
/* Test 22: ROR immediate alias of EXTR */
void test_ror_immediate(void)
{
uint64_t rotated;
asm("ror %0, %1, #8" : "=r"(rotated) : "r"(0x0123456789abcdefULL));
assert(rotated == 0xef0123456789abcdULL);
printf("Test 22 (ror immediate): PASSED\n");
}
/* Test 23: FP/SIMD register constraint and modifier */
void test_fp_register_operand(void)
{
double x = 3.5;
double y;
asm("ldr %d0, [%1]" : "=w"(y) : "r"(&x));
assert(y == x);
printf("Test 23 (fp register operand): PASSED\n");
}
/* Test 24: Zero constraint */
void test_zero_constraint(void)
{
uint64_t x = 41;
uint64_t y;
asm("add %0, %1, %x2" : "=r"(y) : "r"(x), "Z"(0));
assert(y == x);
printf("Test 24 (Z constraint): PASSED\n");
}
/* Test 25: 32-bit logical immediate constraint */
void test_logical_imm32_constraint(void)
{
uint32_t y;
asm("orr %w0, wzr, %1" : "=r"(y) : "K"(0xff));
assert(y == 0xff);
printf("Test 25 (K constraint): PASSED\n");
}
/* Test 26: 64-bit logical immediate constraint */
void test_logical_imm64_constraint(void)
{
uint64_t y;
asm("orr %0, xzr, %1" : "=r"(y) : "L"(0xff00ff00ff00ff00ULL));
assert(y == 0xff00ff00ff00ff00ULL);
printf("Test 26 (L constraint): PASSED\n");
}
/* Test 27: 32-bit MOV pseudo immediate constraint */
void test_mov_imm32_constraint(void)
{
uint32_t y;
asm("mov %w0, %1" : "=r"(y) : "M"(0x1234));
assert(y == 0x1234);
printf("Test 27 (M constraint): PASSED\n");
}
/* Test 28: 64-bit MOV pseudo immediate constraint */
void test_mov_imm64_constraint(void)
{
uint64_t y;
asm("mov %0, %1" : "=r"(y) : "N"(0x12340000ULL));
assert(y == 0x12340000ULL);
printf("Test 28 (N constraint): PASSED\n");
}
/* Test 29: x FP/SIMD register constraint */
void test_x_constraint_fp(void)
{
double x = 6.25;
double y;
asm("ldr %d0, [%1]" : "=x"(y) : "r"(&x));
assert(y == x);
printf("Test 29 (x constraint): PASSED\n");
}
/* Test 30: y FP/SIMD register constraint */
void test_y_constraint_fp(void)
{
double x = 7.25;
double y;
asm("ldr %d0, [%1]" : "=y"(y) : "r"(&x));
assert(y == x);
printf("Test 30 (y constraint): PASSED\n");
}
/* Test 31: Q memory constraint */
static int arm64_q_load(int *ptr)
{
int y;
asm("ldr %w0, %1" : "=r"(y) : "Q"(*ptr));
return y;
}
void test_q_memory_constraint(void)
{
int x = 91;
assert(arm64_q_load(&x) == 91);
printf("Test 31 (Q constraint): PASSED\n");
}
/* Test 32: Ump pair-memory constraint */
void test_ump_memory_constraint(void)
{
struct pair64 pair = { 0x1122334455667788ULL, 0x99aabbccddeeff00ULL };
uint64_t a;
uint64_t b;
asm("ldp %0, %1, %2" : "=r"(a), "=r"(b) : "Ump"(pair));
assert(a == pair.a);
assert(b == pair.b);
printf("Test 32 (Ump constraint): PASSED\n");
}
int main(void)
{
printf("ARM64 Extended Inline Assembly Tests\n");
test_basic_output();
test_input_operand();
test_read_write_operand();
test_memory_load();
test_memory_store();
test_stack_memory_operand();
test_symbol_memory_operand();
test_clobber_list();
test_multiple_outputs();
test_constraint_reference();
test_early_clobber();
test_w_register();
test_immediate_i_constraint();
test_general_operand_constraint();
test_multiple_io();
test_regvar_preservation();
test_complex_arithmetic();
test_named_operand();
test_memory_clobber();
test_cc_clobber();
test_large_immediate();
test_bitwise_ops();
test_register_shift_operands();
test_ror_immediate();
test_fp_register_operand();
test_zero_constraint();
test_logical_imm32_constraint();
test_logical_imm64_constraint();
test_mov_imm32_constraint();
test_mov_imm64_constraint();
test_x_constraint_fp();
test_y_constraint_fp();
test_q_memory_constraint();
test_ump_memory_constraint();
test_symbolic_address_constraint_compile_only();
printf("ARM64 Extended Inline Assembly Tests PASSED!\n");
return 0;
}

View File

@ -1,36 +0,0 @@
ARM64 Extended Inline Assembly Tests
Test 1 (basic output): PASSED
Test 2 (input operand): PASSED
Test 3 (read-write operand): PASSED
Test 4 (memory load): PASSED
Test 5 (memory store): PASSED
Test 5a (stack memory operand): PASSED
Test 5b (symbol memory operand): PASSED
Test 6 (clobber list): PASSED
Test 7 (multiple outputs): PASSED
Test 8 (constraint reference): PASSED
Test 9 (early clobber): PASSED
Test 10 (w register modifier): PASSED
Test 11 (immediate I constraint): PASSED
Test 12 (general operand constraint): PASSED
Test 13 (multiple IO): PASSED
Test 14 (regvar preservation): PASSED
Test 15 (complex arithmetic): PASSED
Test 16 (named operand): PASSED
Test 17 (memory clobber): PASSED
Test 18 (cc clobber): PASSED
Test 19 (large immediate): PASSED
Test 20 (bitwise ops): PASSED
Test 21 (register shifts): PASSED
Test 22 (ror immediate): PASSED
Test 23 (fp register operand): PASSED
Test 24 (Z constraint): PASSED
Test 25 (K constraint): PASSED
Test 26 (L constraint): PASSED
Test 27 (M constraint): PASSED
Test 28 (N constraint): PASSED
Test 29 (x constraint): PASSED
Test 30 (y constraint): PASSED
Test 31 (Q constraint): PASSED
Test 32 (Ump constraint): PASSED
ARM64 Extended Inline Assembly Tests PASSED!

View File

@ -1,356 +0,0 @@
#include <stdio.h>
#ifdef __riscv
/* P0.4 + P1.4: riscv64 asm pseudo-instructions test.
Exercises neg/negw, sext.w, fmv.s/d, fneg.s/d. */
int test_neg(int x)
{
int r;
asm("neg %0, %1" : "=r"(r) : "r"(x));
return r;
}
long long test_negw(long long x)
{
int r;
asm("negw %0, %1" : "=r"(r) : "r"((int)x));
return (long long)r;
}
long long test_sextw(int x)
{
long long r;
asm("sext.w %0, %1" : "=r"(r) : "r"(x));
return r;
}
float test_fmv_s(float a)
{
float r;
asm("fmv.s %0, %1" : "=f"(r) : "f"(a));
return r;
}
float test_fneg_s(float a)
{
float r;
asm("fneg.s %0, %1" : "=f"(r) : "f"(a));
return r;
}
double test_fmv_d(double a)
{
double r;
asm("fmv.d %0, %1" : "=f"(r) : "f"(a));
return r;
}
double test_fneg_d(double a)
{
double r;
asm("fneg.d %0, %1" : "=f"(r) : "f"(a));
return r;
}
int test_pseudo(void)
{
int ok = 1;
if (test_neg(42) != -42) {
printf("FAIL: neg\n");
ok = 0;
}
if (test_negw(100) != -100) {
printf("FAIL: negw\n");
ok = 0;
}
if (test_sextw(0x80000000) != 0xffffffff80000000LL) {
printf("FAIL: sext.w\n");
ok = 0;
}
if (test_fmv_s(3.14f) != 3.14f) {
printf("FAIL: fmv.s\n");
ok = 0;
}
if (test_fneg_s(3.14f) != -3.14f) {
printf("FAIL: fneg.s\n");
ok = 0;
}
if (test_fmv_d(2.718281828) != 2.718281828) {
printf("FAIL: fmv.d\n");
ok = 0;
}
if (test_fneg_d(2.718281828) != -2.718281828) {
printf("FAIL: fneg.d\n");
ok = 0;
}
return ok;
}
/* P1.1: riscv64 inline asm with 64-bit immediate (li).
Tests that long long immediates assemble correctly,
including the lui+addi sequence for large constants. */
long long test_li_small(void)
{
long long r;
asm("li %0, 42" : "=r"(r));
return r;
}
long long test_li_large(void)
{
long long r;
asm("li %0, 0x123456789ABCDEF0" : "=r"(r));
return r;
}
long long test_li_negative(void)
{
long long r;
asm("li %0, -1" : "=r"(r));
return r;
}
int test_ll(void)
{
int ok = 1;
if (test_li_small() != 42) {
printf("FAIL: li small\n");
ok = 0;
}
if (test_li_large() != 0x123456789ABCDEF0LL) {
printf("FAIL: li large\n");
ok = 0;
}
if (test_li_negative() != -1) {
printf("FAIL: li negative\n");
ok = 0;
}
return ok;
}
/* P1.3: riscv64 F/D extension arithmetic instructions.
Tests fadd/fsub/fmul/fdiv for both single and double precision. */
float test_fadd_s(float a, float b)
{
float r;
asm("fadd.s %0, %1, %2" : "=f"(r) : "f"(a), "f"(b));
return r;
}
float test_fsub_s(float a, float b)
{
float r;
asm("fsub.s %0, %1, %2" : "=f"(r) : "f"(a), "f"(b));
return r;
}
float test_fmul_s(float a, float b)
{
float r;
asm("fmul.s %0, %1, %2" : "=f"(r) : "f"(a), "f"(b));
return r;
}
float test_fdiv_s(float a, float b)
{
float r;
asm("fdiv.s %0, %1, %2" : "=f"(r) : "f"(a), "f"(b));
return r;
}
double test_fadd_d(double a, double b)
{
double r;
asm("fadd.d %0, %1, %2" : "=f"(r) : "f"(a), "f"(b));
return r;
}
double test_fsub_d(double a, double b)
{
double r;
asm("fsub.d %0, %1, %2" : "=f"(r) : "f"(a), "f"(b));
return r;
}
double test_fmul_d(double a, double b)
{
double r;
asm("fmul.d %0, %1, %2" : "=f"(r) : "f"(a), "f"(b));
return r;
}
double test_fdiv_d(double a, double b)
{
double r;
asm("fdiv.d %0, %1, %2" : "=f"(r) : "f"(a), "f"(b));
return r;
}
int test_farith(void)
{
int ok = 1;
if (test_fadd_s(1.5f, 2.5f) != 4.0f) {
printf("FAIL: fadd.s\n");
ok = 0;
}
if (test_fsub_s(5.0f, 2.0f) != 3.0f) {
printf("FAIL: fsub.s\n");
ok = 0;
}
if (test_fmul_s(3.0f, 4.0f) != 12.0f) {
printf("FAIL: fmul.s\n");
ok = 0;
}
if (test_fdiv_s(12.0f, 4.0f) != 3.0f) {
printf("FAIL: fdiv.s\n");
ok = 0;
}
if (test_fadd_d(1.5, 2.5) != 4.0) {
printf("FAIL: fadd.d\n");
ok = 0;
}
if (test_fsub_d(5.0, 2.0) != 3.0) {
printf("FAIL: fsub.d\n");
ok = 0;
}
if (test_fmul_d(3.0, 4.0) != 12.0) {
printf("FAIL: fmul.d\n");
ok = 0;
}
if (test_fdiv_d(12.0, 4.0) != 3.0) {
printf("FAIL: fdiv.d\n");
ok = 0;
}
return ok;
}
int csr_pseudo_main(void)
{
int ok = 1;
int old, tmp;
asm volatile("csrr %0, 0x003" : "=r"(old));
asm volatile("csrr %0, 0x003" : "=r"(tmp));
printf("csrr fcsr=%x\n", (unsigned)tmp);
asm volatile("csrw 0x003, %0" : : "r"(0xE0));
asm volatile("csrr %0, 0x003" : "=r"(tmp));
printf("csrw: wrote e0 got %x\n", (unsigned)tmp);
if (tmp != 0xE0) { printf("FAIL: csrw\n"); ok = 0; }
asm volatile("csrw 0x003, %0" : : "r"(old));
asm volatile("csrwi 0x003, 0x10");
asm volatile("csrr %0, 0x003" : "=r"(tmp));
printf("csrwi: wrote 0x10 got %x\n", (unsigned)tmp);
if (tmp != 0x10) { printf("FAIL: csrwi\n"); ok = 0; }
asm volatile("csrw 0x003, %0" : : "r"(old));
asm volatile("csrsi 0x003, 0x03");
asm volatile("csrr %0, 0x003" : "=r"(tmp));
printf("csrsi: old|3=%x\n", (unsigned)tmp);
if ((old | 0x03) != tmp) { printf("FAIL: csrsi\n"); ok = 0; }
asm volatile("csrw 0x003, %0" : : "r"(old));
asm volatile("csrci 0x003, 0x03");
asm volatile("csrr %0, 0x003" : "=r"(tmp));
printf("csrci: old&~3=%x\n", (unsigned)tmp);
if ((old & ~0x03) != tmp) { printf("FAIL: csrci\n"); ok = 0; }
asm volatile("csrw 0x003, %0" : : "r"(old));
return ok;
}
int fp_cmp_cvt_main(void)
{
/* F/D comparison (use raw regs to avoid inline asm float→int bug) */
asm volatile("feq.s a0, fa0, fa1");
asm volatile("feq.d a0, fa0, fa1");
asm volatile("flt.s a0, fa0, fa1");
asm volatile("flt.d a0, fa0, fa1");
asm volatile("fle.s a0, fa0, fa1");
asm volatile("fle.d a0, fa0, fa1");
/* fcvt conversions */
asm volatile("fcvt.w.s a0, fa0");
asm volatile("fcvt.wu.s a0, fa0");
asm volatile("fcvt.s.w fa0, a0");
asm volatile("fcvt.w.d a0, fa0");
asm volatile("fcvt.d.w fa0, a0");
asm volatile("fcvt.d.s fa0, fa0");
asm volatile("fcvt.s.d fa0, fa0");
/* fclass */
asm volatile("fclass.s a0, fa0");
asm volatile("fclass.d a0, fa0");
return 1;
}
int amo_main(void)
{
int x = 0, r;
long long xd = 0xCAFEBABECAFEBABELL, rd, val = 0xDEADBEEFDEADBEEFLL;
asm("amoadd.w %0, %2, (%1)" : "=r"(r) : "r"(&x), "r"(val));
asm("amoswap.w %0, %2, (%1)" : "=r"(r) : "r"(&x), "r"(val));
asm("amoand.w %0, %2, (%1)" : "=r"(r) : "r"(&x), "r"(val));
asm("amoor.d %0, %2, (%1)" : "=r"(rd) : "r"(&xd), "r"(val));
asm("amoxor.w %0, %2, (%1)" : "=r"(r) : "r"(&x), "r"(val));
asm("amomax.w %0, %2, (%1)" : "=r"(r) : "r"(&x), "r"(val));
asm("amomaxu.d %0, %2, (%1)" : "=r"(rd) : "r"(&xd), "r"(val));
asm("amomin.w %0, %2, (%1)" : "=r"(r) : "r"(&x), "r"(val));
asm("amominu.d %0, %2, (%1)" : "=r"(rd) : "r"(&xd), "r"(val));
asm("amoadd.w.aq %0, %2, (%1)" : "=r"(r) : "r"(&x), "r"(val));
asm("amoadd.w.rl %0, %2, (%1)" : "=r"(r) : "r"(&x), "r"(val));
asm("amoadd.d.aqrl %0, %2, (%1)" : "=r"(rd) : "r"(&xd), "r"(val));
asm("amoswap.w.aq %0, %2, (%1)" : "=r"(r) : "r"(&x), "r"(val));
asm("amoswap.d.rl %0, %2, (%1)" : "=r"(rd) : "r"(&xd), "r"(val));
asm("amoand.w.aqrl %0, %2, (%1)" : "=r"(r) : "r"(&x), "r"(val));
asm("amoor.w.rl %0, %2, (%1)" : "=r"(r) : "r"(&x), "r"(val));
asm("amoor.d.aq %0, %2, (%1)" : "=r"(rd) : "r"(&xd), "r"(val));
asm("amoxor.w.aq %0, %2, (%1)" : "=r"(r) : "r"(&x), "r"(val));
asm("amomax.d.rl %0, %2, (%1)" : "=r"(rd) : "r"(&xd), "r"(val));
asm("amomaxu.w.aqrl %0, %2, (%1)" : "=r"(r) : "r"(&x), "r"(val));
asm("amomin.w.rl %0, %2, (%1)" : "=r"(r) : "r"(&x), "r"(val));
asm("amominu.d.aq %0, %2, (%1)" : "=r"(rd) : "r"(&xd), "r"(val));
return 1;
}
int fcvt_round_main(void)
{
asm volatile("fcvt.w.s a0, fa0, rne");
asm volatile("fcvt.w.s a0, fa0, rtz");
asm volatile("fcvt.w.s a0, fa0, rup");
asm volatile("fcvt.w.d a0, fa0, rne");
asm volatile("fcvt.w.d a0, fa0, rtz");
return 1;
}
int main()
{
int ok = 1;
ok &= test_pseudo();
ok &= test_ll();
ok &= test_farith();
ok &= csr_pseudo_main();
ok &= fp_cmp_cvt_main();
ok &= amo_main();
ok &= fcvt_round_main();
printf("%s\n", ok ? "PASS" : "FAIL");
return !ok;
}
#else
int main()
{
printf("SKIP\n");
}
#endif

View File

@ -1,6 +0,0 @@
csrr fcsr=1
csrw: wrote e0 got e0
csrwi: wrote 0x10 got 10
csrsi: old|3=3
csrci: old&~3=0
PASS

View File

@ -1,143 +0,0 @@
#include <stdio.h>
/* PROMOTE_RET test: verify char/short return values are properly
zero/sign-extended to 64-bit per the RISC-V integer calling convention.
Without PROMOTE_RET, upper bits of the return register may contain
garbage, causing incorrect results when assigned to a wider type. */
unsigned char get_uc(void) { return 0x80; }
signed char get_sc(void) { return 0x80; }
unsigned short get_us(void) { return 0x8000; }
signed short get_ss(void) { return 0x8000; }
/* Prevent inlining to force ABI-compliant calling. */
unsigned char (* volatile fp_uc)(void) = get_uc;
signed char (* volatile fp_sc)(void) = get_sc;
unsigned short (* volatile fp_us)(void) = get_us;
signed short (* volatile fp_ss)(void) = get_ss;
int promote_main(void)
{
int ok = 1;
unsigned long long uc = fp_uc();
signed long long sc = fp_sc();
unsigned long long us = fp_us();
signed long long ss = fp_ss();
printf("uc=%llx sc=%llx us=%llx ss=%llx\n",
(unsigned long long)uc,
(unsigned long long)sc,
(unsigned long long)us,
(unsigned long long)ss);
if (uc != 0x80) {
printf("FAIL: uc not zero-extended\n");
ok = 0;
}
if (sc != 0xffffffffffffff80LL) {
printf("FAIL: sc not sign-extended\n");
ok = 0;
}
if (us != 0x8000) {
printf("FAIL: us not zero-extended\n");
ok = 0;
}
if (ss != 0xffffffffffff8000LL) {
printf("FAIL: ss not sign-extended\n");
ok = 0;
}
printf("%s\n", ok ? "PASS" : "FAIL");
return ok ? 0 : 1;
}
/* gen_cvt_csti test: verify narrow-type conversions in expressions.
Without the fix, TCC's riscv64 backend could miss the conversion
step when promoting a narrow result back to int, producing wrong
values (e.g., treating a char as still 32-bit). */
int cast_main(void)
{
int ok = 1;
int x = 0x12345678;
/* Cast to char then add 1 — result must be 8-bit. */
char c = (char)x + 1;
unsigned char uc = (unsigned char)x + 1;
short s = (short)x + 1;
unsigned short us = (unsigned short)x + 1;
printf("c=%x uc=%x s=%x us=%x\n",
(unsigned char)c, (unsigned)uc,
(unsigned short)s, (unsigned)us);
if (c != (char)0x78 + 1) {
printf("FAIL: char conversion\n");
ok = 0;
}
if (uc != (unsigned char)0x78 + 1) {
printf("FAIL: unsigned char conversion\n");
ok = 0;
}
if (s != (short)0x5678 + 1) {
printf("FAIL: short conversion\n");
ok = 0;
}
if (us != (unsigned short)0x5678 + 1) {
printf("FAIL: unsigned short conversion\n");
ok = 0;
}
printf("%s\n", ok ? "PASS" : "FAIL");
return ok ? 0 : 1;
}
/* gen_cvt_sxtw test: verify sign-extension from 32-bit int to 64-bit long long.
Without the fix, the riscv64 backend had an empty stub for gen_cvt_sxtw,
leaving upper 32 bits unmodified (containing whatever was in the register
before), so (long long)(int)x produced wrong results for negative values. */
int sign_main(void)
{
int ok = 1;
int x = 0x80000000;
long long y = (long long)x;
printf("y=%llx\n", (unsigned long long)y);
if (y != 0xffffffff80000000LL) {
printf("FAIL: int→long long sign-extension\n");
ok = 0;
}
/* Also test positive value. */
x = 0x40000000;
y = (long long)x;
printf("y=%llx\n", (unsigned long long)y);
if (y != 0x40000000LL) {
printf("FAIL: int→long long positive value\n");
ok = 0;
}
/* Test via unsigned int to catch zero-extension vs sign-extension. */
unsigned int ux = 0x80000000;
long long uy = (long long)(int)ux;
printf("uy=%llx\n", (unsigned long long)uy);
if (uy != 0xffffffff80000000LL) {
printf("FAIL: unsigned→int→long long sign-extension\n");
ok = 0;
}
printf("%s\n", ok ? "PASS" : "FAIL");
return ok ? 0 : 1;
}
int main()
{
return
promote_main()
| cast_main()
| sign_main();
}

View File

@ -1,8 +0,0 @@
uc=80 sc=ffffffffffffff80 us=8000 ss=ffffffffffff8000
PASS
c=79 uc=79 s=5679 us=5679
PASS
y=ffffffff80000000
y=40000000
uy=ffffffff80000000
PASS

View File

@ -1,17 +0,0 @@
#include <stdio.h>
static void f(int x)
{
printf("f(%d)\n", x);
}
int main(void)
{
int count = 0, i = 0;
for (; i < 3; ++i) {
printf("%d\n", i);
(void)(i || (f(i), ++count));
}
printf("count %d\n", count);
return count == 1 ? 0 : 1;
}

View File

@ -1,5 +0,0 @@
0
f(0)
1
2
count 1

View File

@ -1,50 +0,0 @@
#include <stdio.h>
#include <pthread.h>
__thread int tls_init = 42;
__thread int tls_zero;
static void *thread_func(void *arg)
{
(void)arg;
printf("%d\n", tls_init);
if (tls_init != 42) return (void *)1;
printf("%d\n", tls_zero);
if (tls_zero != 0) return (void *)1;
tls_init = 100;
tls_zero = 200;
printf("%d\n", tls_init);
printf("%d\n", tls_zero);
return (void *)0;
}
int main()
{
pthread_t t;
void *ret;
int errors = 0;
printf("%d\n", tls_init);
if (tls_init != 42) errors = 1;
printf("%d\n", tls_zero);
if (tls_zero != 0) errors = 1;
pthread_create(&t, NULL, thread_func, NULL);
pthread_join(t, &ret);
if (ret) errors = 1;
printf("%d\n", tls_init);
if (tls_init != 42) errors = 1;
printf("%d\n", tls_zero);
if (tls_zero != 0) errors = 1;
return errors;
}

View File

@ -1,8 +0,0 @@
42
0
42
0
100
200
42
0

View File

@ -1,35 +0,0 @@
#include <stdio.h>
#include <windows.h>
#define PTR(x) ((PVOID)(ULONG_PTR)(x))
#define CHECK(name, expr) printf("%s: %s\n", name, (expr) ? "yes" : "no")
int main(void)
{
PVOID volatile slot = PTR(0x1111222233334444ULL);
PVOID old;
old = InterlockedExchangePointer(&slot, PTR(0x5555666677778888ULL));
CHECK("exchange old", old == PTR(0x1111222233334444ULL));
CHECK("exchange stored", slot == PTR(0x5555666677778888ULL));
old = InterlockedCompareExchangePointer(&slot,
PTR(0x9999aaaabbbbccccULL),
PTR(0x5555666677778888ULL));
CHECK("compare old", old == PTR(0x5555666677778888ULL));
CHECK("compare stored", slot == PTR(0x9999aaaabbbbccccULL));
old = InterlockedCompareExchangePointerAcquire(&slot,
PTR(0xdddd111122223333ULL),
PTR(0x0123456789abcdefULL));
CHECK("acquire old", old == PTR(0x9999aaaabbbbccccULL));
CHECK("acquire stored", slot == PTR(0x9999aaaabbbbccccULL));
old = InterlockedCompareExchangePointerRelease(&slot,
PTR(0xdddd111122223333ULL),
PTR(0x9999aaaabbbbccccULL));
CHECK("release old", old == PTR(0x9999aaaabbbbccccULL));
CHECK("release stored", slot == PTR(0xdddd111122223333ULL));
return 0;
}

View File

@ -1,8 +0,0 @@
exchange old: yes
exchange stored: yes
compare old: yes
compare stored: yes
acquire old: yes
acquire stored: yes
release old: yes
release stored: yes

View File

@ -421,7 +421,7 @@ int f() { return v(); }
#elif defined test_switch_W4
#pragma comment(option, "-Wunsupported -Wno-error=implicit-function-declaration -Werror")
#endif
void func(void)
void func()
{
char *ccp = "123";
fink();
@ -551,114 +551,4 @@ int main(int argc, char **argv)
}
#elif defined test_const_array_member_addr_ok
typedef int int_array[1];
typedef struct { int_array arr; } my_struct;
int_array const *get_array(const my_struct *s)
{
return &(s->arr);
}
#elif defined test_const_array_member_decay_ok
typedef int int_array[1];
typedef struct { int_array arr; } my_struct;
const int *good_decay(const my_struct *s)
{
return s->arr;
}
#elif defined test_const_array_member_addr_bad
typedef int int_array[1];
typedef struct { int_array arr; } my_struct;
int_array *bad_array_addr(const my_struct *s)
{
return &(s->arr);
}
#elif defined test_const_array_member_decay_bad
typedef int int_array[1];
typedef struct { int_array arr; } my_struct;
int *bad_decay(const my_struct *s)
{
return s->arr;
}
#elif defined test_const_array_member_write_bad
typedef int int_array[1];
typedef struct { int_array arr; } my_struct;
void bad_write(const my_struct *s)
{
s->arr[0] = 1;
}
#elif defined test_const_struct_array_member_write_bad
typedef struct { int x; } inner;
typedef struct { inner arr[1]; } outer;
void bad_inner_write(const outer *s)
{
s->arr[0].x = 1;
}
#elif defined test_volatile_array_member_addr_ok
typedef int int_array[1];
typedef struct { int_array arr; } my_struct;
int_array volatile *get_volatile_array(volatile my_struct *s)
{
return &(s->arr);
}
#elif defined test_volatile_array_member_decay_ok
typedef int int_array[1];
typedef struct { int_array arr; } my_struct;
volatile int *good_volatile_decay(volatile my_struct *s)
{
return s->arr;
}
#elif defined test_volatile_array_member_addr_bad
typedef int int_array[1];
typedef struct { int_array arr; } my_struct;
int_array *bad_volatile_array_addr(volatile my_struct *s)
{
return &(s->arr);
}
#elif defined test_volatile_array_member_decay_bad
typedef int int_array[1];
typedef struct { int_array arr; } my_struct;
int *bad_volatile_decay(volatile my_struct *s)
{
return s->arr;
}
#elif defined test_volatile_array_member_write_ok
typedef int int_array[1];
typedef struct { int_array arr; } my_struct;
void good_volatile_write(volatile my_struct *s)
{
s->arr[0] = 1;
}
#endif

View File

@ -262,31 +262,3 @@ bar 15 12 34
[test_scope_3]
60_errors_and_warnings.c:548: warning: assignment from incompatible pointer type
60_errors_and_warnings.c:549: error: initialization of incomplete type
[test_const_array_member_addr_ok]
[test_const_array_member_decay_ok]
[test_const_array_member_addr_bad]
60_errors_and_warnings.c:581: warning: assignment discards qualifiers from pointer target type
[test_const_array_member_decay_bad]
60_errors_and_warnings.c:591: warning: assignment discards qualifiers from pointer target type
[test_const_array_member_write_bad]
60_errors_and_warnings.c:601: warning: assignment of read-only location
[test_const_struct_array_member_write_bad]
60_errors_and_warnings.c:611: warning: assignment of read-only location
[test_volatile_array_member_addr_ok]
[test_volatile_array_member_decay_ok]
[test_volatile_array_member_addr_bad]
60_errors_and_warnings.c:641: warning: assignment discards qualifiers from pointer target type
[test_volatile_array_member_decay_bad]
60_errors_and_warnings.c:651: warning: assignment discards qualifiers from pointer target type
[test_volatile_array_member_write_ok]

View File

@ -38,11 +38,6 @@ struct hfa32 { long double a, b; } hfa32 = { 32.1, 32.2 };
struct hfa33 { long double a, b, c; } hfa33 = { 33.1, 33.2, 33.3 };
struct hfa34 { long double a, b, c, d; } hfa34 = { 34.1, 34.2, 34.3, 34.4 };
struct empty { };
/* Keep the top-level offsets at zero without changing the type into a union. */
struct hfae12 { struct empty e; struct hfa12 h; } hfae12 = { { }, { 112.1, 112.2 } };
struct hfae22 { struct empty e; struct hfa22 h; } hfae22 = { { }, { 122.1, 122.2 } };
void fa_s1(struct s1 a) { printf("%.1s\n", a.x); }
void fa_s2(struct s2 a) { printf("%.2s\n", a.x); }
void fa_s3(struct s3 a) { printf("%.3s\n", a.x); }
@ -87,10 +82,6 @@ void fa_hfa33(struct hfa33 a)
{ printf("%.1Lf %.1Lf %.1Lf\n", a.a, a.b, a.c); }
void fa_hfa34(struct hfa34 a)
{ printf("%.1Lf %.1Lf %.1Lf %.1Lf\n", a.a, a.b, a.c, a.d); }
void fa_hfae12(struct hfae12 a)
{ printf("%.1f %.1f\n", a.h.a, a.h.b); }
void fa_hfae22(struct hfae22 a)
{ printf("%.1f %.1f\n", a.h.a, a.h.b); }
void fa1(struct s8 a, struct s9 b, struct s10 c, struct s11 d,
struct s12 e, struct s13 f)
@ -149,8 +140,6 @@ void arg(void)
fa_hfa32(hfa32);
fa_hfa33(hfa33);
fa_hfa34(hfa34);
fa_hfae12(hfae12);
fa_hfae22(hfae22);
fa1(s8, s9, s10, s11, s12, s13);
fa2(s9, s10, s11, s12, s13, s14);
fa3(hfa14, hfa23, hfa32);
@ -189,8 +178,6 @@ struct hfa31 fr_hfa31(void) { return hfa31; }
struct hfa32 fr_hfa32(void) { return hfa32; }
struct hfa33 fr_hfa33(void) { return hfa33; }
struct hfa34 fr_hfa34(void) { return hfa34; }
struct hfae12 fr_hfae12(void) { return hfae12; }
struct hfae22 fr_hfae22(void) { return hfae22; }
void ret(void)
{
@ -241,8 +228,6 @@ void ret(void)
printf("%.1Lf %.1Lf\n", fr_hfa32().a, fr_hfa32().b);
printf("%.1Lf %.1Lf\n", fr_hfa33().a, fr_hfa33().c);
printf("%.1Lf %.1Lf\n", fr_hfa34().a, fr_hfa34().d);
printf("%.1f %.1f\n", fr_hfae12().h.a, fr_hfae12().h.b);
printf("%.1f %.1f\n", fr_hfae22().h.a, fr_hfae22().h.b);
}
void*

View File

@ -28,8 +28,6 @@ cdefghijklmnopqrs
32.1 32.1
33.1 33.2 33.3
34.1 34.2 34.3 34.4
112.1 112.2
122.1 122.2
stu ABC JKL TUV 456 ghi
ABC JKL TUV 456 ghi tuv
14.1 14.4 23.1 23.3 32.1 32.2
@ -64,8 +62,6 @@ cdefghijklmnopqrs
32.1 32.2
33.1 33.3
34.1 34.4
112.1 112.2
122.1 122.2
stdarg:
ABCDEFGHI ABCDEFGHI ABCDEFGHI ABCDEFGHI ABCDEFGHI ABCDEFGHI
lmnopqr ABCDEFGHI ABCDEFGHI ABCDEFGHI ABCDEFGHI ABCDEFGHI

View File

@ -19,9 +19,6 @@ ifeq (,$(filter i386 x86_64,$(ARCH)))
SKIP += 85_asm-outside-function.test # x86 asm
SKIP += 127_asm_goto.test # hardcodes x86 asm
endif
ifeq (,$(filter x86_64 riscv64 arm64 i386,$(ARCH)))
SKIP += 144_tls.test # TLS only implemented on these architectures so far
endif
ifeq ($(CONFIG_backtrace),no)
SKIP += 113_btdll.test
CONFIG_bcheck = no
@ -50,29 +47,12 @@ ifeq (-$(CONFIG_WIN32)-,-yes-)
SKIP += 114_bound_signal.test # No pthread support
SKIP += 117_builtins.test # win32 port doesn't define __builtins
SKIP += 124_atomic_counter.test # No pthread support
SKIP += 144_tls.test # No pthread support
endif
ifneq (,$(filter OpenBSD FreeBSD NetBSD,$(TARGETOS)))
SKIP += 106_versym.test # no pthread_condattr_setpshared
SKIP += 114_bound_signal.test # libc problem signal/fork
SKIP += 116_bound_setjmp2.test # No TLS_FUNC/TLS_VAR in bcheck.c
endif
ifdef CONFIG_OSX
SKIP += 144_tls.test # TLS runtime not supported on Mach-O
endif
ifeq (,$(filter arm64 aarch64,$(ARCH)))
SKIP += 138_arm64_encoding.test
SKIP += 139_arm64_errors.test
SKIP += 140_arm64_extasm.test
endif
ifneq ($(CONFIG_WIN32),yes)
SKIP += 145_winarm64_interlocked.test
else ifeq (,$(filter arm64 aarch64,$(ARCH)))
SKIP += 145_winarm64_interlocked.test
endif
ifeq (,$(filter riscv64,$(ARCH)))
SKIP += 141_riscv_asm.test # riscv64 asm
endif
# Some tests might need arguments
ARGS =
@ -82,7 +62,6 @@ ARGS =
# And some tests don't test the right thing with -run
NORUN =
42_function_pointer.test : NORUN = true
# riscv64 asm tests validate encoding, raw regs may crash at runtime
# Some tests might need different flags
FLAGS =
@ -95,8 +74,8 @@ endif
# These tests run several snippets from the same file one by one
60_errors_and_warnings.test : FLAGS += -dt
96_nodata_wanted.test : FLAGS += -dt
139_arm64_errors.test : FLAGS += -dt
# Always generate certain .expects (don't put these in the GIT),
GEN-ALWAYS =
# GEN-ALWAYS += 95_bitfields.expect # does not work
@ -119,10 +98,6 @@ GEN-ALWAYS =
# constructor/destructor
108_constructor.test: NORUN = true
# TLS needs executable and pthread, not -run
144_tls.test: FLAGS += -pthread
144_tls.test: NORUN = true
112_backtrace.test: FLAGS += -dt -b
112_backtrace.test 113_btdll.test 126_bound_global.test: FILTER += \
-e 's;[0-9A-Fa-fx]\{5,\};........;g' \
@ -150,8 +125,6 @@ endif
126_bound_global.test: NORUN = true
128_run_atexit.test: FLAGS += -dt
132_bound_test.test: FLAGS += -b
140_arm64_extasm.test: GEN = $(GEN-TCC)
141_riscv_asm.test: GEN = $(GEN-TCC)
# Filter source directory in warnings/errors (out-of-tree builds)
FILTER = 2>&1 | sed -e 's,$(SRC)/,,g'

View File

@ -5,15 +5,13 @@
@echo off
setlocal
if (%1)==(-clean) goto :cleanup
set CC=gcc -O2 -Wall
set CC=gcc
set /p VERSION= < ..\VERSION
set TCCDIR=
set BINDIR=
set DOC=no
set TX=
set SELF=%~nx0
set XCC=no
goto :a0
:a2
shift
:a3
@ -29,22 +27,20 @@ if (%1)==(-v) set VERSION=%~2&& goto :a2
if (%1)==(-i) set TCCDIR=%2&& goto :a2
if (%1)==(-b) set BINDIR=%2&& goto :a2
if (%1)==(-d) set DOC=yes&& goto :a3
if (%1)==(-x) set TX=%2&& goto :a2
if (%1)==(-x) set XCC=yes&& goto :a3
if (%1)==() goto :p1
:usage
echo usage: build-tcc.bat [ options ... ]
echo options:
echo -c prog use prog (gcc/tcc/cl) to compile tcc
echo -c "prog options" use prog with options to compile tcc
echo -t target set target
echo -x target build tcc cross-compiler for target
echo -t 32/64 force 32/64 bit default target
echo -v "version" set tcc version
echo -i tccdir install tcc into tccdir
echo -b bindir but install tcc.exe and libtcc.dll into bindir
echo -d create tcc-doc.html too (needs makeinfo)
echo -x build the cross compiler too
echo -clean delete all previously produced files and directories
echo supported targets i386 x86_64 arm64
exit /B 1
@rem ------------------------------------------------------
@ -69,7 +65,6 @@ exit /B 0
if exist %1 rmdir /Q/S %1 && %LOG% %1
exit /B 0
@rem ------------------------------------------------------
:cl
@echo off
set CMD=cl
@ -89,19 +84,36 @@ echo on
@rem main program
:p1
if not _%TX%_==__ set T=%TX%&&set TX=%TX%-win32-
if _%T%_%PROCESSOR_ARCHITECTURE%_==__x86_ set T=i386
if _%T%_%PROCESSOR_ARCHITECTURE%_==__ARM64_ set T=arm64
if _%T%_==__ set T=x86_64
if %T%==i386 set D=-DTCC_TARGET_PE -DTCC_TARGET_I386
if %T%==x86_64 set D=-DTCC_TARGET_PE -DTCC_TARGET_X86_64
if %T%==arm64 set D=-DTCC_TARGET_PE -DTCC_TARGET_ARM64
if "%D%"=="" echo %SELF%: error: unknown target '%T%'&&exit /B 1
if not %T%_==_ goto :p2
set T=32
if %PROCESSOR_ARCHITECTURE%_==AMD64_ set T=64
if %PROCESSOR_ARCHITEW6432%_==AMD64_ set T=64
:p2
if "%CC:~-3%"=="gcc" set CC=%CC% -O2 -s -static
if (%BINDIR%)==() set BINDIR=%TCCDIR%
@if (%CC:~0,3%)==(gcc) set CC=%CC% -s -static
@if (%BINDIR%)==() set BINDIR=%TCCDIR%
set D32=-DTCC_TARGET_PE -DTCC_TARGET_I386
set D64=-DTCC_TARGET_PE -DTCC_TARGET_X86_64
set P32=i386-win32
set P64=x86_64-win32
:git_hash
if %T%==64 goto :t64
set D=%D32%
set P=%P32%
set DX=%D64%
set PX=%P64%
set TX=64
goto :p3
:t64
set D=%D64%
set P=%P64%
set DX=%D32%
set PX=%P32%
set TX=32
goto :p3
:p3
git.exe --version 2>nul
if not %ERRORLEVEL%==0 goto :git_done
for /f %%b in ('git.exe rev-parse --abbrev-ref HEAD') do set GITHASH=%%b
@ -113,37 +125,34 @@ if %ERRORLEVEL%==1 set GITHASH=%GITHASH%*
:config.h
echo>..\config.h #define TCC_VERSION "%VERSION%"
@if not "%GITHASH%"=="" echo>>..\config.h #define TCC_GITHASH "%GITHASH%"
@if not _%BINDIR%_==_%TCCDIR%_ echo>>..\config.h #define CONFIG_TCCDIR "%TCCDIR:\=/%"
@if not _%TX%_==__ @echo>>..\config.h #define CONFIG_TCC_CROSSPREFIX "%TX%"
if not (%GITHASH%)==() echo>> ..\config.h #define TCC_GITHASH "%GITHASH%"
@if not (%BINDIR%)==(%TCCDIR%) echo>> ..\config.h #define CONFIG_TCCDIR "%TCCDIR:\=/%"
if %TX%==64 echo>> ..\config.h #ifdef TCC_TARGET_X86_64
if %TX%==32 echo>> ..\config.h #ifdef TCC_TARGET_I386
echo>> ..\config.h #define CONFIG_TCC_CROSSPREFIX "%PX%-"
echo>> ..\config.h #endif
@rem echo>> ..\config.h #define CONFIG_TCC_PREDEFS 1
@rem %CC% -DC2STR ..\conftest.c -o c2str.exe
@rem .\c2str.exe ../include/tccdefs.h ../tccdefs_.h
@if not _%TX%_==__ goto :tcc_cross
@if not _%TCC_C%_==__ goto :tcc_only
for %%f in (*tcc.exe *tcc.dll) do @del %%f
@if _%LIBTCC_C%_==__ set LIBTCC_C=..\libtcc.c
@set IMPLIB=libtcc.dll
@if "%CC:~0,5%"=="clang" set IMPLIB=libtcc.lib
%CC% -o libtcc.dll -shared %LIBTCC_C% %D% -DLIBTCC_AS_DLL
@if errorlevel 1 goto :the_end
%CC% -o tcc.exe ..\tcc.c %IMPLIB% %D% -DONE_SOURCE"=0"
@if errorlevel 1 goto :the_end
@goto :compiler_done
:tcc_only
@if _%TCC_C%_==__ goto compiler_2parts
@rem if TCC_C was defined then build only tcc.exe
%CC% -o tcc.exe %TCC_C% %D%
@if errorlevel 1 goto :the_end
@goto :compiler_done
:tcc_cross
%CC% -o %TX%tcc.exe ..\tcc.c %D%
:compiler_2parts
@if _%LIBTCC_C%_==__ set LIBTCC_C=..\libtcc.c
%CC% -o libtcc.dll -shared %LIBTCC_C% %D% -DLIBTCC_AS_DLL
@if errorlevel 1 goto :the_end
%CC% -o tcc.exe ..\tcc.c libtcc.dll %D% -DONE_SOURCE"=0"
@if errorlevel 1 goto :the_end
if not _%XCC%_==_yes_ goto :compiler_done
%CC% -o %PX%-tcc.exe ..\tcc.c %DX%
@if errorlevel 1 goto :the_end
@goto :compiler_done
:compiler_done
@if (%EXES_ONLY%)==(yes) goto :files_done
@ -159,7 +168,8 @@ if exist libtcc.dll .\tcc -impdef libtcc.dll -o libtcc\libtcc.def
@if errorlevel 1 goto :the_end
:lib
@call :make_lib %TX% || goto :the_end
call :make_lib %T% || goto :the_end
@if exist %PX%-tcc.exe call :make_lib %TX% %PX%- || goto :the_end
:tcc-doc.html
@if not (%DOC%)==(yes) goto :doc-done
@ -183,26 +193,23 @@ for %%f in (include examples libtcc doc) do @xcopy>nul /s/i/q/y %%f %TCCDIR%\%%f
exit /B %ERRORLEVEL%
:make_lib
@set LIBTCC1=libtcc1
@if _%1_==_arm64_ set LIBTCC1=lib-arm64
.\%1tcc -B. -c ../lib/%LIBTCC1%.c
.\%1tcc -B. -c lib/crt1.c
.\%1tcc -B. -c lib/crt1w.c
.\%1tcc -B. -c lib/wincrt1.c
.\%1tcc -B. -c lib/wincrt1w.c
.\%1tcc -B. -c lib/dllcrt1.c
.\%1tcc -B. -c lib/dllmain.c
.\%1tcc -B. -c lib/winex.c
.\%1tcc -B. -c lib/chkstk.S
.\%1tcc -B. -c ../lib/alloca.S
.\%1tcc -B. -c ../lib/alloca-bt.S
.\%1tcc -B. -c ../lib/stdatomic.c
.\%1tcc -B. -c ../lib/atomic.S
.\%1tcc -B. -c ../lib/builtin.c
.\%1tcc -ar lib/%1libtcc1.a %LIBTCC1%.o crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o winex.o chkstk.o alloca.o alloca-bt.o stdatomic.o atomic.o builtin.o
.\%1tcc -B. -c ../lib/bcheck.c -o lib/%1bcheck.o -bt -I..
.\%1tcc -B. -c ../lib/bt-exe.c -o lib/%1bt-exe.o
.\%1tcc -B. -c ../lib/bt-log.c -o lib/%1bt-log.o
.\%1tcc -B. -c ../lib/bt-dll.c -o lib/%1bt-dll.o
.\%1tcc -B. -c ../lib/runmain.c -o lib/%1runmain.o
.\tcc -B. -m%1 -c ../lib/libtcc1.c
.\tcc -B. -m%1 -c lib/crt1.c
.\tcc -B. -m%1 -c lib/crt1w.c
.\tcc -B. -m%1 -c lib/wincrt1.c
.\tcc -B. -m%1 -c lib/wincrt1w.c
.\tcc -B. -m%1 -c lib/dllcrt1.c
.\tcc -B. -m%1 -c lib/dllmain.c
.\tcc -B. -m%1 -c lib/chkstk.S
.\tcc -B. -m%1 -c ../lib/alloca.S
.\tcc -B. -m%1 -c ../lib/alloca-bt.S
.\tcc -B. -m%1 -c ../lib/stdatomic.c
.\tcc -B. -m%1 -c ../lib/atomic.S
.\tcc -B. -m%1 -c ../lib/builtin.c
.\tcc -B. -m%1 -ar lib/%2libtcc1.a libtcc1.o crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o chkstk.o alloca.o alloca-bt.o stdatomic.o atomic.o builtin.o
.\tcc -B. -m%1 -c ../lib/bcheck.c -o lib/%2bcheck.o -bt -I..
.\tcc -B. -m%1 -c ../lib/bt-exe.c -o lib/%2bt-exe.o
.\tcc -B. -m%1 -c ../lib/bt-log.c -o lib/%2bt-log.o
.\tcc -B. -m%1 -c ../lib/bt-dll.c -o lib/%2bt-dll.o
.\tcc -B. -m%1 -c ../lib/runmain.c -o lib/%2runmain.o
exit /B %ERRORLEVEL%

View File

@ -70,15 +70,12 @@
#ifdef _WIN64
#define __stdcall
#if defined(__aarch64__)
#define _M_ARM64 1
#define _ARM64_ 1
#else
#define _AMD64_ 1
#define __x86_64 1
#define _M_X64 100 /* Visual Studio */
#define _M_AMD64 100 /* Visual Studio */
#endif
#define USE_MINGW_SETJMP_TWO_ARGS
#define mingw_getsp tinyc_getbp
#else
#define __stdcall __attribute__((__stdcall__))
#define _X86_ 1

View File

@ -124,76 +124,37 @@ extern "C" {
SETJMP_FLOAT128 Xmm14;
SETJMP_FLOAT128 Xmm15;
} _JUMP_BUFFER;
#elif defined(_ARM_)
#define _JBLEN 28
#define _JBTYPE int
typedef struct __JUMP_BUFFER {
unsigned long Frame;
unsigned long R4;
unsigned long R5;
unsigned long R6;
unsigned long R7;
unsigned long R8;
unsigned long R9;
unsigned long R10;
unsigned long R11;
unsigned long Sp;
unsigned long Pc;
unsigned long Fpscr;
unsigned long long D[8];
} _JUMP_BUFFER;
#elif defined(_ARM64_)
#define _JBLEN 24
#define _JBTYPE unsigned __int64
typedef struct __JUMP_BUFFER {
unsigned __int64 Frame;
unsigned __int64 Reserved;
unsigned __int64 X19;
unsigned __int64 X20;
unsigned __int64 X21;
unsigned __int64 X22;
unsigned __int64 X23;
unsigned __int64 X24;
unsigned __int64 X25;
unsigned __int64 X26;
unsigned __int64 X27;
unsigned __int64 X28;
unsigned __int64 Fp;
unsigned __int64 Lr;
unsigned __int64 Sp;
unsigned long Fpcr;
unsigned long Fpsr;
double D[8];
} _JUMP_BUFFER;
#else
#define _JBLEN 1
#define _JBTYPE int
#endif
#ifndef _JMP_BUF_DEFINED
typedef _JBTYPE jmp_buf[_JBLEN];
#define _JMP_BUF_DEFINED
#endif
#pragma pack(pop)
void * __cdecl __attribute__ ((__nothrow__)) mingw_getsp(void);
#if defined __aarch64__
int _setjmpex(jmp_buf _Buf, void *frame);
#define setjmp(BUF) _setjmpex((BUF), (char*)__builtin_frame_address(0) + 224)
#elif defined __x86_64__
int _setjmp(jmp_buf _Buf, void *frame);
#define setjmp(BUF) _setjmp((BUF), __builtin_frame_address(0))
#else /* __i386__ */
int _setjmp(jmp_buf _Buf);
#define setjmp _setjmp
#ifdef USE_MINGW_SETJMP_TWO_ARGS
#ifndef _INC_SETJMPEX
#define setjmp(BUF) _setjmp((BUF),mingw_getsp())
int __cdecl __attribute__ ((__nothrow__)) _setjmp(jmp_buf _Buf,void *_Ctx);
#else
#undef setjmp
#define setjmp(BUF) _setjmpex((BUF),mingw_getsp())
#define setjmpex(BUF) _setjmpex((BUF),mingw_getsp())
int __cdecl __attribute__ ((__nothrow__)) _setjmpex(jmp_buf _Buf,void *_Ctx);
#endif
#else
#ifndef _INC_SETJMPEX
#define setjmp _setjmp
#endif
int __cdecl __attribute__ ((__nothrow__)) setjmp(jmp_buf _Buf);
#endif
__declspec(noreturn) void longjmp(jmp_buf _Buf,int _Value);
__declspec(noreturn) __attribute__ ((__nothrow__)) void __cdecl ms_longjmp(jmp_buf _Buf,int _Value)/* throw(...)*/;
__declspec(noreturn) __attribute__ ((__nothrow__)) void __cdecl longjmp(jmp_buf _Buf,int _Value);
#ifdef __cplusplus
}
#endif
#pragma pack(pop)
#endif

View File

@ -207,21 +207,6 @@ extern "C" {
#endif
#endif
#endif
#if defined __aarch64__
/* something does not work using those from msvcrt.dll */
# undef __argc
# undef __argv
# undef __wargv
# undef _wenviron
# undef _environ
extern int __argc;
extern char **__argv;
extern wchar_t **__wargv;
extern char **_environ;
extern wchar_t **_wenviron;
#endif
#ifndef _pgmptr
#ifdef _MSVCRT_
extern char *_pgmptr;

View File

@ -972,9 +972,7 @@ extern "C" {
LONG WINAPI InterlockedDecrement(LONG volatile *lpAddend);
LONG WINAPI InterlockedExchange(LONG volatile *Target,LONG Value);
#ifndef InterlockedExchangePointer
#define InterlockedExchangePointer(Target,Value) (PVOID)InterlockedExchange((PLONG)(Target),(LONG)(Value))
#endif
LONG WINAPI InterlockedExchangeAdd(LONG volatile *Addend,LONG Value);
LONG WINAPI InterlockedCompareExchange(LONG volatile *Destination,LONG Exchange,LONG Comperand);
@ -1037,7 +1035,6 @@ extern "C" {
return Old;
}
#ifndef InterlockedCompareExchangePointer
#ifdef __cplusplus
__CRT_INLINE PVOID __cdecl __InlineInterlockedCompareExchangePointer(PVOID volatile *Destination,PVOID ExChange,PVOID Comperand) {
return((PVOID)(LONG_PTR)InterlockedCompareExchange((LONG volatile *)Destination,(LONG)(LONG_PTR)ExChange,(LONG)(LONG_PTR)Comperand));
@ -1046,7 +1043,6 @@ extern "C" {
#else
#define InterlockedCompareExchangePointer(Destination,ExChange,Comperand)(PVOID)(LONG_PTR)InterlockedCompareExchange((LONG volatile *)(Destination),(LONG)(LONG_PTR)(ExChange),(LONG)(LONG_PTR)(Comperand))
#endif
#endif
#define InterlockedIncrementAcquire InterlockedIncrement
#define InterlockedIncrementRelease InterlockedIncrement
@ -1058,13 +1054,9 @@ extern "C" {
#define InterlockedCompareExchangeRelease InterlockedCompareExchange
#define InterlockedCompareExchangeAcquire64 InterlockedCompareExchange64
#define InterlockedCompareExchangeRelease64 InterlockedCompareExchange64
#ifndef InterlockedCompareExchangePointerAcquire
#define InterlockedCompareExchangePointerAcquire InterlockedCompareExchangePointer
#endif
#ifndef InterlockedCompareExchangePointerRelease
#define InterlockedCompareExchangePointerRelease InterlockedCompareExchangePointer
#endif
#endif
#if defined(_SLIST_HEADER_) && !defined(_NTOSP_)
WINBASEAPI VOID WINAPI InitializeSListHead(PSLIST_HEADER ListHead);

View File

@ -21,7 +21,7 @@ extern "C" {
#define __CRT_UNALIGNED
#endif
#if defined(__ia64__) || defined(__x86_64) || defined(__aarch64__)
#if defined(__ia64__) || defined(__x86_64)
#define UNALIGNED __CRT_UNALIGNED
#ifdef _WIN64
#define UNALIGNED64 __CRT_UNALIGNED
@ -65,7 +65,7 @@ extern "C" {
#ifdef _WIN64
#ifdef _AMD64_
#define PROBE_ALIGNMENT(_s) TYPE_ALIGNMENT(DWORD)
#elif defined(_IA64_) || defined(_ARM64_)
#elif defined(_IA64_)
#define PROBE_ALIGNMENT(_s) (TYPE_ALIGNMENT(_s) > TYPE_ALIGNMENT(DWORD) ? TYPE_ALIGNMENT(_s) : TYPE_ALIGNMENT(DWORD))
#else
#error No Target Architecture
@ -79,7 +79,7 @@ extern "C" {
#include <basetsd.h>
#if defined(_X86_) || defined(__ia64__) || defined(__x86_64) || defined(__aarch64__)
#if defined(_X86_) || defined(__ia64__) || defined(__x86_64)
#define DECLSPEC_IMPORT __declspec(dllimport)
#else
#define DECLSPEC_IMPORT
@ -321,7 +321,7 @@ typedef DWORD LCID;
#define Int32x32To64(a,b) (LONGLONG)((LONGLONG)(LONG)(a) *(LONG)(b))
#define UInt32x32To64(a,b) (ULONGLONG)((ULONGLONG)(DWORD)(a) *(DWORD)(b))
#define Int64ShrlMod32(a,b) ((DWORDLONG)(a)>>(b))
#elif defined(__ia64__) || defined(__x86_64) || defined(__aarch64__)
#elif defined(__ia64__) || defined(__x86_64)
#define Int32x32To64(a,b) ((LONGLONG)((LONG)(a)) *(LONGLONG)((LONG)(b)))
#define UInt32x32To64(a,b) ((ULONGLONG)((DWORD)(a)) *(ULONGLONG)((DWORD)(b)))
#define Int64ShrlMod32(a,b) ((ULONGLONG)(a) >> (b))
@ -829,6 +829,8 @@ typedef DWORD LCID;
typedef ULONG_PTR KSPIN_LOCK;
typedef KSPIN_LOCK *PKSPIN_LOCK;
#ifdef _AMD64_
#if defined(__x86_64) && !defined(RC_INVOKED)
#ifdef __cplusplus
@ -1280,6 +1282,7 @@ typedef DWORD LCID;
#ifdef __cplusplus
}
#endif
#endif
#define EXCEPTION_READ_FAULT 0
#define EXCEPTION_WRITE_FAULT 1
@ -1417,160 +1420,7 @@ typedef DWORD LCID;
typedef DWORD (*POUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK)(HANDLE Process,PVOID TableAddress,PDWORD Entries,PRUNTIME_FUNCTION *Functions);
#define OUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK_EXPORT_NAME "OutOfProcessFunctionTableCallback"
#endif /* defined(__x86_64) && !defined(RC_INVOKED) */
#if defined(__TINYC__) && (defined(__aarch64__) || defined(__arm64__)) && !defined(RC_INVOKED)
#define __TCC_WINNT_ATOMIC_SEQ_CST 5
/* TCC lowers __atomic_compare_exchange's fourth argument as weak, but the
ARM64 helper reads it as success_memorder. Strong CAS passes weak == 0,
so keep Interlocked's barriers explicit here. */
#define __TCC_WINNT_MEMORY_BARRIER() __asm__ __volatile__("dmb ish" : : : "memory")
/* This covers the LONG operations needed by TCC's semaphore code and the
pointer helpers that winbase.h exposes through Interlocked pointer macros.
Add local helpers before relying on increment/decrement, add/exchange-add,
bitwise, or 64-bit Interlocked forms on Windows ARM64 with TCC. */
__CRT_INLINE LONG InterlockedExchange(LONG volatile *Target,LONG Value) {
LONG Old;
__atomic_load(Target,&Old,__TCC_WINNT_ATOMIC_SEQ_CST);
__TCC_WINNT_MEMORY_BARRIER();
while (!__atomic_compare_exchange(Target,&Old,&Value,0,
__TCC_WINNT_ATOMIC_SEQ_CST,__TCC_WINNT_ATOMIC_SEQ_CST))
;
__TCC_WINNT_MEMORY_BARRIER();
return Old;
}
__CRT_INLINE LONG InterlockedCompareExchange(LONG volatile *Destination,LONG ExChange,LONG Comperand) {
LONG Old = Comperand;
__TCC_WINNT_MEMORY_BARRIER();
__atomic_compare_exchange(Destination,&Old,&ExChange,0,
__TCC_WINNT_ATOMIC_SEQ_CST,__TCC_WINNT_ATOMIC_SEQ_CST);
__TCC_WINNT_MEMORY_BARRIER();
return Old;
}
__CRT_INLINE PVOID __TCC_WINNT_InterlockedExchangePointer(PVOID volatile *Target,PVOID Value) {
PVOID Old;
__atomic_load(Target,&Old,__TCC_WINNT_ATOMIC_SEQ_CST);
__TCC_WINNT_MEMORY_BARRIER();
while (!__atomic_compare_exchange(Target,&Old,&Value,0,
__TCC_WINNT_ATOMIC_SEQ_CST,__TCC_WINNT_ATOMIC_SEQ_CST))
;
__TCC_WINNT_MEMORY_BARRIER();
return Old;
}
__CRT_INLINE PVOID __TCC_WINNT_InterlockedCompareExchangePointer(PVOID volatile *Destination,PVOID ExChange,PVOID Comperand) {
PVOID Old = Comperand;
__TCC_WINNT_MEMORY_BARRIER();
__atomic_compare_exchange(Destination,&Old,&ExChange,0,
__TCC_WINNT_ATOMIC_SEQ_CST,__TCC_WINNT_ATOMIC_SEQ_CST);
__TCC_WINNT_MEMORY_BARRIER();
return Old;
}
#define InterlockedExchangePointer __TCC_WINNT_InterlockedExchangePointer
#define InterlockedCompareExchangePointer __TCC_WINNT_InterlockedCompareExchangePointer
#define InterlockedCompareExchangePointerAcquire InterlockedCompareExchangePointer
#define InterlockedCompareExchangePointerRelease InterlockedCompareExchangePointer
#define InterlockedCompareExchangeAcquire InterlockedCompareExchange
#define InterlockedCompareExchangeRelease InterlockedCompareExchange
#undef __TCC_WINNT_MEMORY_BARRIER
#undef __TCC_WINNT_ATOMIC_SEQ_CST
#endif /* defined(__TINYC__) && (defined(__aarch64__) || defined(__arm64__)) && !defined(RC_INVOKED) */
#if defined(_ARM64_)
/* ARM64 Context Definition */
#define CONTEXT_ARM64 0x00400000
#define CONTEXT_CONTROL (CONTEXT_ARM64 | 0x00000001L)
#define CONTEXT_INTEGER (CONTEXT_ARM64 | 0x00000002L)
#define CONTEXT_FLOATING_POINT (CONTEXT_ARM64 | 0x00000004L)
#define CONTEXT_DEBUG (CONTEXT_ARM64 | 0x00000008L)
#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT)
#define CONTEXT_ALL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG)
#define ARM64_MAX_BREAKPOINTS 8
#define ARM64_MAX_WATCHPOINTS 2
typedef union _ARM64_NT_NEON128 {
struct {
ULONGLONG Low;
LONGLONG High;
} DUMMYSTRUCTNAME;
double D[2];
float S[4];
WORD H[8];
BYTE B[16];
} ARM64_NT_NEON128,*PARM64_NT_NEON128;
typedef struct DECLSPEC_ALIGN(16) _ARM64_NT_CONTEXT {
ULONG ContextFlags;
ULONG Cpsr;
union {
struct {
DWORD64 X0;
DWORD64 X1;
DWORD64 X2;
DWORD64 X3;
DWORD64 X4;
DWORD64 X5;
DWORD64 X6;
DWORD64 X7;
DWORD64 X8;
DWORD64 X9;
DWORD64 X10;
DWORD64 X11;
DWORD64 X12;
DWORD64 X13;
DWORD64 X14;
DWORD64 X15;
DWORD64 X16;
DWORD64 X17;
DWORD64 X18;
DWORD64 X19;
DWORD64 X20;
DWORD64 X21;
DWORD64 X22;
DWORD64 X23;
DWORD64 X24;
DWORD64 X25;
DWORD64 X26;
DWORD64 X27;
DWORD64 X28;
DWORD64 Fp;
DWORD64 Lr;
} DUMMYSTRUCTNAME;
DWORD64 X[31];
} DUMMYUNIONNAME;
DWORD64 Sp;
DWORD64 Pc;
ARM64_NT_NEON128 V[32];
DWORD Fpcr;
DWORD Fpsr;
DWORD Bcr[ARM64_MAX_BREAKPOINTS];
DWORD64 Bvr[ARM64_MAX_BREAKPOINTS];
DWORD Wcr[ARM64_MAX_WATCHPOINTS];
DWORD64 Wvr[ARM64_MAX_WATCHPOINTS];
} ARM64_NT_CONTEXT,*PARM64_NT_CONTEXT;
C_ASSERT(sizeof(ARM64_NT_CONTEXT) == 0x390);
typedef ARM64_NT_CONTEXT CONTEXT,*PCONTEXT;
typedef struct _RUNTIME_FUNCTION {
DWORD BeginAddress;
DWORD UnwindData;
} RUNTIME_FUNCTION,*PRUNTIME_FUNCTION;
typedef PRUNTIME_FUNCTION (*PGET_RUNTIME_FUNCTION_CALLBACK)(DWORD64 ControlPc,PVOID Context);
typedef DWORD (*POUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK)(HANDLE Process,PVOID TableAddress,PDWORD Entries,PRUNTIME_FUNCTION *Functions);
#endif /* _ARM64_ */
#if (defined _ARM64_ || defined _AMD64_) && !defined RC_INVOKED
NTSYSAPI VOID __cdecl RtlRestoreContext (PCONTEXT ContextRecord,struct _EXCEPTION_RECORD *ExceptionRecord);
NTSYSAPI BOOLEAN __cdecl RtlAddFunctionTable(PRUNTIME_FUNCTION FunctionTable,DWORD EntryCount,DWORD64 BaseAddress);
NTSYSAPI BOOLEAN __cdecl RtlInstallFunctionTableCallback(DWORD64 TableIdentifier,DWORD64 BaseAddress,DWORD Length,PGET_RUNTIME_FUNCTION_CALLBACK Callback,PVOID Context,PCWSTR OutOfProcessCallbackDll);
@ -3851,7 +3701,6 @@ typedef DWORD LCID;
#define IMAGE_FILE_MACHINE_CEF 0x0CEF
#define IMAGE_FILE_MACHINE_EBC 0x0EBC
#define IMAGE_FILE_MACHINE_AMD64 0x8664
#define IMAGE_FILE_MACHINE_ARM64 0xAA64
#define IMAGE_FILE_MACHINE_M32R 0x9041
#define IMAGE_FILE_MACHINE_CEE 0xC0EE
@ -4008,16 +3857,10 @@ typedef DWORD LCID;
#define IMAGE_SUBSYSTEM_EFI_ROM 13
#define IMAGE_SUBSYSTEM_XBOX 14
#define IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA 0x0020
#define IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE 0x0040
#define IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY 0x0080
#define IMAGE_DLLCHARACTERISTICS_NX_COMPAT 0x0100
#define IMAGE_DLLCHARACTERISTICS_NO_ISOLATION 0x0200
#define IMAGE_DLLCHARACTERISTICS_NO_SEH 0x0400
#define IMAGE_DLLCHARACTERISTICS_NO_BIND 0x0800
#define IMAGE_DLLCHARACTERISTICS_APPCONTAINER 0x1000
#define IMAGE_DLLCHARACTERISTICS_WDM_DRIVER 0x2000
#define IMAGE_DLLCHARACTERISTICS_GUARD_CF 0x4000
#define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 0x8000
#define IMAGE_DIRECTORY_ENTRY_EXPORT 0

View File

@ -8,32 +8,8 @@
#endif
/* ---------------------------------------------- */
#if defined(__aarch64__)
.globl __chkstk
__chkstk:
/* Windows ARM64 stack probing helper.
arm64-gen.c passes the requested frame size in x15, scaled in 16-byte
units. Probe one 4 KiB page at a time and leave SP unchanged; the caller
subtracts SP after the probe returns. */
mov x16, sp
lsl x17, x15, 4
cbz x17, L_chkstk_done
L_chkstk_loop:
subs x0, x17, 4096
bls L_chkstk_tail
sub x16, x16, 4096
ldr xzr, [x16]
sub x17, x17, 4096
b L_chkstk_loop
L_chkstk_tail:
sub x16, x16, x17
ldr xzr, [x16]
L_chkstk_done:
ret
#ifndef __x86_64__
/* ---------------------------------------------- */
#elif defined(__i386__)
.globl _(__chkstk)
_(__chkstk):
@ -57,7 +33,8 @@ P0:
jmp *4(%eax)
/* ---------------------------------------------- */
#else /* __x86_64__ */
#else
/* ---------------------------------------------- */
.globl _(__chkstk)
_(__chkstk):
@ -81,6 +58,16 @@ P0:
mov (%rax),%rcx /* restore ecx */
jmp *8(%rax)
/* ---------------------------------------------- */
/* setjmp/longjmp support */
.globl _(tinyc_getbp)
_(tinyc_getbp):
mov %rbp,%rax
ret
/* ---------------------------------------------- */
#endif
/* ---------------------------------------------- */

View File

@ -75,11 +75,10 @@ __attribute__((weak)) extern int __run_on_exit();
int _runtmain(int argc, /* as tcc passed in */ char **argv)
{
int ret;
#if defined UNICODE || defined __aarch64__
_startupinfo start_info = {0};
__tgetmainargs(&__argc, &__targv, &_tenviron, 0, &start_info);
#endif
#ifdef UNICODE
_startupinfo start_info = {0};
__tgetmainargs(&__argc, &__targv, &_tenviron, _dowildcard, &start_info);
/* may be wrong when tcc has received wildcards (*.c) */
if (argc < __argc) {
__targv += __argc - argc;
@ -94,8 +93,6 @@ int _runtmain(int argc, /* as tcc passed in */ char **argv)
#endif
run_ctors(__argc, __targv, _tenviron);
ret = _tmain(__argc, __targv, _tenviron);
fflush(stdout);
fflush(stderr);
run_dtors();
__run_on_exit(ret);
return ret;

View File

@ -9,7 +9,6 @@ AllocConsole
AllocLSCallback
AllocSLCallback
AreFileApisANSI
AttachConsole
BackupRead
BackupSeek
BackupWrite

View File

@ -1,27 +0,0 @@
/* ------------------------------------------------------------------------- */
/* winex.c : extra stuff */
#if __aarch64__
#include <stdlib.h>
/* replaces environ from arm64-msvcrt.dll which does not exist */
char **_environ;
wchar_t **_wenviron;
/* those do exist but have problems */
int __argc;
char **__argv;
wchar_t **__wargv;
#endif
#if __aarch64__ || __x86_64__
/* MSVC x64 intrinsic */
void __faststorefence(void)
{
#if __aarch64__
/* ARM64: Data Memory Barrier (Inner Shareable) */
__asm__("dmb ish");
#elif __x86_64__
/* x86-64: lock prefix to flush store buffer */
__asm__("lock; orl $0,(%%rsp)" ::: "memory");
#endif
}
#endif

View File

@ -266,6 +266,14 @@ ST_FUNC void gen_addr32(int r, Sym *sym, int c)
gen_le32(c);
}
/* output constant with relocation if 'r & VT_SYM' is true */
ST_FUNC void gen_addr64(int r, Sym *sym, int64_t c)
{
if (r & VT_SYM)
greloca(cur_text_section, sym, ind, R_X86_64_64, c), c=0;
gen_le64(c);
}
/* output constant with relocation if 'r & VT_SYM' is true */
ST_FUNC void gen_addrpc32(int r, Sym *sym, int c)
{
@ -314,7 +322,7 @@ static void gen_modrm_impl(int op_reg, int r, Sym *sym, int c, int is_got)
}
} else if ((r & VT_VALMASK) == VT_LOCAL) {
/* currently, we use only ebp as base */
if (c == (signed char)c) {
if (c == (char)c) {
/* short reference */
o(0x45 | op_reg);
g(c);
@ -368,8 +376,7 @@ void load(int r, SValue *sv)
#ifndef TCC_TARGET_PE
/* we use indirect access via got */
if ((fr & VT_VALMASK) == VT_CONST && (fr & VT_SYM) &&
(fr & VT_LVAL) && !(sv->sym->type.t & VT_STATIC)
&& !(sv->sym->type.t & VT_TLS)) {
(fr & VT_LVAL) && !(sv->sym->type.t & VT_STATIC)) {
/* use the result register as a temporal register */
int tr = r | TREG_MEM;
if (is_float(ft)) {
@ -386,19 +393,6 @@ void load(int r, SValue *sv)
v = fr & VT_VALMASK;
if (fr & VT_LVAL) {
int b, ll;
if ((fr & VT_SYM) && sv->sym->type.t & VT_TLS) {
int dst_reg = REG_VALUE(r);
int is64 = is64_type(ft);
o(0x64); /* fs segment prefix */
if (is64 || REX_BASE(r))
o(0x40 | (REX_BASE(r) << 0) | (is64 << 3)); /* rex.w/rex.r */
o(0x8b); /* mov r/m, r */
o(0x04 | (dst_reg << 3)); /* modrm: [sib] | destreg */
o(0x25); /* sib: disp32 */
greloca(cur_text_section, sv->sym, ind, R_X86_64_TPOFF32, fc);
gen_le32(0);
return;
}
if (v == VT_LLOCAL) {
v1.type.t = VT_PTR;
v1.r = VT_LOCAL | VT_LVAL;
@ -450,7 +444,8 @@ void load(int r, SValue *sv)
b = 0xdb, r = 5; /* fldt */
} else if ((ft & VT_TYPE) == VT_BYTE || (ft & VT_TYPE) == VT_BOOL) {
b = 0xbe0f; /* movsbl */
} else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED)) {
} else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED) ||
(ft & VT_TYPE) == (VT_BOOL | VT_UNSIGNED)) {
b = 0xb60f; /* movzbl */
} else if ((ft & VT_TYPE) == VT_SHORT) {
b = 0xbf0f; /* movswl */
@ -545,7 +540,8 @@ void load(int r, SValue *sv)
o(0x44 + REG_VALUE(r)*8); /* %xmmN */
o(0xf024);
} else {
assert((v >= TREG_XMM0) && (v <= TREG_XMM7));
if (!nocode_wanted)
assert((v >= TREG_XMM0) && (v <= TREG_XMM7));
if ((ft & VT_BTYPE) == VT_FLOAT) {
o(0x100ff3);
} else {
@ -555,7 +551,8 @@ void load(int r, SValue *sv)
o(0xc0 + REG_VALUE(v) + REG_VALUE(r)*8);
}
} else if (r == TREG_ST0) {
assert((v >= TREG_XMM0) && (v <= TREG_XMM7));
if (!nocode_wanted)
assert((v >= TREG_XMM0) && (v <= TREG_XMM7));
/* gen_cvt_ftof(VT_LDOUBLE); */
/* movsd %xmmN,-0x10(%rsp) */
o(0x110ff2);
@ -586,20 +583,6 @@ void store(int r, SValue *v)
ft &= ~(VT_VOLATILE | VT_CONSTANT);
bt = ft & VT_BTYPE;
if ((v->r & VT_SYM) && v->sym->type.t & VT_TLS) {
int src_reg = REG_VALUE(r);
int is64 = is64_type(bt);
o(0x64);
if (is64 || REX_BASE(r))
o(0x40 | (REX_BASE(r) << 0) | (is64 << 3));
o(0x89);
o(0x04 | (src_reg << 3));
o(0x25);
greloca(cur_text_section, v->sym, ind, R_X86_64_TPOFF32, fc);
gen_le32(0);
return;
}
#ifndef TCC_TARGET_PE
/* we need to access the variable via got */
if (fr == VT_CONST
@ -774,7 +757,7 @@ static int arg_prepare_reg(int idx) {
static void gen_offs_sp(int b, int r, int d)
{
orex(1,0,r & 0x100 ? 0 : r, b);
if (d == (signed char)d) {
if (d == (char)d) {
o(0x2444 | (REG_VALUE(r) << 3));
g(d);
} else {
@ -1077,7 +1060,7 @@ void gfunc_epilog(void)
static void gadd_sp(int val)
{
if (val == (signed char)val) {
if (val == (char)val) {
o(0xc48348);
g(val);
} else {
@ -1660,7 +1643,7 @@ void gjmp_addr(int a)
{
int r;
r = a - ind - 2;
if (r == (signed char)r) {
if (r == (char)r) {
g(0xeb);
g(r);
} else {
@ -1729,7 +1712,7 @@ void gen_opi(int op)
r = gv(RC_INT);
vswap();
c = vtop->c.i;
if (c == (signed char)c) {
if (c == (char)c) {
/* XXX: generate inc and dec for smaller code ? */
orex(ll, r, 0, 0x83);
o(0xc0 | (opc << 3) | REG_VALUE(r));
@ -1857,7 +1840,6 @@ void gen_opf(int op)
o(0x80); /* xor $0x80, $n(rbp) */
gen_modrm(6, vtop->r, NULL, vtop->c.i + (bt == VT_DOUBLE ? 7 : 3));
o(0x80);
gv(float_type); /* -n is not a lvalue */
}
return;
}

View File

@ -13,7 +13,7 @@
#define R_NUM R_X86_64_NUM
#define ELF_START_ADDR 0x400000
#define ELF_PAGE_SIZE 0x1000
#define ELF_PAGE_SIZE 0x200000
#define PCRELATIVE_DLLPLT 1
#define RELOCATE_DLLPLT 1
@ -96,15 +96,13 @@ ST_FUNC int gotplt_entry_type (int reloc_type)
case R_X86_64_TLSGD:
case R_X86_64_TLSLD:
case R_X86_64_DTPOFF32:
case R_X86_64_TPOFF32:
case R_X86_64_DTPOFF64:
case R_X86_64_TPOFF64:
case R_X86_64_REX_GOTPCRELX:
case R_X86_64_PLT32:
case R_X86_64_PLTOFF64:
return ALWAYS_GOTPLT_ENTRY;
case R_X86_64_TPOFF32:
case R_X86_64_TPOFF64:
return NO_GOTPLT_ENTRY;
}
return -1;
@ -374,30 +372,10 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
ElfW(Sym) *sym;
Section *sec;
int32_t x;
addr_t tls_start = 0, tls_end = 0, tls_align = 1;
int i;
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
sec = s1->sections[sym->st_shndx];
for (i = 1; i < s1->nb_sections; i++) {
Section *s = s1->sections[i];
if (s->sh_flags & SHF_TLS && s->sh_size) {
if (!tls_start || s->sh_addr < tls_start)
tls_start = s->sh_addr;
if (s->sh_addr + s->sh_size > tls_end)
tls_end = s->sh_addr + s->sh_size;
if (s->sh_addralign > tls_align)
tls_align = s->sh_addralign;
}
}
if (tls_end > tls_start) {
addr_t tls_size = tls_end - tls_start;
addr_t aligned_size = (tls_size + tls_align - 1) & ~(tls_align - 1);
x = val - (tls_start + aligned_size);
} else {
x = val - sec->sh_addr - sec->data_offset;
}
x = val - sec->sh_addr - sec->data_offset;
add32le(ptr, x);
}
break;
@ -407,30 +385,10 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
ElfW(Sym) *sym;
Section *sec;
int32_t x;
addr_t tls_start = 0, tls_end = 0, tls_align = 1;
int i;
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
sec = s1->sections[sym->st_shndx];
for (i = 1; i < s1->nb_sections; i++) {
Section *s = s1->sections[i];
if (s->sh_flags & SHF_TLS && s->sh_size) {
if (!tls_start || s->sh_addr < tls_start)
tls_start = s->sh_addr;
if (s->sh_addr + s->sh_size > tls_end)
tls_end = s->sh_addr + s->sh_size;
if (s->sh_addralign > tls_align)
tls_align = s->sh_addralign;
}
}
if (tls_end > tls_start) {
addr_t tls_size = tls_end - tls_start;
addr_t aligned_size = (tls_size + tls_align - 1) & ~(tls_align - 1);
x = val - (tls_start + aligned_size);
} else {
x = val - sec->sh_addr - sec->data_offset;
}
x = val - sec->sh_addr - sec->data_offset;
add64le(ptr, x);
}
break;