mirror of
git://repo.or.cz/tinycc.git
synced 2026-06-17 15:44:18 +08:00
Compare commits
59 Commits
b39da9f6fa
...
a338258d30
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a338258d30 | ||
|
|
fb4077f2da | ||
|
|
724b24eeb4 | ||
|
|
d8aee9b26e | ||
|
|
b8f680a3b4 | ||
|
|
1444843fd1 | ||
|
|
6b53465347 | ||
|
|
3b1fe97a59 | ||
|
|
904e95cbdf | ||
|
|
601a088214 | ||
|
|
1a54e47dda | ||
|
|
37b7247796 | ||
|
|
6a7c3df4d5 | ||
|
|
757507eb02 | ||
|
|
6728a64f1b | ||
|
|
256b4ef63c | ||
|
|
8502540b4a | ||
|
|
841ce0da03 | ||
|
|
8abaf10ab5 | ||
|
|
11f5c6e1f9 | ||
|
|
ea26b85ac0 | ||
|
|
8443e25bf5 | ||
|
|
fad812360b | ||
|
|
2888e49f39 | ||
|
|
c77339ab41 | ||
|
|
7f764f340f | ||
|
|
a672babc6f | ||
|
|
44977b0de8 | ||
|
|
6daf1617ef | ||
|
|
923fba83f1 | ||
|
|
7e01b20362 | ||
|
|
016087c954 | ||
|
|
f8011ea9b7 | ||
|
|
199369bb17 | ||
|
|
3935c3bb55 | ||
|
|
273978b927 | ||
|
|
2a33daedca | ||
|
|
3257afa160 | ||
|
|
419b527657 | ||
|
|
5c2240a896 | ||
|
|
366569eb7a | ||
|
|
ff917c09aa | ||
|
|
9f0915a506 | ||
|
|
69c8e92566 | ||
|
|
30afb50e64 | ||
|
|
576cd2a923 | ||
|
|
44e6853cb1 | ||
|
|
5c728d6506 | ||
|
|
90d17c9748 | ||
|
|
99713bcbfa | ||
|
|
303badef22 | ||
|
|
41bcb4a78f | ||
|
|
f459aff5f6 | ||
|
|
ea823189d6 | ||
|
|
03d58b0746 | ||
|
|
ff5d3b4874 | ||
|
|
d9a6d9aec0 | ||
|
|
a66ac623b2 | ||
|
|
4768b11737 |
79
.github/workflows/build.yml
vendored
79
.github/workflows/build.yml
vendored
@ -34,56 +34,49 @@ jobs:
|
||||
timeout-minutes: 6
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: make & test tcc (x86_64-win32)
|
||||
- name: build 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
|
||||
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
|
||||
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
|
||||
|
||||
test-i386-win32:
|
||||
runs-on: windows-2025
|
||||
timeout-minutes: 6
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: make & test tcc (i386-win32)
|
||||
- name: build 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
|
||||
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
|
||||
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
|
||||
|
||||
test-armv7-linux:
|
||||
runs-on: ubuntu-22.04
|
||||
@ -138,3 +131,13 @@ 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
1
.gitignore
vendored
@ -62,7 +62,6 @@ 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
|
||||
|
||||
70
Makefile
70
Makefile
@ -31,9 +31,11 @@ ifdef CONFIG_WIN32
|
||||
LIBTCCDEF = libtcc.def
|
||||
endif
|
||||
ifneq ($(CONFIG_debug),yes)
|
||||
ifneq ($(CC_NAME),clang)
|
||||
LDFLAGS += -s
|
||||
endif
|
||||
NATIVE_TARGET = $(ARCH)-win$(if $(findstring arm,$(ARCH)),ce,32)
|
||||
endif
|
||||
NATIVE_TARGET = $(if $(findstring arm64,$(ARCH)),arm64-win32,$(ARCH)-win$(if $(findstring arm,$(ARCH)),ce,32))
|
||||
else
|
||||
CFG = -unx
|
||||
LIBS+=-lm
|
||||
@ -113,6 +115,7 @@ 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
|
||||
@ -130,7 +133,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 arm-wince c67
|
||||
TCC_X = i386 x86_64 i386-win32 x86_64-win32 x86_64-osx arm arm64 arm64-win32 arm-wince c67
|
||||
TCC_X += riscv64 arm64-osx
|
||||
# TCC_X += arm-fpa arm-fpa-ld arm-vfp arm-eabi
|
||||
|
||||
@ -155,10 +158,27 @@ all : cross
|
||||
endif
|
||||
|
||||
# --------------------------------------------
|
||||
|
||||
T = $(or $(CROSS_TARGET),$(NATIVE_TARGET),unknown)
|
||||
T = $(or $(CROSS_TARGET),$(NATIVE_TARGET))
|
||||
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)\"")
|
||||
@ -166,36 +186,17 @@ 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))
|
||||
|
||||
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) =
|
||||
DEFINES += -DCONFIG_TCC_CROSSPREFIX="\"$X\""
|
||||
endif
|
||||
|
||||
# include custom configuration (see make help)
|
||||
-include config-extra.mak
|
||||
|
||||
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
|
||||
# so one can use: make EXTRA-DEFS=...
|
||||
DEFINES += $(EXTRA-DEFS)
|
||||
|
||||
# find config.h with 'out of tree' builds
|
||||
DEFINES += -I$(TOP)
|
||||
|
||||
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
|
||||
@ -206,14 +207,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_FILES = $(CORE_FILES) arm64-gen.c arm64-link.c arm64-asm.c arm64-tok.h
|
||||
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
|
||||
|
||||
@ -237,7 +238,6 @@ $(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,$1)),$S $1 $2)
|
||||
run-if = $(if $(shell $(call WHICH,$1x)),$S $1 $2,@true||echo "(skipping $@ - no $1)")
|
||||
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
110
arm-gen.c
@ -124,16 +124,17 @@ 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
|
||||
|
||||
#ifdef TCC_ARM_HARDFLOAT
|
||||
# define ARM_FLOAT_ABI ARM_HARD_FLOAT
|
||||
#else
|
||||
# define ARM_FLOAT_ABI ARM_SOFTFP_FLOAT
|
||||
#endif
|
||||
#define ARM_SOFTFP_FLOAT 0
|
||||
#define ARM_HARD_FLOAT 1
|
||||
|
||||
/******************************************************/
|
||||
#else /* ! TARGET_DEFS_ONLY */
|
||||
@ -156,8 +157,6 @@ 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,
|
||||
@ -176,6 +175,7 @@ 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,16 +237,6 @@ 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*/
|
||||
@ -582,7 +572,7 @@ static void load_value(SValue *sv, int r)
|
||||
void load(int r, SValue *sv)
|
||||
{
|
||||
int v, ft, fc, fr, sign;
|
||||
uint32_t op;
|
||||
uint32_t op, base;
|
||||
SValue v1;
|
||||
|
||||
fr = sv->r;
|
||||
@ -598,7 +588,15 @@ void load(int r, SValue *sv)
|
||||
|
||||
v = fr & VT_VALMASK;
|
||||
if (fr & VT_LVAL) {
|
||||
uint32_t base = 0xB; // fp
|
||||
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
|
||||
if(v == VT_LLOCAL) {
|
||||
v1.type.t = VT_PTR;
|
||||
v1.r = VT_LOCAL | VT_LVAL;
|
||||
@ -635,12 +633,9 @@ 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
|
||||
@ -716,7 +711,7 @@ void store(int r, SValue *sv)
|
||||
{
|
||||
SValue v1;
|
||||
int v, ft, fc, fr, sign;
|
||||
uint32_t op;
|
||||
uint32_t op, base;
|
||||
|
||||
fr = sv->r;
|
||||
ft = sv->type.t;
|
||||
@ -731,7 +726,15 @@ void store(int r, SValue *sv)
|
||||
|
||||
v = fr & VT_VALMASK;
|
||||
if (fr & VT_LVAL || fr == VT_LOCAL) {
|
||||
uint32_t base = 0xb; /* fp */
|
||||
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 */
|
||||
if(v < VT_CONST) {
|
||||
base=intr(v);
|
||||
v=VT_LOCAL;
|
||||
@ -760,13 +763,10 @@ 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 ((ft & VT_BTYPE) == VT_LDOUBLE)
|
||||
#if LDOUBLE_SIZE != 8
|
||||
else if ((ft & VT_BTYPE) == VT_LDOUBLE)
|
||||
op|=0x400000;
|
||||
#endif
|
||||
o(op|(fpr(r)<<12)|(fc>>2)|(base<<16));
|
||||
@ -904,15 +904,6 @@ 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.
|
||||
@ -926,9 +917,10 @@ static int is_hgen_float_aggr(CType *type)
|
||||
|
||||
ref = type->ref->next;
|
||||
if (ref) {
|
||||
btype = unalias_ldbl(ref->type.t & VT_BTYPE);
|
||||
btype = ref->type.t & VT_BTYPE;
|
||||
if (btype == VT_FLOAT || btype == VT_DOUBLE) {
|
||||
for(; ref && btype == unalias_ldbl(ref->type.t & VT_BTYPE); ref = ref->next, nb_fields++);
|
||||
for(; ref && btype == (ref->type.t & VT_BTYPE); ref = ref->next, nb_fields++)
|
||||
;
|
||||
return !ref && nb_fields <= 4;
|
||||
}
|
||||
}
|
||||
@ -1254,7 +1246,6 @@ again:
|
||||
size = 8;
|
||||
else
|
||||
size = LDOUBLE_SIZE;
|
||||
|
||||
if (size == 12)
|
||||
r |= 0x400000;
|
||||
else if(size == 8)
|
||||
@ -1946,15 +1937,13 @@ 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 '+':
|
||||
@ -2190,6 +2179,12 @@ 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;
|
||||
@ -2197,15 +2192,7 @@ 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));
|
||||
@ -2239,14 +2226,12 @@ 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));
|
||||
@ -2257,14 +2242,12 @@ 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);
|
||||
@ -2283,8 +2266,9 @@ 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)) {
|
||||
uint32_t r = vfpr(gv(RC_FLOAT));
|
||||
r = vfpr(r);
|
||||
o(0xEEB70AC0|(r<<12)|r|T2CPR(vtop->type.t));
|
||||
}
|
||||
#else
|
||||
|
||||
37
arm-link.c
37
arm-link.c
@ -18,11 +18,6 @@
|
||||
#define PCRELATIVE_DLLPLT 1
|
||||
#define RELOCATE_DLLPLT 1
|
||||
|
||||
enum float_abi {
|
||||
ARM_SOFTFP_FLOAT,
|
||||
ARM_HARD_FLOAT,
|
||||
};
|
||||
|
||||
#else /* !TARGET_DEFS_ONLY */
|
||||
|
||||
#include "tcc.h"
|
||||
@ -49,6 +44,7 @@ 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:
|
||||
@ -75,6 +71,7 @@ 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:
|
||||
@ -435,6 +432,36 @@ 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);
|
||||
|
||||
2218
arm64-asm.c
2218
arm64-asm.c
File diff suppressed because it is too large
Load Diff
590
arm64-gen.c
590
arm64-gen.c
File diff suppressed because it is too large
Load Diff
116
arm64-link.c
116
arm64-link.c
@ -43,6 +43,8 @@ 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;
|
||||
@ -50,6 +52,8 @@ 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;
|
||||
@ -76,6 +80,10 @@ 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:
|
||||
@ -127,17 +135,18 @@ 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, 0xa9bf7bf0); // stp x16,x30,[sp,#-16]!
|
||||
write32le(p + 4, (0x90000010 | // adrp x16,...
|
||||
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,...
|
||||
(off & 0x1ffffc) << 3 | (off & 3) << 29));
|
||||
write32le(p + 8, (0xf9400211 | // ldr x17,[x16,#...]
|
||||
write32le(p + 8, (ARM64_LDR_X | ARM64_RT(17) | ARM64_RN(16) | // ldr x17,[x16,#...]
|
||||
(got & 0xff8) << 7));
|
||||
write32le(p + 12, (0x91000210 | // add x16,x16,#...
|
||||
write32le(p + 12, (ARM64_ADD_IMM | ARM64_SF(1) | ARM64_RD(16) | ARM64_RN(16) | // add x16,x16,#...
|
||||
(got & 0xfff) << 10));
|
||||
write32le(p + 16, 0xd61f0220); // br x17
|
||||
write32le(p + 20, 0xd503201f); // nop
|
||||
write32le(p + 24, 0xd503201f); // nop
|
||||
write32le(p + 28, 0xd503201f); // nop
|
||||
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
|
||||
p += 32;
|
||||
got = s1->got->sh_addr;
|
||||
while (p < p_end) {
|
||||
@ -146,13 +155,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, (0x90000010 | // adrp x16,...
|
||||
write32le(p, (ARM64_ADRP | ARM64_RD(16) | // adrp x16,...
|
||||
(off & 0x1ffffc) << 3 | (off & 3) << 29));
|
||||
write32le(p + 4, (0xf9400211 | // ldr x17,[x16,#...]
|
||||
write32le(p + 4, (ARM64_LDR_X | ARM64_RT(17) | ARM64_RN(16) | // ldr x17,[x16,#...]
|
||||
(addr & 0xff8) << 7));
|
||||
write32le(p + 8, (0x91000210 | // add x16,x16,#...
|
||||
write32le(p + 8, (ARM64_ADD_IMM | ARM64_SF(1) | ARM64_RD(16) | ARM64_RN(16) | // add x16,x16,#...
|
||||
(addr & 0xfff) << 10));
|
||||
write32le(p + 12, 0xd61f0220); // br x17
|
||||
write32le(p + 12, ARM64_BR | ARM64_RN(17)); // br x17
|
||||
p += 16;
|
||||
}
|
||||
}
|
||||
@ -238,8 +247,23 @@ 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;
|
||||
@ -265,19 +289,58 @@ 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_JUMP26:
|
||||
case R_AARCH64_CALL26:
|
||||
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 << 27)) & ~(uint64_t)0xffffffc)
|
||||
tcc_error_noabort("R_AARCH64_(JUMP|CALL)26 relocation failed"
|
||||
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;
|
||||
tcc_error_noabort("R_AARCH64_(JUMP|CALL)26 relocation failed"
|
||||
" for '%s' (val=%lx, addr=%lx)",
|
||||
name, (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 +
|
||||
@ -306,6 +369,27 @@ 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);
|
||||
|
||||
840
arm64-tok.h
Normal file
840
arm64-tok.h
Normal file
@ -0,0 +1,840 @@
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* 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
29
configure
vendored
@ -35,13 +35,11 @@ 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
|
||||
@ -53,6 +51,7 @@ cpuver=
|
||||
dwarf=
|
||||
targetos=
|
||||
build_cross=
|
||||
quiet=
|
||||
|
||||
# use CC/AR from environment when set
|
||||
test -n "$CC" && cc="$CC"
|
||||
@ -160,8 +159,6 @@ for opt do
|
||||
;;
|
||||
--debug) confvars_set debug
|
||||
;;
|
||||
--with-libgcc) confvars_set libgcc
|
||||
;;
|
||||
--with-selinux) confvars_set selinux
|
||||
;;
|
||||
--tcc-switches=*) assign_opt "$opt" tcc_switches
|
||||
@ -174,6 +171,8 @@ for opt do
|
||||
;;
|
||||
--help|-h) show_help="yes"
|
||||
;;
|
||||
-q) quiet=yes
|
||||
;;
|
||||
*) echo "configure: WARNING: unrecognized option $opt"
|
||||
;;
|
||||
esac
|
||||
@ -197,6 +196,7 @@ 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,9 +210,8 @@ 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 cross compilers (see also 'make help')
|
||||
--enable-cross build all cross compilers (see also 'make help')
|
||||
|
||||
--sysincludepaths=... specify system include paths, colon separated
|
||||
--libpaths=... specify system library paths, colon separated
|
||||
@ -266,7 +265,11 @@ default os_release "$(uname -r)"
|
||||
case $buildos in
|
||||
Windows_NT|MINGW*|MSYS*|CYGWIN*)
|
||||
buildos="WIN32"
|
||||
test "$MSYSTEM" = "MINGW32" && cpu_sys=i386
|
||||
case "$MSYSTEM" in
|
||||
MINGW32) cpu_sys=i386 ;;
|
||||
MINGW64) cpu_sys=x86_64 ;;
|
||||
CLANGARM64|MINGW_ARM64) cpu_sys=arm64 ;;
|
||||
esac
|
||||
;;
|
||||
Linux)
|
||||
if test "$(uname -o)" = "Android"; then
|
||||
@ -363,6 +366,7 @@ 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
|
||||
@ -474,7 +478,8 @@ 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
|
||||
tcc_lddir="lib64"
|
||||
default tcc_libpaths "{B}:/usr/lib64"
|
||||
default tcc_crtprefix "/usr/lib64"
|
||||
fi
|
||||
esac
|
||||
fi
|
||||
@ -548,6 +553,7 @@ 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"
|
||||
@ -556,7 +562,6 @@ 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)"
|
||||
@ -570,6 +575,7 @@ fcho "Elfinterp " "$tcc_elfinterp"
|
||||
fcho "Switches " "$tcc_switches"
|
||||
fcho "Config " "${confvars# }"
|
||||
echo "Creating config.mak and config.h"
|
||||
fi
|
||||
|
||||
version=$(head "$source_path/VERSION")
|
||||
|
||||
@ -687,7 +693,6 @@ 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 ;;
|
||||
@ -702,13 +707,11 @@ 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
|
||||
@ -720,7 +723,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
|
||||
else
|
||||
elif test -z "$quiet"; then
|
||||
echo "config.h is unchanged"
|
||||
fi
|
||||
|
||||
|
||||
1
elf.h
1
elf.h
@ -2337,6 +2337,7 @@ typedef Elf32_Addr Elf32_Conflict;
|
||||
#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
|
||||
|
||||
|
||||
/* AArch64 relocs. */
|
||||
|
||||
@ -494,13 +494,6 @@ 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)
|
||||
{
|
||||
|
||||
30
i386-gen.c
30
i386-gen.c
@ -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 == (char)c) {
|
||||
if (c == (signed char)c) {
|
||||
/* short reference */
|
||||
o(0x45 | op_reg);
|
||||
g(c);
|
||||
@ -313,6 +313,16 @@ 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;
|
||||
@ -429,6 +439,16 @@ 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) {
|
||||
@ -439,7 +459,7 @@ ST_FUNC void store(int r, SValue *v)
|
||||
|
||||
static void gadd_sp(int val)
|
||||
{
|
||||
if (val == (char)val) {
|
||||
if (val == (signed char)val) {
|
||||
o(0xc483);
|
||||
g(val);
|
||||
} else {
|
||||
@ -774,7 +794,7 @@ ST_FUNC void gjmp_addr(int a)
|
||||
{
|
||||
int r;
|
||||
r = a - ind - 2;
|
||||
if (r == (char)r) {
|
||||
if (r == (signed char)r) {
|
||||
g(0xeb);
|
||||
g(r);
|
||||
} else {
|
||||
@ -787,7 +807,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 == (char)r)
|
||||
if (r == (signed char)r)
|
||||
g(op - 32), g(r);
|
||||
else
|
||||
g(0x0f), gjmp2(op - 16, r - 4);
|
||||
@ -830,7 +850,7 @@ ST_FUNC void gen_opi(int op)
|
||||
r = gv(RC_INT);
|
||||
vswap();
|
||||
c = vtop->c.i;
|
||||
if (c == (char)c) {
|
||||
if (c == (signed char)c) {
|
||||
/* generate inc and dec for smaller code */
|
||||
if ((c == 1 || c == -1) && (op == '+' || op == '-')) {
|
||||
opc = (c == 1) ^ (op == '+');
|
||||
|
||||
33
i386-link.c
33
i386-link.c
@ -305,7 +305,6 @@ 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;
|
||||
@ -317,6 +316,38 @@ 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:
|
||||
|
||||
@ -90,8 +90,6 @@
|
||||
#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
|
||||
@ -142,12 +140,6 @@
|
||||
#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)
|
||||
@ -187,14 +179,17 @@
|
||||
# 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. */
|
||||
|
||||
enum __va_arg_type {
|
||||
__va_gen_reg, __va_float_reg, __va_stack
|
||||
};
|
||||
/* This should be in sync with the declaration in our lib/va_list.c */
|
||||
typedef struct {
|
||||
unsigned gp_offset, fp_offset;
|
||||
union {
|
||||
@ -204,43 +199,7 @@
|
||||
char *reg_save_area;
|
||||
} __builtin_va_list[1];
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
void *__va_arg(__builtin_va_list ap, int arg_type, int size, int align);
|
||||
#define __builtin_va_start(ap, last) \
|
||||
(*(ap) = *(__builtin_va_list)((char*)__builtin_frame_address(0) - 24))
|
||||
#define __builtin_va_arg(ap, t) \
|
||||
@ -263,7 +222,9 @@
|
||||
&~3), *(type *)(ap - ((sizeof(type)+3)&~3)))
|
||||
|
||||
#elif defined __aarch64__
|
||||
#if defined __APPLE__
|
||||
#if defined _WIN32
|
||||
typedef char *__builtin_va_list;
|
||||
#elif defined __APPLE__
|
||||
typedef struct {
|
||||
void *__stack;
|
||||
} __builtin_va_list;
|
||||
|
||||
11
lib/Makefile
11
lib/Makefile
@ -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
|
||||
WIN_O = crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o winex.o
|
||||
LIN_O = dsohandle.o
|
||||
OSX_O =
|
||||
|
||||
@ -59,12 +59,13 @@ $(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) $(LIN_O)
|
||||
OBJ-x86_64-osx = $(X86_64_O) $(OSX_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-i386-win32 = $(I386_O) chkstk.o $(WIN_O)
|
||||
OBJ-x86_64-win32 = $(X86_64_O) chkstk.o $(WIN_O)
|
||||
OBJ-arm64 = $(ARM64_O) $(LIN_O)
|
||||
OBJ-arm64 = $(ARM64_O) armflush.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)
|
||||
@ -72,7 +73,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) $(LIN_O)
|
||||
OBJ-riscv64 = $(RISCV64_O) lib-riscv.o $(LIN_O)
|
||||
|
||||
OBJ-extra = $(filter $(EXTRA_O),$(OBJ-$T))
|
||||
OBJ-libtcc1 = $(addprefix $(X),$(filter-out $(OBJ-extra),$(OBJ-$T)))
|
||||
|
||||
@ -4,6 +4,9 @@
|
||||
intrinsic with gcc. However tcc in order to compile
|
||||
itself needs this function */
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
#if defined __arm__
|
||||
|
||||
#ifdef __TINYC__
|
||||
|
||||
/* syscall wrapper */
|
||||
@ -49,3 +52,13 @@ 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
|
||||
|
||||
25
lib/bt-dll.c
25
lib/bt-dll.c
@ -34,7 +34,11 @@
|
||||
REDIR(__bound_strncmp) \
|
||||
REDIR(__bound_strcat) \
|
||||
REDIR(__bound_strchr) \
|
||||
REDIR(__bound_strdup)
|
||||
REDIR(__bound_strdup) \
|
||||
REDIR(__bound_strncat) \
|
||||
REDIR(__bound_strrchr) \
|
||||
REDIR(__bound_setjmp) \
|
||||
REDIR(__bound_longjmp)
|
||||
|
||||
#ifdef __leading_underscore
|
||||
#define _(s) "_"#s
|
||||
@ -45,11 +49,28 @@
|
||||
#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
|
||||
#define REDIR(s) __asm__(".global " _(s) ";" _(s) ": jmp *%0" : : "m" (all_ptrs.s) );
|
||||
|
||||
#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
|
||||
#undef REDIR
|
||||
|
||||
void __bt_init_dll(int bcheck)
|
||||
|
||||
19
lib/bt-exe.c
19
lib/bt-exe.c
@ -11,6 +11,21 @@
|
||||
# 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)
|
||||
{
|
||||
@ -24,6 +39,10 @@ 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;
|
||||
|
||||
133
lib/lib-arm64.c
133
lib/lib-arm64.c
@ -18,49 +18,40 @@ 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
|
||||
|
||||
#if !defined __riscv && !defined __APPLE__
|
||||
void __clear_cache(void *beg, void *end)
|
||||
{
|
||||
__arm64_clear_cache(beg, end);
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
uint64_t x0, x1;
|
||||
typedef union {
|
||||
struct { uint64_t x0, x1; };
|
||||
long double f;
|
||||
} 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 };
|
||||
memcpy(&f, &x, 16);
|
||||
return f;
|
||||
return x.f;
|
||||
}
|
||||
|
||||
static long double f3_infinity(int sgn)
|
||||
{
|
||||
long double f;
|
||||
u128_t x = { 0, (uint64_t)sgn << 63 | 0x7fff000000000000 };
|
||||
memcpy(&f, &x, 16);
|
||||
return f;
|
||||
return x.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 };
|
||||
@ -68,28 +59,31 @@ static long double f3_NaN(void)
|
||||
// GCC's library sets all fraction bits:
|
||||
u128_t x = { -1, 0x7fffffffffffffff };
|
||||
#endif
|
||||
memcpy(&f, &x, 16);
|
||||
return f;
|
||||
return x.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 };
|
||||
memcpy(f, &x, 16);
|
||||
u128_t x = { mnt->x0,
|
||||
mnt->x1 | 0x7fff800000000000 | (uint64_t)sgn << 63 };
|
||||
*f = x.f;
|
||||
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)
|
||||
int a_sgn, int a_exp, u128_t *a,
|
||||
int b_sgn, int b_exp, u128_t *b)
|
||||
#define a (*a)
|
||||
#define b (*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);
|
||||
@ -97,12 +91,16 @@ 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;
|
||||
memcpy(&x, &f, 16);
|
||||
|
||||
x.f = f;
|
||||
*sgn = x.x1 >> 63;
|
||||
*exp = x.x1 >> 48 & 32767;
|
||||
x.x1 = x.x1 << 16 >> 16;
|
||||
@ -110,7 +108,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;
|
||||
memcpy(mnt, &x, 16);
|
||||
mnt->f = x.f;
|
||||
}
|
||||
|
||||
static void f3_normalise(int32_t *exp, u128_t *mnt)
|
||||
@ -184,8 +182,7 @@ 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;
|
||||
memcpy(&f, x, 16);
|
||||
return f;
|
||||
return x->f;
|
||||
}
|
||||
|
||||
static long double f3_add(long double fa, long double fb, int neg)
|
||||
@ -380,23 +377,20 @@ long double __divtf3(long double fa, long double fb)
|
||||
|
||||
long double __negtf2(long double f)
|
||||
{
|
||||
u128_t a;
|
||||
|
||||
memcpy(&a, &f, 16);
|
||||
a.x1 ^= 1UL << 63;
|
||||
memcpy(&f, &a, 16);
|
||||
|
||||
((u128_t*)&f)->x1 ^= 1UL << 63;
|
||||
return f;
|
||||
}
|
||||
|
||||
long double __extendsftf2(float f)
|
||||
{
|
||||
long double fx;
|
||||
u128_t x;
|
||||
u32_t u;
|
||||
uint32_t a;
|
||||
uint64_t aa;
|
||||
memcpy(&a, &f, 4);
|
||||
|
||||
u.f = f, a = u.x;
|
||||
aa = a;
|
||||
|
||||
x.x0 = 0;
|
||||
if (!(a << 1))
|
||||
x.x1 = aa << 32;
|
||||
@ -411,16 +405,17 @@ long double __extendsftf2(float f)
|
||||
} else
|
||||
x.x1 = (aa >> 31 << 63 | ((aa >> 23 & 255) + 16256) << 48 |
|
||||
aa << 41 >> 16);
|
||||
memcpy(&fx, &x, 16);
|
||||
return fx;
|
||||
return x.f;
|
||||
}
|
||||
|
||||
long double __extenddftf2(double f)
|
||||
{
|
||||
long double fx;
|
||||
u128_t x;
|
||||
u64_t u;
|
||||
uint64_t a;
|
||||
memcpy(&a, &f, 8);
|
||||
|
||||
u.f = f, a = u.x;
|
||||
|
||||
x.x0 = a << 60;
|
||||
if (!(a << 1))
|
||||
x.x1 = a;
|
||||
@ -435,8 +430,7 @@ 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;
|
||||
memcpy(&fx, &x, 16);
|
||||
return fx;
|
||||
return x.f;
|
||||
}
|
||||
|
||||
float __trunctfsf2(long double f)
|
||||
@ -444,11 +438,10 @@ float __trunctfsf2(long double f)
|
||||
u128_t mnt;
|
||||
int32_t exp;
|
||||
int sgn;
|
||||
uint32_t x;
|
||||
float fx;
|
||||
u32_t x;
|
||||
#define x x.x
|
||||
|
||||
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)
|
||||
@ -466,8 +459,8 @@ float __trunctfsf2(long double f)
|
||||
x += 4;
|
||||
x = ((x >> 2) + (exp << 23)) | (uint32_t)sgn << 31;
|
||||
}
|
||||
memcpy(&fx, &x, 4);
|
||||
return fx;
|
||||
#undef x
|
||||
return x.f;
|
||||
}
|
||||
|
||||
double __trunctfdf2(long double f)
|
||||
@ -475,11 +468,10 @@ double __trunctfdf2(long double f)
|
||||
u128_t mnt;
|
||||
int32_t exp;
|
||||
int sgn;
|
||||
uint64_t x;
|
||||
double fx;
|
||||
u64_t x;
|
||||
#define x x.x
|
||||
|
||||
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);
|
||||
@ -498,8 +490,8 @@ double __trunctfdf2(long double f)
|
||||
x += 4;
|
||||
x = ((x >> 2) + ((uint64_t)exp << 52)) | (uint64_t)sgn << 63;
|
||||
}
|
||||
memcpy(&fx, &x, 8);
|
||||
return fx;
|
||||
#undef x
|
||||
return x.f;
|
||||
}
|
||||
|
||||
int32_t __fixtfsi(long double fa)
|
||||
@ -564,7 +556,6 @@ 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) {
|
||||
@ -579,8 +570,7 @@ long double __floatsitf(int32_t a)
|
||||
x.x1 = ((uint64_t)sgn << 63 | (uint64_t)exp << 48 |
|
||||
(uint64_t)(mnt << 1) << 16);
|
||||
}
|
||||
memcpy(&f, &x, 16);
|
||||
return f;
|
||||
return x.f;
|
||||
}
|
||||
|
||||
long double __floatditf(int64_t a)
|
||||
@ -589,7 +579,6 @@ 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) {
|
||||
@ -604,8 +593,7 @@ long double __floatditf(int64_t a)
|
||||
x.x0 = mnt << 49;
|
||||
x.x1 = (uint64_t)sgn << 63 | (uint64_t)exp << 48 | mnt << 1 >> 16;
|
||||
}
|
||||
memcpy(&f, &x, 16);
|
||||
return f;
|
||||
return x.f;
|
||||
}
|
||||
|
||||
long double __floatunsitf(uint32_t a)
|
||||
@ -613,7 +601,6 @@ 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)
|
||||
@ -623,8 +610,7 @@ long double __floatunsitf(uint32_t a)
|
||||
}
|
||||
x.x1 = (uint64_t)exp << 48 | (uint64_t)(mnt << 1) << 16;
|
||||
}
|
||||
memcpy(&f, &x, 16);
|
||||
return f;
|
||||
return x.f;
|
||||
}
|
||||
|
||||
long double __floatunditf(uint64_t a)
|
||||
@ -643,15 +629,14 @@ long double __floatunditf(uint64_t a)
|
||||
x.x0 = mnt << 49;
|
||||
x.x1 = (uint64_t)exp << 48 | mnt << 1 >> 16;
|
||||
}
|
||||
memcpy(&f, &x, 16);
|
||||
return f;
|
||||
return x.f;
|
||||
}
|
||||
|
||||
static int f3_cmp(long double fa, long double fb)
|
||||
{
|
||||
u128_t a, b;
|
||||
memcpy(&a, &fa, 16);
|
||||
memcpy(&b, &fb, 16);
|
||||
a.f = fa;
|
||||
b.f = fb;
|
||||
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 :
|
||||
|
||||
20
lib/lib-riscv.c
Normal file
20
lib/lib-riscv.c
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
@ -107,10 +107,9 @@ union float_long {
|
||||
};
|
||||
|
||||
/* XXX: we don't support several builtin supports for now */
|
||||
#if !defined __x86_64__ && !defined __arm__ && !defined __riscv && !defined __aarch64__
|
||||
#if defined __i386__
|
||||
|
||||
/* 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)), \
|
||||
@ -139,9 +138,6 @@ 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 */
|
||||
|
||||
@ -478,7 +474,7 @@ long long __ashldi3(long long a, int b)
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* !__x86_64__ */
|
||||
#endif /* __i386__ */
|
||||
|
||||
/* XXX: fix tcc's code generator to do this instead */
|
||||
float __floatundisf(unsigned long long a)
|
||||
@ -625,11 +621,3 @@ 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
|
||||
|
||||
67
lib/va_list.c
Normal file
67
lib/va_list.c
Normal file
@ -0,0 +1,67 @@
|
||||
/* 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
|
||||
157
libtcc.c
157
libtcc.c
@ -124,8 +124,15 @@ 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)
|
||||
@ -245,7 +252,7 @@ static void *default_reallocator(void *ptr, unsigned long size)
|
||||
else {
|
||||
ptr1 = realloc(ptr, size);
|
||||
if (!ptr1) {
|
||||
fprintf(stderr, "memory full\n");
|
||||
fprintf(stderr, "tcc: memory full\n");
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
@ -791,7 +798,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, const char *filename)
|
||||
static int tcc_compile(TCCState *s1, int filetype, const char *str, int fd)
|
||||
{
|
||||
/* Here we enter the code section where we use the global variables for
|
||||
parsing and code generation (tccpp.c, tccgen.c, <target>-gen.c).
|
||||
@ -807,16 +814,8 @@ static int tcc_compile(TCCState *s1, int filetype, const char *str, int fd, cons
|
||||
|
||||
if (fd == -1) {
|
||||
int len = strlen(str);
|
||||
tcc_open_bf(s1, filename ? filename : "<string>", len);
|
||||
tcc_open_bf(s1, "<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;
|
||||
@ -846,12 +845,7 @@ static int tcc_compile(TCCState *s1, int filetype, const char *str, int fd, cons
|
||||
|
||||
LIBTCCAPI int tcc_compile_string(TCCState *s, const char *str)
|
||||
{
|
||||
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);
|
||||
return tcc_compile(s, s->filetype, str, -1);
|
||||
}
|
||||
|
||||
/* define a preprocessor symbol. value can be NULL, sym can be "sym=val" */
|
||||
@ -902,8 +896,8 @@ LIBTCCAPI TCCState *tcc_new(void)
|
||||
#if defined TCC_TARGET_MACHO /* || defined TCC_TARGET_PE */
|
||||
s->leading_underscore = 1;
|
||||
#endif
|
||||
#ifdef TCC_TARGET_ARM
|
||||
s->float_abi = ARM_FLOAT_ABI;
|
||||
#ifdef TCC_ARM_HARDFLOAT
|
||||
s->float_abi = ARM_HARD_FLOAT;
|
||||
#endif
|
||||
#ifdef CONFIG_NEW_DTAGS
|
||||
s->enable_new_dtags = 1;
|
||||
@ -1001,17 +995,19 @@ 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);
|
||||
tccelf_add_crtbegin(s); /* may produce errors */
|
||||
#endif
|
||||
return 0;
|
||||
return s->nb_errors ? -1 : 0;
|
||||
}
|
||||
|
||||
LIBTCCAPI int tcc_add_include_path(TCCState *s, const char *pathname)
|
||||
@ -1246,7 +1242,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, NULL);
|
||||
return tcc_compile(s1, flags, filename, fd);
|
||||
}
|
||||
|
||||
LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename)
|
||||
@ -1368,10 +1364,11 @@ struct lopt {
|
||||
/* match linker option */
|
||||
static int link_option(struct lopt *o, const char *q)
|
||||
{
|
||||
const char *p = o->opt;
|
||||
const char *p;
|
||||
int c;
|
||||
|
||||
redo:
|
||||
/* there should be 1 or 2 dashes */
|
||||
p = o->opt;
|
||||
if (*p++ != '-')
|
||||
return 0;
|
||||
if (*p == '-')
|
||||
@ -1384,16 +1381,22 @@ static int link_option(struct lopt *o, const char *q)
|
||||
goto succ; /* -Wl,-opt=arg */
|
||||
++q;
|
||||
}
|
||||
if (c == '=' || c == ':') {
|
||||
if (*p == '\0') {
|
||||
if (c == '|')
|
||||
goto succ;
|
||||
if (c == '=' || c == ':') {
|
||||
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;
|
||||
return 0;
|
||||
succ:
|
||||
o->arg = p;
|
||||
@ -1403,6 +1406,20 @@ 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)
|
||||
{
|
||||
@ -1421,9 +1438,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=") || link_option(&o, "entry=")) {
|
||||
} else if (link_option(&o, "e=|entry=")) {
|
||||
tcc_set_str(&s->elf_entryname, o.arg);
|
||||
} else if (link_option(&o, "image-base=") || link_option(&o, "Ttext=")) {
|
||||
} else if (link_option(&o, "image-base=|Ttext=")) {
|
||||
s->text_addr = strtoull(o.arg, &end, 16);
|
||||
s->has_text_addr = 1;
|
||||
} else if (link_option(&o, "init=")) {
|
||||
@ -1452,18 +1469,17 @@ static int tcc_set_linker(TCCState *s, const char *optarg)
|
||||
#endif
|
||||
else
|
||||
goto err;
|
||||
} else if (link_option(&o, "export-all-symbols")
|
||||
|| link_option(&o, "export-dynamic")) {
|
||||
} else if (link_option(&o, "export-all-symbols|export-dynamic|E")) {
|
||||
s->rdynamic = 1;
|
||||
} else if (link_option(&o, "rpath=")) {
|
||||
tcc_concat_str(&s->rpath, o.arg, ':');
|
||||
} else if (link_option(&o, "dynamic-linker=") || link_option(&o, "I:")) {
|
||||
} else if (link_option(&o, "dynamic-linker=|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=") || link_option(&o, "install_name=")) {
|
||||
} else if (link_option(&o, "soname=|install_name=")) {
|
||||
tcc_set_str(&s->soname, o.arg);
|
||||
} else if (link_option(&o, "whole-archive")) {
|
||||
s->filetype |= AFF_WHOLE_ARCHIVE;
|
||||
@ -1473,7 +1489,31 @@ 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 |= 0x20;
|
||||
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);
|
||||
} else if (link_option(&o, "file-alignment=")) {
|
||||
s->pe_file_align = strtoul(o.arg, &end, 16);
|
||||
} else if (link_option(&o, "stack=")) {
|
||||
@ -1585,30 +1625,6 @@ 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 },
|
||||
@ -1848,27 +1864,6 @@ 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)
|
||||
{
|
||||
@ -2075,7 +2070,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);
|
||||
break;
|
||||
continue;
|
||||
#endif
|
||||
case TCC_OPTION_m:
|
||||
if (set_flag(s, options_m, optarg) < 0) {
|
||||
@ -2217,7 +2212,7 @@ unsupported_option:
|
||||
if (run) {
|
||||
if (*run && tcc_set_options(s, run) < 0)
|
||||
return -1;
|
||||
x = 0;
|
||||
x = 0, r = 0;
|
||||
goto extra_action;
|
||||
}
|
||||
if (!empty)
|
||||
|
||||
12
libtcc.h
12
libtcc.h
@ -105,18 +105,6 @@ 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
38
optclash
@ -1,38 +0,0 @@
|
||||
#!/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"}
|
||||
'
|
||||
497
riscv64-asm.c
497
riscv64-asm.c
@ -247,11 +247,9 @@ 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)) {
|
||||
greloca(cur_text_section, op->e.sym, ind, R_RISCV_BRANCH, 0);
|
||||
|
||||
/* XXX: Implement far branches */
|
||||
|
||||
op->type = OP_IM12S;
|
||||
/* For extern/static symbols, always use far-branch expansion
|
||||
since linker relaxation (R_RISCV_RELAX) is not implemented. */
|
||||
op->type = OP_IM32;
|
||||
op->e.v = 0;
|
||||
} else {
|
||||
expect("operand");
|
||||
@ -678,15 +676,37 @@ 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, rs */
|
||||
imm.e.v = 1;
|
||||
asm_emit_i(token, (0x4 << 2) | 3 | (4 << 12), &ops[0], &zero, &imm);
|
||||
/* sub rd, x0, rs2 */
|
||||
asm_emit_r(token, (0xC << 2) | 3 | (32 << 25), &ops[0], &zero, &ops[1]);
|
||||
return;
|
||||
case TOK_ASM_negw:
|
||||
/* sub rd, x0, rs */
|
||||
imm.e.v = 1;
|
||||
asm_emit_i(token, (0x4 << 2) | 3 | (4 << 12), &ops[0], &zero, &imm);
|
||||
/* subw rd, x0, rs2 */
|
||||
asm_emit_r(token, (0xE << 2) | 3 | (32 << 25), &ops[0], &zero, &ops[1]);
|
||||
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));
|
||||
@ -722,6 +742,15 @@ 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));
|
||||
@ -738,6 +767,18 @@ 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");
|
||||
}
|
||||
@ -1213,6 +1254,30 @@ 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;
|
||||
@ -1232,6 +1297,26 @@ 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");
|
||||
}
|
||||
@ -1275,56 +1360,205 @@ static void asm_atomic_opcode(TCCState *s1, int token)
|
||||
|
||||
switch(token){
|
||||
case TOK_ASM_lr_w:
|
||||
asm_emit_a(token, 0x2F | 0x2<<12 | 0x2<<27, &ops[0], &ops[1], &ops[2], 0, 0);
|
||||
asm_emit_a(token, 0x2F | 0x2<<12 | 0xC<<27, &ops[0], &ops[1], &ops[2], 0, 0);
|
||||
break;
|
||||
case TOK_ASM_lr_w_aq:
|
||||
asm_emit_a(token, 0x2F | 0x2<<12 | 0x2<<27, &ops[0], &ops[1], &ops[2], 1, 0);
|
||||
asm_emit_a(token, 0x2F | 0x2<<12 | 0xC<<27, &ops[0], &ops[1], &ops[2], 1, 0);
|
||||
break;
|
||||
case TOK_ASM_lr_w_rl:
|
||||
asm_emit_a(token, 0x2F | 0x2<<12 | 0x2<<27, &ops[0], &ops[1], &ops[2], 0, 1);
|
||||
asm_emit_a(token, 0x2F | 0x2<<12 | 0xC<<27, &ops[0], &ops[1], &ops[2], 0, 1);
|
||||
break;
|
||||
case TOK_ASM_lr_w_aqrl:
|
||||
asm_emit_a(token, 0x2F | 0x2<<12 | 0x2<<27, &ops[0], &ops[1], &ops[2], 1, 1);
|
||||
asm_emit_a(token, 0x2F | 0x2<<12 | 0xC<<27, &ops[0], &ops[1], &ops[2], 1, 1);
|
||||
break;
|
||||
|
||||
case TOK_ASM_lr_d:
|
||||
asm_emit_a(token, 0x2F | 0x3<<12 | 0x2<<27, &ops[0], &ops[1], &ops[2], 0, 0);
|
||||
asm_emit_a(token, 0x2F | 0x3<<12 | 0xC<<27, &ops[0], &ops[1], &ops[2], 0, 0);
|
||||
break;
|
||||
case TOK_ASM_lr_d_aq:
|
||||
asm_emit_a(token, 0x2F | 0x3<<12 | 0x2<<27, &ops[0], &ops[1], &ops[2], 1, 0);
|
||||
asm_emit_a(token, 0x2F | 0x3<<12 | 0xC<<27, &ops[0], &ops[1], &ops[2], 1, 0);
|
||||
break;
|
||||
case TOK_ASM_lr_d_rl:
|
||||
asm_emit_a(token, 0x2F | 0x3<<12 | 0x2<<27, &ops[0], &ops[1], &ops[2], 0, 1);
|
||||
asm_emit_a(token, 0x2F | 0x3<<12 | 0xC<<27, &ops[0], &ops[1], &ops[2], 0, 1);
|
||||
break;
|
||||
case TOK_ASM_lr_d_aqrl:
|
||||
asm_emit_a(token, 0x2F | 0x3<<12 | 0x2<<27, &ops[0], &ops[1], &ops[2], 1, 1);
|
||||
asm_emit_a(token, 0x2F | 0x3<<12 | 0xC<<27, &ops[0], &ops[1], &ops[2], 1, 1);
|
||||
break;
|
||||
|
||||
case TOK_ASM_sc_w:
|
||||
asm_emit_a(token, 0x2F | 0x2<<12 | 0x3<<27, &ops[0], &ops[1], &ops[2], 0, 0);
|
||||
asm_emit_a(token, 0x2F | 0x2<<12 | 0x18<<27, &ops[0], &ops[1], &ops[2], 0, 0);
|
||||
break;
|
||||
case TOK_ASM_sc_w_aq:
|
||||
asm_emit_a(token, 0x2F | 0x2<<12 | 0x3<<27, &ops[0], &ops[1], &ops[2], 1, 0);
|
||||
asm_emit_a(token, 0x2F | 0x2<<12 | 0x18<<27, &ops[0], &ops[1], &ops[2], 1, 0);
|
||||
break;
|
||||
case TOK_ASM_sc_w_rl:
|
||||
asm_emit_a(token, 0x2F | 0x2<<12 | 0x3<<27, &ops[0], &ops[1], &ops[2], 0, 1);
|
||||
asm_emit_a(token, 0x2F | 0x2<<12 | 0x18<<27, &ops[0], &ops[1], &ops[2], 0, 1);
|
||||
break;
|
||||
case TOK_ASM_sc_w_aqrl:
|
||||
asm_emit_a(token, 0x2F | 0x2<<12 | 0x3<<27, &ops[0], &ops[1], &ops[2], 1, 1);
|
||||
asm_emit_a(token, 0x2F | 0x2<<12 | 0x18<<27, &ops[0], &ops[1], &ops[2], 1, 1);
|
||||
break;
|
||||
|
||||
case TOK_ASM_sc_d:
|
||||
asm_emit_a(token, 0x2F | 0x3<<12 | 0x3<<27, &ops[0], &ops[1], &ops[2], 0, 0);
|
||||
asm_emit_a(token, 0x2F | 0x3<<12 | 0x18<<27, &ops[0], &ops[1], &ops[2], 0, 0);
|
||||
break;
|
||||
case TOK_ASM_sc_d_aq:
|
||||
asm_emit_a(token, 0x2F | 0x3<<12 | 0x3<<27, &ops[0], &ops[1], &ops[2], 1, 0);
|
||||
asm_emit_a(token, 0x2F | 0x3<<12 | 0x18<<27, &ops[0], &ops[1], &ops[2], 1, 0);
|
||||
break;
|
||||
case TOK_ASM_sc_d_rl:
|
||||
asm_emit_a(token, 0x2F | 0x3<<12 | 0x3<<27, &ops[0], &ops[1], &ops[2], 0, 1);
|
||||
asm_emit_a(token, 0x2F | 0x3<<12 | 0x18<<27, &ops[0], &ops[1], &ops[2], 0, 1);
|
||||
break;
|
||||
case TOK_ASM_sc_d_aqrl:
|
||||
asm_emit_a(token, 0x2F | 0x3<<12 | 0x3<<27, &ops[0], &ops[1], &ops[2], 1, 1);
|
||||
asm_emit_a(token, 0x2F | 0x3<<12 | 0x18<<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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1386,6 +1620,26 @@ 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));
|
||||
}
|
||||
@ -1404,6 +1658,62 @@ 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) {
|
||||
@ -1437,6 +1747,30 @@ 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:
|
||||
@ -1513,12 +1847,26 @@ 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:
|
||||
@ -1618,10 +1966,20 @@ 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);
|
||||
@ -1660,6 +2018,82 @@ 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);
|
||||
break;
|
||||
|
||||
@ -1839,9 +2273,8 @@ ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands,
|
||||
} else {
|
||||
load(tcc_ireg(op->reg), op->vt);
|
||||
}
|
||||
if (op->is_llong) {
|
||||
tcc_error("long long not implemented");
|
||||
}
|
||||
/* RV64: long long fits in a single 64-bit register;
|
||||
the load/store above already handles it correctly */
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1869,9 +2302,7 @@ ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands,
|
||||
} else {
|
||||
store(tcc_ireg(op->reg), op->vt);
|
||||
}
|
||||
if (op->is_llong) {
|
||||
tcc_error("long long not implemented");
|
||||
}
|
||||
/* RV64: long long fits in a single 64-bit register */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,6 +30,10 @@
|
||||
|
||||
#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"
|
||||
@ -175,6 +179,19 @@ 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);
|
||||
@ -277,13 +294,29 @@ 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;
|
||||
assert((!is_float(sv->type.t) && is_ireg(r)) || bt == VT_LDOUBLE);
|
||||
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);
|
||||
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;
|
||||
@ -1241,10 +1274,31 @@ 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)
|
||||
{
|
||||
/* XXX on risc-v the registers are usually sign-extended already.
|
||||
Let's try to not do anything here. */
|
||||
int r = ireg(gv(RC_INT));
|
||||
EI(0x1b, 0, r, r, 0); // addiw r, r, 0
|
||||
}
|
||||
|
||||
ST_FUNC void gen_cvt_itof(int t)
|
||||
@ -1431,4 +1485,12 @@ 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
|
||||
|
||||
@ -53,6 +53,8 @@ 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:
|
||||
@ -101,6 +103,10 @@ 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;
|
||||
}
|
||||
@ -175,38 +181,24 @@ ST_FUNC void relocate_plt(TCCState *s1)
|
||||
|
||||
static void riscv64_record_pcrel_hi(TCCState *s1, addr_t addr, addr_t val)
|
||||
{
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
||||
static int riscv64_lookup_pcrel_hi(TCCState *s1, addr_t hi_addr, addr_t *hi_val)
|
||||
{
|
||||
int 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];
|
||||
for (i = s1->nb_pcrel_hi_entries; i > 0; ) {
|
||||
struct pcrel_hi *entry = s1->pcrel_hi_entries[--i];
|
||||
if (entry->addr == hi_addr) {
|
||||
last_hi = *entry;
|
||||
*hi_val = entry->val;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return tcc_error_noabort("unsupported hi/lo pcrel reloc scheme");
|
||||
}
|
||||
|
||||
ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
|
||||
addr_t addr, addr_t val)
|
||||
@ -279,15 +271,13 @@ 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;
|
||||
if (!riscv64_lookup_pcrel_hi(s1, addr, &val))
|
||||
tcc_error_noabort("unsupported hi/lo pcrel reloc scheme");
|
||||
riscv64_lookup_pcrel_hi(s1, addr, &val);
|
||||
write32le(ptr, (read32le(ptr) & 0xfffff)
|
||||
| (((val - addr) & 0xfff) << 20));
|
||||
return;
|
||||
case R_RISCV_PCREL_LO12_S:
|
||||
addr = val;
|
||||
if (!riscv64_lookup_pcrel_hi(s1, addr, &val))
|
||||
tcc_error_noabort("unsupported hi/lo pcrel reloc scheme");
|
||||
riscv64_lookup_pcrel_hi(s1, addr, &val);
|
||||
off32 = val - addr;
|
||||
write32le(ptr, (read32le(ptr) & ~0xfe000f80)
|
||||
| ((off32 & 0xfe0) << 20)
|
||||
@ -409,6 +399,37 @@ 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",
|
||||
|
||||
122
riscv64-tok.h
122
riscv64-tok.h
@ -270,6 +270,14 @@
|
||||
/* 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)
|
||||
@ -279,6 +287,34 @@
|
||||
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 */
|
||||
DEF_ASM_WITH_SUFFIX(c, nop)
|
||||
/* Loads */
|
||||
@ -464,6 +500,92 @@
|
||||
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 */
|
||||
/* NOTE: Order is important */
|
||||
DEF_ASM_FENCE(w)
|
||||
|
||||
@ -386,6 +386,15 @@ 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.
|
||||
|
||||
|
||||
26
tcc.c
26
tcc.c
@ -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 [with custom stdin: -rstdin FILE]\n"
|
||||
" -run run compiled source\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,6 +105,7 @@ 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"
|
||||
@ -225,7 +226,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", DEFAULT_ELFINTERP(s));
|
||||
printf("elfinterp:\n %s\n", s->elfint);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -293,7 +294,7 @@ int main(int argc, char **argv)
|
||||
const char *first_file;
|
||||
int argc0 = argc;
|
||||
char **argv0 = argv;
|
||||
FILE *ppfp = stdout;
|
||||
FILE *ppfp = NULL;
|
||||
|
||||
redo:
|
||||
argc = argc0, argv = argv0;
|
||||
@ -335,7 +336,7 @@ redo:
|
||||
tcc_error_noabort("no input files");
|
||||
} else if (s->output_type == TCC_OUTPUT_PREPROCESS) {
|
||||
if (s->outfile && 0!=strcmp("-",s->outfile)) {
|
||||
ppfp = fopen(s->outfile, "wb");
|
||||
ppfp = tcc_fopen(s->outfile, "wb");
|
||||
if (!ppfp)
|
||||
tcc_error_noabort("could not write '%s'", s->outfile);
|
||||
}
|
||||
@ -354,7 +355,8 @@ redo:
|
||||
set_environment(s);
|
||||
if (s->output_type == 0)
|
||||
s->output_type = TCC_OUTPUT_EXE;
|
||||
tcc_set_output_type(s, s->output_type);
|
||||
ret = tcc_set_output_type(s, s->output_type);
|
||||
if (ppfp)
|
||||
s->ppfp = ppfp;
|
||||
|
||||
if ((s->output_type == TCC_OUTPUT_MEMORY
|
||||
@ -369,7 +371,7 @@ redo:
|
||||
|
||||
/* compile or add each files or library */
|
||||
first_file = NULL;
|
||||
do {
|
||||
while (0 == ret) {
|
||||
struct filespec *f = s->files[n];
|
||||
s->filetype = f->type;
|
||||
if (f->type & AFF_TYPE_LIB) {
|
||||
@ -381,9 +383,11 @@ redo:
|
||||
first_file = f->name;
|
||||
ret = tcc_add_file(s, f->name);
|
||||
}
|
||||
} while (++n < s->nb_files
|
||||
&& 0 == ret
|
||||
&& (s->output_type != TCC_OUTPUT_OBJ || s->option_r));
|
||||
if (++n == s->nb_files)
|
||||
break;
|
||||
if (s->output_type == TCC_OUTPUT_OBJ && !s->option_r)
|
||||
break;
|
||||
}
|
||||
|
||||
if (s->do_bench)
|
||||
end_time = getclock_ms();
|
||||
@ -422,7 +426,7 @@ redo:
|
||||
tcc_delete(s);
|
||||
if (!done)
|
||||
goto redo;
|
||||
if (ppfp && ppfp != stdout)
|
||||
fclose(ppfp);
|
||||
if (ppfp)
|
||||
tcc_fclose(ppfp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
117
tcc.h
117
tcc.h
@ -52,6 +52,9 @@ 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 */
|
||||
@ -86,6 +89,9 @@ 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
|
||||
@ -228,8 +234,7 @@ 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 _WIN32 && !defined __GNUC__)
|
||||
|| (defined TCC_TARGET_MACHO && defined TCC_TARGET_ARM64)
|
||||
# define TCC_USING_DOUBLE_FOR_LDOUBLE 1
|
||||
#endif
|
||||
|
||||
@ -247,15 +252,14 @@ 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) ":" s
|
||||
# define ALSO_TRIPLET(s) USE_TRIPLET(s) PATHSEP s
|
||||
#else
|
||||
# define USE_TRIPLET(s) s
|
||||
# define ALSO_TRIPLET(s) s
|
||||
@ -263,11 +267,8 @@ 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/" CONFIG_LDDIR)
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_USR_INCLUDE
|
||||
# define CONFIG_USR_INCLUDE "/usr/include"
|
||||
# define CONFIG_TCC_CRTPREFIX \
|
||||
USE_TRIPLET(CONFIG_SYSROOT "/usr/lib")
|
||||
#endif
|
||||
|
||||
/* Below: {B} is substituted by CONFIG_TCCDIR (rsp. -B option) */
|
||||
@ -275,25 +276,22 @@ 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" \
|
||||
":" ALSO_TRIPLET(CONFIG_SYSROOT "/usr/local/include") \
|
||||
":" ALSO_TRIPLET(CONFIG_SYSROOT CONFIG_USR_INCLUDE)
|
||||
"{B}/include" PATHSEP ALSO_TRIPLET(CONFIG_SYSROOT "/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}" \
|
||||
":" ALSO_TRIPLET(CONFIG_SYSROOT "/usr/" CONFIG_LDDIR) \
|
||||
":" ALSO_TRIPLET(CONFIG_SYSROOT "/" CONFIG_LDDIR) \
|
||||
":" ALSO_TRIPLET(CONFIG_SYSROOT "/usr/local/" CONFIG_LDDIR)
|
||||
"{B}" PATHSEP ALSO_TRIPLET(CONFIG_SYSROOT "/usr/lib")
|
||||
# endif
|
||||
#endif
|
||||
|
||||
@ -309,28 +307,19 @@ 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_ARM_EABI)
|
||||
# define DEFAULT_ELFINTERP(s) default_elfinterp(s)
|
||||
# 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"
|
||||
# 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 ""
|
||||
@ -470,6 +459,9 @@ 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;
|
||||
@ -480,7 +472,7 @@ typedef union CValue {
|
||||
char *data;
|
||||
int size;
|
||||
} str;
|
||||
int tab[LDOUBLE_SIZE/4];
|
||||
int tab[LDOUBLE_WORDS];
|
||||
} CValue;
|
||||
|
||||
/* value on stack */
|
||||
@ -735,6 +727,15 @@ 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 */
|
||||
@ -897,6 +898,7 @@ 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
|
||||
@ -938,23 +940,23 @@ struct TCCState {
|
||||
#define qrel s1->qrel
|
||||
|
||||
#ifdef TCC_TARGET_RISCV64
|
||||
struct pcrel_hi { addr_t addr, val; } last_hi;
|
||||
struct pcrel_hi *pcrel_hi_entries;
|
||||
struct pcrel_hi { addr_t addr, val; } **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;
|
||||
# ifdef TCC_TARGET_X86_64
|
||||
# if defined(TCC_TARGET_X86_64) || defined(TCC_TARGET_ARM64)
|
||||
Section *uw_pdata;
|
||||
int uw_sym;
|
||||
int uw_xsym;
|
||||
unsigned uw_offs;
|
||||
# endif
|
||||
#endif
|
||||
@ -1073,7 +1075,8 @@ struct filespec {
|
||||
#define VT_STATIC 0x00002000 /* static variable */
|
||||
#define VT_TYPEDEF 0x00004000 /* typedef definition */
|
||||
#define VT_INLINE 0x00008000 /* inline definition */
|
||||
/* currently unused: 0x000[1248]0000 */
|
||||
#define VT_TLS 0x00010000 /* thread-local storage */
|
||||
/* currently unused: 0x000[248]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)
|
||||
@ -1091,7 +1094,7 @@ struct filespec {
|
||||
#define VT_ATOMIC VT_VOLATILE
|
||||
|
||||
/* type mask (except storage) */
|
||||
#define VT_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE)
|
||||
#define VT_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE | VT_TLS)
|
||||
#define VT_TYPE (~(VT_STORAGE|VT_STRUCT_MASK))
|
||||
|
||||
/* symbol was created by tccasm.c first */
|
||||
@ -1314,6 +1317,11 @@ 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);
|
||||
@ -1438,8 +1446,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;
|
||||
ST_DATA int func_ind;
|
||||
ST_DATA int func_vc; /* stack address for implicit struct return storage */
|
||||
ST_DATA int func_ind; /* function start address */
|
||||
ST_DATA const char *funcname;
|
||||
|
||||
ST_FUNC void tccgen_init(TCCState *s1);
|
||||
@ -1685,7 +1693,6 @@ 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);
|
||||
@ -1718,11 +1725,12 @@ 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 ------------ */
|
||||
@ -1744,11 +1752,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);
|
||||
/* ------------ i386-asm.c ------------ */
|
||||
ST_FUNC void gen_expr32(ExprValue *pe);
|
||||
#ifdef TCC_TARGET_X86_64
|
||||
#if PTR_SIZE == 8
|
||||
ST_FUNC void gen_expr64(ExprValue *pe);
|
||||
#endif
|
||||
/* ------------ i386-asm.c ------------ */
|
||||
ST_FUNC void gen_expr32(ExprValue *pe);
|
||||
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);
|
||||
@ -1765,7 +1773,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
|
||||
#ifdef TCC_TARGET_X86_64
|
||||
#if defined(TCC_TARGET_X86_64) || defined(TCC_TARGET_ARM64)
|
||||
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);
|
||||
@ -1922,10 +1930,15 @@ dwarf_read_sleb128(unsigned char **ln, unsigned char *end)
|
||||
/********************************************************/
|
||||
#if CONFIG_TCC_SEMLOCK
|
||||
#if defined _WIN32
|
||||
typedef struct { int init; CRITICAL_SECTION cs; } TCCSem;
|
||||
typedef struct { volatile LONG init; CRITICAL_SECTION cs; } TCCSem;
|
||||
static inline void wait_sem(TCCSem *p) {
|
||||
if (!p->init)
|
||||
InitializeCriticalSection(&p->cs), p->init = 1;
|
||||
if (InterlockedCompareExchange(&p->init, 1, 0) == 0) {
|
||||
InitializeCriticalSection(&p->cs);
|
||||
InterlockedExchange(&p->init, 2);
|
||||
} else {
|
||||
while (InterlockedCompareExchange(&p->init, 2, 2) != 2)
|
||||
Sleep(0);
|
||||
}
|
||||
EnterCriticalSection(&p->cs);
|
||||
}
|
||||
static inline void post_sem(TCCSem *p) {
|
||||
@ -1976,6 +1989,8 @@ 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
105
tccasm.c
@ -25,6 +25,26 @@
|
||||
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];
|
||||
@ -37,10 +57,6 @@ 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
|
||||
@ -328,12 +344,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 += esym1->st_value - esym2->st_value;
|
||||
pe->v += (int)(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 += 0 - esym2->st_value;
|
||||
pe->v += (int)(0 - esym2->st_value);
|
||||
pe->pcrel = 1;
|
||||
e2.sym = NULL;
|
||||
} else {
|
||||
@ -494,7 +510,7 @@ static void pop_section(TCCState *s1)
|
||||
|
||||
static void asm_parse_directive(TCCState *s1, int global)
|
||||
{
|
||||
int n, offset, v, size, tok1;
|
||||
int n, offset, v, size, tok1, c;
|
||||
Section *sec;
|
||||
uint8_t *ptr;
|
||||
|
||||
@ -524,18 +540,25 @@ 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;
|
||||
size = n, c = 0;
|
||||
}
|
||||
v = 0;
|
||||
if (tok == ',') {
|
||||
next();
|
||||
v = asm_int_expr(s1);
|
||||
v = asm_int_expr(s1), c = 0;
|
||||
}
|
||||
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);
|
||||
@ -543,7 +566,7 @@ static void asm_parse_directive(TCCState *s1, int global)
|
||||
ind += size;
|
||||
break;
|
||||
case TOK_ASMDIR_quad:
|
||||
#ifdef TCC_TARGET_X86_64
|
||||
#if PTR_SIZE == 8
|
||||
size = 8;
|
||||
goto asm_data;
|
||||
#else
|
||||
@ -592,7 +615,7 @@ static void asm_parse_directive(TCCState *s1, int global)
|
||||
if (sec->sh_type != SHT_NOBITS) {
|
||||
if (size == 4) {
|
||||
gen_expr32(&e);
|
||||
#ifdef TCC_TARGET_X86_64
|
||||
#if PTR_SIZE == 8
|
||||
} else if (size == 8) {
|
||||
gen_expr64(&e);
|
||||
#endif
|
||||
@ -690,11 +713,9 @@ 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 = 0;
|
||||
v = c = 0;
|
||||
size = n - ind;
|
||||
goto zero_pad;
|
||||
}
|
||||
@ -812,6 +833,7 @@ static void asm_parse_directive(TCCState *s1, int global)
|
||||
case TOK_ASMDIR_size:
|
||||
{
|
||||
Sym *sym;
|
||||
ElfSym *esym;
|
||||
|
||||
next();
|
||||
if (tok < TOK_IDENT)
|
||||
@ -823,8 +845,10 @@ static void asm_parse_directive(TCCState *s1, int global)
|
||||
tcc_warning_c(warn_unsupported)("ignoring .size %s,*", get_tok_str(tok, NULL));
|
||||
next();
|
||||
skip(',');
|
||||
while (tok != TOK_LINEFEED && tok != ';' && tok != CH_EOF) {
|
||||
next();
|
||||
n = asm_int_expr(s1);
|
||||
esym = elfsym(sym);
|
||||
if (esym) {
|
||||
esym->st_size = n;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -952,7 +976,7 @@ static void asm_parse_directive(TCCState *s1, int global)
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef TCC_TARGET_X86_64
|
||||
#if PTR_SIZE == 8
|
||||
/* added for compatibility with GAS */
|
||||
case TOK_ASMDIR_code64:
|
||||
next();
|
||||
@ -995,17 +1019,41 @@ 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(get_tok_str(tok, NULL), "R_AARCH64_CALL26"))
|
||||
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;
|
||||
#endif
|
||||
tcc_error("unimp: reloc '%s' unknown", get_tok_str(tok, NULL));
|
||||
if (reloc_type < 0)
|
||||
tcc_error("unimp: reloc '%s' unknown", reloc_name);
|
||||
next();
|
||||
skip(',');
|
||||
greloca(cur_text_section, get_asm_sym(tok, NULL), e.v, R_AARCH64_CALL26, 0);
|
||||
greloca(cur_text_section, get_asm_sym(tok, NULL), e.v, reloc_type, 0);
|
||||
next();
|
||||
}
|
||||
break;
|
||||
@ -1032,11 +1080,14 @@ 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 if (tok >= TOK_ASMDIR_FIRST && tok <= TOK_ASMDIR_LAST) {
|
||||
} else
|
||||
#endif
|
||||
if (tok >= TOK_ASMDIR_FIRST && tok <= TOK_ASMDIR_LAST) {
|
||||
asm_parse_directive(s1, global);
|
||||
} else if (tok == TOK_PPNUM) {
|
||||
const char *p;
|
||||
@ -1176,6 +1227,9 @@ 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
|
||||
@ -1196,7 +1250,7 @@ static void subst_asm_operands(ASMOperand *operands, int nb_operands,
|
||||
sv = *op->vt;
|
||||
if (op->reg >= 0) {
|
||||
sv.r = op->reg;
|
||||
if ((op->vt->r & VT_VALMASK) == VT_LLOCAL && op->is_memory)
|
||||
if (op->is_memory)
|
||||
sv.r |= VT_LVAL;
|
||||
}
|
||||
subst_asm_operand(out_str, &sv, modifier);
|
||||
@ -1248,7 +1302,12 @@ 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')) {
|
||||
!strchr(op->constraint, 'm')
|
||||
#ifdef TCC_TARGET_ARM64
|
||||
&& !strchr(op->constraint, 'Q')
|
||||
&& !strstr(op->constraint, "Ump")
|
||||
#endif
|
||||
) {
|
||||
gv(RC_INT);
|
||||
}
|
||||
}
|
||||
|
||||
120
tccelf.c
120
tccelf.c
@ -70,6 +70,8 @@ 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;
|
||||
|
||||
@ -110,6 +112,21 @@ 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)
|
||||
@ -145,9 +162,6 @@ 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() */
|
||||
}
|
||||
|
||||
@ -1109,7 +1123,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("undefined symbol '%s'", name);
|
||||
tcc_error_noabort("unresolved reference to '%s'", name);
|
||||
|
||||
} else if (sh_num < SHN_LORESERVE) {
|
||||
/* add section base */
|
||||
@ -1130,10 +1144,6 @@ 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 */
|
||||
@ -1155,6 +1165,7 @@ 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) {
|
||||
@ -1172,6 +1183,10 @@ 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 */
|
||||
@ -2076,7 +2091,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("undefined symbol '%s'", name);
|
||||
tcc_error_noabort("unresolved reference to '%s'", name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2107,7 +2122,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("undefined dynamic symbol '%s'", name);
|
||||
tcc_warning("unresolved dynamic reference to '%s'", name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2281,7 +2296,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|SHF_TLS);
|
||||
f = s->sh_flags & (SHF_ALLOC|SHF_WRITE|SHF_EXECINSTR);
|
||||
#if TARGETOS_NetBSD
|
||||
/* NetBSD only supports 2 PT_LOAD sections.
|
||||
See: https://blog.netbsd.org/tnf/entry/the_first_report_on_lld */
|
||||
@ -2340,6 +2355,18 @@ 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)));
|
||||
|
||||
@ -2416,10 +2443,6 @@ 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;
|
||||
@ -2464,6 +2487,34 @@ 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) {
|
||||
@ -2839,6 +2890,28 @@ 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,
|
||||
@ -2941,18 +3014,10 @@ 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;
|
||||
ptr = section_ptr_add(interp, 1 + strlen(elfint));
|
||||
strcpy(ptr, elfint);
|
||||
put_elf_str(interp, s1->elfint);
|
||||
dyninf.interp = interp;
|
||||
}
|
||||
|
||||
@ -3103,10 +3168,13 @@ static void alloc_sec_names(TCCState *s1, int is_obj)
|
||||
}
|
||||
|
||||
/* Output an elf .o file */
|
||||
LIBTCCAPI int elf_output_obj(TCCState *s1, const char *filename)
|
||||
static 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;
|
||||
@ -3303,6 +3371,8 @@ 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;
|
||||
|
||||
223
tccgen.c
223
tccgen.c
@ -70,8 +70,9 @@ 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;
|
||||
ST_DATA int func_ind;
|
||||
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 const char *funcname;
|
||||
ST_DATA CType int_type, func_old_type, char_type, char_pointer_type;
|
||||
static CString initstr;
|
||||
@ -322,12 +323,6 @@ 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))
|
||||
@ -531,6 +526,8 @@ 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;
|
||||
}
|
||||
@ -1385,7 +1382,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 */
|
||||
s = sym_copy(s, &local_stack);
|
||||
sym_copy(s, &local_stack);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
@ -1906,6 +1903,8 @@ 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 */
|
||||
@ -2521,11 +2520,17 @@ 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);
|
||||
@ -2534,6 +2539,8 @@ void gen_negf(int op)
|
||||
gen_op('^');
|
||||
vstore();
|
||||
vpop();
|
||||
gv2:
|
||||
gv(RC_TYPE(bt)); /* -n is not a lvalue */
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -2919,7 +2926,8 @@ static int combine_types(CType *dest, SValue *op1, SValue *op2, int op)
|
||||
type.ref = NULL;
|
||||
|
||||
if (bt1 == VT_VOID || bt2 == VT_VOID) {
|
||||
ret = op == '?' ? 1 : 0;
|
||||
if (op != '?')
|
||||
tcc_error("operation on void value");
|
||||
/* NOTE: as an extension, we accept void on only one side */
|
||||
type.t = VT_VOID;
|
||||
} else if (bt1 == VT_PTR || bt2 == VT_PTR) {
|
||||
@ -3097,9 +3105,7 @@ op_err:
|
||||
#endif
|
||||
type1 = vtop[-1].type;
|
||||
vpush_type_size(pointed_type(&vtop[-1].type), &align);
|
||||
if (!(vtop[-1].type.t & VT_UNSIGNED)) {
|
||||
gen_cast_s(VT_PTRDIFF_T);
|
||||
}
|
||||
vtop->type.t &= ~VT_UNSIGNED;
|
||||
gen_op('*');
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (tcc_state->do_bounds_check && !CONST_WANTED) {
|
||||
@ -3168,7 +3174,7 @@ op_err:
|
||||
}
|
||||
// Make sure that we have converted to an rvalue:
|
||||
if (vtop->r & VT_LVAL)
|
||||
gv(is_float(vtop->type.t & VT_BTYPE) ? RC_FLOAT : RC_INT);
|
||||
gv(RC_TYPE(vtop->type.t));
|
||||
}
|
||||
|
||||
#if defined TCC_TARGET_ARM64 || defined TCC_TARGET_RISCV64 || defined TCC_TARGET_ARM
|
||||
@ -3273,20 +3279,15 @@ 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 */
|
||||
@ -3353,8 +3354,11 @@ error:
|
||||
}
|
||||
|
||||
/* cannot generate code for global or static initializers */
|
||||
if (nocode_wanted & DATA_ONLY_WANTED)
|
||||
if (nocode_wanted & DATA_ONLY_WANTED) {
|
||||
if (df)
|
||||
vtop->r = get_reg(RC_FLOAT); /* don't confuse backends */
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* non constant case: generate code */
|
||||
if (dbt == VT_BOOL) {
|
||||
@ -3463,7 +3467,7 @@ error:
|
||||
|
||||
if (ds >= ss)
|
||||
goto done;
|
||||
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 || defined TCC_TARGET_ARM64
|
||||
#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;
|
||||
@ -4745,6 +4749,8 @@ 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)
|
||||
@ -4927,7 +4933,12 @@ static int parse_btype(CType *type, AttributeDef *ad, int ignore_label)
|
||||
}
|
||||
goto basic_type2;
|
||||
case TOK_THREAD_LOCAL:
|
||||
tcc_error("_Thread_local is not implemented");
|
||||
case TOK___thread:
|
||||
if (t & VT_TLS)
|
||||
tcc_error("multiple thread-local storage specifiers");
|
||||
t |= VT_TLS;
|
||||
next();
|
||||
break;
|
||||
default:
|
||||
if (typespec_found)
|
||||
goto the_end;
|
||||
@ -5627,6 +5638,7 @@ 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
|
||||
@ -5941,6 +5953,8 @@ 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();
|
||||
@ -5949,6 +5963,17 @@ 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:
|
||||
@ -6104,6 +6129,7 @@ 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);
|
||||
@ -6158,7 +6184,8 @@ special_math_val:
|
||||
gen_op('+');
|
||||
/* change type to field type, and set to lvalue */
|
||||
vtop->type = s->type;
|
||||
vtop->type.t |= qualifiers;
|
||||
if (qualifiers)
|
||||
parse_btype_qualify(&vtop->type, qualifiers);
|
||||
/* an array is never an lvalue */
|
||||
if (!(vtop->type.t & VT_ARRAY)) {
|
||||
vtop->r |= VT_LVAL;
|
||||
@ -6652,7 +6679,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 = (vtop->r & VT_LVAL) && (sv.r & VT_LVAL) && VT_STRUCT == (type.t & VT_BTYPE);
|
||||
islv = VT_STRUCT == (type.t & VT_BTYPE);
|
||||
|
||||
/* now we convert second operand */
|
||||
if (c != 1) {
|
||||
@ -6660,8 +6687,7 @@ 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);
|
||||
@ -6672,6 +6698,7 @@ static void expr_cond(void)
|
||||
|
||||
tt = r2 = 0;
|
||||
if (c < 0) {
|
||||
if (type.t != VT_VOID)
|
||||
r2 = gv(rc);
|
||||
tt = gjmp(0);
|
||||
}
|
||||
@ -6687,14 +6714,15 @@ 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;
|
||||
}
|
||||
gsym(tt);
|
||||
}
|
||||
|
||||
@ -6737,6 +6765,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));
|
||||
}
|
||||
}
|
||||
@ -6847,11 +6876,10 @@ static void check_func_return(void)
|
||||
{
|
||||
if ((func_vt.t & VT_BTYPE) == VT_VOID)
|
||||
return;
|
||||
if (!strcmp (funcname, "main")
|
||||
if ((!strcmp(funcname, "main") || func_old)
|
||||
&& (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);
|
||||
@ -7234,6 +7262,8 @@ 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;
|
||||
@ -7758,6 +7788,71 @@ 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)
|
||||
{
|
||||
@ -7798,21 +7893,12 @@ static void init_putv(init_params *p, CType *type, unsigned long c)
|
||||
ptr = sec->data + c;
|
||||
val = vtop->c.i;
|
||||
|
||||
/* 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. */
|
||||
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. */
|
||||
Section *ssec;
|
||||
ElfSym *esym;
|
||||
ElfW_Rel *rel;
|
||||
@ -7879,34 +7965,7 @@ static void init_putv(init_params *p, CType *type, unsigned long c)
|
||||
write64le(ptr, val);
|
||||
break;
|
||||
case VT_LDOUBLE:
|
||||
#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
|
||||
write_ldouble(ptr, &vtop->c.ld);
|
||||
break;
|
||||
|
||||
#if PTR_SIZE == 8
|
||||
@ -8064,6 +8123,8 @@ 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:
|
||||
@ -8336,7 +8397,12 @@ 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 (tp->t & VT_CONSTANT) {
|
||||
if (type->t & VT_TLS) {
|
||||
if (has_init)
|
||||
sec = tdata_section;
|
||||
else
|
||||
sec = tbss_section;
|
||||
} else if (tp->t & VT_CONSTANT) {
|
||||
sec = rodata_section;
|
||||
} else if (has_init) {
|
||||
sec = data_section;
|
||||
@ -8520,6 +8586,7 @@ 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);
|
||||
|
||||
2
tcclib.h
2
tcclib.h
@ -19,6 +19,7 @@ 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;
|
||||
@ -39,6 +40,7 @@ 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, ...);
|
||||
|
||||
@ -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("undefined local symbo: '%s'",
|
||||
tcc_error("unresolved local reference to '%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("undefined local symbo: '%s'",
|
||||
tcc_error("unresolved local reference to '%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("undefined symbol '%s'", name);
|
||||
tcc_error_noabort("unresolved reference to '%s'", name);
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
@ -1058,6 +1058,7 @@ 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;
|
||||
|
||||
245
tccpe.c
245
tccpe.c
@ -27,6 +27,8 @@
|
||||
#define stricmp strcasecmp
|
||||
#define strnicmp strncasecmp
|
||||
#include <sys/stat.h> /* chmod() */
|
||||
#else
|
||||
#include <process.h>
|
||||
#endif
|
||||
|
||||
#ifdef TCC_TARGET_X86_64
|
||||
@ -50,6 +52,16 @@
|
||||
# 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
|
||||
@ -126,7 +138,7 @@ typedef struct _IMAGE_OPTIONAL_HEADER {
|
||||
DWORD SizeOfUninitializedData;
|
||||
DWORD AddressOfEntryPoint;
|
||||
DWORD BaseOfCode;
|
||||
#ifndef TCC_TARGET_X86_64
|
||||
#if !defined(TCC_TARGET_X86_64) && !defined(TCC_TARGET_ARM64)
|
||||
DWORD BaseOfData;
|
||||
#endif
|
||||
/* NT additional fields. */
|
||||
@ -225,6 +237,19 @@ 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
|
||||
@ -250,6 +275,24 @@ 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
|
||||
@ -261,7 +304,7 @@ struct pe_header
|
||||
BYTE dosstub[0x40];
|
||||
DWORD nt_sig;
|
||||
IMAGE_FILE_HEADER filehdr;
|
||||
#ifdef TCC_TARGET_X86_64
|
||||
#if defined(TCC_TARGET_X86_64) || defined(TCC_TARGET_ARM64)
|
||||
IMAGE_OPTIONAL_HEADER64 opthdr;
|
||||
#else
|
||||
#ifdef _WIN64
|
||||
@ -537,17 +580,55 @@ 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)
|
||||
{
|
||||
char buf[300]; int r;
|
||||
snprintf(buf, sizeof buf, "cv2pdb.exe %s", exename);
|
||||
r = system(buf);
|
||||
strcpy(tcc_fileextension(strcpy(buf, exename)), ".pdb");
|
||||
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);
|
||||
if (r) {
|
||||
tcc_error_noabort("could not create '%s'\n(need working cv2pdb from https://github.com/rainers/cv2pdb)", buf);
|
||||
tcc_error_noabort("could not create '%s'\n(need working cv2pdb from https://github.com/rainers/cv2pdb)", pdbfile);
|
||||
} else if (s1->verbose) {
|
||||
printf("<- %s\n", buf);
|
||||
printf("<- %s\n", pdbfile);
|
||||
}
|
||||
tcc_free(pdbfile);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
@ -605,11 +686,15 @@ 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. */
|
||||
#ifdef TCC_TARGET_X86_64
|
||||
#if defined(TCC_TARGET_X86_64) || defined(TCC_TARGET_ARM64)
|
||||
0x020B, /*WORD Magic; */
|
||||
#else
|
||||
0x010B, /*WORD Magic; */
|
||||
@ -621,23 +706,35 @@ static int pe_write(struct pe_info *pe)
|
||||
0x00000000, /*DWORD SizeOfUninitializedData; */
|
||||
0x00000000, /*DWORD AddressOfEntryPoint; */
|
||||
0x00000000, /*DWORD BaseOfCode; */
|
||||
#ifndef TCC_TARGET_X86_64
|
||||
#if !defined(TCC_TARGET_X86_64) && !defined(TCC_TARGET_ARM64)
|
||||
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; */
|
||||
@ -702,7 +799,7 @@ static int pe_write(struct pe_info *pe)
|
||||
break;
|
||||
|
||||
case sec_data:
|
||||
#ifndef TCC_TARGET_X86_64
|
||||
#if !defined(TCC_TARGET_X86_64) && !defined(TCC_TARGET_ARM64)
|
||||
if (!pe_header.opthdr.BaseOfData)
|
||||
pe_header.opthdr.BaseOfData = addr;
|
||||
#endif
|
||||
@ -764,11 +861,14 @@ 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);
|
||||
@ -1191,7 +1291,8 @@ static int pe_assign_addresses (struct pe_info *pe)
|
||||
Section *s;
|
||||
TCCState *s1 = pe->s1;
|
||||
|
||||
if (PE_DLL == pe->type)
|
||||
if (PE_DLL == pe->type ||
|
||||
(pe_get_dll_characteristics(s1) & PE_DLLCHARACTERISTICS_DYNAMIC_BASE))
|
||||
pe->reloc = new_section(s1, ".reloc", SHT_PROGBITS, 0);
|
||||
//pe->thunk = new_section(s1, ".iedat", SHT_PROGBITS, SHF_ALLOC);
|
||||
|
||||
@ -1380,6 +1481,18 @@ 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);
|
||||
@ -1611,7 +1724,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) {
|
||||
} else if (ih.Machine == 0x8664 || ih.Machine == IMAGE_FILE_MACHINE_ARM64) {
|
||||
IMAGE_OPTIONAL_HEADER64 oh;
|
||||
sec_hdroffset = opt_hdroffset + sizeof oh;
|
||||
if (!read_mem(fd, opt_hdroffset, &oh, sizeof oh))
|
||||
@ -1834,7 +1947,7 @@ PUB_FUNC int tcc_get_dllexports(const char *filename, char **pp)
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
#ifdef TCC_TARGET_X86_64
|
||||
static unsigned pe_add_uwwind_info(TCCState *s1)
|
||||
static unsigned pe_add_unwind_info(TCCState *s1)
|
||||
{
|
||||
if (NULL == s1->uw_pdata) {
|
||||
s1->uw_pdata = find_section(s1, ".pdata");
|
||||
@ -1879,7 +1992,7 @@ ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack)
|
||||
DWORD UnwindData;
|
||||
} *p;
|
||||
|
||||
d = pe_add_uwwind_info(s1);
|
||||
d = pe_add_unwind_info(s1);
|
||||
pd = s1->uw_pdata;
|
||||
o = pd->data_offset;
|
||||
p = section_ptr_add(pd, sizeof *p);
|
||||
@ -1893,9 +2006,85 @@ 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
|
||||
/* ------------------------------------------------------------- */
|
||||
#ifdef TCC_TARGET_X86_64
|
||||
#if defined(TCC_TARGET_X86_64) || defined(TCC_TARGET_ARM64)
|
||||
#define PE_STDSYM(n,s) n
|
||||
#else
|
||||
#define PE_STDSYM(n,s) "_" n s
|
||||
@ -1991,7 +2180,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)
|
||||
#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64) || defined(TCC_TARGET_ARM64)
|
||||
{ "native", 1 },
|
||||
{ "gui", 2 },
|
||||
{ "windows", 2 },
|
||||
@ -2020,10 +2209,16 @@ 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
|
||||
@ -2080,29 +2275,33 @@ 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)
|
||||
;
|
||||
else if (filename) {
|
||||
goto done;
|
||||
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 (0 == s1->nb_errors)
|
||||
if (s1->nb_errors)
|
||||
goto done;
|
||||
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;
|
||||
#ifdef TCC_TARGET_X86_64
|
||||
#if defined(TCC_TARGET_X86_64) || defined(TCC_TARGET_ARM64)
|
||||
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)
|
||||
|
||||
87
tccpp.c
87
tccpp.c
@ -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)
|
||||
#if !defined(TCC_TARGET_ARM) && !defined(TCC_TARGET_ARM64)
|
||||
else if (parse_flags & PARSE_FLAG_ASM_FILE)
|
||||
p = parse_line_comment(p - 1);
|
||||
#else
|
||||
/* ARM assembly uses '#' for constants */
|
||||
/* ARM/ARM64 assembly uses '#' for constants */
|
||||
#endif
|
||||
break;
|
||||
_default:
|
||||
@ -987,11 +987,7 @@ static inline int tok_size(const int *p)
|
||||
case TOK_CULLONG:
|
||||
return 1 + 2;
|
||||
case TOK_CLDOUBLE:
|
||||
#ifdef TCC_USING_DOUBLE_FOR_LDOUBLE
|
||||
return 1 + 8 / 4;
|
||||
#else
|
||||
return 1 + LDOUBLE_SIZE / 4;
|
||||
#endif
|
||||
return 1 + LDOUBLE_WORDS;
|
||||
default:
|
||||
return 1 + 0;
|
||||
}
|
||||
@ -1130,22 +1126,12 @@ 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;
|
||||
}
|
||||
@ -1219,15 +1205,7 @@ static inline void tok_get(int *t, const int **pp, CValue *cv)
|
||||
n = 2;
|
||||
goto copy;
|
||||
case TOK_CLDOUBLE:
|
||||
#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
|
||||
n = LDOUBLE_WORDS;
|
||||
copy:
|
||||
do
|
||||
*tab++ = *p++;
|
||||
@ -2234,13 +2212,8 @@ 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)
|
||||
@ -2272,11 +2245,7 @@ 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;
|
||||
@ -2391,16 +2360,11 @@ static void parse_number(const char *p)
|
||||
|
||||
/* 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++;
|
||||
@ -2410,11 +2374,7 @@ 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;
|
||||
@ -2464,18 +2424,14 @@ 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 = 0, n1 = 0;
|
||||
unsigned long long n, n1;
|
||||
int lcount, ucount, ov = 0;
|
||||
const char *p1;
|
||||
|
||||
@ -2486,6 +2442,7 @@ 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 */
|
||||
@ -2499,14 +2456,11 @@ static void parse_number(const char *p)
|
||||
t = t - '0';
|
||||
if (t >= b)
|
||||
tcc_error("invalid digit");
|
||||
n1 = n;
|
||||
n = n * b + t;
|
||||
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
|
||||
@ -2556,26 +2510,7 @@ static void parse_number(const char *p)
|
||||
}
|
||||
|
||||
if (ov)
|
||||
/* 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);
|
||||
tcc_warning("integer constant overflow");
|
||||
|
||||
tok = TOK_CINT;
|
||||
if (lcount) {
|
||||
@ -2699,7 +2634,7 @@ maybe_newline:
|
||||
p++;
|
||||
tok = TOK_TWOSHARPS;
|
||||
} else {
|
||||
#if !defined(TCC_TARGET_ARM)
|
||||
#if !defined(TCC_TARGET_ARM) && !defined(TCC_TARGET_ARM64)
|
||||
if (parse_flags & PARSE_FLAG_ASM_FILE) {
|
||||
p = parse_line_comment(p - 1);
|
||||
goto redo_no_start;
|
||||
|
||||
52
tccrun.c
52
tccrun.c
@ -129,9 +129,16 @@ static int rt_mem(TCCState *s1, int size)
|
||||
ptr_diff = (char*)prw - (char*)ptr; /* = 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;
|
||||
@ -187,6 +194,13 @@ ST_FUNC void tcc_run_free(TCCState *s1)
|
||||
size = s1->run_size;
|
||||
#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*/);
|
||||
@ -195,6 +209,7 @@ ST_FUNC void tcc_run_free(TCCState *s1)
|
||||
# endif
|
||||
tcc_free(ptr);
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
|
||||
#define RT_EXIT_ZERO 0xE0E00E0E /* passed from longjmp instead of '0' */
|
||||
@ -287,7 +302,7 @@ static void cleanup_sections(TCCState *s1)
|
||||
do {
|
||||
for (i = --f; i < p->nb_secs; i++) {
|
||||
Section *s = p->secs[i];
|
||||
if (s1->do_debug || s == s1->symtab || s == s1->symtab->link || s == s1->symtab->hash) {
|
||||
if (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;
|
||||
@ -299,11 +314,10 @@ 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 = .debug .debug ro (optional) */
|
||||
/* 3 = .text rx .rdata ro .data/.bss rw (memory >= 4 pages) */
|
||||
/* 2 = .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=2.
|
||||
executable code. These targets need CONFIG_RUNMEM_RO=1.
|
||||
The disadvantage of this is that it requires a little bit more memory. */
|
||||
|
||||
#ifndef CONFIG_RUNMEM_RO
|
||||
@ -344,13 +358,12 @@ redo:
|
||||
if (copy == 3)
|
||||
return 0;
|
||||
|
||||
for (k = 0; k < 4; ++k) { /* 0:rx, 1:ro, 2:ro debug , 3:rw sections */
|
||||
for (k = 0; k < 3; ++k) { /* 0:rx, 1:ro, 2:rw sections */
|
||||
n = 0; addr = 0;
|
||||
for(i = 1; i < s1->nb_sections; i++) {
|
||||
static const char shf[] = {
|
||||
SHF_ALLOC|SHF_EXECINSTR, SHF_ALLOC, 0, SHF_ALLOC|SHF_WRITE
|
||||
SHF_ALLOC|SHF_EXECINSTR, SHF_ALLOC, 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;
|
||||
@ -414,7 +427,11 @@ 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
|
||||
}
|
||||
}
|
||||
|
||||
@ -436,6 +453,8 @@ 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;
|
||||
@ -471,7 +490,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
|
||||
# if (defined TCC_TARGET_ARM && !TARGETOS_BSD) || defined TCC_TARGET_ARM64 || defined TCC_TARGET_RISCV64
|
||||
if (mode == 0 || mode == 3) {
|
||||
void __clear_cache(void *beginning, void *end);
|
||||
__clear_cache(ptr, (char *)ptr + length);
|
||||
@ -487,11 +506,14 @@ static void *win64_add_function_table(TCCState *s1)
|
||||
void *p = NULL;
|
||||
if (s1->uw_pdata) {
|
||||
p = (void*)s1->uw_pdata->sh_addr;
|
||||
RtlAddFunctionTable(
|
||||
if (!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;
|
||||
@ -1201,7 +1223,11 @@ 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
|
||||
#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
|
||||
rc->ip = uc->Rip;
|
||||
rc->fp = uc->Rbp;
|
||||
rc->sp = uc->Rsp;
|
||||
@ -1400,7 +1426,11 @@ 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
|
||||
|
||||
21
tcctok.h
21
tcctok.h
@ -39,6 +39,7 @@
|
||||
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")
|
||||
@ -306,8 +307,13 @@
|
||||
#if defined TCC_TARGET_PE
|
||||
DEF(TOK___chkstk, "__chkstk")
|
||||
#endif
|
||||
#if defined TCC_TARGET_ARM64 || defined TCC_TARGET_RISCV64
|
||||
#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___addtf3, "__addtf3")
|
||||
DEF(TOK___subtf3, "__subtf3")
|
||||
DEF(TOK___multf3, "__multf3")
|
||||
@ -402,12 +408,13 @@
|
||||
DEF_ASMDIR(endr)
|
||||
DEF_ASMDIR(org)
|
||||
DEF_ASMDIR(quad)
|
||||
#if defined(TCC_TARGET_I386)
|
||||
#if PTR_SIZE == 4
|
||||
DEF_ASMDIR(code16)
|
||||
DEF_ASMDIR(code32)
|
||||
#elif defined(TCC_TARGET_X86_64)
|
||||
#else
|
||||
DEF_ASMDIR(code64)
|
||||
#elif defined(TCC_TARGET_RISCV64)
|
||||
#endif
|
||||
#if defined(TCC_TARGET_RISCV64)
|
||||
DEF_ASMDIR(option)
|
||||
#endif
|
||||
DEF_ASMDIR(short)
|
||||
@ -421,10 +428,14 @@
|
||||
#include "i386-tok.h"
|
||||
#endif
|
||||
|
||||
#if defined TCC_TARGET_ARM || defined TCC_TARGET_ARM64
|
||||
#if defined TCC_TARGET_ARM
|
||||
#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
|
||||
|
||||
@ -13,7 +13,6 @@ TESTS = \
|
||||
hello-run \
|
||||
libtest \
|
||||
libtest_mt \
|
||||
libtest_xor_rex \
|
||||
test3 \
|
||||
abitest \
|
||||
asm-c-connect-test \
|
||||
@ -41,9 +40,6 @@ 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
|
||||
@ -76,9 +72,9 @@ endif
|
||||
RUN_TCC = -run $(TOPSRC)/tcc.c $(TCCFLAGS)
|
||||
DISAS = objdump -d
|
||||
ifdef CONFIG_OSX
|
||||
DUMPTCC = (set -x; $(TOP)/tcc -vv; otool -L $(TOP)/tcc; exit 1)
|
||||
DUMPTCC = (set -x; $(TCC_LOCAL) -vv; otool -L $(TCC_LOCAL); exit 1)
|
||||
else
|
||||
DUMPTCC = (set -x; $(TOP)/tcc -vv; ldd $(TOP)/tcc; exit 1)
|
||||
DUMPTCC = (set -x; $(TCC_LOCAL) -vv; ldd $(TCC_LOCAL); exit 1)
|
||||
endif
|
||||
|
||||
all test :
|
||||
@ -86,6 +82,7 @@ all test :
|
||||
@$(TCC_LOCAL) -v
|
||||
@$(MAKE) --no-print-directory -s clean
|
||||
@$(MAKE) --no-print-directory -s -r _all
|
||||
@echo ------- ALL TESTS PASSED --------
|
||||
|
||||
_all : $(TESTS)
|
||||
|
||||
@ -107,17 +104,14 @@ 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 $< $(CFLAGS) -w -O0 -std=gnu99 -fno-omit-frame-pointer
|
||||
./tcctest.gcc > $@
|
||||
$(CC) -o tcctest.gcc$(EXESUF) $< $(CFLAGS) -w -O0 -std=gnu99 -fno-omit-frame-pointer
|
||||
./tcctest.gcc$(EXESUF) > $@
|
||||
|
||||
# auto test
|
||||
test1 test1b: tcctest.c test.ref
|
||||
@ -316,6 +310,7 @@ CROSS-TGTS = \
|
||||
arm-NetBSD \
|
||||
arm-wince \
|
||||
arm64 \
|
||||
arm64-win32 \
|
||||
arm64-osx \
|
||||
arm64-FreeBSD \
|
||||
arm64-NetBSD \
|
||||
|
||||
@ -1,58 +0,0 @@
|
||||
#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;
|
||||
}
|
||||
@ -162,6 +162,7 @@ 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;
|
||||
@ -337,8 +338,16 @@ int main(int argc, char **argv)
|
||||
|
||||
#else
|
||||
#include <tcclib.h>
|
||||
|
||||
unsigned int sleep(unsigned int seconds);
|
||||
#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
|
||||
|
||||
int fib(n)
|
||||
{
|
||||
@ -347,7 +356,7 @@ int fib(n)
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
sleep(1);
|
||||
sleep_ms(333);
|
||||
printf(" %d", fib(atoi(argv[1])));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1,128 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
164
tests/msvcrt_start.c
Normal file
164
tests/msvcrt_start.c
Normal file
@ -0,0 +1,164 @@
|
||||
/* ------------------------------------------------------------- */
|
||||
/* 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 */
|
||||
@ -1,155 +0,0 @@
|
||||
#!/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);
|
||||
}
|
||||
@ -46,6 +46,7 @@ clean:
|
||||
rm -f *.output
|
||||
|
||||
02.test : DIFF_OPTS += -w
|
||||
16.test : DIFF_OPTS += -B
|
||||
# 15.test : DIFF_OPTS += -I"^XXX:"
|
||||
|
||||
# diff options:
|
||||
|
||||
@ -32,8 +32,9 @@
|
||||
#define XLONG_LONG_FORMAT "%Lx"
|
||||
#endif
|
||||
|
||||
// MinGW has 80-bit rather than 64-bit long double which isn't compatible with TCC or MSVC
|
||||
#if defined(_WIN32) && defined(__GNUC__)
|
||||
/* MinGW has 80-bit rather than 64-bit long double which isn't
|
||||
compatible with printf in msvcrt */
|
||||
#if defined(_WIN32)
|
||||
#define LONG_DOUBLE double
|
||||
#define LONG_DOUBLE_LITERAL(x) x
|
||||
#else
|
||||
@ -81,9 +82,6 @@ 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);
|
||||
@ -287,6 +285,7 @@ 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. */
|
||||
@ -295,6 +294,8 @@ comment
|
||||
fn += 2;
|
||||
printf("filefromheader %s\n", fn);
|
||||
}
|
||||
#endif
|
||||
|
||||
printf("file %s\n", __FILE__);
|
||||
|
||||
/* Check that funnily named include was in fact included */
|
||||
@ -1095,8 +1096,10 @@ 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",
|
||||
@ -1105,8 +1108,10 @@ 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",
|
||||
@ -1117,7 +1122,9 @@ 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));
|
||||
@ -1168,7 +1175,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__)
|
||||
#if !defined __arm__ && !defined __riscv
|
||||
/* 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);
|
||||
@ -1459,17 +1466,37 @@ 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;
|
||||
int cinit1; /* a global variable can be defined several times without error ! */
|
||||
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]);
|
||||
@ -2176,15 +2203,6 @@ 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)\
|
||||
{\
|
||||
@ -2240,7 +2258,7 @@ void prefix ## fcast(type a)\
|
||||
b = llia;\
|
||||
printf("lltof: " fmt "\n", b);\
|
||||
b = llua;\
|
||||
printf("ulltof: " fmt "\n", b);\
|
||||
if (CC_NAME != CC_clang) printf("ulltof: " fmt "\n", b);\
|
||||
}\
|
||||
\
|
||||
float prefix ## retf(type a) { return a; }\
|
||||
@ -2300,7 +2318,7 @@ void prefix ## test(void)\
|
||||
prefix ## fcast(-2334.6);\
|
||||
prefix ## call();\
|
||||
prefix ## signed_zeros();\
|
||||
if (enable_nan_test) prefix ## nan();\
|
||||
if (CC_NAME != CC_clang) prefix ## nan();\
|
||||
}
|
||||
|
||||
FTEST(f, float, float, "%f")
|
||||
@ -2556,7 +2574,7 @@ 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 " %Lx\n",
|
||||
printf(LONG_LONG_FORMAT " " LONG_LONG_FORMAT " " LONG_LONG_FORMAT " "XLONG_LONG_FORMAT"\n",
|
||||
(long long)1,
|
||||
(long long)-2,
|
||||
1LL,
|
||||
@ -2867,12 +2885,14 @@ 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 };
|
||||
@ -3289,7 +3309,7 @@ void local_label_test(void)
|
||||
}
|
||||
|
||||
/* inline assembler test */
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
#if (defined(__i386__) || defined(__x86_64__)) && !(defined _WIN32 && CC_NAME == CC_clang)
|
||||
|
||||
typedef __SIZE_TYPE__ word;
|
||||
|
||||
@ -3551,8 +3571,8 @@ void asm_local_label_diff (void)
|
||||
{
|
||||
printf ("asm_local_label_diff: %d %d\n", alld_stuff[0], alld_stuff[1]);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#endif //!__APPLE__
|
||||
#endif //!_WIN32
|
||||
|
||||
/* This checks that static local variables are available from assembler. */
|
||||
void asm_local_statics (void)
|
||||
|
||||
74
tests/test-win32.bat
Normal file
74
tests/test-win32.bat
Normal file
@ -0,0 +1,74 @@
|
||||
@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%
|
||||
280
tests/tests2/138_arm64_encoding.c
Normal file
280
tests/tests2/138_arm64_encoding.c
Normal file
@ -0,0 +1,280 @@
|
||||
/* 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;
|
||||
}
|
||||
50
tests/tests2/138_arm64_encoding.expect
Normal file
50
tests/tests2/138_arm64_encoding.expect
Normal file
@ -0,0 +1,50 @@
|
||||
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
|
||||
91
tests/tests2/139_arm64_errors.c
Normal file
91
tests/tests2/139_arm64_errors.c
Normal file
@ -0,0 +1,91 @@
|
||||
/* 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
|
||||
32
tests/tests2/139_arm64_errors.expect
Normal file
32
tests/tests2/139_arm64_errors.expect
Normal file
@ -0,0 +1,32 @@
|
||||
[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'
|
||||
451
tests/tests2/140_arm64_extasm.c
Normal file
451
tests/tests2/140_arm64_extasm.c
Normal file
@ -0,0 +1,451 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
36
tests/tests2/140_arm64_extasm.expect
Normal file
36
tests/tests2/140_arm64_extasm.expect
Normal file
@ -0,0 +1,36 @@
|
||||
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!
|
||||
356
tests/tests2/141_riscv_asm.c
Normal file
356
tests/tests2/141_riscv_asm.c
Normal file
@ -0,0 +1,356 @@
|
||||
#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
|
||||
6
tests/tests2/141_riscv_asm.expect
Normal file
6
tests/tests2/141_riscv_asm.expect
Normal file
@ -0,0 +1,6 @@
|
||||
csrr fcsr=1
|
||||
csrw: wrote e0 got e0
|
||||
csrwi: wrote 0x10 got 10
|
||||
csrsi: old|3=3
|
||||
csrci: old&~3=0
|
||||
PASS
|
||||
143
tests/tests2/142_int_conversion.c
Normal file
143
tests/tests2/142_int_conversion.c
Normal file
@ -0,0 +1,143 @@
|
||||
#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();
|
||||
}
|
||||
8
tests/tests2/142_int_conversion.expect
Normal file
8
tests/tests2/142_int_conversion.expect
Normal file
@ -0,0 +1,8 @@
|
||||
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
|
||||
17
tests/tests2/143_void_expr.c
Normal file
17
tests/tests2/143_void_expr.c
Normal file
@ -0,0 +1,17 @@
|
||||
#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;
|
||||
}
|
||||
5
tests/tests2/143_void_expr.expect
Normal file
5
tests/tests2/143_void_expr.expect
Normal file
@ -0,0 +1,5 @@
|
||||
0
|
||||
f(0)
|
||||
1
|
||||
2
|
||||
count 1
|
||||
50
tests/tests2/144_tls.c
Normal file
50
tests/tests2/144_tls.c
Normal file
@ -0,0 +1,50 @@
|
||||
#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;
|
||||
}
|
||||
8
tests/tests2/144_tls.expect
Normal file
8
tests/tests2/144_tls.expect
Normal file
@ -0,0 +1,8 @@
|
||||
42
|
||||
0
|
||||
42
|
||||
0
|
||||
100
|
||||
200
|
||||
42
|
||||
0
|
||||
35
tests/tests2/145_winarm64_interlocked.c
Normal file
35
tests/tests2/145_winarm64_interlocked.c
Normal file
@ -0,0 +1,35 @@
|
||||
#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;
|
||||
}
|
||||
8
tests/tests2/145_winarm64_interlocked.expect
Normal file
8
tests/tests2/145_winarm64_interlocked.expect
Normal file
@ -0,0 +1,8 @@
|
||||
exchange old: yes
|
||||
exchange stored: yes
|
||||
compare old: yes
|
||||
compare stored: yes
|
||||
acquire old: yes
|
||||
acquire stored: yes
|
||||
release old: yes
|
||||
release stored: yes
|
||||
@ -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 func(void)
|
||||
{
|
||||
char *ccp = "123";
|
||||
fink();
|
||||
@ -551,4 +551,114 @@ 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
|
||||
|
||||
@ -262,3 +262,31 @@ 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]
|
||||
|
||||
@ -38,6 +38,11 @@ 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); }
|
||||
@ -82,6 +87,10 @@ 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)
|
||||
@ -140,6 +149,8 @@ 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);
|
||||
@ -178,6 +189,8 @@ 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)
|
||||
{
|
||||
@ -228,6 +241,8 @@ 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*
|
||||
|
||||
@ -28,6 +28,8 @@ 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
|
||||
@ -62,6 +64,8 @@ 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
|
||||
|
||||
@ -19,6 +19,9 @@ 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
|
||||
@ -47,12 +50,29 @@ 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 =
|
||||
@ -62,6 +82,7 @@ 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 =
|
||||
@ -74,8 +95,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
|
||||
|
||||
@ -98,6 +119,10 @@ 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' \
|
||||
@ -125,6 +150,8 @@ 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'
|
||||
|
||||
@ -5,13 +5,15 @@
|
||||
@echo off
|
||||
setlocal
|
||||
if (%1)==(-clean) goto :cleanup
|
||||
set CC=gcc
|
||||
set CC=gcc -O2 -Wall
|
||||
set /p VERSION= < ..\VERSION
|
||||
set TCCDIR=
|
||||
set BINDIR=
|
||||
set DOC=no
|
||||
set XCC=no
|
||||
set TX=
|
||||
set SELF=%~nx0
|
||||
goto :a0
|
||||
|
||||
:a2
|
||||
shift
|
||||
:a3
|
||||
@ -27,20 +29,22 @@ 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 XCC=yes&& goto :a3
|
||||
if (%1)==(-x) set TX=%2&& goto :a2
|
||||
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 32/64 force 32/64 bit default target
|
||||
echo -t target set target
|
||||
echo -x target build tcc cross-compiler for 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 ------------------------------------------------------
|
||||
@ -65,6 +69,7 @@ exit /B 0
|
||||
if exist %1 rmdir /Q/S %1 && %LOG% %1
|
||||
exit /B 0
|
||||
|
||||
@rem ------------------------------------------------------
|
||||
:cl
|
||||
@echo off
|
||||
set CMD=cl
|
||||
@ -84,36 +89,19 @@ echo on
|
||||
@rem main program
|
||||
|
||||
:p1
|
||||
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 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
|
||||
|
||||
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
|
||||
@if (%CC:~0,3%)==(gcc) set CC=%CC% -s -static
|
||||
@if (%BINDIR%)==() set BINDIR=%TCCDIR%
|
||||
|
||||
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_hash
|
||||
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
|
||||
@ -125,34 +113,37 @@ 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 %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
|
||||
@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%"
|
||||
|
||||
@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
|
||||
|
||||
for %%f in (*tcc.exe *tcc.dll) do @del %%f
|
||||
@if not _%TX%_==__ goto :tcc_cross
|
||||
@if not _%TCC_C%_==__ goto :tcc_only
|
||||
|
||||
@if _%TCC_C%_==__ goto compiler_2parts
|
||||
@rem if TCC_C was defined then build only tcc.exe
|
||||
@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
|
||||
%CC% -o tcc.exe %TCC_C% %D%
|
||||
@if errorlevel 1 goto :the_end
|
||||
@goto :compiler_done
|
||||
|
||||
: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%
|
||||
:tcc_cross
|
||||
%CC% -o %TX%tcc.exe ..\tcc.c %D%
|
||||
@if errorlevel 1 goto :the_end
|
||||
@goto :compiler_done
|
||||
|
||||
:compiler_done
|
||||
@if (%EXES_ONLY%)==(yes) goto :files_done
|
||||
|
||||
@ -168,8 +159,7 @@ if exist libtcc.dll .\tcc -impdef libtcc.dll -o libtcc\libtcc.def
|
||||
@if errorlevel 1 goto :the_end
|
||||
|
||||
:lib
|
||||
call :make_lib %T% || goto :the_end
|
||||
@if exist %PX%-tcc.exe call :make_lib %TX% %PX%- || goto :the_end
|
||||
@call :make_lib %TX% || goto :the_end
|
||||
|
||||
:tcc-doc.html
|
||||
@if not (%DOC%)==(yes) goto :doc-done
|
||||
@ -193,23 +183,26 @@ for %%f in (include examples libtcc doc) do @xcopy>nul /s/i/q/y %%f %TCCDIR%\%%f
|
||||
exit /B %ERRORLEVEL%
|
||||
|
||||
:make_lib
|
||||
.\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
|
||||
@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
|
||||
exit /B %ERRORLEVEL%
|
||||
|
||||
@ -70,12 +70,15 @@
|
||||
|
||||
#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 */
|
||||
#define USE_MINGW_SETJMP_TWO_ARGS
|
||||
#define mingw_getsp tinyc_getbp
|
||||
#endif
|
||||
#else
|
||||
#define __stdcall __attribute__((__stdcall__))
|
||||
#define _X86_ 1
|
||||
|
||||
@ -124,37 +124,76 @@ 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
|
||||
|
||||
void * __cdecl __attribute__ ((__nothrow__)) mingw_getsp(void);
|
||||
#pragma pack(pop)
|
||||
|
||||
#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
|
||||
#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
|
||||
#endif
|
||||
int __cdecl __attribute__ ((__nothrow__)) setjmp(jmp_buf _Buf);
|
||||
#endif
|
||||
|
||||
__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);
|
||||
__declspec(noreturn) void longjmp(jmp_buf _Buf,int _Value);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
|
||||
@ -207,6 +207,21 @@ 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;
|
||||
|
||||
@ -972,7 +972,9 @@ 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);
|
||||
@ -1035,6 +1037,7 @@ 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));
|
||||
@ -1043,6 +1046,7 @@ 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
|
||||
@ -1054,9 +1058,13 @@ 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);
|
||||
|
||||
@ -21,7 +21,7 @@ extern "C" {
|
||||
#define __CRT_UNALIGNED
|
||||
#endif
|
||||
|
||||
#if defined(__ia64__) || defined(__x86_64)
|
||||
#if defined(__ia64__) || defined(__x86_64) || defined(__aarch64__)
|
||||
#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_)
|
||||
#elif defined(_IA64_) || defined(_ARM64_)
|
||||
#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)
|
||||
#if defined(_X86_) || defined(__ia64__) || defined(__x86_64) || defined(__aarch64__)
|
||||
#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)
|
||||
#elif defined(__ia64__) || defined(__x86_64) || defined(__aarch64__)
|
||||
#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,8 +829,6 @@ typedef DWORD LCID;
|
||||
typedef ULONG_PTR KSPIN_LOCK;
|
||||
typedef KSPIN_LOCK *PKSPIN_LOCK;
|
||||
|
||||
#ifdef _AMD64_
|
||||
|
||||
#if defined(__x86_64) && !defined(RC_INVOKED)
|
||||
|
||||
#ifdef __cplusplus
|
||||
@ -1282,7 +1280,6 @@ typedef DWORD LCID;
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define EXCEPTION_READ_FAULT 0
|
||||
#define EXCEPTION_WRITE_FAULT 1
|
||||
@ -1420,7 +1417,160 @@ 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);
|
||||
@ -3701,6 +3851,7 @@ 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
|
||||
|
||||
@ -3857,10 +4008,16 @@ 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
|
||||
|
||||
@ -8,8 +8,32 @@
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------- */
|
||||
#ifndef __x86_64__
|
||||
#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
|
||||
|
||||
/* ---------------------------------------------- */
|
||||
#elif defined(__i386__)
|
||||
|
||||
.globl _(__chkstk)
|
||||
_(__chkstk):
|
||||
@ -33,8 +57,7 @@ P0:
|
||||
jmp *4(%eax)
|
||||
|
||||
/* ---------------------------------------------- */
|
||||
#else
|
||||
/* ---------------------------------------------- */
|
||||
#else /* __x86_64__ */
|
||||
|
||||
.globl _(__chkstk)
|
||||
_(__chkstk):
|
||||
@ -58,16 +81,6 @@ P0:
|
||||
mov (%rax),%rcx /* restore ecx */
|
||||
jmp *8(%rax)
|
||||
|
||||
/* ---------------------------------------------- */
|
||||
/* setjmp/longjmp support */
|
||||
|
||||
.globl _(tinyc_getbp)
|
||||
_(tinyc_getbp):
|
||||
mov %rbp,%rax
|
||||
ret
|
||||
|
||||
/* ---------------------------------------------- */
|
||||
#endif
|
||||
/* ---------------------------------------------- */
|
||||
|
||||
|
||||
|
||||
@ -75,10 +75,11 @@ __attribute__((weak)) extern int __run_on_exit();
|
||||
int _runtmain(int argc, /* as tcc passed in */ char **argv)
|
||||
{
|
||||
int ret;
|
||||
#ifdef UNICODE
|
||||
#if defined UNICODE || defined __aarch64__
|
||||
_startupinfo start_info = {0};
|
||||
|
||||
__tgetmainargs(&__argc, &__targv, &_tenviron, _dowildcard, &start_info);
|
||||
__tgetmainargs(&__argc, &__targv, &_tenviron, 0, &start_info);
|
||||
#endif
|
||||
#ifdef UNICODE
|
||||
/* may be wrong when tcc has received wildcards (*.c) */
|
||||
if (argc < __argc) {
|
||||
__targv += __argc - argc;
|
||||
@ -93,6 +94,8 @@ 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;
|
||||
|
||||
@ -9,6 +9,7 @@ AllocConsole
|
||||
AllocLSCallback
|
||||
AllocSLCallback
|
||||
AreFileApisANSI
|
||||
AttachConsole
|
||||
BackupRead
|
||||
BackupSeek
|
||||
BackupWrite
|
||||
|
||||
27
win32/lib/winex.c
Normal file
27
win32/lib/winex.c
Normal file
@ -0,0 +1,27 @@
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* 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
|
||||
54
x86_64-gen.c
54
x86_64-gen.c
@ -266,14 +266,6 @@ 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)
|
||||
{
|
||||
@ -322,7 +314,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 == (char)c) {
|
||||
if (c == (signed char)c) {
|
||||
/* short reference */
|
||||
o(0x45 | op_reg);
|
||||
g(c);
|
||||
@ -376,7 +368,8 @@ 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)) {
|
||||
(fr & VT_LVAL) && !(sv->sym->type.t & VT_STATIC)
|
||||
&& !(sv->sym->type.t & VT_TLS)) {
|
||||
/* use the result register as a temporal register */
|
||||
int tr = r | TREG_MEM;
|
||||
if (is_float(ft)) {
|
||||
@ -393,6 +386,19 @@ 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;
|
||||
@ -444,8 +450,7 @@ 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) ||
|
||||
(ft & VT_TYPE) == (VT_BOOL | VT_UNSIGNED)) {
|
||||
} else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED)) {
|
||||
b = 0xb60f; /* movzbl */
|
||||
} else if ((ft & VT_TYPE) == VT_SHORT) {
|
||||
b = 0xbf0f; /* movswl */
|
||||
@ -540,7 +545,6 @@ void load(int r, SValue *sv)
|
||||
o(0x44 + REG_VALUE(r)*8); /* %xmmN */
|
||||
o(0xf024);
|
||||
} else {
|
||||
if (!nocode_wanted)
|
||||
assert((v >= TREG_XMM0) && (v <= TREG_XMM7));
|
||||
if ((ft & VT_BTYPE) == VT_FLOAT) {
|
||||
o(0x100ff3);
|
||||
@ -551,7 +555,6 @@ void load(int r, SValue *sv)
|
||||
o(0xc0 + REG_VALUE(v) + REG_VALUE(r)*8);
|
||||
}
|
||||
} else if (r == TREG_ST0) {
|
||||
if (!nocode_wanted)
|
||||
assert((v >= TREG_XMM0) && (v <= TREG_XMM7));
|
||||
/* gen_cvt_ftof(VT_LDOUBLE); */
|
||||
/* movsd %xmmN,-0x10(%rsp) */
|
||||
@ -583,6 +586,20 @@ 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
|
||||
@ -757,7 +774,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 == (char)d) {
|
||||
if (d == (signed char)d) {
|
||||
o(0x2444 | (REG_VALUE(r) << 3));
|
||||
g(d);
|
||||
} else {
|
||||
@ -1060,7 +1077,7 @@ void gfunc_epilog(void)
|
||||
|
||||
static void gadd_sp(int val)
|
||||
{
|
||||
if (val == (char)val) {
|
||||
if (val == (signed char)val) {
|
||||
o(0xc48348);
|
||||
g(val);
|
||||
} else {
|
||||
@ -1643,7 +1660,7 @@ void gjmp_addr(int a)
|
||||
{
|
||||
int r;
|
||||
r = a - ind - 2;
|
||||
if (r == (char)r) {
|
||||
if (r == (signed char)r) {
|
||||
g(0xeb);
|
||||
g(r);
|
||||
} else {
|
||||
@ -1712,7 +1729,7 @@ void gen_opi(int op)
|
||||
r = gv(RC_INT);
|
||||
vswap();
|
||||
c = vtop->c.i;
|
||||
if (c == (char)c) {
|
||||
if (c == (signed char)c) {
|
||||
/* XXX: generate inc and dec for smaller code ? */
|
||||
orex(ll, r, 0, 0x83);
|
||||
o(0xc0 | (opc << 3) | REG_VALUE(r));
|
||||
@ -1840,6 +1857,7 @@ 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;
|
||||
}
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
#define R_NUM R_X86_64_NUM
|
||||
|
||||
#define ELF_START_ADDR 0x400000
|
||||
#define ELF_PAGE_SIZE 0x200000
|
||||
#define ELF_PAGE_SIZE 0x1000
|
||||
|
||||
#define PCRELATIVE_DLLPLT 1
|
||||
#define RELOCATE_DLLPLT 1
|
||||
@ -96,13 +96,15 @@ 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;
|
||||
@ -372,10 +374,30 @@ 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;
|
||||
}
|
||||
add32le(ptr, x);
|
||||
}
|
||||
break;
|
||||
@ -385,10 +407,30 @@ 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;
|
||||
}
|
||||
add64le(ptr, x);
|
||||
}
|
||||
break;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user