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
|
timeout-minutes: 6
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: make & test tcc (x86_64-win32)
|
- name: build tcc (x86_64-win32)
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: |
|
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
|
cd win32
|
||||||
call build-tcc.bat -t 64 -c cl
|
for /f "delims=" %%i in ('vswhere.exe -latest -property installationPath') do call "%%i\VC\Auxiliary\Build\vcvarsall.bat" amd64
|
||||||
echo ::endgroup::
|
call build-tcc.bat -c cl -t x86_64
|
||||||
.\tcc -I.. libtcc.dll -v ../tests/libtcc_test.c -o libtest.exe && .\libtest.exe
|
- name: test (x86_64-win32)
|
||||||
.\tcc -I.. libtcc.dll -run ../tests/libtcc_test.c
|
shell: cmd
|
||||||
|
run: |
|
||||||
|
cd tests
|
||||||
|
call test-win32.bat all -k
|
||||||
|
|
||||||
test-i386-win32:
|
test-i386-win32:
|
||||||
runs-on: windows-2025
|
runs-on: windows-2025
|
||||||
timeout-minutes: 6
|
timeout-minutes: 6
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: make & test tcc (i386-win32)
|
- name: build tcc (i386-win32)
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: |
|
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
|
cd win32
|
||||||
call build-tcc.bat -t 32 -c cl
|
for /f "delims=" %%i in ('vswhere.exe -latest -property installationPath') do call "%%i\VC\Auxiliary\Build\vcvarsall.bat" x86
|
||||||
echo ::endgroup::
|
call build-tcc.bat -c cl -t i386
|
||||||
.\tcc -I.. libtcc.dll -v ../tests/libtcc_test.c -o libtest.exe && .\libtest.exe
|
- name: test (i386-win32)
|
||||||
.\tcc -I.. libtcc.dll -run ../tests/libtcc_test.c
|
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:
|
test-armv7-linux:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
@ -138,3 +131,13 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
echo "::endgroup::" # flatten 'run container'
|
echo "::endgroup::" # flatten 'run container'
|
||||||
./configure && make && make test -k
|
./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/*-tcc*
|
||||||
tests/libtcc_test
|
tests/libtcc_test
|
||||||
tests/libtcc_test_mt
|
tests/libtcc_test_mt
|
||||||
tests/libtcc_test_xor_rex
|
|
||||||
tests/asm-c-connect
|
tests/asm-c-connect
|
||||||
tests/asm-c-connect-sep
|
tests/asm-c-connect-sep
|
||||||
tests/vla_test
|
tests/vla_test
|
||||||
|
|||||||
72
Makefile
72
Makefile
@ -31,9 +31,11 @@ ifdef CONFIG_WIN32
|
|||||||
LIBTCCDEF = libtcc.def
|
LIBTCCDEF = libtcc.def
|
||||||
endif
|
endif
|
||||||
ifneq ($(CONFIG_debug),yes)
|
ifneq ($(CONFIG_debug),yes)
|
||||||
LDFLAGS += -s
|
ifneq ($(CC_NAME),clang)
|
||||||
|
LDFLAGS += -s
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
NATIVE_TARGET = $(ARCH)-win$(if $(findstring arm,$(ARCH)),ce,32)
|
NATIVE_TARGET = $(if $(findstring arm64,$(ARCH)),arm64-win32,$(ARCH)-win$(if $(findstring arm,$(ARCH)),ce,32))
|
||||||
else
|
else
|
||||||
CFG = -unx
|
CFG = -unx
|
||||||
LIBS+=-lm
|
LIBS+=-lm
|
||||||
@ -113,6 +115,7 @@ DEF-arm64-osx = $(DEF-arm64) -DTCC_TARGET_MACHO
|
|||||||
DEF-arm64-FreeBSD = $(DEF-arm64) -DTARGETOS_FreeBSD
|
DEF-arm64-FreeBSD = $(DEF-arm64) -DTARGETOS_FreeBSD
|
||||||
DEF-arm64-NetBSD = $(DEF-arm64) -DTARGETOS_NetBSD
|
DEF-arm64-NetBSD = $(DEF-arm64) -DTARGETOS_NetBSD
|
||||||
DEF-arm64-OpenBSD = $(DEF-arm64) -DTARGETOS_OpenBSD
|
DEF-arm64-OpenBSD = $(DEF-arm64) -DTARGETOS_OpenBSD
|
||||||
|
DEF-arm64-win32 = $(DEF-arm64) -DTCC_TARGET_PE
|
||||||
DEF-riscv64 = -DTCC_TARGET_RISCV64
|
DEF-riscv64 = -DTCC_TARGET_RISCV64
|
||||||
DEF-c67 = -DTCC_TARGET_C67 -w # disable warnigs
|
DEF-c67 = -DTCC_TARGET_C67 -w # disable warnigs
|
||||||
DEF-x86_64-FreeBSD = $(DEF-x86_64) -DTARGETOS_FreeBSD
|
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)
|
all: $(PROGS) $(TCCLIBS) $(TCCDOCS)
|
||||||
|
|
||||||
# cross compiler targets to build
|
# 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 += riscv64 arm64-osx
|
||||||
# TCC_X += arm-fpa arm-fpa-ld arm-vfp arm-eabi
|
# TCC_X += arm-fpa arm-fpa-ld arm-vfp arm-eabi
|
||||||
|
|
||||||
@ -155,10 +158,27 @@ all : cross
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
# --------------------------------------------
|
# --------------------------------------------
|
||||||
|
T = $(or $(CROSS_TARGET),$(NATIVE_TARGET))
|
||||||
T = $(or $(CROSS_TARGET),$(NATIVE_TARGET),unknown)
|
|
||||||
X = $(if $(CROSS_TARGET),$(CROSS_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 += $(DEF-$T)
|
||||||
DEFINES += $(if $(ROOT-$T),-DCONFIG_SYSROOT="\"$(ROOT-$T)\"")
|
DEFINES += $(if $(ROOT-$T),-DCONFIG_SYSROOT="\"$(ROOT-$T)\"")
|
||||||
DEFINES += $(if $(CRT-$T),-DCONFIG_TCC_CRTPREFIX="\"$(CRT-$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 $(INC-$T),-DCONFIG_TCC_SYSINCLUDEPATHS="\"$(INC-$T)\"")
|
||||||
DEFINES += $(if $(ELF-$T),-DCONFIG_TCC_ELFINTERP="\"$(ELF-$T)\"")
|
DEFINES += $(if $(ELF-$T),-DCONFIG_TCC_ELFINTERP="\"$(ELF-$T)\"")
|
||||||
DEFINES += $(DEF-$(or $(findstring win,$T),unx))
|
DEFINES += $(DEF-$(or $(findstring win,$T),unx))
|
||||||
|
DEFINES += -DCONFIG_TCC_CROSSPREFIX="\"$X\""
|
||||||
ifneq ($(X),)
|
|
||||||
$(if $(DEF-$T),,$(error error: unknown target: '$T'))
|
|
||||||
DEF-$(NATIVE_TARGET) =
|
|
||||||
DEF-$T += -DCONFIG_TCC_CROSSPREFIX="\"$X\""
|
|
||||||
ifneq ($(CONFIG_WIN32),yes)
|
|
||||||
DEF-win += -DCONFIG_TCCDIR="\"$(tccdir)/win32\""
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
# using values from config.h
|
|
||||||
DEF-$(NATIVE_TARGET) =
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# include custom configuration (see make help)
|
# include custom configuration (see make help)
|
||||||
-include config-extra.mak
|
-include config-extra.mak
|
||||||
|
|
||||||
ifneq ($(T),$(NATIVE_TARGET))
|
# so one can use: make EXTRA-DEFS=...
|
||||||
# assume support files for cross-targets in "/usr/<triplet>" by default
|
DEFINES += $(EXTRA-DEFS)
|
||||||
TRIPLET-i386 ?= i686-linux-gnu
|
|
||||||
TRIPLET-x86_64 ?= x86_64-linux-gnu
|
# find config.h with 'out of tree' builds
|
||||||
TRIPLET-arm ?= arm-linux-gnueabi
|
DEFINES += -I$(TOP)
|
||||||
TRIPLET-arm64 ?= aarch64-linux-gnu
|
|
||||||
TRIPLET-riscv64 ?= riscv64-linux-gnu
|
|
||||||
MARCH-i386 ?= i386-linux-gnu
|
|
||||||
MARCH-$T ?= $(TRIPLET-$T)
|
|
||||||
TR = $(if $(TRIPLET-$T),$T,ignored)
|
|
||||||
CRT-$(TR) ?= /usr/$(TRIPLET-$T)/lib
|
|
||||||
LIB-$(TR) ?= {B}:/usr/$(TRIPLET-$T)/lib:/usr/lib/$(MARCH-$T)
|
|
||||||
INC-$(TR) ?= {B}/include:/usr/$(TRIPLET-$T)/include:/usr/include
|
|
||||||
endif
|
|
||||||
|
|
||||||
CORE_FILES = tcc.c tcctools.c libtcc.c tccpp.c tccgen.c tccdbg.c tccelf.c tccasm.c tccrun.c
|
CORE_FILES = tcc.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
|
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
|
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_FILES = $(CORE_FILES) arm-gen.c arm-link.c arm-asm.c arm-tok.h
|
||||||
arm-wince_FILES = $(arm_FILES) tccpe.c
|
arm-wince_FILES = $(arm_FILES) tccpe.c
|
||||||
arm-eabihf_FILES = $(arm_FILES)
|
|
||||||
arm-fpa_FILES = $(arm_FILES)
|
arm-fpa_FILES = $(arm_FILES)
|
||||||
arm-fpa-ld_FILES = $(arm_FILES)
|
arm-fpa-ld_FILES = $(arm_FILES)
|
||||||
arm-vfp_FILES = $(arm_FILES)
|
arm-vfp_FILES = $(arm_FILES)
|
||||||
arm-eabi_FILES = $(arm_FILES)
|
arm-eabi_FILES = $(arm_FILES)
|
||||||
arm-eabihf_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-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
|
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
|
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
|
endif
|
||||||
# native tcc always made from tcc.o and libtcc.[so|a]
|
# native tcc always made from tcc.o and libtcc.[so|a]
|
||||||
tcc.o : DEFINES += -DONE_SOURCE=0
|
tcc.o : DEFINES += -DONE_SOURCE=0
|
||||||
DEFINES += -I$(TOP)
|
|
||||||
|
|
||||||
GITHASH:=$(shell git rev-parse --abbrev-ref HEAD 2>/dev/null || echo no)
|
GITHASH:=$(shell git rev-parse --abbrev-ref HEAD 2>/dev/null || echo no)
|
||||||
ifneq ($(GITHASH),no)
|
ifneq ($(GITHASH),no)
|
||||||
@ -336,7 +336,7 @@ FORCE:
|
|||||||
# some versions of gnu-make do not recognize 'command' as a shell builtin
|
# some versions of gnu-make do not recognize 'command' as a shell builtin
|
||||||
WHICH = sh -c 'command -v $1'
|
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 * $@))
|
S = $(if $(findstring yes,$(SILENT)),@$(info * $@))
|
||||||
|
|
||||||
# --------------------------------------------------------------------------
|
# --------------------------------------------------------------------------
|
||||||
@ -497,14 +497,14 @@ distclean: clean
|
|||||||
help:
|
help:
|
||||||
@echo "make"
|
@echo "make"
|
||||||
@echo " build native compiler (from separate objects)"
|
@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 "make ONE_SOURCE=no/yes SILENT=no/yes"
|
||||||
@echo " force building from separate/one object(s), less/more silently"
|
@echo " force building from separate/one object(s), less/more silently"
|
||||||
@echo "make cross-TARGET"
|
@echo "make cross-TARGET"
|
||||||
@echo " build one specific cross compiler for 'TARGET'. Currently supported:"
|
@echo " build one specific cross compiler for 'TARGET'. Currently supported:"
|
||||||
@echo " $(wordlist 1,8,$(TCC_X))"
|
@echo " $(wordlist 1,8,$(TCC_X))"
|
||||||
@echo " $(wordlist 9,99,$(TCC_X))"
|
@echo " $(wordlist 9,99,$(TCC_X))"
|
||||||
|
@echo "make cross"
|
||||||
|
@echo " build all cross compilers"
|
||||||
@echo "make test"
|
@echo "make test"
|
||||||
@echo " run all tests"
|
@echo " run all tests"
|
||||||
@echo "make tests2.all / make tests2.37 / make tests2.37+"
|
@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
|
#define LDOUBLE_ALIGN 4
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if LDOUBLE_SIZE == 8
|
||||||
|
# define TCC_USING_DOUBLE_FOR_LDOUBLE 1
|
||||||
|
#endif
|
||||||
|
|
||||||
/* maximum alignment (for aligned attribute support) */
|
/* maximum alignment (for aligned attribute support) */
|
||||||
#define MAX_ALIGN 8
|
#define MAX_ALIGN 8
|
||||||
|
|
||||||
#define CHAR_IS_UNSIGNED
|
#define CHAR_IS_UNSIGNED
|
||||||
|
|
||||||
#ifdef TCC_ARM_HARDFLOAT
|
#define ARM_SOFTFP_FLOAT 0
|
||||||
# define ARM_FLOAT_ABI ARM_HARD_FLOAT
|
#define ARM_HARD_FLOAT 1
|
||||||
#else
|
|
||||||
# define ARM_FLOAT_ABI ARM_SOFTFP_FLOAT
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/******************************************************/
|
/******************************************************/
|
||||||
#else /* ! TARGET_DEFS_ONLY */
|
#else /* ! TARGET_DEFS_ONLY */
|
||||||
@ -156,8 +157,6 @@ ST_DATA const char * const target_machine_defs =
|
|||||||
#endif
|
#endif
|
||||||
;
|
;
|
||||||
|
|
||||||
enum float_abi float_abi;
|
|
||||||
|
|
||||||
ST_DATA const int reg_classes[NB_REGS] = {
|
ST_DATA const int reg_classes[NB_REGS] = {
|
||||||
/* r0 */ RC_INT | RC_R0,
|
/* r0 */ RC_INT | RC_R0,
|
||||||
/* r1 */ RC_INT | RC_R1,
|
/* r1 */ RC_INT | RC_R1,
|
||||||
@ -176,6 +175,7 @@ ST_DATA const int reg_classes[NB_REGS] = {
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int float_abi;
|
||||||
static int func_sub_sp_offset, last_itod_magic;
|
static int func_sub_sp_offset, last_itod_magic;
|
||||||
static int leaffunc;
|
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)
|
void o(uint32_t i)
|
||||||
{
|
{
|
||||||
/* this is a good place to start adding big-endian support*/
|
/* 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)
|
void load(int r, SValue *sv)
|
||||||
{
|
{
|
||||||
int v, ft, fc, fr, sign;
|
int v, ft, fc, fr, sign;
|
||||||
uint32_t op;
|
uint32_t op, base;
|
||||||
SValue v1;
|
SValue v1;
|
||||||
|
|
||||||
fr = sv->r;
|
fr = sv->r;
|
||||||
@ -598,7 +588,15 @@ void load(int r, SValue *sv)
|
|||||||
|
|
||||||
v = fr & VT_VALMASK;
|
v = fr & VT_VALMASK;
|
||||||
if (fr & VT_LVAL) {
|
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) {
|
if(v == VT_LLOCAL) {
|
||||||
v1.type.t = VT_PTR;
|
v1.type.t = VT_PTR;
|
||||||
v1.r = VT_LOCAL | VT_LVAL;
|
v1.r = VT_LOCAL | VT_LVAL;
|
||||||
@ -635,12 +633,9 @@ void load(int r, SValue *sv)
|
|||||||
op=0xED100100;
|
op=0xED100100;
|
||||||
if(!sign)
|
if(!sign)
|
||||||
op|=0x800000;
|
op|=0x800000;
|
||||||
#if LDOUBLE_SIZE == 8
|
|
||||||
if ((ft & VT_BTYPE) != VT_FLOAT)
|
|
||||||
op|=0x8000;
|
|
||||||
#else
|
|
||||||
if ((ft & VT_BTYPE) == VT_DOUBLE)
|
if ((ft & VT_BTYPE) == VT_DOUBLE)
|
||||||
op|=0x8000;
|
op|=0x8000;
|
||||||
|
#if LDOUBLE_SIZE != 8
|
||||||
else if ((ft & VT_BTYPE) == VT_LDOUBLE)
|
else if ((ft & VT_BTYPE) == VT_LDOUBLE)
|
||||||
op|=0x400000;
|
op|=0x400000;
|
||||||
#endif
|
#endif
|
||||||
@ -716,7 +711,7 @@ void store(int r, SValue *sv)
|
|||||||
{
|
{
|
||||||
SValue v1;
|
SValue v1;
|
||||||
int v, ft, fc, fr, sign;
|
int v, ft, fc, fr, sign;
|
||||||
uint32_t op;
|
uint32_t op, base;
|
||||||
|
|
||||||
fr = sv->r;
|
fr = sv->r;
|
||||||
ft = sv->type.t;
|
ft = sv->type.t;
|
||||||
@ -731,7 +726,15 @@ void store(int r, SValue *sv)
|
|||||||
|
|
||||||
v = fr & VT_VALMASK;
|
v = fr & VT_VALMASK;
|
||||||
if (fr & VT_LVAL || fr == VT_LOCAL) {
|
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) {
|
if(v < VT_CONST) {
|
||||||
base=intr(v);
|
base=intr(v);
|
||||||
v=VT_LOCAL;
|
v=VT_LOCAL;
|
||||||
@ -760,13 +763,10 @@ void store(int r, SValue *sv)
|
|||||||
op=0xED000100;
|
op=0xED000100;
|
||||||
if(!sign)
|
if(!sign)
|
||||||
op|=0x800000;
|
op|=0x800000;
|
||||||
#if LDOUBLE_SIZE == 8
|
|
||||||
if ((ft & VT_BTYPE) != VT_FLOAT)
|
|
||||||
op|=0x8000;
|
|
||||||
#else
|
|
||||||
if ((ft & VT_BTYPE) == VT_DOUBLE)
|
if ((ft & VT_BTYPE) == VT_DOUBLE)
|
||||||
op|=0x8000;
|
op|=0x8000;
|
||||||
if ((ft & VT_BTYPE) == VT_LDOUBLE)
|
#if LDOUBLE_SIZE != 8
|
||||||
|
else if ((ft & VT_BTYPE) == VT_LDOUBLE)
|
||||||
op|=0x400000;
|
op|=0x400000;
|
||||||
#endif
|
#endif
|
||||||
o(op|(fpr(r)<<12)|(fc>>2)|(base<<16));
|
o(op|(fpr(r)<<12)|(fc>>2)|(base<<16));
|
||||||
@ -904,15 +904,6 @@ static void gen_bounds_epilog(void)
|
|||||||
}
|
}
|
||||||
#endif
|
#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.
|
/* 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
|
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.
|
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;
|
ref = type->ref->next;
|
||||||
if (ref) {
|
if (ref) {
|
||||||
btype = unalias_ldbl(ref->type.t & VT_BTYPE);
|
btype = ref->type.t & VT_BTYPE;
|
||||||
if (btype == VT_FLOAT || btype == VT_DOUBLE) {
|
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;
|
return !ref && nb_fields <= 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1254,7 +1246,6 @@ again:
|
|||||||
size = 8;
|
size = 8;
|
||||||
else
|
else
|
||||||
size = LDOUBLE_SIZE;
|
size = LDOUBLE_SIZE;
|
||||||
|
|
||||||
if (size == 12)
|
if (size == 12)
|
||||||
r |= 0x400000;
|
r |= 0x400000;
|
||||||
else if(size == 8)
|
else if(size == 8)
|
||||||
@ -1946,15 +1937,13 @@ void gen_opf(int op)
|
|||||||
vswap();
|
vswap();
|
||||||
c2 = is_fconst();
|
c2 = is_fconst();
|
||||||
x=0xEE000100;
|
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)
|
if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE)
|
||||||
x|=0x80;
|
x|=0x80;
|
||||||
|
#if LDOUBLE_SIZE != 8
|
||||||
else if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE)
|
else if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE)
|
||||||
x|=0x80000;
|
x|=0x80000;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
switch(op)
|
switch(op)
|
||||||
{
|
{
|
||||||
case '+':
|
case '+':
|
||||||
@ -2190,6 +2179,12 @@ ST_FUNC void gen_cvt_itof(int t)
|
|||||||
func=TOK___floatundisf;
|
func=TOK___floatundisf;
|
||||||
else
|
else
|
||||||
func=TOK___floatdisf;
|
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
|
#if LDOUBLE_SIZE != 8
|
||||||
} else if((t & VT_BTYPE) == VT_LDOUBLE) {
|
} else if((t & VT_BTYPE) == VT_LDOUBLE) {
|
||||||
func_type = &func_ldouble_type;
|
func_type = &func_ldouble_type;
|
||||||
@ -2197,15 +2192,7 @@ ST_FUNC void gen_cvt_itof(int t)
|
|||||||
func=TOK___floatundixf;
|
func=TOK___floatundixf;
|
||||||
else
|
else
|
||||||
func=TOK___floatdixf;
|
func=TOK___floatdixf;
|
||||||
} else if((t & VT_BTYPE) == VT_DOUBLE) {
|
|
||||||
#else
|
|
||||||
} else if((t & VT_BTYPE) == VT_DOUBLE || (t & VT_BTYPE) == VT_LDOUBLE) {
|
|
||||||
#endif
|
#endif
|
||||||
func_type = &func_double_type;
|
|
||||||
if(vtop->type.t & VT_UNSIGNED)
|
|
||||||
func=TOK___floatundidf;
|
|
||||||
else
|
|
||||||
func=TOK___floatdidf;
|
|
||||||
}
|
}
|
||||||
if(func_type) {
|
if(func_type) {
|
||||||
vpushsym(func_type, external_helper_sym(func));
|
vpushsym(func_type, external_helper_sym(func));
|
||||||
@ -2239,14 +2226,12 @@ void gen_cvt_ftoi(int t)
|
|||||||
if(u) {
|
if(u) {
|
||||||
if(r2 == VT_FLOAT)
|
if(r2 == VT_FLOAT)
|
||||||
func=TOK___fixunssfsi;
|
func=TOK___fixunssfsi;
|
||||||
|
else if(r2 == VT_DOUBLE)
|
||||||
|
func=TOK___fixunsdfsi;
|
||||||
#if LDOUBLE_SIZE != 8
|
#if LDOUBLE_SIZE != 8
|
||||||
else if(r2 == VT_LDOUBLE)
|
else if(r2 == VT_LDOUBLE)
|
||||||
func=TOK___fixunsxfsi;
|
func=TOK___fixunsxfsi;
|
||||||
else if(r2 == VT_DOUBLE)
|
|
||||||
#else
|
|
||||||
else if(r2 == VT_LDOUBLE || r2 == VT_DOUBLE)
|
|
||||||
#endif
|
#endif
|
||||||
func=TOK___fixunsdfsi;
|
|
||||||
} else {
|
} else {
|
||||||
r=fpr(gv(RC_FLOAT));
|
r=fpr(gv(RC_FLOAT));
|
||||||
r2=intr(vtop->r=get_reg(RC_INT));
|
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
|
} else if(t == VT_LLONG) { // unsigned handled in gen_cvt_ftoi1
|
||||||
if(r2 == VT_FLOAT)
|
if(r2 == VT_FLOAT)
|
||||||
func=TOK___fixsfdi;
|
func=TOK___fixsfdi;
|
||||||
|
else if(r2 == VT_DOUBLE)
|
||||||
|
func=TOK___fixdfdi;
|
||||||
#if LDOUBLE_SIZE != 8
|
#if LDOUBLE_SIZE != 8
|
||||||
else if(r2 == VT_LDOUBLE)
|
else if(r2 == VT_LDOUBLE)
|
||||||
func=TOK___fixxfdi;
|
func=TOK___fixxfdi;
|
||||||
else if(r2 == VT_DOUBLE)
|
|
||||||
#else
|
|
||||||
else if(r2 == VT_LDOUBLE || r2 == VT_DOUBLE)
|
|
||||||
#endif
|
#endif
|
||||||
func=TOK___fixdfdi;
|
|
||||||
}
|
}
|
||||||
if(func) {
|
if(func) {
|
||||||
vpush_helper_func(func);
|
vpush_helper_func(func);
|
||||||
@ -2283,8 +2266,9 @@ void gen_cvt_ftoi(int t)
|
|||||||
void gen_cvt_ftof(int t)
|
void gen_cvt_ftof(int t)
|
||||||
{
|
{
|
||||||
#ifdef TCC_ARM_VFP
|
#ifdef TCC_ARM_VFP
|
||||||
|
uint32_t r = gv(RC_FLOAT);
|
||||||
if(((vtop->type.t & VT_BTYPE) == VT_FLOAT) != ((t & VT_BTYPE) == VT_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));
|
o(0xEEB70AC0|(r<<12)|r|T2CPR(vtop->type.t));
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
|||||||
37
arm-link.c
37
arm-link.c
@ -18,11 +18,6 @@
|
|||||||
#define PCRELATIVE_DLLPLT 1
|
#define PCRELATIVE_DLLPLT 1
|
||||||
#define RELOCATE_DLLPLT 1
|
#define RELOCATE_DLLPLT 1
|
||||||
|
|
||||||
enum float_abi {
|
|
||||||
ARM_SOFTFP_FLOAT,
|
|
||||||
ARM_HARD_FLOAT,
|
|
||||||
};
|
|
||||||
|
|
||||||
#else /* !TARGET_DEFS_ONLY */
|
#else /* !TARGET_DEFS_ONLY */
|
||||||
|
|
||||||
#include "tcc.h"
|
#include "tcc.h"
|
||||||
@ -49,6 +44,7 @@ ST_FUNC int code_reloc (int reloc_type)
|
|||||||
case R_ARM_TARGET1:
|
case R_ARM_TARGET1:
|
||||||
case R_ARM_MOVT_PREL:
|
case R_ARM_MOVT_PREL:
|
||||||
case R_ARM_MOVW_PREL_NC:
|
case R_ARM_MOVW_PREL_NC:
|
||||||
|
case R_ARM_TLS_LE32:
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case R_ARM_PC24:
|
case R_ARM_PC24:
|
||||||
@ -75,6 +71,7 @@ ST_FUNC int gotplt_entry_type (int reloc_type)
|
|||||||
case R_ARM_COPY:
|
case R_ARM_COPY:
|
||||||
case R_ARM_GLOB_DAT:
|
case R_ARM_GLOB_DAT:
|
||||||
case R_ARM_JUMP_SLOT:
|
case R_ARM_JUMP_SLOT:
|
||||||
|
case R_ARM_TLS_LE32:
|
||||||
return NO_GOTPLT_ENTRY;
|
return NO_GOTPLT_ENTRY;
|
||||||
|
|
||||||
case R_ARM_PC24:
|
case R_ARM_PC24:
|
||||||
@ -435,6 +432,36 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
|
|||||||
#endif
|
#endif
|
||||||
/* do nothing */
|
/* do nothing */
|
||||||
return;
|
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:
|
default:
|
||||||
fprintf(stderr,"FIXME: handle reloc type %d at %x [%p] to %x\n",
|
fprintf(stderr,"FIXME: handle reloc type %d at %x [%p] to %x\n",
|
||||||
type, (unsigned)addr, ptr, (unsigned)val);
|
type, (unsigned)addr, ptr, (unsigned)val);
|
||||||
|
|||||||
2226
arm64-asm.c
2226
arm64-asm.c
File diff suppressed because it is too large
Load Diff
600
arm64-gen.c
600
arm64-gen.c
File diff suppressed because it is too large
Load Diff
112
arm64-link.c
112
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_LDST32_ABS_LO12_NC:
|
||||||
case R_AARCH64_LDST16_ABS_LO12_NC:
|
case R_AARCH64_LDST16_ABS_LO12_NC:
|
||||||
case R_AARCH64_LDST8_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_GLOB_DAT:
|
||||||
case R_AARCH64_COPY:
|
case R_AARCH64_COPY:
|
||||||
return 0;
|
return 0;
|
||||||
@ -50,6 +52,8 @@ ST_FUNC int code_reloc (int reloc_type)
|
|||||||
case R_AARCH64_JUMP26:
|
case R_AARCH64_JUMP26:
|
||||||
case R_AARCH64_CALL26:
|
case R_AARCH64_CALL26:
|
||||||
case R_AARCH64_JUMP_SLOT:
|
case R_AARCH64_JUMP_SLOT:
|
||||||
|
case R_AARCH64_CONDBR19:
|
||||||
|
case R_AARCH64_TSTBR14:
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
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_GLOB_DAT:
|
||||||
case R_AARCH64_JUMP_SLOT:
|
case R_AARCH64_JUMP_SLOT:
|
||||||
case R_AARCH64_COPY:
|
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;
|
return NO_GOTPLT_ENTRY;
|
||||||
|
|
||||||
case R_AARCH64_ABS32:
|
case R_AARCH64_ABS32:
|
||||||
@ -127,17 +135,18 @@ ST_FUNC void relocate_plt(TCCState *s1)
|
|||||||
uint64_t off = (got >> 12) - (plt >> 12);
|
uint64_t off = (got >> 12) - (plt >> 12);
|
||||||
if ((off + ((uint32_t)1 << 20)) >> 21)
|
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);
|
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, ARM64_STP_X_PRE | ARM64_RT(16) | ARM64_RT2(30) |
|
||||||
write32le(p + 4, (0x90000010 | // adrp x16,...
|
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));
|
(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));
|
(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));
|
(got & 0xfff) << 10));
|
||||||
write32le(p + 16, 0xd61f0220); // br x17
|
write32le(p + 16, ARM64_BR | ARM64_RN(17)); // br x17
|
||||||
write32le(p + 20, 0xd503201f); // nop
|
write32le(p + 20, ARM64_NOP); // nop
|
||||||
write32le(p + 24, 0xd503201f); // nop
|
write32le(p + 24, ARM64_NOP); // nop
|
||||||
write32le(p + 28, 0xd503201f); // nop
|
write32le(p + 28, ARM64_NOP); // nop
|
||||||
p += 32;
|
p += 32;
|
||||||
got = s1->got->sh_addr;
|
got = s1->got->sh_addr;
|
||||||
while (p < p_end) {
|
while (p < p_end) {
|
||||||
@ -146,13 +155,13 @@ ST_FUNC void relocate_plt(TCCState *s1)
|
|||||||
uint64_t off = (addr >> 12) - (pc >> 12);
|
uint64_t off = (addr >> 12) - (pc >> 12);
|
||||||
if ((off + ((uint32_t)1 << 20)) >> 21)
|
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);
|
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));
|
(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));
|
(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));
|
(addr & 0xfff) << 10));
|
||||||
write32le(p + 12, 0xd61f0220); // br x17
|
write32le(p + 12, ARM64_BR | ARM64_RN(17)); // br x17
|
||||||
p += 16;
|
p += 16;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -238,8 +247,23 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
|
|||||||
return;
|
return;
|
||||||
case R_AARCH64_ADR_PREL_PG_HI21: {
|
case R_AARCH64_ADR_PREL_PG_HI21: {
|
||||||
uint64_t off = (val >> 12) - (addr >> 12);
|
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)
|
if ((off + ((uint64_t)1 << 20)) >> 21)
|
||||||
tcc_error_noabort("R_AARCH64_ADR_PREL_PG_HI21 relocation failed");
|
tcc_error_noabort("R_AARCH64_ADR_PREL_PG_HI21 relocation failed");
|
||||||
|
#endif
|
||||||
write32le(ptr, ((read32le(ptr) & 0x9f00001f) |
|
write32le(ptr, ((read32le(ptr) & 0x9f00001f) |
|
||||||
(off & 0x1ffffc) << 3 | (off & 3) << 29));
|
(off & 0x1ffffc) << 3 | (off & 3) << 29));
|
||||||
return;
|
return;
|
||||||
@ -265,19 +289,58 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
|
|||||||
write32le(ptr, ((read32le(ptr) & 0xffc003ff) |
|
write32le(ptr, ((read32le(ptr) & 0xffc003ff) |
|
||||||
(val & 0xff0) << 6));
|
(val & 0xff0) << 6));
|
||||||
return;
|
return;
|
||||||
|
case R_AARCH64_CONDBR19:
|
||||||
|
/* Conditional branch: 19-bit signed offset, bits 23:5 */
|
||||||
|
#ifdef DEBUG_RELOC
|
||||||
|
printf ("reloc %d @ 0x%lx: val=0x%lx name=%s\n", type, addr, val,
|
||||||
|
(char *) symtab_section->link->data + sym->st_name);
|
||||||
|
#endif
|
||||||
|
if (((val - addr) + ((uint64_t)1 << 20)) & ~(uint64_t)0x1ffffc)
|
||||||
|
tcc_error_noabort("R_AARCH64_CONDBR19 relocation failed"
|
||||||
|
" (val=%lx, addr=%lx)", (long)val, (long)addr);
|
||||||
|
write32le(ptr, ((read32le(ptr) & 0xff00001f) |
|
||||||
|
(((val - addr) >> 2 & 0x7ffff) << 5)));
|
||||||
|
return;
|
||||||
|
case R_AARCH64_TSTBR14:
|
||||||
|
/* Test and branch: 14-bit signed offset, bits 20:5 */
|
||||||
|
#ifdef DEBUG_RELOC
|
||||||
|
printf ("reloc %d @ 0x%lx: val=0x%lx name=%s\n", type, addr, val,
|
||||||
|
(char *) symtab_section->link->data + sym->st_name);
|
||||||
|
#endif
|
||||||
|
if (((val - addr) + ((uint64_t)1 << 15)) & ~(uint64_t)0xfffc)
|
||||||
|
tcc_error_noabort("R_AARCH64_TSTBR14 relocation failed"
|
||||||
|
" (val=%lx, addr=%lx)", (long)val, (long)addr);
|
||||||
|
write32le(ptr, ((read32le(ptr) & 0xfff8001f) |
|
||||||
|
(((val - addr) >> 2 & 0x3fff) << 5)));
|
||||||
|
return;
|
||||||
case R_AARCH64_JUMP26:
|
case R_AARCH64_JUMP26:
|
||||||
case R_AARCH64_CALL26:
|
case R_AARCH64_CALL26:
|
||||||
|
{
|
||||||
|
const char *name;
|
||||||
#ifdef DEBUG_RELOC
|
#ifdef DEBUG_RELOC
|
||||||
printf ("reloc %d @ 0x%lx: val=0x%lx name=%s\n", type, addr, val,
|
printf ("reloc %d @ 0x%lx: val=0x%lx name=%s\n", type, addr, val,
|
||||||
(char *) symtab_section->link->data + sym->st_name);
|
(char *) symtab_section->link->data + sym->st_name);
|
||||||
#endif
|
#endif
|
||||||
if (((val - addr) + ((uint64_t)1 << 27)) & ~(uint64_t)0xffffffc)
|
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"
|
tcc_error_noabort("R_AARCH64_(JUMP|CALL)26 relocation failed"
|
||||||
" (val=%lx, addr=%lx)", (long)val, (long)addr);
|
" for '%s' (val=%lx, addr=%lx)",
|
||||||
|
name, (long)val, (long)addr);
|
||||||
|
}
|
||||||
write32le(ptr, (0x14000000 |
|
write32le(ptr, (0x14000000 |
|
||||||
(uint32_t)(type == R_AARCH64_CALL26) << 31 |
|
(uint32_t)(type == R_AARCH64_CALL26) << 31 |
|
||||||
((val - addr) >> 2 & 0x3ffffff)));
|
((val - addr) >> 2 & 0x3ffffff)));
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
case R_AARCH64_ADR_GOT_PAGE: {
|
case R_AARCH64_ADR_GOT_PAGE: {
|
||||||
uint64_t off =
|
uint64_t off =
|
||||||
(((s1->got->sh_addr +
|
(((s1->got->sh_addr +
|
||||||
@ -306,6 +369,27 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
|
|||||||
#endif
|
#endif
|
||||||
write64le(ptr, val - rel->r_addend);
|
write64le(ptr, val - rel->r_addend);
|
||||||
return;
|
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:
|
case R_AARCH64_RELATIVE:
|
||||||
#ifdef TCC_TARGET_PE
|
#ifdef TCC_TARGET_PE
|
||||||
add32le(ptr, val - s1->pe_imagebase);
|
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"
|
LIBSUF=".a"
|
||||||
EXESUF=""
|
EXESUF=""
|
||||||
DLLSUF=".so"
|
DLLSUF=".so"
|
||||||
tcc_usrinclude=""
|
|
||||||
tcc_sysincludepaths=""
|
tcc_sysincludepaths=""
|
||||||
tcc_libpaths=""
|
tcc_libpaths=""
|
||||||
tcc_crtprefix=""
|
tcc_crtprefix=""
|
||||||
tcc_elfinterp=""
|
tcc_elfinterp=""
|
||||||
triplet=
|
triplet=
|
||||||
tcc_lddir=
|
|
||||||
confvars=
|
confvars=
|
||||||
suggest="yes"
|
suggest="yes"
|
||||||
gcc_major=0
|
gcc_major=0
|
||||||
@ -53,6 +51,7 @@ cpuver=
|
|||||||
dwarf=
|
dwarf=
|
||||||
targetos=
|
targetos=
|
||||||
build_cross=
|
build_cross=
|
||||||
|
quiet=
|
||||||
|
|
||||||
# use CC/AR from environment when set
|
# use CC/AR from environment when set
|
||||||
test -n "$CC" && cc="$CC"
|
test -n "$CC" && cc="$CC"
|
||||||
@ -160,8 +159,6 @@ for opt do
|
|||||||
;;
|
;;
|
||||||
--debug) confvars_set debug
|
--debug) confvars_set debug
|
||||||
;;
|
;;
|
||||||
--with-libgcc) confvars_set libgcc
|
|
||||||
;;
|
|
||||||
--with-selinux) confvars_set selinux
|
--with-selinux) confvars_set selinux
|
||||||
;;
|
;;
|
||||||
--tcc-switches=*) assign_opt "$opt" tcc_switches
|
--tcc-switches=*) assign_opt "$opt" tcc_switches
|
||||||
@ -174,6 +171,8 @@ for opt do
|
|||||||
;;
|
;;
|
||||||
--help|-h) show_help="yes"
|
--help|-h) show_help="yes"
|
||||||
;;
|
;;
|
||||||
|
-q) quiet=yes
|
||||||
|
;;
|
||||||
*) echo "configure: WARNING: unrecognized option $opt"
|
*) echo "configure: WARNING: unrecognized option $opt"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
@ -197,6 +196,7 @@ Standard options:
|
|||||||
--docdir=DIR documentation in DIR [SHAREDIR/doc/tcc]
|
--docdir=DIR documentation in DIR [SHAREDIR/doc/tcc]
|
||||||
--mandir=DIR man documentation in DIR [SHAREDIR/man]
|
--mandir=DIR man documentation in DIR [SHAREDIR/man]
|
||||||
--infodir=DIR info documentation in DIR [SHAREDIR/info]
|
--infodir=DIR info documentation in DIR [SHAREDIR/info]
|
||||||
|
-q be quiet
|
||||||
|
|
||||||
Advanced options (experts only):
|
Advanced options (experts only):
|
||||||
--source-path=PATH path of source code [$source_path]
|
--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
|
--disable-static make libtcc.so instead of libtcc.a
|
||||||
--enable-static make libtcc.a instead of libtcc.dll (win32)
|
--enable-static make libtcc.a instead of libtcc.dll (win32)
|
||||||
--disable-rpath disable use of -rpath with libtcc.so
|
--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)
|
--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
|
--sysincludepaths=... specify system include paths, colon separated
|
||||||
--libpaths=... specify system library paths, colon separated
|
--libpaths=... specify system library paths, colon separated
|
||||||
@ -266,7 +265,11 @@ default os_release "$(uname -r)"
|
|||||||
case $buildos in
|
case $buildos in
|
||||||
Windows_NT|MINGW*|MSYS*|CYGWIN*)
|
Windows_NT|MINGW*|MSYS*|CYGWIN*)
|
||||||
buildos="WIN32"
|
buildos="WIN32"
|
||||||
test "$MSYSTEM" = "MINGW32" && cpu_sys=i386
|
case "$MSYSTEM" in
|
||||||
|
MINGW32) cpu_sys=i386 ;;
|
||||||
|
MINGW64) cpu_sys=x86_64 ;;
|
||||||
|
CLANGARM64|MINGW_ARM64) cpu_sys=arm64 ;;
|
||||||
|
esac
|
||||||
;;
|
;;
|
||||||
Linux)
|
Linux)
|
||||||
if test "$(uname -o)" = "Android"; then
|
if test "$(uname -o)" = "Android"; then
|
||||||
@ -363,6 +366,7 @@ case $targetos in
|
|||||||
cc=`command -v cc`
|
cc=`command -v cc`
|
||||||
cc=`readlink $cc || echo clang`
|
cc=`readlink $cc || echo clang`
|
||||||
tcc_usrinclude="`xcrun --show-sdk-path`/usr/include"
|
tcc_usrinclude="`xcrun --show-sdk-path`/usr/include"
|
||||||
|
default tcc_sysincludepaths "{B}/include:$tcc_usrinclude"
|
||||||
if test "${confvars%new_macho*}" = "${confvars}"; then
|
if test "${confvars%new_macho*}" = "${confvars}"; then
|
||||||
# if new_macho was not specified and (known) ver <= 10, use old (=no)
|
# if new_macho was not specified and (known) ver <= 10, use old (=no)
|
||||||
osxver=$(sw_vers -productVersion 2>/dev/null) # X.Y.Z
|
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
|
if test -z "$triplet"; then
|
||||||
case $cpu in x86_64|arm64|riscv64)
|
case $cpu in x86_64|arm64|riscv64)
|
||||||
if test -f "/usr/lib64/crti.o" ; then
|
if test -f "/usr/lib64/crti.o" ; then
|
||||||
tcc_lddir="lib64"
|
default tcc_libpaths "{B}:/usr/lib64"
|
||||||
|
default tcc_crtprefix "/usr/lib64"
|
||||||
fi
|
fi
|
||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
@ -548,6 +553,7 @@ fi
|
|||||||
|
|
||||||
fcho() { if test -n "$2"; then echo "$1$2"; fi }
|
fcho() { if test -n "$2"; then echo "$1$2"; fi }
|
||||||
|
|
||||||
|
if test -z "$quiet"; then
|
||||||
fcho "Binary directory " "$bindir"
|
fcho "Binary directory " "$bindir"
|
||||||
fcho "TinyCC directory " "$tccdir"
|
fcho "TinyCC directory " "$tccdir"
|
||||||
fcho "Library directory " "$libdir"
|
fcho "Library directory " "$libdir"
|
||||||
@ -556,7 +562,6 @@ fcho "Manual directory " "$mandir"
|
|||||||
fcho "Info directory " "$infodir"
|
fcho "Info directory " "$infodir"
|
||||||
fcho "Doc directory " "$docdir"
|
fcho "Doc directory " "$docdir"
|
||||||
fcho "Target root prefix " "$sysroot"
|
fcho "Target root prefix " "$sysroot"
|
||||||
fcho "/usr/include dir " "$tcc_usrinclude"
|
|
||||||
echo "Source path $source_path"
|
echo "Source path $source_path"
|
||||||
echo "Build OS $(uname -m -s)"
|
echo "Build OS $(uname -m -s)"
|
||||||
echo "C compiler $cc ($gcc_major.$gcc_minor)"
|
echo "C compiler $cc ($gcc_major.$gcc_minor)"
|
||||||
@ -570,6 +575,7 @@ fcho "Elfinterp " "$tcc_elfinterp"
|
|||||||
fcho "Switches " "$tcc_switches"
|
fcho "Switches " "$tcc_switches"
|
||||||
fcho "Config " "${confvars# }"
|
fcho "Config " "${confvars# }"
|
||||||
echo "Creating config.mak and config.h"
|
echo "Creating config.mak and config.h"
|
||||||
|
fi
|
||||||
|
|
||||||
version=$(head "$source_path/VERSION")
|
version=$(head "$source_path/VERSION")
|
||||||
|
|
||||||
@ -687,7 +693,6 @@ for v in $cpu $confvars ; do
|
|||||||
esac
|
esac
|
||||||
;;
|
;;
|
||||||
# other
|
# other
|
||||||
CONFIG_libgcc=yes) print_num CONFIG_USE_LIBGCC 1 ;;
|
|
||||||
CONFIG_selinux=yes) print_num CONFIG_SELINUX 1 ;;
|
CONFIG_selinux=yes) print_num CONFIG_SELINUX 1 ;;
|
||||||
CONFIG_pie=yes) print_num CONFIG_TCC_PIE 1 ;;
|
CONFIG_pie=yes) print_num CONFIG_TCC_PIE 1 ;;
|
||||||
CONFIG_pic=yes) print_num CONFIG_TCC_PIC 1 ;;
|
CONFIG_pic=yes) print_num CONFIG_TCC_PIC 1 ;;
|
||||||
@ -702,13 +707,11 @@ for v in $cpu $confvars ; do
|
|||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
print_str CONFIG_USR_INCLUDE "$tcc_usrinclude"
|
|
||||||
print_str CONFIG_TCC_SYSINCLUDEPATHS "$tcc_sysincludepaths"
|
print_str CONFIG_TCC_SYSINCLUDEPATHS "$tcc_sysincludepaths"
|
||||||
print_str CONFIG_TCC_LIBPATHS "$tcc_libpaths"
|
print_str CONFIG_TCC_LIBPATHS "$tcc_libpaths"
|
||||||
print_str CONFIG_TCC_CRTPREFIX "$tcc_crtprefix"
|
print_str CONFIG_TCC_CRTPREFIX "$tcc_crtprefix"
|
||||||
print_str CONFIG_TCC_ELFINTERP "$tcc_elfinterp"
|
print_str CONFIG_TCC_ELFINTERP "$tcc_elfinterp"
|
||||||
print_str CONFIG_TCC_SWITCHES "$tcc_switches"
|
print_str CONFIG_TCC_SWITCHES "$tcc_switches"
|
||||||
print_str CONFIG_LDDIR "$tcc_lddir"
|
|
||||||
print_str CONFIG_TRIPLET "$triplet"
|
print_str CONFIG_TRIPLET "$triplet"
|
||||||
print_str CONFIG_OS_RELEASE "$os_release"
|
print_str CONFIG_OS_RELEASE "$os_release"
|
||||||
echo "#endif" >> $TMPH && echo >> $TMPH
|
echo "#endif" >> $TMPH && echo >> $TMPH
|
||||||
@ -720,7 +723,7 @@ print_num CONFIG_TCC_PREDEFS "$predefs"
|
|||||||
diff $TMPH config.h >/dev/null 2>&1
|
diff $TMPH config.h >/dev/null 2>&1
|
||||||
if test $? -ne 0 ; then
|
if test $? -ne 0 ; then
|
||||||
mv -f $TMPH config.h
|
mv -f $TMPH config.h
|
||||||
else
|
elif test -z "$quiet"; then
|
||||||
echo "config.h is unchanged"
|
echo "config.h is unchanged"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
3
elf.h
3
elf.h
@ -2336,7 +2336,8 @@ typedef Elf32_Addr Elf32_Conflict;
|
|||||||
/* Processor specific values for the Shdr sh_type field. */
|
/* Processor specific values for the Shdr sh_type field. */
|
||||||
#define SHT_ARM_EXIDX (SHT_LOPROC + 1) /* ARM unwind section. */
|
#define SHT_ARM_EXIDX (SHT_LOPROC + 1) /* ARM unwind section. */
|
||||||
#define SHT_ARM_PREEMPTMAP (SHT_LOPROC + 2) /* Preemption details. */
|
#define SHT_ARM_PREEMPTMAP (SHT_LOPROC + 2) /* Preemption details. */
|
||||||
#define SHT_ARM_ATTRIBUTES (SHT_LOPROC + 3) /* ARM attributes section. */
|
#define SHT_ARM_ATTRIBUTES (SHT_LOPROC + 3) /* ARM attributes section. */
|
||||||
|
#define SHT_RISCV_ATTRIBUTES 0x70000003
|
||||||
|
|
||||||
|
|
||||||
/* AArch64 relocs. */
|
/* AArch64 relocs. */
|
||||||
|
|||||||
@ -494,13 +494,6 @@ ST_FUNC void gen_expr32(ExprValue *pe)
|
|||||||
gen_addr32(pe->sym ? VT_SYM : 0, pe->sym, pe->v);
|
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 ? */
|
/* XXX: unify with C code output ? */
|
||||||
static void gen_disp32(ExprValue *pe)
|
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) {
|
} else if ((r & VT_VALMASK) == VT_LOCAL) {
|
||||||
o(opc);
|
o(opc);
|
||||||
/* currently, we use only ebp as base */
|
/* currently, we use only ebp as base */
|
||||||
if (c == (char)c) {
|
if (c == (signed char)c) {
|
||||||
/* short reference */
|
/* short reference */
|
||||||
o(0x45 | op_reg);
|
o(0x45 | op_reg);
|
||||||
g(c);
|
g(c);
|
||||||
@ -313,6 +313,16 @@ ST_FUNC void load(int r, SValue *sv)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (fr & VT_LVAL) {
|
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) {
|
if (v == VT_LLOCAL) {
|
||||||
v1.type.t = VT_INT;
|
v1.type.t = VT_INT;
|
||||||
v1.r = VT_LOCAL | VT_LVAL;
|
v1.r = VT_LOCAL | VT_LVAL;
|
||||||
@ -429,6 +439,16 @@ ST_FUNC void store(int r, SValue *v)
|
|||||||
} else
|
} else
|
||||||
#endif
|
#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)) {
|
if (fr == VT_CONST || fr == VT_LOCAL || (v->r & VT_LVAL)) {
|
||||||
gen_modrm(opc, r, v->r, v->sym, fc);
|
gen_modrm(opc, r, v->r, v->sym, fc);
|
||||||
} else if (fr != r) {
|
} else if (fr != r) {
|
||||||
@ -439,7 +459,7 @@ ST_FUNC void store(int r, SValue *v)
|
|||||||
|
|
||||||
static void gadd_sp(int val)
|
static void gadd_sp(int val)
|
||||||
{
|
{
|
||||||
if (val == (char)val) {
|
if (val == (signed char)val) {
|
||||||
o(0xc483);
|
o(0xc483);
|
||||||
g(val);
|
g(val);
|
||||||
} else {
|
} else {
|
||||||
@ -774,7 +794,7 @@ ST_FUNC void gjmp_addr(int a)
|
|||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
r = a - ind - 2;
|
r = a - ind - 2;
|
||||||
if (r == (char)r) {
|
if (r == (signed char)r) {
|
||||||
g(0xeb);
|
g(0xeb);
|
||||||
g(r);
|
g(r);
|
||||||
} else {
|
} else {
|
||||||
@ -787,7 +807,7 @@ ST_FUNC void gjmp_addr(int a)
|
|||||||
ST_FUNC void gjmp_cond_addr(int a, int op)
|
ST_FUNC void gjmp_cond_addr(int a, int op)
|
||||||
{
|
{
|
||||||
int r = a - ind - 2;
|
int r = a - ind - 2;
|
||||||
if (r == (char)r)
|
if (r == (signed char)r)
|
||||||
g(op - 32), g(r);
|
g(op - 32), g(r);
|
||||||
else
|
else
|
||||||
g(0x0f), gjmp2(op - 16, r - 4);
|
g(0x0f), gjmp2(op - 16, r - 4);
|
||||||
@ -830,7 +850,7 @@ ST_FUNC void gen_opi(int op)
|
|||||||
r = gv(RC_INT);
|
r = gv(RC_INT);
|
||||||
vswap();
|
vswap();
|
||||||
c = vtop->c.i;
|
c = vtop->c.i;
|
||||||
if (c == (char)c) {
|
if (c == (signed char)c) {
|
||||||
/* generate inc and dec for smaller code */
|
/* generate inc and dec for smaller code */
|
||||||
if ((c == 1 || c == -1) && (op == '+' || op == '-')) {
|
if ((c == 1 || c == -1) && (op == '+' || op == '-')) {
|
||||||
opc = (c == 1) ^ (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;
|
return;
|
||||||
case R_386_TLS_LDO_32:
|
case R_386_TLS_LDO_32:
|
||||||
case R_386_TLS_LE:
|
|
||||||
{
|
{
|
||||||
ElfW(Sym) *sym;
|
ElfW(Sym) *sym;
|
||||||
Section *sec;
|
Section *sec;
|
||||||
@ -317,6 +316,38 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
|
|||||||
add32le(ptr, x);
|
add32le(ptr, x);
|
||||||
}
|
}
|
||||||
return;
|
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:
|
case R_386_NONE:
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@ -90,8 +90,6 @@
|
|||||||
#define __NO_TLS 1
|
#define __NO_TLS 1
|
||||||
#define __RUNETYPE_INTERNAL 1
|
#define __RUNETYPE_INTERNAL 1
|
||||||
# if __SIZEOF_POINTER__ == 8
|
# 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_SIZE_T__ 8
|
||||||
#define __SIZEOF_PTRDIFF_T__ 8
|
#define __SIZEOF_PTRDIFF_T__ 8
|
||||||
#else
|
#else
|
||||||
@ -142,12 +140,6 @@
|
|||||||
#endif
|
#endif
|
||||||
#define __INT32_TYPE__ int
|
#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
|
#if !defined _WIN32
|
||||||
/* glibc defines. We do not support __USER_NAME_PREFIX__ */
|
/* glibc defines. We do not support __USER_NAME_PREFIX__ */
|
||||||
#define __REDIRECT(name, proto, alias) name proto __asm__ (#alias)
|
#define __REDIRECT(name, proto, alias) name proto __asm__ (#alias)
|
||||||
@ -187,14 +179,17 @@
|
|||||||
# endif
|
# endif
|
||||||
#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 */
|
/* __builtin_va_list */
|
||||||
#if defined __x86_64__
|
#if defined __x86_64__
|
||||||
#if !defined _WIN32
|
#if !defined _WIN32
|
||||||
/* GCC compatible definition of va_list. */
|
/* GCC compatible definition of va_list. */
|
||||||
|
/* This should be in sync with the declaration in our lib/va_list.c */
|
||||||
enum __va_arg_type {
|
|
||||||
__va_gen_reg, __va_float_reg, __va_stack
|
|
||||||
};
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
unsigned gp_offset, fp_offset;
|
unsigned gp_offset, fp_offset;
|
||||||
union {
|
union {
|
||||||
@ -204,43 +199,7 @@
|
|||||||
char *reg_save_area;
|
char *reg_save_area;
|
||||||
} __builtin_va_list[1];
|
} __builtin_va_list[1];
|
||||||
|
|
||||||
static inline void *__va_arg(__builtin_va_list ap, int arg_type,
|
void *__va_arg(__builtin_va_list ap, int arg_type, int size, int align);
|
||||||
int size, int align)
|
|
||||||
{
|
|
||||||
size = (size + 7) & ~7;
|
|
||||||
align = (align + 7) & ~7;
|
|
||||||
switch ((enum __va_arg_type)arg_type) {
|
|
||||||
case __va_gen_reg:
|
|
||||||
if (ap->gp_offset + size <= 48) {
|
|
||||||
ap->gp_offset += size;
|
|
||||||
return ap->reg_save_area + ap->gp_offset - size;
|
|
||||||
}
|
|
||||||
goto use_overflow_area;
|
|
||||||
case __va_float_reg:
|
|
||||||
if (ap->fp_offset < 128 + 48) {
|
|
||||||
ap->fp_offset += 16;
|
|
||||||
if (size == 8)
|
|
||||||
return ap->reg_save_area + ap->fp_offset - 16;
|
|
||||||
if (ap->fp_offset < 128 + 48) {
|
|
||||||
double *p = (double *)(ap->reg_save_area + ap->fp_offset);
|
|
||||||
p[-1] = p[0];
|
|
||||||
ap->fp_offset += 16;
|
|
||||||
return ap->reg_save_area + ap->fp_offset - 32;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
goto use_overflow_area;
|
|
||||||
case __va_stack:
|
|
||||||
use_overflow_area:
|
|
||||||
ap->overflow_arg_area += size;
|
|
||||||
ap->overflow_arg_area =
|
|
||||||
(char*)((long long)(ap->overflow_arg_area + align - 1) & -align);
|
|
||||||
return ap->overflow_arg_area - size;
|
|
||||||
default: /* should never happen */
|
|
||||||
char *a = (char *)0; *a = 0; // abort
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#define __builtin_va_start(ap, last) \
|
#define __builtin_va_start(ap, last) \
|
||||||
(*(ap) = *(__builtin_va_list)((char*)__builtin_frame_address(0) - 24))
|
(*(ap) = *(__builtin_va_list)((char*)__builtin_frame_address(0) - 24))
|
||||||
#define __builtin_va_arg(ap, t) \
|
#define __builtin_va_arg(ap, t) \
|
||||||
@ -263,7 +222,9 @@
|
|||||||
&~3), *(type *)(ap - ((sizeof(type)+3)&~3)))
|
&~3), *(type *)(ap - ((sizeof(type)+3)&~3)))
|
||||||
|
|
||||||
#elif defined __aarch64__
|
#elif defined __aarch64__
|
||||||
#if defined __APPLE__
|
#if defined _WIN32
|
||||||
|
typedef char *__builtin_va_list;
|
||||||
|
#elif defined __APPLE__
|
||||||
typedef struct {
|
typedef struct {
|
||||||
void *__stack;
|
void *__stack;
|
||||||
} __builtin_va_list;
|
} __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)
|
ARM64_O = lib-arm64.o $(COMMON_O)
|
||||||
RISCV64_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
|
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
|
LIN_O = dsohandle.o
|
||||||
OSX_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
|
EXTRA_O = runmain.o bt-exe.o bt-dll.o bt-log.o bcheck.o
|
||||||
|
|
||||||
OBJ-i386 = $(I386_O) pic86.o $(LIN_O)
|
OBJ-i386 = $(I386_O) pic86.o $(LIN_O)
|
||||||
OBJ-x86_64 = $(X86_64_O) $(LIN_O)
|
OBJ-x86_64 = $(X86_64_O) va_list.o $(LIN_O)
|
||||||
OBJ-x86_64-osx = $(X86_64_O) $(OSX_O)
|
OBJ-x86_64-osx = $(X86_64_O) va_list.o $(OSX_O)
|
||||||
OBJ-i386-win32 = $(I386_O) chkstk.o $(WIN_O)
|
OBJ-i386-win32 = $(I386_O) chkstk.o $(WIN_O)
|
||||||
OBJ-x86_64-win32 = $(X86_64_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-osx = $(ARM64_O) $(OSX_O)
|
||||||
|
OBJ-arm64-win32 = $(ARM64_O) chkstk.o $(WIN_O)
|
||||||
OBJ-arm = $(ARM_O) $(LIN_O)
|
OBJ-arm = $(ARM_O) $(LIN_O)
|
||||||
OBJ-arm-fpa = $(OBJ-arm)
|
OBJ-arm-fpa = $(OBJ-arm)
|
||||||
OBJ-arm-fpa-ld = $(OBJ-arm)
|
OBJ-arm-fpa-ld = $(OBJ-arm)
|
||||||
@ -72,7 +73,7 @@ OBJ-arm-vfp = $(OBJ-arm)
|
|||||||
OBJ-arm-eabi = $(OBJ-arm)
|
OBJ-arm-eabi = $(OBJ-arm)
|
||||||
OBJ-arm-eabihf = $(OBJ-arm)
|
OBJ-arm-eabihf = $(OBJ-arm)
|
||||||
OBJ-arm-wince = $(ARM_O) $(WIN_O)
|
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-extra = $(filter $(EXTRA_O),$(OBJ-$T))
|
||||||
OBJ-libtcc1 = $(addprefix $(X),$(filter-out $(OBJ-extra),$(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
|
intrinsic with gcc. However tcc in order to compile
|
||||||
itself needs this function */
|
itself needs this function */
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------- */
|
||||||
|
#if defined __arm__
|
||||||
|
|
||||||
#ifdef __TINYC__
|
#ifdef __TINYC__
|
||||||
|
|
||||||
/* syscall wrapper */
|
/* 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 */
|
* However, there is no ARM asm parser in tcc so we use it for now */
|
||||||
syscall(__ARM_NR_cacheflush, beginning, end, 0);
|
syscall(__ARM_NR_cacheflush, beginning, end, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------- */
|
||||||
|
#elif defined __aarch64__
|
||||||
|
void __clear_cache(void *beg, void *end)
|
||||||
|
{
|
||||||
|
__arm64_clear_cache(beg, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------- */
|
||||||
|
#endif
|
||||||
|
|||||||
27
lib/bt-dll.c
27
lib/bt-dll.c
@ -34,7 +34,11 @@
|
|||||||
REDIR(__bound_strncmp) \
|
REDIR(__bound_strncmp) \
|
||||||
REDIR(__bound_strcat) \
|
REDIR(__bound_strcat) \
|
||||||
REDIR(__bound_strchr) \
|
REDIR(__bound_strchr) \
|
||||||
REDIR(__bound_strdup)
|
REDIR(__bound_strdup) \
|
||||||
|
REDIR(__bound_strncat) \
|
||||||
|
REDIR(__bound_strrchr) \
|
||||||
|
REDIR(__bound_setjmp) \
|
||||||
|
REDIR(__bound_longjmp)
|
||||||
|
|
||||||
#ifdef __leading_underscore
|
#ifdef __leading_underscore
|
||||||
#define _(s) "_"#s
|
#define _(s) "_"#s
|
||||||
@ -45,11 +49,28 @@
|
|||||||
#define REDIR(s) void *s;
|
#define REDIR(s) void *s;
|
||||||
static struct { REDIR_ALL } all_ptrs;
|
static struct { REDIR_ALL } all_ptrs;
|
||||||
#undef REDIR
|
#undef REDIR
|
||||||
|
|
||||||
#define REDIR(s) #s"\0"
|
#define REDIR(s) #s"\0"
|
||||||
static const char all_names[] = REDIR_ALL;
|
static const char all_names[] = REDIR_ALL;
|
||||||
#undef REDIR
|
#undef REDIR
|
||||||
#define REDIR(s) __asm__(".global " _(s) ";" _(s) ": jmp *%0" : : "m" (all_ptrs.s) );
|
|
||||||
static void all_jmps() { REDIR_ALL }
|
#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
|
#undef REDIR
|
||||||
|
|
||||||
void __bt_init_dll(int bcheck)
|
void __bt_init_dll(int bcheck)
|
||||||
|
|||||||
19
lib/bt-exe.c
19
lib/bt-exe.c
@ -11,6 +11,21 @@
|
|||||||
# define __declspec(n)
|
# define __declspec(n)
|
||||||
#endif
|
#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)
|
__declspec(dllexport)
|
||||||
void __bt_init(rt_context *p, int is_exe)
|
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)
|
if (p->bounds_start)
|
||||||
__bound_init(p->bounds_start, -1);
|
__bound_init(p->bounds_start, -1);
|
||||||
|
|
||||||
|
#ifdef _WIN64
|
||||||
|
bt_init_pe_prog_base(p);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* add to chain */
|
/* add to chain */
|
||||||
rt_wait_sem();
|
rt_wait_sem();
|
||||||
p->next = g_rc, g_rc = p;
|
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 unsigned uint32_t;
|
||||||
typedef long long int64_t;
|
typedef long long int64_t;
|
||||||
typedef unsigned long long uint64_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
|
#else
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined __riscv && !defined __APPLE__
|
typedef union {
|
||||||
void __clear_cache(void *beg, void *end)
|
struct { uint64_t x0, x1; };
|
||||||
{
|
long double f;
|
||||||
__arm64_clear_cache(beg, end);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint64_t x0, x1;
|
|
||||||
} u128_t;
|
} 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)
|
static long double f3_zero(int sgn)
|
||||||
{
|
{
|
||||||
long double f;
|
|
||||||
u128_t x = { 0, (uint64_t)sgn << 63 };
|
u128_t x = { 0, (uint64_t)sgn << 63 };
|
||||||
memcpy(&f, &x, 16);
|
return x.f;
|
||||||
return f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static long double f3_infinity(int sgn)
|
static long double f3_infinity(int sgn)
|
||||||
{
|
{
|
||||||
long double f;
|
|
||||||
u128_t x = { 0, (uint64_t)sgn << 63 | 0x7fff000000000000 };
|
u128_t x = { 0, (uint64_t)sgn << 63 | 0x7fff000000000000 };
|
||||||
memcpy(&f, &x, 16);
|
return x.f;
|
||||||
return f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static long double f3_NaN(void)
|
static long double f3_NaN(void)
|
||||||
{
|
{
|
||||||
long double f;
|
|
||||||
#if 0
|
#if 0
|
||||||
// ARM's default NaN usually has just the top fraction bit set:
|
// ARM's default NaN usually has just the top fraction bit set:
|
||||||
u128_t x = { 0, 0x7fff800000000000 };
|
u128_t x = { 0, 0x7fff800000000000 };
|
||||||
@ -68,28 +59,31 @@ static long double f3_NaN(void)
|
|||||||
// GCC's library sets all fraction bits:
|
// GCC's library sets all fraction bits:
|
||||||
u128_t x = { -1, 0x7fffffffffffffff };
|
u128_t x = { -1, 0x7fffffffffffffff };
|
||||||
#endif
|
#endif
|
||||||
memcpy(&f, &x, 16);
|
return x.f;
|
||||||
return f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fp3_convert_NaN(long double *f, int sgn, u128_t mnt)
|
static int fp3_convert_NaN(long double *f, int sgn, u128_t *mnt)
|
||||||
{
|
{
|
||||||
u128_t x = { mnt.x0,
|
u128_t x = { mnt->x0,
|
||||||
mnt.x1 | 0x7fff800000000000 | (uint64_t)sgn << 63 };
|
mnt->x1 | 0x7fff800000000000 | (uint64_t)sgn << 63 };
|
||||||
memcpy(f, &x, 16);
|
*f = x.f;
|
||||||
return 1;
|
return 1;
|
||||||
|
#define fp3_convert_NaN(a,b,c) fp3_convert_NaN(a,b,&c)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fp3_detect_NaNs(long double *f,
|
static int fp3_detect_NaNs(long double *f,
|
||||||
int a_sgn, int a_exp, u128_t a,
|
int a_sgn, int a_exp, u128_t *a,
|
||||||
int b_sgn, int b_exp, u128_t b)
|
int b_sgn, int b_exp, u128_t *b)
|
||||||
|
#define a (*a)
|
||||||
|
#define b (*b)
|
||||||
{
|
{
|
||||||
|
#if 0
|
||||||
// Detect signalling NaNs:
|
// Detect signalling NaNs:
|
||||||
if (a_exp == 32767 && (a.x0 | a.x1 << 16) && !(a.x1 >> 47 & 1))
|
if (a_exp == 32767 && (a.x0 | a.x1 << 16) && !(a.x1 >> 47 & 1))
|
||||||
return fp3_convert_NaN(f, a_sgn, a);
|
return fp3_convert_NaN(f, a_sgn, a);
|
||||||
if (b_exp == 32767 && (b.x0 | b.x1 << 16) && !(b.x1 >> 47 & 1))
|
if (b_exp == 32767 && (b.x0 | b.x1 << 16) && !(b.x1 >> 47 & 1))
|
||||||
return fp3_convert_NaN(f, b_sgn, b);
|
return fp3_convert_NaN(f, b_sgn, b);
|
||||||
|
#endif
|
||||||
// Detect quiet NaNs:
|
// Detect quiet NaNs:
|
||||||
if (a_exp == 32767 && (a.x0 | a.x1 << 16))
|
if (a_exp == 32767 && (a.x0 | a.x1 << 16))
|
||||||
return fp3_convert_NaN(f, a_sgn, a);
|
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 fp3_convert_NaN(f, b_sgn, b);
|
||||||
|
|
||||||
return 0;
|
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)
|
static void f3_unpack(int *sgn, int32_t *exp, u128_t *mnt, long double f)
|
||||||
{
|
{
|
||||||
u128_t x;
|
u128_t x;
|
||||||
memcpy(&x, &f, 16);
|
|
||||||
|
x.f = f;
|
||||||
*sgn = x.x1 >> 63;
|
*sgn = x.x1 >> 63;
|
||||||
*exp = x.x1 >> 48 & 32767;
|
*exp = x.x1 >> 48 & 32767;
|
||||||
x.x1 = x.x1 << 16 >> 16;
|
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;
|
x.x1 |= (uint64_t)1 << 48;
|
||||||
else
|
else
|
||||||
*exp = 1;
|
*exp = 1;
|
||||||
memcpy(mnt, &x, 16);
|
mnt->f = x.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void f3_normalise(int32_t *exp, u128_t *mnt)
|
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);
|
return f3_infinity(sgn);
|
||||||
|
|
||||||
x->x1 = x->x1 << 16 >> 16 | (uint64_t)exp << 48 | (uint64_t)sgn << 63;
|
x->x1 = x->x1 << 16 >> 16 | (uint64_t)exp << 48 | (uint64_t)sgn << 63;
|
||||||
memcpy(&f, x, 16);
|
return x->f;
|
||||||
return f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static long double f3_add(long double fa, long double fb, int neg)
|
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)
|
long double __negtf2(long double f)
|
||||||
{
|
{
|
||||||
u128_t a;
|
((u128_t*)&f)->x1 ^= 1UL << 63;
|
||||||
|
|
||||||
memcpy(&a, &f, 16);
|
|
||||||
a.x1 ^= 1UL << 63;
|
|
||||||
memcpy(&f, &a, 16);
|
|
||||||
|
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
long double __extendsftf2(float f)
|
long double __extendsftf2(float f)
|
||||||
{
|
{
|
||||||
long double fx;
|
|
||||||
u128_t x;
|
u128_t x;
|
||||||
|
u32_t u;
|
||||||
uint32_t a;
|
uint32_t a;
|
||||||
uint64_t aa;
|
uint64_t aa;
|
||||||
memcpy(&a, &f, 4);
|
|
||||||
|
u.f = f, a = u.x;
|
||||||
aa = a;
|
aa = a;
|
||||||
|
|
||||||
x.x0 = 0;
|
x.x0 = 0;
|
||||||
if (!(a << 1))
|
if (!(a << 1))
|
||||||
x.x1 = aa << 32;
|
x.x1 = aa << 32;
|
||||||
@ -411,16 +405,17 @@ long double __extendsftf2(float f)
|
|||||||
} else
|
} else
|
||||||
x.x1 = (aa >> 31 << 63 | ((aa >> 23 & 255) + 16256) << 48 |
|
x.x1 = (aa >> 31 << 63 | ((aa >> 23 & 255) + 16256) << 48 |
|
||||||
aa << 41 >> 16);
|
aa << 41 >> 16);
|
||||||
memcpy(&fx, &x, 16);
|
return x.f;
|
||||||
return fx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
long double __extenddftf2(double f)
|
long double __extenddftf2(double f)
|
||||||
{
|
{
|
||||||
long double fx;
|
|
||||||
u128_t x;
|
u128_t x;
|
||||||
|
u64_t u;
|
||||||
uint64_t a;
|
uint64_t a;
|
||||||
memcpy(&a, &f, 8);
|
|
||||||
|
u.f = f, a = u.x;
|
||||||
|
|
||||||
x.x0 = a << 60;
|
x.x0 = a << 60;
|
||||||
if (!(a << 1))
|
if (!(a << 1))
|
||||||
x.x1 = a;
|
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;
|
x.x1 = a >> 63 << 63 | (15360 - adj + 1) << 48 | a << adj << 12 >> 16;
|
||||||
} else
|
} else
|
||||||
x.x1 = a >> 63 << 63 | ((a >> 52 & 2047) + 15360) << 48 | a << 12 >> 16;
|
x.x1 = a >> 63 << 63 | ((a >> 52 & 2047) + 15360) << 48 | a << 12 >> 16;
|
||||||
memcpy(&fx, &x, 16);
|
return x.f;
|
||||||
return fx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float __trunctfsf2(long double f)
|
float __trunctfsf2(long double f)
|
||||||
@ -444,11 +438,10 @@ float __trunctfsf2(long double f)
|
|||||||
u128_t mnt;
|
u128_t mnt;
|
||||||
int32_t exp;
|
int32_t exp;
|
||||||
int sgn;
|
int sgn;
|
||||||
uint32_t x;
|
u32_t x;
|
||||||
float fx;
|
#define x x.x
|
||||||
|
|
||||||
f3_unpack(&sgn, &exp, &mnt, f);
|
f3_unpack(&sgn, &exp, &mnt, f);
|
||||||
|
|
||||||
if (exp == 32767 && (mnt.x0 | mnt.x1 << 16))
|
if (exp == 32767 && (mnt.x0 | mnt.x1 << 16))
|
||||||
x = 0x7fc00000 | (uint32_t)sgn << 31 | (mnt.x1 >> 25 & 0x007fffff);
|
x = 0x7fc00000 | (uint32_t)sgn << 31 | (mnt.x1 >> 25 & 0x007fffff);
|
||||||
else if (exp > 16510)
|
else if (exp > 16510)
|
||||||
@ -466,8 +459,8 @@ float __trunctfsf2(long double f)
|
|||||||
x += 4;
|
x += 4;
|
||||||
x = ((x >> 2) + (exp << 23)) | (uint32_t)sgn << 31;
|
x = ((x >> 2) + (exp << 23)) | (uint32_t)sgn << 31;
|
||||||
}
|
}
|
||||||
memcpy(&fx, &x, 4);
|
#undef x
|
||||||
return fx;
|
return x.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
double __trunctfdf2(long double f)
|
double __trunctfdf2(long double f)
|
||||||
@ -475,11 +468,10 @@ double __trunctfdf2(long double f)
|
|||||||
u128_t mnt;
|
u128_t mnt;
|
||||||
int32_t exp;
|
int32_t exp;
|
||||||
int sgn;
|
int sgn;
|
||||||
uint64_t x;
|
u64_t x;
|
||||||
double fx;
|
#define x x.x
|
||||||
|
|
||||||
f3_unpack(&sgn, &exp, &mnt, f);
|
f3_unpack(&sgn, &exp, &mnt, f);
|
||||||
|
|
||||||
if (exp == 32767 && (mnt.x0 | mnt.x1 << 16))
|
if (exp == 32767 && (mnt.x0 | mnt.x1 << 16))
|
||||||
x = (0x7ff8000000000000 | (uint64_t)sgn << 63 |
|
x = (0x7ff8000000000000 | (uint64_t)sgn << 63 |
|
||||||
mnt.x1 << 16 >> 12 | mnt.x0 >> 60);
|
mnt.x1 << 16 >> 12 | mnt.x0 >> 60);
|
||||||
@ -498,8 +490,8 @@ double __trunctfdf2(long double f)
|
|||||||
x += 4;
|
x += 4;
|
||||||
x = ((x >> 2) + ((uint64_t)exp << 52)) | (uint64_t)sgn << 63;
|
x = ((x >> 2) + ((uint64_t)exp << 52)) | (uint64_t)sgn << 63;
|
||||||
}
|
}
|
||||||
memcpy(&fx, &x, 8);
|
#undef x
|
||||||
return fx;
|
return x.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t __fixtfsi(long double fa)
|
int32_t __fixtfsi(long double fa)
|
||||||
@ -564,7 +556,6 @@ long double __floatsitf(int32_t a)
|
|||||||
int exp = 16414;
|
int exp = 16414;
|
||||||
uint32_t mnt = a;
|
uint32_t mnt = a;
|
||||||
u128_t x = { 0, 0 };
|
u128_t x = { 0, 0 };
|
||||||
long double f;
|
|
||||||
int i;
|
int i;
|
||||||
if (a) {
|
if (a) {
|
||||||
if (a < 0) {
|
if (a < 0) {
|
||||||
@ -579,8 +570,7 @@ long double __floatsitf(int32_t a)
|
|||||||
x.x1 = ((uint64_t)sgn << 63 | (uint64_t)exp << 48 |
|
x.x1 = ((uint64_t)sgn << 63 | (uint64_t)exp << 48 |
|
||||||
(uint64_t)(mnt << 1) << 16);
|
(uint64_t)(mnt << 1) << 16);
|
||||||
}
|
}
|
||||||
memcpy(&f, &x, 16);
|
return x.f;
|
||||||
return f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
long double __floatditf(int64_t a)
|
long double __floatditf(int64_t a)
|
||||||
@ -589,7 +579,6 @@ long double __floatditf(int64_t a)
|
|||||||
int exp = 16446;
|
int exp = 16446;
|
||||||
uint64_t mnt = a;
|
uint64_t mnt = a;
|
||||||
u128_t x = { 0, 0 };
|
u128_t x = { 0, 0 };
|
||||||
long double f;
|
|
||||||
int i;
|
int i;
|
||||||
if (a) {
|
if (a) {
|
||||||
if (a < 0) {
|
if (a < 0) {
|
||||||
@ -604,8 +593,7 @@ long double __floatditf(int64_t a)
|
|||||||
x.x0 = mnt << 49;
|
x.x0 = mnt << 49;
|
||||||
x.x1 = (uint64_t)sgn << 63 | (uint64_t)exp << 48 | mnt << 1 >> 16;
|
x.x1 = (uint64_t)sgn << 63 | (uint64_t)exp << 48 | mnt << 1 >> 16;
|
||||||
}
|
}
|
||||||
memcpy(&f, &x, 16);
|
return x.f;
|
||||||
return f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
long double __floatunsitf(uint32_t a)
|
long double __floatunsitf(uint32_t a)
|
||||||
@ -613,7 +601,6 @@ long double __floatunsitf(uint32_t a)
|
|||||||
int exp = 16414;
|
int exp = 16414;
|
||||||
uint32_t mnt = a;
|
uint32_t mnt = a;
|
||||||
u128_t x = { 0, 0 };
|
u128_t x = { 0, 0 };
|
||||||
long double f;
|
|
||||||
int i;
|
int i;
|
||||||
if (a) {
|
if (a) {
|
||||||
for (i = 16; i; i >>= 1)
|
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;
|
x.x1 = (uint64_t)exp << 48 | (uint64_t)(mnt << 1) << 16;
|
||||||
}
|
}
|
||||||
memcpy(&f, &x, 16);
|
return x.f;
|
||||||
return f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
long double __floatunditf(uint64_t a)
|
long double __floatunditf(uint64_t a)
|
||||||
@ -643,15 +629,14 @@ long double __floatunditf(uint64_t a)
|
|||||||
x.x0 = mnt << 49;
|
x.x0 = mnt << 49;
|
||||||
x.x1 = (uint64_t)exp << 48 | mnt << 1 >> 16;
|
x.x1 = (uint64_t)exp << 48 | mnt << 1 >> 16;
|
||||||
}
|
}
|
||||||
memcpy(&f, &x, 16);
|
return x.f;
|
||||||
return f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int f3_cmp(long double fa, long double fb)
|
static int f3_cmp(long double fa, long double fb)
|
||||||
{
|
{
|
||||||
u128_t a, b;
|
u128_t a, b;
|
||||||
memcpy(&a, &fa, 16);
|
a.f = fa;
|
||||||
memcpy(&b, &fb, 16);
|
b.f = fb;
|
||||||
return (!(a.x0 | a.x1 << 1 | b.x0 | b.x1 << 1) ? 0 :
|
return (!(a.x0 | a.x1 << 1 | b.x0 | b.x1 << 1) ? 0 :
|
||||||
((a.x1 << 1 >> 49 == 0x7fff && (a.x0 | a.x1 << 16)) ||
|
((a.x1 << 1 >> 49 == 0x7fff && (a.x0 | a.x1 << 16)) ||
|
||||||
(b.x1 << 1 >> 49 == 0x7fff && (b.x0 | b.x1 << 16))) ? 2 :
|
(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 */
|
/* 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 ? */
|
/* XXX: use gcc/tcc intrinsic ? */
|
||||||
#if defined __i386__
|
|
||||||
#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
|
#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
|
||||||
__asm__ ("subl %5,%1\n\tsbbl %3,%0" \
|
__asm__ ("subl %5,%1\n\tsbbl %3,%0" \
|
||||||
: "=r" ((USItype) (sh)), \
|
: "=r" ((USItype) (sh)), \
|
||||||
@ -139,9 +138,6 @@ union float_long {
|
|||||||
: "=r" (__cbtmp) : "rm" ((USItype) (x))); \
|
: "=r" (__cbtmp) : "rm" ((USItype) (x))); \
|
||||||
(count) = __cbtmp ^ 31; \
|
(count) = __cbtmp ^ 31; \
|
||||||
} while (0)
|
} while (0)
|
||||||
#else
|
|
||||||
#error unsupported CPU type
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* most of this code is taken from libgcc2.c from gcc */
|
/* 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
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* !__x86_64__ */
|
#endif /* __i386__ */
|
||||||
|
|
||||||
/* XXX: fix tcc's code generator to do this instead */
|
/* XXX: fix tcc's code generator to do this instead */
|
||||||
float __floatundisf(unsigned long long a)
|
float __floatundisf(unsigned long long a)
|
||||||
@ -625,11 +621,3 @@ long long __fixxfdi (long double a1)
|
|||||||
return s ? ret : -ret;
|
return s ? ret : -ret;
|
||||||
}
|
}
|
||||||
#endif /* !ARM */
|
#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
|
||||||
163
libtcc.c
163
libtcc.c
@ -124,8 +124,15 @@ static void tcc_add_systemdir(TCCState *s)
|
|||||||
tcc_add_library_path(s, normalize_slashes(buf));
|
tcc_add_library_path(s, normalize_slashes(buf));
|
||||||
}
|
}
|
||||||
#endif
|
#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
|
#endif
|
||||||
|
|
||||||
/********************************************************/
|
/********************************************************/
|
||||||
|
|
||||||
PUB_FUNC void tcc_enter_state(TCCState *s1)
|
PUB_FUNC void tcc_enter_state(TCCState *s1)
|
||||||
@ -245,7 +252,7 @@ static void *default_reallocator(void *ptr, unsigned long size)
|
|||||||
else {
|
else {
|
||||||
ptr1 = realloc(ptr, size);
|
ptr1 = realloc(ptr, size);
|
||||||
if (!ptr1) {
|
if (!ptr1) {
|
||||||
fprintf(stderr, "memory full\n");
|
fprintf(stderr, "tcc: memory full\n");
|
||||||
exit (1);
|
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. */
|
/* 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
|
/* Here we enter the code section where we use the global variables for
|
||||||
parsing and code generation (tccpp.c, tccgen.c, <target>-gen.c).
|
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) {
|
if (fd == -1) {
|
||||||
int len = strlen(str);
|
int len = strlen(str);
|
||||||
tcc_open_bf(s1, filename ? filename : "<string>", len);
|
tcc_open_bf(s1, "<string>", len);
|
||||||
memcpy(file->buffer, str, len);
|
memcpy(file->buffer, str, len);
|
||||||
if (s1->do_debug && filename) {
|
|
||||||
FILE *fp = fopen(filename, "w");
|
|
||||||
|
|
||||||
if (fp) {
|
|
||||||
fputs(str, fp);
|
|
||||||
fclose(fp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
tcc_open_bf(s1, str, 0);
|
tcc_open_bf(s1, str, 0);
|
||||||
file->fd = fd;
|
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)
|
LIBTCCAPI int tcc_compile_string(TCCState *s, const char *str)
|
||||||
{
|
{
|
||||||
return tcc_compile(s, s->filetype, str, -1, NULL);
|
return tcc_compile(s, s->filetype, str, -1);
|
||||||
}
|
|
||||||
|
|
||||||
LIBTCCAPI int tcc_compile_string_file(TCCState *s, const char *str, const char *filename)
|
|
||||||
{
|
|
||||||
return tcc_compile(s, s->filetype, str, -1, filename);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* define a preprocessor symbol. value can be NULL, sym can be "sym=val" */
|
/* 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 */
|
#if defined TCC_TARGET_MACHO /* || defined TCC_TARGET_PE */
|
||||||
s->leading_underscore = 1;
|
s->leading_underscore = 1;
|
||||||
#endif
|
#endif
|
||||||
#ifdef TCC_TARGET_ARM
|
#ifdef TCC_ARM_HARDFLOAT
|
||||||
s->float_abi = ARM_FLOAT_ABI;
|
s->float_abi = ARM_HARD_FLOAT;
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_NEW_DTAGS
|
#ifdef CONFIG_NEW_DTAGS
|
||||||
s->enable_new_dtags = 1;
|
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 */
|
/* allow linking with system dll's directly */
|
||||||
tcc_add_systemdir(s);
|
tcc_add_systemdir(s);
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
#elif defined TCC_TARGET_MACHO
|
#elif defined TCC_TARGET_MACHO
|
||||||
# ifdef TCC_IS_NATIVE
|
# ifdef TCC_IS_NATIVE
|
||||||
tcc_add_macos_sdkpath(s);
|
tcc_add_macos_sdkpath(s);
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
#else
|
#else
|
||||||
/* paths for crt objects */
|
/* paths for crt objects */
|
||||||
tcc_split_path(s, &s->crt_paths, &s->nb_crt_paths, CONFIG_TCC_CRTPREFIX);
|
tcc_split_path(s, &s->crt_paths, &s->nb_crt_paths, CONFIG_TCC_CRTPREFIX);
|
||||||
if (output_type != TCC_OUTPUT_MEMORY && !s->nostdlib)
|
if (output_type != TCC_OUTPUT_MEMORY && !s->nostdlib)
|
||||||
tccelf_add_crtbegin(s);
|
tccelf_add_crtbegin(s); /* may produce errors */
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return s->nb_errors ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
LIBTCCAPI int tcc_add_include_path(TCCState *s, const char *pathname)
|
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);
|
return tcc_add_binary(s1, flags, filename, fd);
|
||||||
|
|
||||||
dynarray_add(&s1->target_deps, &s1->nb_target_deps, tcc_strdup(filename));
|
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)
|
LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename)
|
||||||
@ -1368,10 +1364,11 @@ struct lopt {
|
|||||||
/* match linker option */
|
/* match linker option */
|
||||||
static int link_option(struct lopt *o, const char *q)
|
static int link_option(struct lopt *o, const char *q)
|
||||||
{
|
{
|
||||||
const char *p = o->opt;
|
const char *p;
|
||||||
int c;
|
int c;
|
||||||
|
redo:
|
||||||
/* there should be 1 or 2 dashes */
|
/* there should be 1 or 2 dashes */
|
||||||
|
p = o->opt;
|
||||||
if (*p++ != '-')
|
if (*p++ != '-')
|
||||||
return 0;
|
return 0;
|
||||||
if (*p == '-')
|
if (*p == '-')
|
||||||
@ -1384,16 +1381,22 @@ static int link_option(struct lopt *o, const char *q)
|
|||||||
goto succ; /* -Wl,-opt=arg */
|
goto succ; /* -Wl,-opt=arg */
|
||||||
++q;
|
++q;
|
||||||
}
|
}
|
||||||
if (c == '=' || c == ':') {
|
if (*p == '\0') {
|
||||||
if (*p == '\0') {
|
if (c == '|')
|
||||||
|
goto succ;
|
||||||
|
if (c == '=' || c == ':') {
|
||||||
if (o->s->link_optind + 1 < o->s->link_argc) {
|
if (o->s->link_optind + 1 < o->s->link_argc) {
|
||||||
p = o->s->link_argv[++o->s->link_optind];
|
p = o->s->link_argv[++o->s->link_optind];
|
||||||
goto succ; /* -Wl,-opt,arg */
|
goto succ; /* -Wl,-opt,arg */
|
||||||
}
|
}
|
||||||
o->match = 1; /* -Wl,-opt -Wl,arg */
|
o->match = 1; /* -Wl,-opt -Wl,arg */
|
||||||
} else if (c == ':')
|
return 0;
|
||||||
goto succ; /* -Wl,-Iarg */
|
}
|
||||||
}
|
} else if (c == ':')
|
||||||
|
goto succ; /* -Wl,-Iarg */
|
||||||
|
while (*q)
|
||||||
|
if (*q++ == '|')
|
||||||
|
goto redo;
|
||||||
return 0;
|
return 0;
|
||||||
succ:
|
succ:
|
||||||
o->arg = p;
|
o->arg = p;
|
||||||
@ -1403,6 +1406,20 @@ succ:
|
|||||||
|
|
||||||
static void args_parser_add_file(TCCState *s, const char* filename, int filetype);
|
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 */
|
/* set linker options */
|
||||||
static int tcc_set_linker(TCCState *s, const char *optarg)
|
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;
|
s->symbolic = 1;
|
||||||
} else if (link_option(&o, "nostdlib")) {
|
} else if (link_option(&o, "nostdlib")) {
|
||||||
s->nostdlib_paths = 1;
|
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);
|
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->text_addr = strtoull(o.arg, &end, 16);
|
||||||
s->has_text_addr = 1;
|
s->has_text_addr = 1;
|
||||||
} else if (link_option(&o, "init=")) {
|
} else if (link_option(&o, "init=")) {
|
||||||
@ -1452,18 +1469,17 @@ static int tcc_set_linker(TCCState *s, const char *optarg)
|
|||||||
#endif
|
#endif
|
||||||
else
|
else
|
||||||
goto err;
|
goto err;
|
||||||
} else if (link_option(&o, "export-all-symbols")
|
} else if (link_option(&o, "export-all-symbols|export-dynamic|E")) {
|
||||||
|| link_option(&o, "export-dynamic")) {
|
|
||||||
s->rdynamic = 1;
|
s->rdynamic = 1;
|
||||||
} else if (link_option(&o, "rpath=")) {
|
} else if (link_option(&o, "rpath=")) {
|
||||||
tcc_concat_str(&s->rpath, o.arg, ':');
|
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);
|
tcc_set_str(&s->elfint, o.arg);
|
||||||
} else if (link_option(&o, "enable-new-dtags")) {
|
} else if (link_option(&o, "enable-new-dtags")) {
|
||||||
s->enable_new_dtags = 1;
|
s->enable_new_dtags = 1;
|
||||||
} else if (link_option(&o, "section-alignment=")) {
|
} else if (link_option(&o, "section-alignment=")) {
|
||||||
s->section_align = strtoul(o.arg, &end, 16);
|
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);
|
tcc_set_str(&s->soname, o.arg);
|
||||||
} else if (link_option(&o, "whole-archive")) {
|
} else if (link_option(&o, "whole-archive")) {
|
||||||
s->filetype |= AFF_WHOLE_ARCHIVE;
|
s->filetype |= AFF_WHOLE_ARCHIVE;
|
||||||
@ -1473,7 +1489,31 @@ static int tcc_set_linker(TCCState *s, const char *optarg)
|
|||||||
s->znodelete = 1;
|
s->znodelete = 1;
|
||||||
#ifdef TCC_TARGET_PE
|
#ifdef TCC_TARGET_PE
|
||||||
} else if (link_option(&o, "large-address-aware")) {
|
} 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=")) {
|
} else if (link_option(&o, "file-alignment=")) {
|
||||||
s->pe_file_align = strtoul(o.arg, &end, 16);
|
s->pe_file_align = strtoul(o.arg, &end, 16);
|
||||||
} else if (link_option(&o, "stack=")) {
|
} else if (link_option(&o, "stack=")) {
|
||||||
@ -1585,30 +1625,6 @@ enum {
|
|||||||
#define TCC_OPTION_HAS_ARG 0x0001
|
#define TCC_OPTION_HAS_ARG 0x0001
|
||||||
#define TCC_OPTION_NOSEP 0x0002 /* cannot have space before option and arg */
|
#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[] = {
|
static const TCCOption tcc_options[] = {
|
||||||
{ "h", TCC_OPTION_HELP, 0 },
|
{ "h", TCC_OPTION_HELP, 0 },
|
||||||
{ "-help", 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;
|
++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 */
|
/* using * to argc/argv to let "tcc -ar" benefit from @listfile expansion */
|
||||||
PUB_FUNC int tcc_parse_args(TCCState *s, int *pargc, char ***pargv)
|
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;
|
s->float_abi = ARM_HARD_FLOAT;
|
||||||
else
|
else
|
||||||
return tcc_error_noabort("unsupported float abi '%s'", optarg);
|
return tcc_error_noabort("unsupported float abi '%s'", optarg);
|
||||||
break;
|
continue;
|
||||||
#endif
|
#endif
|
||||||
case TCC_OPTION_m:
|
case TCC_OPTION_m:
|
||||||
if (set_flag(s, options_m, optarg) < 0) {
|
if (set_flag(s, options_m, optarg) < 0) {
|
||||||
@ -2217,7 +2212,7 @@ unsupported_option:
|
|||||||
if (run) {
|
if (run) {
|
||||||
if (*run && tcc_set_options(s, run) < 0)
|
if (*run && tcc_set_options(s, run) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
x = 0;
|
x = 0, r = 0;
|
||||||
goto extra_action;
|
goto extra_action;
|
||||||
}
|
}
|
||||||
if (!empty)
|
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);
|
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))
|
#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 */
|
/* 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);
|
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*);
|
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"}
|
|
||||||
'
|
|
||||||
499
riscv64-asm.c
499
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)
|
if ((int) op->e.v >= -0x1000 && (int) op->e.v < 0x1000)
|
||||||
op->type = OP_IM12S;
|
op->type = OP_IM12S;
|
||||||
} else if (op->e.sym->type.t & (VT_EXTERN | VT_STATIC)) {
|
} else if (op->e.sym->type.t & (VT_EXTERN | VT_STATIC)) {
|
||||||
greloca(cur_text_section, op->e.sym, ind, R_RISCV_BRANCH, 0);
|
/* For extern/static symbols, always use far-branch expansion
|
||||||
|
since linker relaxation (R_RISCV_RELAX) is not implemented. */
|
||||||
/* XXX: Implement far branches */
|
op->type = OP_IM32;
|
||||||
|
|
||||||
op->type = OP_IM12S;
|
|
||||||
op->e.v = 0;
|
op->e.v = 0;
|
||||||
} else {
|
} else {
|
||||||
expect("operand");
|
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);
|
asm_emit_i(token, (0x4 << 2) | 3 | (4 << 12), &ops[0], &ops[1], &imm);
|
||||||
return;
|
return;
|
||||||
case TOK_ASM_neg:
|
case TOK_ASM_neg:
|
||||||
/* sub rd, x0, rs */
|
/* sub rd, x0, rs2 */
|
||||||
imm.e.v = 1;
|
asm_emit_r(token, (0xC << 2) | 3 | (32 << 25), &ops[0], &zero, &ops[1]);
|
||||||
asm_emit_i(token, (0x4 << 2) | 3 | (4 << 12), &ops[0], &zero, &imm);
|
|
||||||
return;
|
return;
|
||||||
case TOK_ASM_negw:
|
case TOK_ASM_negw:
|
||||||
/* sub rd, x0, rs */
|
/* subw rd, x0, rs2 */
|
||||||
imm.e.v = 1;
|
asm_emit_r(token, (0xE << 2) | 3 | (32 << 25), &ops[0], &zero, &ops[1]);
|
||||||
asm_emit_i(token, (0x4 << 2) | 3 | (4 << 12), &ops[0], &zero, &imm);
|
|
||||||
return;
|
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:
|
case TOK_ASM_jump:
|
||||||
/* auipc x5, 0 */
|
/* auipc x5, 0 */
|
||||||
asm_emit_opcode(3 | (5 << 2) | ENCODE_RD(5));
|
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]);
|
asm_emit_f(token, 0x53 | (4 << 27) | (0 << 25) | (2 << 12), &ops[0], &ops[1], &ops[1]);
|
||||||
return;
|
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:
|
case TOK_ASM_csrs:
|
||||||
/* csrrs x0, csr, rs */
|
/* csrrs x0, csr, rs */
|
||||||
asm_emit_opcode(0x73 | (2 << 12) | (ops[0].e.v << 20) | ENCODE_RS1(ops[1].reg));
|
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 */
|
/* csrrw rd, fcsr, rs */
|
||||||
asm_emit_opcode(0x73 | (1 << 12) | (3 << 20) | ENCODE_RD(ops[0].reg) | ENCODE_RS1(ops[1].reg));
|
asm_emit_opcode(0x73 | (1 << 12) | (3 << 20) | ENCODE_RD(ops[0].reg) | ENCODE_RS1(ops[1].reg));
|
||||||
return;
|
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:
|
default:
|
||||||
expect("binary instruction");
|
expect("binary instruction");
|
||||||
}
|
}
|
||||||
@ -1213,6 +1254,30 @@ static void asm_ternary_opcode(TCCState *s1, int token)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
/* F/D extension */
|
/* 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:
|
case TOK_ASM_fsgnj_d:
|
||||||
asm_emit_f(token, 0x53 | (4 << 27) | (1 << 25) | (0 << 12), ops, ops + 1, ops + 2);
|
asm_emit_f(token, 0x53 | (4 << 27) | (1 << 25) | (0 << 12), ops, ops + 1, ops + 2);
|
||||||
return;
|
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);
|
asm_emit_f(token, 0x53 | (5 << 27) | (0 << 25) | (0 << 12), ops, ops + 1, ops + 2);
|
||||||
return;
|
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:
|
default:
|
||||||
expect("ternary instruction");
|
expect("ternary instruction");
|
||||||
}
|
}
|
||||||
@ -1275,56 +1360,205 @@ static void asm_atomic_opcode(TCCState *s1, int token)
|
|||||||
|
|
||||||
switch(token){
|
switch(token){
|
||||||
case TOK_ASM_lr_w:
|
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;
|
break;
|
||||||
case TOK_ASM_lr_w_aq:
|
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;
|
break;
|
||||||
case TOK_ASM_lr_w_rl:
|
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;
|
break;
|
||||||
case TOK_ASM_lr_w_aqrl:
|
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;
|
break;
|
||||||
|
|
||||||
case TOK_ASM_lr_d:
|
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;
|
break;
|
||||||
case TOK_ASM_lr_d_aq:
|
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;
|
break;
|
||||||
case TOK_ASM_lr_d_rl:
|
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;
|
break;
|
||||||
case TOK_ASM_lr_d_aqrl:
|
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;
|
break;
|
||||||
|
|
||||||
case TOK_ASM_sc_w:
|
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;
|
break;
|
||||||
case TOK_ASM_sc_w_aq:
|
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;
|
break;
|
||||||
case TOK_ASM_sc_w_rl:
|
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;
|
break;
|
||||||
case TOK_ASM_sc_w_aqrl:
|
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;
|
break;
|
||||||
|
|
||||||
case TOK_ASM_sc_d:
|
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;
|
break;
|
||||||
case TOK_ASM_sc_d_aq:
|
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;
|
break;
|
||||||
case TOK_ASM_sc_d_rl:
|
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;
|
break;
|
||||||
case TOK_ASM_sc_d_aqrl:
|
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;
|
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) {
|
if (rs2->type != OP_REG) {
|
||||||
tcc_error("'%s': Expected destination operand that is a register", get_tok_str(token, NULL));
|
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) {
|
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));
|
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));
|
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)
|
ST_FUNC void asm_opcode(TCCState *s1, int token)
|
||||||
{
|
{
|
||||||
switch (token) {
|
switch (token) {
|
||||||
@ -1437,6 +1747,30 @@ ST_FUNC void asm_opcode(TCCState *s1, int token)
|
|||||||
asm_binary_opcode(s1, token);
|
asm_binary_opcode(s1, token);
|
||||||
return;
|
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_lb:
|
||||||
case TOK_ASM_lh:
|
case TOK_ASM_lh:
|
||||||
case TOK_ASM_lw:
|
case TOK_ASM_lw:
|
||||||
@ -1513,12 +1847,26 @@ ST_FUNC void asm_opcode(TCCState *s1, int token)
|
|||||||
case TOK_ASM_csrrw:
|
case TOK_ASM_csrrw:
|
||||||
case TOK_ASM_csrrwi:
|
case TOK_ASM_csrrwi:
|
||||||
/* F/D extension */
|
/* 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_d:
|
||||||
case TOK_ASM_fsgnj_s:
|
case TOK_ASM_fsgnj_s:
|
||||||
case TOK_ASM_fmax_s:
|
case TOK_ASM_fmax_s:
|
||||||
case TOK_ASM_fmax_d:
|
case TOK_ASM_fmax_d:
|
||||||
case TOK_ASM_fmin_s:
|
case TOK_ASM_fmin_s:
|
||||||
case TOK_ASM_fmin_d:
|
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);
|
asm_ternary_opcode(s1, token);
|
||||||
return;
|
return;
|
||||||
case TOK_ASM_fmadd_d:
|
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_not:
|
||||||
case TOK_ASM_neg:
|
case TOK_ASM_neg:
|
||||||
case TOK_ASM_negw:
|
case TOK_ASM_negw:
|
||||||
|
case TOK_ASM_sext_w:
|
||||||
case TOK_ASM_fabs_s:
|
case TOK_ASM_fabs_s:
|
||||||
case TOK_ASM_fabs_d:
|
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_csrc:
|
||||||
case TOK_ASM_csrs:
|
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_fsrm:
|
||||||
case TOK_ASM_fscsr:
|
case TOK_ASM_fscsr:
|
||||||
asm_binary_opcode(s1, token);
|
asm_binary_opcode(s1, token);
|
||||||
@ -1660,7 +2018,83 @@ ST_FUNC void asm_opcode(TCCState *s1, int token)
|
|||||||
case TOK_ASM_sc_d_aq:
|
case TOK_ASM_sc_d_aq:
|
||||||
case TOK_ASM_sc_d_rl:
|
case TOK_ASM_sc_d_rl:
|
||||||
case TOK_ASM_sc_d_aqrl:
|
case TOK_ASM_sc_d_aqrl:
|
||||||
asm_atomic_opcode(s1, token);
|
/* 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;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -1839,9 +2273,8 @@ ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands,
|
|||||||
} else {
|
} else {
|
||||||
load(tcc_ireg(op->reg), op->vt);
|
load(tcc_ireg(op->reg), op->vt);
|
||||||
}
|
}
|
||||||
if (op->is_llong) {
|
/* RV64: long long fits in a single 64-bit register;
|
||||||
tcc_error("long long not implemented");
|
the load/store above already handles it correctly */
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1869,9 +2302,7 @@ ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands,
|
|||||||
} else {
|
} else {
|
||||||
store(tcc_ireg(op->reg), op->vt);
|
store(tcc_ireg(op->reg), op->vt);
|
||||||
}
|
}
|
||||||
if (op->is_llong) {
|
/* RV64: long long fits in a single 64-bit register */
|
||||||
tcc_error("long long not implemented");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,6 +30,10 @@
|
|||||||
|
|
||||||
#define CHAR_IS_UNSIGNED
|
#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
|
#else
|
||||||
#define USING_GLOBALS
|
#define USING_GLOBALS
|
||||||
#include "tcc.h"
|
#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) {
|
if (sv->r & VT_SYM) {
|
||||||
Sym label = {0};
|
Sym label = {0};
|
||||||
assert(v == VT_CONST);
|
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
|
if (sv->sym->type.t & VT_STATIC) { // XXX do this per linker relax
|
||||||
greloca(cur_text_section, sv->sym, ind,
|
greloca(cur_text_section, sv->sym, ind,
|
||||||
R_RISCV_PCREL_HI20, sv->c.i);
|
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)
|
EI(opcode, func3, rr, br, fc); // l[bhwd][u] / fl[wd] RR, fc(BR)
|
||||||
} else if (v == VT_CONST) {
|
} else if (v == VT_CONST) {
|
||||||
int rb = 0, do32bit = 8, zext = 0;
|
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) {
|
if (fr & VT_SYM) {
|
||||||
rb = load_symofs(r, sv, 0, &fc);
|
rb = load_symofs(r, sv, 0, &fc);
|
||||||
do32bit = 0;
|
do32bit = 0;
|
||||||
}
|
}
|
||||||
if (is_float(sv->type.t) && bt != VT_LDOUBLE)
|
|
||||||
tcc_error("unimp: load(float)");
|
|
||||||
if (do32bit && fc != sv->c.i) {
|
if (do32bit && fc != sv->c.i) {
|
||||||
int64_t si = sv->c.i;
|
int64_t si = sv->c.i;
|
||||||
si >>= 32;
|
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)
|
ST_FUNC void gen_cvt_sxtw(void)
|
||||||
{
|
{
|
||||||
/* XXX on risc-v the registers are usually sign-extended already.
|
int r = ireg(gv(RC_INT));
|
||||||
Let's try to not do anything here. */
|
EI(0x1b, 0, r, r, 0); // addiw r, r, 0
|
||||||
}
|
}
|
||||||
|
|
||||||
ST_FUNC void gen_cvt_itof(int t)
|
ST_FUNC void gen_cvt_itof(int t)
|
||||||
@ -1431,4 +1485,12 @@ ST_FUNC void gen_vla_alloc(CType *type, int align)
|
|||||||
}
|
}
|
||||||
#endif
|
#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
|
#endif
|
||||||
|
|||||||
@ -53,6 +53,8 @@ ST_FUNC int code_reloc (int reloc_type)
|
|||||||
case R_RISCV_64:
|
case R_RISCV_64:
|
||||||
case R_RISCV_SET_ULEB128:
|
case R_RISCV_SET_ULEB128:
|
||||||
case R_RISCV_SUB_ULEB128:
|
case R_RISCV_SUB_ULEB128:
|
||||||
|
case R_RISCV_TPREL_HI20:
|
||||||
|
case R_RISCV_TPREL_LO12_I:
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case R_RISCV_CALL_PLT:
|
case R_RISCV_CALL_PLT:
|
||||||
@ -101,6 +103,10 @@ ST_FUNC int gotplt_entry_type (int reloc_type)
|
|||||||
|
|
||||||
case R_RISCV_GOT_HI20:
|
case R_RISCV_GOT_HI20:
|
||||||
return ALWAYS_GOTPLT_ENTRY;
|
return ALWAYS_GOTPLT_ENTRY;
|
||||||
|
|
||||||
|
case R_RISCV_TPREL_HI20:
|
||||||
|
case R_RISCV_TPREL_LO12_I:
|
||||||
|
return NO_GOTPLT_ENTRY;
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -175,37 +181,23 @@ ST_FUNC void relocate_plt(TCCState *s1)
|
|||||||
|
|
||||||
static void riscv64_record_pcrel_hi(TCCState *s1, addr_t addr, addr_t val)
|
static void riscv64_record_pcrel_hi(TCCState *s1, addr_t addr, addr_t val)
|
||||||
{
|
{
|
||||||
int n = s1->nb_pcrel_hi_entries;
|
struct pcrel_hi *entry = tcc_malloc(sizeof *entry);
|
||||||
if (n >= s1->alloc_pcrel_hi_entries) {
|
entry->addr = addr;
|
||||||
int new_alloc = s1->alloc_pcrel_hi_entries ? s1->alloc_pcrel_hi_entries * 2 : 64;
|
entry->val = val;
|
||||||
s1->pcrel_hi_entries = tcc_realloc(s1->pcrel_hi_entries,
|
dynarray_add(&s1->pcrel_hi_entries, &s1->nb_pcrel_hi_entries, entry);
|
||||||
new_alloc * sizeof(*s1->pcrel_hi_entries));
|
|
||||||
s1->alloc_pcrel_hi_entries = new_alloc;
|
|
||||||
}
|
|
||||||
s1->pcrel_hi_entries[n].addr = addr;
|
|
||||||
s1->pcrel_hi_entries[n].val = val;
|
|
||||||
s1->nb_pcrel_hi_entries = n + 1;
|
|
||||||
last_hi.addr = addr;
|
|
||||||
last_hi.val = val;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int riscv64_lookup_pcrel_hi(TCCState *s1, addr_t hi_addr, addr_t *hi_val)
|
static int riscv64_lookup_pcrel_hi(TCCState *s1, addr_t hi_addr, addr_t *hi_val)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct pcrel_hi *entry;
|
for (i = s1->nb_pcrel_hi_entries; i > 0; ) {
|
||||||
if (s1->nb_pcrel_hi_entries && hi_addr == last_hi.addr) {
|
struct pcrel_hi *entry = s1->pcrel_hi_entries[--i];
|
||||||
*hi_val = last_hi.val;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
for (i = s1->nb_pcrel_hi_entries - 1; i >= 0; --i) {
|
|
||||||
entry = &s1->pcrel_hi_entries[i];
|
|
||||||
if (entry->addr == hi_addr) {
|
if (entry->addr == hi_addr) {
|
||||||
last_hi = *entry;
|
|
||||||
*hi_val = entry->val;
|
*hi_val = entry->val;
|
||||||
return 1;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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,
|
ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
|
||||||
@ -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);
|
printf("PCREL_LO12_I: val=%lx addr=%lx\n", (long)val, (long)addr);
|
||||||
#endif
|
#endif
|
||||||
addr = val;
|
addr = val;
|
||||||
if (!riscv64_lookup_pcrel_hi(s1, addr, &val))
|
riscv64_lookup_pcrel_hi(s1, addr, &val);
|
||||||
tcc_error_noabort("unsupported hi/lo pcrel reloc scheme");
|
|
||||||
write32le(ptr, (read32le(ptr) & 0xfffff)
|
write32le(ptr, (read32le(ptr) & 0xfffff)
|
||||||
| (((val - addr) & 0xfff) << 20));
|
| (((val - addr) & 0xfff) << 20));
|
||||||
return;
|
return;
|
||||||
case R_RISCV_PCREL_LO12_S:
|
case R_RISCV_PCREL_LO12_S:
|
||||||
addr = val;
|
addr = val;
|
||||||
if (!riscv64_lookup_pcrel_hi(s1, addr, &val))
|
riscv64_lookup_pcrel_hi(s1, addr, &val);
|
||||||
tcc_error_noabort("unsupported hi/lo pcrel reloc scheme");
|
|
||||||
off32 = val - addr;
|
off32 = val - addr;
|
||||||
write32le(ptr, (read32le(ptr) & ~0xfe000f80)
|
write32le(ptr, (read32le(ptr) & ~0xfe000f80)
|
||||||
| ((off32 & 0xfe0) << 20)
|
| ((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:
|
case R_RISCV_COPY:
|
||||||
/* XXX */
|
/* XXX */
|
||||||
return;
|
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:
|
default:
|
||||||
fprintf(stderr, "FIXME: handle reloc type %x at %x [%p] to %x\n",
|
fprintf(stderr, "FIXME: handle reloc type %x at %x [%p] to %x\n",
|
||||||
|
|||||||
126
riscv64-tok.h
126
riscv64-tok.h
@ -270,6 +270,14 @@
|
|||||||
/* enough implemented for musl */
|
/* enough implemented for musl */
|
||||||
DEF_ASM_WITH_SUFFIX(fsgnj, s)
|
DEF_ASM_WITH_SUFFIX(fsgnj, s)
|
||||||
DEF_ASM_WITH_SUFFIX(fsgnj, d)
|
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, s)
|
||||||
DEF_ASM_WITH_SUFFIX(fmadd, d)
|
DEF_ASM_WITH_SUFFIX(fmadd, d)
|
||||||
DEF_ASM_WITH_SUFFIX(fmax, s)
|
DEF_ASM_WITH_SUFFIX(fmax, s)
|
||||||
@ -279,7 +287,35 @@
|
|||||||
DEF_ASM_WITH_SUFFIX(fsqrt, s)
|
DEF_ASM_WITH_SUFFIX(fsqrt, s)
|
||||||
DEF_ASM_WITH_SUFFIX(fsqrt, d)
|
DEF_ASM_WITH_SUFFIX(fsqrt, d)
|
||||||
|
|
||||||
/* "C" Extension for Compressed Instructions, V2.0 */
|
/* 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)
|
DEF_ASM_WITH_SUFFIX(c, nop)
|
||||||
/* Loads */
|
/* Loads */
|
||||||
DEF_ASM_WITH_SUFFIX(c, li)
|
DEF_ASM_WITH_SUFFIX(c, li)
|
||||||
@ -464,7 +500,93 @@
|
|||||||
DEF_ASM_WITH_SUFFIXES(sc, d, rl)
|
DEF_ASM_WITH_SUFFIXES(sc, d, rl)
|
||||||
DEF_ASM_WITH_SUFFIXES(sc, d, aqrl)
|
DEF_ASM_WITH_SUFFIXES(sc, d, aqrl)
|
||||||
|
|
||||||
/* `fence` arguments */
|
/* "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 */
|
/* NOTE: Order is important */
|
||||||
DEF_ASM_FENCE(w)
|
DEF_ASM_FENCE(w)
|
||||||
DEF_ASM_FENCE(r)
|
DEF_ASM_FENCE(r)
|
||||||
|
|||||||
@ -386,6 +386,15 @@ Set type for PE (Windows) executables.
|
|||||||
@item -Wl,-[Ttext=# | section-alignment=# | file-alignment=# | image-base=# | stack=#]
|
@item -Wl,-[Ttext=# | section-alignment=# | file-alignment=# | image-base=# | stack=#]
|
||||||
Modify executable layout.
|
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
|
@item -Wl,-Bsymbolic
|
||||||
Set DT_SYMBOLIC tag.
|
Set DT_SYMBOLIC tag.
|
||||||
|
|
||||||
|
|||||||
28
tcc.c
28
tcc.c
@ -35,7 +35,7 @@ static const char help[] =
|
|||||||
"General options:\n"
|
"General options:\n"
|
||||||
" -c compile only - generate an object file\n"
|
" -c compile only - generate an object file\n"
|
||||||
" -o outfile set output filename\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"
|
" -fflag set or reset (with 'no-' prefix) 'flag' (see tcc -hh)\n"
|
||||||
" -Wwarning set or reset (with 'no-' prefix) 'warning' (see tcc -hh)\n"
|
" -Wwarning set or reset (with 'no-' prefix) 'warning' (see tcc -hh)\n"
|
||||||
" -w disable all warnings\n"
|
" -w disable all warnings\n"
|
||||||
@ -105,6 +105,7 @@ static const char help2[] =
|
|||||||
" -static link to static libraries (not recommended)\n"
|
" -static link to static libraries (not recommended)\n"
|
||||||
" -dumpversion print version\n"
|
" -dumpversion print version\n"
|
||||||
" -print-search-dirs print search paths\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"
|
" -dt with -run/-E: auto-define 'test_...' macros\n"
|
||||||
"Ignored options:\n"
|
"Ignored options:\n"
|
||||||
" -arch -C --param -pedantic -pipe -s -traditional\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);
|
printf("libtcc1:\n %s/%s\n", s->library_paths[0], CONFIG_TCC_CROSSPREFIX TCC_LIBTCC1);
|
||||||
#ifdef TCC_TARGET_UNIX
|
#ifdef TCC_TARGET_UNIX
|
||||||
print_dirs("crt", s->crt_paths, s->nb_crt_paths);
|
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
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -293,7 +294,7 @@ int main(int argc, char **argv)
|
|||||||
const char *first_file;
|
const char *first_file;
|
||||||
int argc0 = argc;
|
int argc0 = argc;
|
||||||
char **argv0 = argv;
|
char **argv0 = argv;
|
||||||
FILE *ppfp = stdout;
|
FILE *ppfp = NULL;
|
||||||
|
|
||||||
redo:
|
redo:
|
||||||
argc = argc0, argv = argv0;
|
argc = argc0, argv = argv0;
|
||||||
@ -335,7 +336,7 @@ redo:
|
|||||||
tcc_error_noabort("no input files");
|
tcc_error_noabort("no input files");
|
||||||
} else if (s->output_type == TCC_OUTPUT_PREPROCESS) {
|
} else if (s->output_type == TCC_OUTPUT_PREPROCESS) {
|
||||||
if (s->outfile && 0!=strcmp("-",s->outfile)) {
|
if (s->outfile && 0!=strcmp("-",s->outfile)) {
|
||||||
ppfp = fopen(s->outfile, "wb");
|
ppfp = tcc_fopen(s->outfile, "wb");
|
||||||
if (!ppfp)
|
if (!ppfp)
|
||||||
tcc_error_noabort("could not write '%s'", s->outfile);
|
tcc_error_noabort("could not write '%s'", s->outfile);
|
||||||
}
|
}
|
||||||
@ -354,8 +355,9 @@ redo:
|
|||||||
set_environment(s);
|
set_environment(s);
|
||||||
if (s->output_type == 0)
|
if (s->output_type == 0)
|
||||||
s->output_type = TCC_OUTPUT_EXE;
|
s->output_type = TCC_OUTPUT_EXE;
|
||||||
tcc_set_output_type(s, s->output_type);
|
ret = tcc_set_output_type(s, s->output_type);
|
||||||
s->ppfp = ppfp;
|
if (ppfp)
|
||||||
|
s->ppfp = ppfp;
|
||||||
|
|
||||||
if ((s->output_type == TCC_OUTPUT_MEMORY
|
if ((s->output_type == TCC_OUTPUT_MEMORY
|
||||||
|| s->output_type == TCC_OUTPUT_PREPROCESS)
|
|| s->output_type == TCC_OUTPUT_PREPROCESS)
|
||||||
@ -369,7 +371,7 @@ redo:
|
|||||||
|
|
||||||
/* compile or add each files or library */
|
/* compile or add each files or library */
|
||||||
first_file = NULL;
|
first_file = NULL;
|
||||||
do {
|
while (0 == ret) {
|
||||||
struct filespec *f = s->files[n];
|
struct filespec *f = s->files[n];
|
||||||
s->filetype = f->type;
|
s->filetype = f->type;
|
||||||
if (f->type & AFF_TYPE_LIB) {
|
if (f->type & AFF_TYPE_LIB) {
|
||||||
@ -381,9 +383,11 @@ redo:
|
|||||||
first_file = f->name;
|
first_file = f->name;
|
||||||
ret = tcc_add_file(s, f->name);
|
ret = tcc_add_file(s, f->name);
|
||||||
}
|
}
|
||||||
} while (++n < s->nb_files
|
if (++n == s->nb_files)
|
||||||
&& 0 == ret
|
break;
|
||||||
&& (s->output_type != TCC_OUTPUT_OBJ || s->option_r));
|
if (s->output_type == TCC_OUTPUT_OBJ && !s->option_r)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (s->do_bench)
|
if (s->do_bench)
|
||||||
end_time = getclock_ms();
|
end_time = getclock_ms();
|
||||||
@ -422,7 +426,7 @@ redo:
|
|||||||
tcc_delete(s);
|
tcc_delete(s);
|
||||||
if (!done)
|
if (!done)
|
||||||
goto redo;
|
goto redo;
|
||||||
if (ppfp && ppfp != stdout)
|
if (ppfp)
|
||||||
fclose(ppfp);
|
tcc_fclose(ppfp);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
117
tcc.h
117
tcc.h
@ -52,6 +52,9 @@ extern long double strtold (const char *__nptr, char **__endptr);
|
|||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
# define WIN32_LEAN_AND_MEAN 1
|
# define WIN32_LEAN_AND_MEAN 1
|
||||||
|
# ifndef _WIN32_WINNT
|
||||||
|
# define _WIN32_WINNT 0x502 /* AddVectoredExceptionHandler */
|
||||||
|
# endif
|
||||||
# include <windows.h>
|
# include <windows.h>
|
||||||
# include <io.h> /* open, close etc. */
|
# include <io.h> /* open, close etc. */
|
||||||
# include <direct.h> /* getcwd */
|
# include <direct.h> /* getcwd */
|
||||||
@ -86,6 +89,9 @@ extern long double strtold (const char *__nptr, char **__endptr);
|
|||||||
# define __x86_64__ 1
|
# define __x86_64__ 1
|
||||||
# endif
|
# endif
|
||||||
# endif
|
# endif
|
||||||
|
# if defined(_M_ARM64) && !defined(__aarch64__)
|
||||||
|
# define __aarch64__ 1
|
||||||
|
# endif
|
||||||
# ifndef va_copy
|
# ifndef va_copy
|
||||||
# define va_copy(a,b) a = b
|
# define va_copy(a,b) a = b
|
||||||
# endif
|
# 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
|
/* No ten-byte long doubles on window and macos except in
|
||||||
cross-compilers made by a mingw-GCC */
|
cross-compilers made by a mingw-GCC */
|
||||||
#if defined TCC_TARGET_PE \
|
#if defined TCC_TARGET_PE \
|
||||||
|| (defined TCC_TARGET_MACHO && defined TCC_TARGET_ARM64) \
|
|| (defined TCC_TARGET_MACHO && defined TCC_TARGET_ARM64)
|
||||||
|| (defined _WIN32 && !defined __GNUC__)
|
|
||||||
# define TCC_USING_DOUBLE_FOR_LDOUBLE 1
|
# define TCC_USING_DOUBLE_FOR_LDOUBLE 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -247,15 +252,14 @@ extern long double strtold (const char *__nptr, char **__endptr);
|
|||||||
#ifndef CONFIG_SYSROOT
|
#ifndef CONFIG_SYSROOT
|
||||||
# define CONFIG_SYSROOT ""
|
# define CONFIG_SYSROOT ""
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined CONFIG_TCCDIR && !defined _WIN32
|
#if !defined CONFIG_TCCDIR && !defined _WIN32
|
||||||
# define CONFIG_TCCDIR "/usr/local/lib/tcc"
|
# define CONFIG_TCCDIR "/usr/local/lib/tcc"
|
||||||
#endif
|
#endif
|
||||||
#ifndef CONFIG_LDDIR
|
|
||||||
# define CONFIG_LDDIR "lib"
|
|
||||||
#endif
|
|
||||||
#ifdef CONFIG_TRIPLET
|
#ifdef CONFIG_TRIPLET
|
||||||
# define USE_TRIPLET(s) s "/" 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
|
#else
|
||||||
# define USE_TRIPLET(s) s
|
# define USE_TRIPLET(s) s
|
||||||
# define ALSO_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 */
|
/* path to find crt1.o, crti.o and crtn.o */
|
||||||
#ifndef CONFIG_TCC_CRTPREFIX
|
#ifndef CONFIG_TCC_CRTPREFIX
|
||||||
# define CONFIG_TCC_CRTPREFIX USE_TRIPLET(CONFIG_SYSROOT "/usr/" CONFIG_LDDIR)
|
# define CONFIG_TCC_CRTPREFIX \
|
||||||
#endif
|
USE_TRIPLET(CONFIG_SYSROOT "/usr/lib")
|
||||||
|
|
||||||
#ifndef CONFIG_USR_INCLUDE
|
|
||||||
# define CONFIG_USR_INCLUDE "/usr/include"
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Below: {B} is substituted by CONFIG_TCCDIR (rsp. -B option) */
|
/* 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 */
|
/* system include paths */
|
||||||
#ifndef CONFIG_TCC_SYSINCLUDEPATHS
|
#ifndef CONFIG_TCC_SYSINCLUDEPATHS
|
||||||
# if defined TCC_TARGET_PE || defined _WIN32
|
# 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
|
# else
|
||||||
# define CONFIG_TCC_SYSINCLUDEPATHS \
|
# define CONFIG_TCC_SYSINCLUDEPATHS \
|
||||||
"{B}/include" \
|
"{B}/include" PATHSEP ALSO_TRIPLET(CONFIG_SYSROOT "/usr/include")
|
||||||
":" ALSO_TRIPLET(CONFIG_SYSROOT "/usr/local/include") \
|
|
||||||
":" ALSO_TRIPLET(CONFIG_SYSROOT CONFIG_USR_INCLUDE)
|
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* library search paths */
|
/* library search paths */
|
||||||
#ifndef CONFIG_TCC_LIBPATHS
|
#ifndef CONFIG_TCC_LIBPATHS
|
||||||
# if defined TCC_TARGET_PE || defined _WIN32
|
# if defined TCC_TARGET_PE || defined _WIN32
|
||||||
# define CONFIG_TCC_LIBPATHS "{B}/lib"
|
# define CONFIG_TCC_LIBPATHS \
|
||||||
|
"{B}/lib"
|
||||||
# else
|
# else
|
||||||
# define CONFIG_TCC_LIBPATHS \
|
# define CONFIG_TCC_LIBPATHS \
|
||||||
"{B}" \
|
"{B}" PATHSEP ALSO_TRIPLET(CONFIG_SYSROOT "/usr/lib")
|
||||||
":" ALSO_TRIPLET(CONFIG_SYSROOT "/usr/" CONFIG_LDDIR) \
|
|
||||||
":" ALSO_TRIPLET(CONFIG_SYSROOT "/" CONFIG_LDDIR) \
|
|
||||||
":" ALSO_TRIPLET(CONFIG_SYSROOT "/usr/local/" CONFIG_LDDIR)
|
|
||||||
# endif
|
# endif
|
||||||
#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"
|
# define CONFIG_TCC_ELFINTERP "/lib64/ld-linux-x86-64.so.2"
|
||||||
# elif defined(TCC_TARGET_RISCV64)
|
# elif defined(TCC_TARGET_RISCV64)
|
||||||
# define CONFIG_TCC_ELFINTERP "/lib/ld-linux-riscv64-lp64d.so.1"
|
# define CONFIG_TCC_ELFINTERP "/lib/ld-linux-riscv64-lp64d.so.1"
|
||||||
# elif defined(TCC_ARM_EABI)
|
# elif defined(TCC_TARGET_ARM)
|
||||||
# define DEFAULT_ELFINTERP(s) default_elfinterp(s)
|
# define CONFIG_TCC_ELFINTERP "/lib/ld-linux.so.3"
|
||||||
|
# define CONFIG_TCC_ELFINTERP_ARMHF "/lib/ld-linux-armhf.so.3"
|
||||||
# else
|
# else
|
||||||
# define CONFIG_TCC_ELFINTERP "/lib/ld-linux.so.2"
|
# define CONFIG_TCC_ELFINTERP "/lib/ld-linux.so.2"
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* var elf_interp dans *-gen.c */
|
|
||||||
#ifndef DEFAULT_ELFINTERP
|
|
||||||
# define DEFAULT_ELFINTERP(s) CONFIG_TCC_ELFINTERP
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* (target specific) libtcc1.a */
|
/* (target specific) libtcc1.a */
|
||||||
#ifndef TCC_LIBTCC1
|
#ifndef TCC_LIBTCC1
|
||||||
# define TCC_LIBTCC1 "libtcc1.a"
|
# define TCC_LIBTCC1 "libtcc1.a"
|
||||||
#endif
|
#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 */
|
/* <cross-prefix-to->libtcc1.a */
|
||||||
#ifndef CONFIG_TCC_CROSSPREFIX
|
#ifndef CONFIG_TCC_CROSSPREFIX
|
||||||
# define CONFIG_TCC_CROSSPREFIX ""
|
# define CONFIG_TCC_CROSSPREFIX ""
|
||||||
@ -470,6 +459,9 @@ typedef struct CType {
|
|||||||
struct Sym *ref;
|
struct Sym *ref;
|
||||||
} CType;
|
} CType;
|
||||||
|
|
||||||
|
/* long double words on host(!) platform */
|
||||||
|
#define LDOUBLE_WORDS ((sizeof(long double)+3)/4)
|
||||||
|
|
||||||
/* constant value */
|
/* constant value */
|
||||||
typedef union CValue {
|
typedef union CValue {
|
||||||
long double ld;
|
long double ld;
|
||||||
@ -480,7 +472,7 @@ typedef union CValue {
|
|||||||
char *data;
|
char *data;
|
||||||
int size;
|
int size;
|
||||||
} str;
|
} str;
|
||||||
int tab[LDOUBLE_SIZE/4];
|
int tab[LDOUBLE_WORDS];
|
||||||
} CValue;
|
} CValue;
|
||||||
|
|
||||||
/* value on stack */
|
/* value on stack */
|
||||||
@ -735,6 +727,15 @@ struct sym_attr {
|
|||||||
#endif
|
#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 {
|
struct TCCState {
|
||||||
unsigned char verbose; /* if true, display some information during compilation */
|
unsigned char verbose; /* if true, display some information during compilation */
|
||||||
unsigned char nostdinc; /* if true, no standard headers are added */
|
unsigned char nostdinc; /* if true, no standard headers are added */
|
||||||
@ -897,6 +898,7 @@ struct TCCState {
|
|||||||
|
|
||||||
/* predefined sections */
|
/* predefined sections */
|
||||||
Section *text_section, *data_section, *rodata_section, *bss_section;
|
Section *text_section, *data_section, *rodata_section, *bss_section;
|
||||||
|
Section *tdata_section, *tbss_section;
|
||||||
Section *common_section;
|
Section *common_section;
|
||||||
Section *cur_text_section; /* current section where function code is generated */
|
Section *cur_text_section; /* current section where function code is generated */
|
||||||
#ifdef CONFIG_TCC_BCHECK
|
#ifdef CONFIG_TCC_BCHECK
|
||||||
@ -938,23 +940,23 @@ struct TCCState {
|
|||||||
#define qrel s1->qrel
|
#define qrel s1->qrel
|
||||||
|
|
||||||
#ifdef TCC_TARGET_RISCV64
|
#ifdef TCC_TARGET_RISCV64
|
||||||
struct pcrel_hi { addr_t addr, val; } last_hi;
|
struct pcrel_hi { addr_t addr, val; } **pcrel_hi_entries;
|
||||||
struct pcrel_hi *pcrel_hi_entries;
|
|
||||||
int nb_pcrel_hi_entries;
|
int nb_pcrel_hi_entries;
|
||||||
int alloc_pcrel_hi_entries;
|
|
||||||
#define last_hi s1->last_hi
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef TCC_TARGET_PE
|
#ifdef TCC_TARGET_PE
|
||||||
/* PE info */
|
/* PE info */
|
||||||
int pe_subsystem;
|
int pe_subsystem;
|
||||||
unsigned pe_characteristics;
|
unsigned pe_characteristics;
|
||||||
|
unsigned pe_dll_characteristics;
|
||||||
|
unsigned pe_dll_characteristics_clear;
|
||||||
unsigned pe_file_align;
|
unsigned pe_file_align;
|
||||||
unsigned pe_stack_size;
|
unsigned pe_stack_size;
|
||||||
addr_t pe_imagebase;
|
addr_t pe_imagebase;
|
||||||
# ifdef TCC_TARGET_X86_64
|
# if defined(TCC_TARGET_X86_64) || defined(TCC_TARGET_ARM64)
|
||||||
Section *uw_pdata;
|
Section *uw_pdata;
|
||||||
int uw_sym;
|
int uw_sym;
|
||||||
|
int uw_xsym;
|
||||||
unsigned uw_offs;
|
unsigned uw_offs;
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
@ -1073,7 +1075,8 @@ struct filespec {
|
|||||||
#define VT_STATIC 0x00002000 /* static variable */
|
#define VT_STATIC 0x00002000 /* static variable */
|
||||||
#define VT_TYPEDEF 0x00004000 /* typedef definition */
|
#define VT_TYPEDEF 0x00004000 /* typedef definition */
|
||||||
#define VT_INLINE 0x00008000 /* inline 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_SHIFT 20 /* shift for bitfield shift values (32 - 2*6) */
|
||||||
#define VT_STRUCT_MASK (((1U << (6+6)) - 1) << VT_STRUCT_SHIFT | VT_BITFIELD)
|
#define VT_STRUCT_MASK (((1U << (6+6)) - 1) << VT_STRUCT_SHIFT | VT_BITFIELD)
|
||||||
@ -1091,7 +1094,7 @@ struct filespec {
|
|||||||
#define VT_ATOMIC VT_VOLATILE
|
#define VT_ATOMIC VT_VOLATILE
|
||||||
|
|
||||||
/* type mask (except storage) */
|
/* 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))
|
#define VT_TYPE (~(VT_STORAGE|VT_STRUCT_MASK))
|
||||||
|
|
||||||
/* symbol was created by tccasm.c first */
|
/* 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);
|
PUB_FUNC int tcc_parse_args(TCCState *s, int *argc, char ***argv);
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
ST_FUNC char *normalize_slashes(char *path);
|
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
|
#endif
|
||||||
ST_FUNC DLLReference *tcc_add_dllref(TCCState *s1, const char *dllname, int level);
|
ST_FUNC DLLReference *tcc_add_dllref(TCCState *s1, const char *dllname, int level);
|
||||||
ST_FUNC char *tcc_load_text(int fd);
|
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 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 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_var; /* true if current function is variadic */
|
||||||
ST_DATA int func_vc;
|
ST_DATA int func_vc; /* stack address for implicit struct return storage */
|
||||||
ST_DATA int func_ind;
|
ST_DATA int func_ind; /* function start address */
|
||||||
ST_DATA const char *funcname;
|
ST_DATA const char *funcname;
|
||||||
|
|
||||||
ST_FUNC void tccgen_init(TCCState *s1);
|
ST_FUNC void tccgen_init(TCCState *s1);
|
||||||
@ -1685,7 +1693,6 @@ ST_FUNC void gen_increment_tcov (SValue *sv);
|
|||||||
|
|
||||||
/* ------------ x86_64-gen.c ------------ */
|
/* ------------ x86_64-gen.c ------------ */
|
||||||
#ifdef TCC_TARGET_X86_64
|
#ifdef TCC_TARGET_X86_64
|
||||||
ST_FUNC void gen_addr64(int r, Sym *sym, int64_t c);
|
|
||||||
ST_FUNC void gen_opl(int op);
|
ST_FUNC void gen_opl(int op);
|
||||||
#ifdef TCC_TARGET_PE
|
#ifdef TCC_TARGET_PE
|
||||||
ST_FUNC void gen_vla_result(int addr);
|
ST_FUNC void gen_vla_result(int addr);
|
||||||
@ -1718,11 +1725,12 @@ ST_FUNC void gen_increment_tcov (SValue *sv);
|
|||||||
/* ------------ riscv64-gen.c ------------ */
|
/* ------------ riscv64-gen.c ------------ */
|
||||||
#ifdef TCC_TARGET_RISCV64
|
#ifdef TCC_TARGET_RISCV64
|
||||||
ST_FUNC void gen_opl(int op);
|
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 gen_va_start(void);
|
||||||
ST_FUNC void arch_transfer_ret_regs(int);
|
ST_FUNC void arch_transfer_ret_regs(int);
|
||||||
ST_FUNC void gen_cvt_sxtw(void);
|
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_increment_tcov (SValue *sv);
|
||||||
|
ST_FUNC void gen_clear_cache(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* ------------ c67-gen.c ------------ */
|
/* ------------ 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 Sym* get_asm_sym(int name, Sym *csym);
|
||||||
ST_FUNC void asm_expr(TCCState *s1, ExprValue *pe);
|
ST_FUNC void asm_expr(TCCState *s1, ExprValue *pe);
|
||||||
ST_FUNC int asm_int_expr(TCCState *s1);
|
ST_FUNC int asm_int_expr(TCCState *s1);
|
||||||
/* ------------ i386-asm.c ------------ */
|
#if PTR_SIZE == 8
|
||||||
ST_FUNC void gen_expr32(ExprValue *pe);
|
|
||||||
#ifdef TCC_TARGET_X86_64
|
|
||||||
ST_FUNC void gen_expr64(ExprValue *pe);
|
ST_FUNC void gen_expr64(ExprValue *pe);
|
||||||
#endif
|
#endif
|
||||||
|
/* ------------ i386-asm.c ------------ */
|
||||||
|
ST_FUNC void gen_expr32(ExprValue *pe);
|
||||||
ST_FUNC void asm_opcode(TCCState *s1, int opcode);
|
ST_FUNC void asm_opcode(TCCState *s1, int opcode);
|
||||||
ST_FUNC int asm_parse_regvar(int t);
|
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);
|
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);
|
ST_FUNC int pe_setsubsy(TCCState *s1, const char *arg);
|
||||||
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
|
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
|
||||||
#endif
|
#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);
|
ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack);
|
||||||
#endif
|
#endif
|
||||||
PUB_FUNC int tcc_get_dllexports(const char *filename, char **pp);
|
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 CONFIG_TCC_SEMLOCK
|
||||||
#if defined _WIN32
|
#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) {
|
static inline void wait_sem(TCCSem *p) {
|
||||||
if (!p->init)
|
if (InterlockedCompareExchange(&p->init, 1, 0) == 0) {
|
||||||
InitializeCriticalSection(&p->cs), p->init = 1;
|
InitializeCriticalSection(&p->cs);
|
||||||
|
InterlockedExchange(&p->init, 2);
|
||||||
|
} else {
|
||||||
|
while (InterlockedCompareExchange(&p->init, 2, 2) != 2)
|
||||||
|
Sleep(0);
|
||||||
|
}
|
||||||
EnterCriticalSection(&p->cs);
|
EnterCriticalSection(&p->cs);
|
||||||
}
|
}
|
||||||
static inline void post_sem(TCCSem *p) {
|
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 data_section TCC_STATE_VAR(data_section)
|
||||||
#define rodata_section TCC_STATE_VAR(rodata_section)
|
#define rodata_section TCC_STATE_VAR(rodata_section)
|
||||||
#define bss_section TCC_STATE_VAR(bss_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 common_section TCC_STATE_VAR(common_section)
|
||||||
#define cur_text_section TCC_STATE_VAR(cur_text_section)
|
#define cur_text_section TCC_STATE_VAR(cur_text_section)
|
||||||
#define bounds_section TCC_STATE_VAR(bounds_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 Section *last_text_section; /* to handle .previous asm directive */
|
||||||
static int asmgoto_n;
|
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)
|
static int asm_get_prefix_name(TCCState *s1, const char *prefix, unsigned int n)
|
||||||
{
|
{
|
||||||
char buf[64];
|
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);
|
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
|
/* If a C name has an _ prepended then only asm labels that start
|
||||||
with _ are representable in C, by removing the first _. ASM names
|
with _ are representable in C, by removing the first _. ASM names
|
||||||
without _ at the beginning don't correspond to C names, but we use
|
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
|
if (esym1 && esym1->st_shndx == esym2->st_shndx
|
||||||
&& esym1->st_shndx != SHN_UNDEF) {
|
&& esym1->st_shndx != SHN_UNDEF) {
|
||||||
/* we also accept defined symbols in the same section */
|
/* 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;
|
pe->sym = NULL;
|
||||||
} else if (esym2->st_shndx == cur_text_section->sh_num) {
|
} else if (esym2->st_shndx == cur_text_section->sh_num) {
|
||||||
/* When subtracting a defined symbol in current section
|
/* When subtracting a defined symbol in current section
|
||||||
this actually makes the value PC-relative. */
|
this actually makes the value PC-relative. */
|
||||||
pe->v += 0 - esym2->st_value;
|
pe->v += (int)(0 - esym2->st_value);
|
||||||
pe->pcrel = 1;
|
pe->pcrel = 1;
|
||||||
e2.sym = NULL;
|
e2.sym = NULL;
|
||||||
} else {
|
} else {
|
||||||
@ -494,7 +510,7 @@ static void pop_section(TCCState *s1)
|
|||||||
|
|
||||||
static void asm_parse_directive(TCCState *s1, int global)
|
static void asm_parse_directive(TCCState *s1, int global)
|
||||||
{
|
{
|
||||||
int n, offset, v, size, tok1;
|
int n, offset, v, size, tok1, c;
|
||||||
Section *sec;
|
Section *sec;
|
||||||
uint8_t *ptr;
|
uint8_t *ptr;
|
||||||
|
|
||||||
@ -524,18 +540,25 @@ static void asm_parse_directive(TCCState *s1, int global)
|
|||||||
/* the section must have a compatible alignment */
|
/* the section must have a compatible alignment */
|
||||||
if (sec->sh_addralign < n)
|
if (sec->sh_addralign < n)
|
||||||
sec->sh_addralign = n;
|
sec->sh_addralign = n;
|
||||||
|
c = sec->sh_flags & SHF_EXECINSTR;
|
||||||
} else {
|
} else {
|
||||||
if (n < 0)
|
if (n < 0)
|
||||||
n = 0;
|
n = 0;
|
||||||
size = n;
|
size = n, c = 0;
|
||||||
}
|
}
|
||||||
v = 0;
|
v = 0;
|
||||||
if (tok == ',') {
|
if (tok == ',') {
|
||||||
next();
|
next();
|
||||||
v = asm_int_expr(s1);
|
v = asm_int_expr(s1), c = 0;
|
||||||
}
|
}
|
||||||
zero_pad:
|
zero_pad:
|
||||||
|
if ((uint64_t)ind + size >= 1<<30)
|
||||||
|
tcc_error("too much data");
|
||||||
if (sec->sh_type != SHT_NOBITS) {
|
if (sec->sh_type != SHT_NOBITS) {
|
||||||
|
if (c) {
|
||||||
|
gen_fill_nops(size);
|
||||||
|
break;
|
||||||
|
}
|
||||||
sec->data_offset = ind;
|
sec->data_offset = ind;
|
||||||
ptr = section_ptr_add(sec, size);
|
ptr = section_ptr_add(sec, size);
|
||||||
memset(ptr, v, size);
|
memset(ptr, v, size);
|
||||||
@ -543,7 +566,7 @@ static void asm_parse_directive(TCCState *s1, int global)
|
|||||||
ind += size;
|
ind += size;
|
||||||
break;
|
break;
|
||||||
case TOK_ASMDIR_quad:
|
case TOK_ASMDIR_quad:
|
||||||
#ifdef TCC_TARGET_X86_64
|
#if PTR_SIZE == 8
|
||||||
size = 8;
|
size = 8;
|
||||||
goto asm_data;
|
goto asm_data;
|
||||||
#else
|
#else
|
||||||
@ -592,7 +615,7 @@ static void asm_parse_directive(TCCState *s1, int global)
|
|||||||
if (sec->sh_type != SHT_NOBITS) {
|
if (sec->sh_type != SHT_NOBITS) {
|
||||||
if (size == 4) {
|
if (size == 4) {
|
||||||
gen_expr32(&e);
|
gen_expr32(&e);
|
||||||
#ifdef TCC_TARGET_X86_64
|
#if PTR_SIZE == 8
|
||||||
} else if (size == 8) {
|
} else if (size == 8) {
|
||||||
gen_expr64(&e);
|
gen_expr64(&e);
|
||||||
#endif
|
#endif
|
||||||
@ -690,11 +713,9 @@ static void asm_parse_directive(TCCState *s1, int global)
|
|||||||
expect("constant or same-section symbol");
|
expect("constant or same-section symbol");
|
||||||
n += esym->st_value;
|
n += esym->st_value;
|
||||||
}
|
}
|
||||||
if (n < 0 || n > 0x100000)
|
|
||||||
tcc_error(".org out of range");
|
|
||||||
if (n < ind)
|
if (n < ind)
|
||||||
tcc_error("attempt to .org backwards");
|
tcc_error("attempt to .org backwards");
|
||||||
v = 0;
|
v = c = 0;
|
||||||
size = n - ind;
|
size = n - ind;
|
||||||
goto zero_pad;
|
goto zero_pad;
|
||||||
}
|
}
|
||||||
@ -812,6 +833,7 @@ static void asm_parse_directive(TCCState *s1, int global)
|
|||||||
case TOK_ASMDIR_size:
|
case TOK_ASMDIR_size:
|
||||||
{
|
{
|
||||||
Sym *sym;
|
Sym *sym;
|
||||||
|
ElfSym *esym;
|
||||||
|
|
||||||
next();
|
next();
|
||||||
if (tok < TOK_IDENT)
|
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));
|
tcc_warning_c(warn_unsupported)("ignoring .size %s,*", get_tok_str(tok, NULL));
|
||||||
next();
|
next();
|
||||||
skip(',');
|
skip(',');
|
||||||
while (tok != TOK_LINEFEED && tok != ';' && tok != CH_EOF) {
|
n = asm_int_expr(s1);
|
||||||
next();
|
esym = elfsym(sym);
|
||||||
|
if (esym) {
|
||||||
|
esym->st_size = n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -952,7 +976,7 @@ static void asm_parse_directive(TCCState *s1, int global)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#ifdef TCC_TARGET_X86_64
|
#if PTR_SIZE == 8
|
||||||
/* added for compatibility with GAS */
|
/* added for compatibility with GAS */
|
||||||
case TOK_ASMDIR_code64:
|
case TOK_ASMDIR_code64:
|
||||||
next();
|
next();
|
||||||
@ -995,17 +1019,41 @@ static void asm_parse_directive(TCCState *s1, int global)
|
|||||||
case TOK_ASMDIR_reloc:
|
case TOK_ASMDIR_reloc:
|
||||||
{
|
{
|
||||||
ExprValue e;
|
ExprValue e;
|
||||||
|
const char *reloc_name;
|
||||||
|
int reloc_type = -1;
|
||||||
|
|
||||||
next();
|
next();
|
||||||
asm_expr(s1, &e);
|
asm_expr(s1, &e);
|
||||||
skip(',');
|
skip(',');
|
||||||
|
reloc_name = get_tok_str(tok, NULL);
|
||||||
#if defined(TCC_TARGET_ARM64)
|
#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
|
#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();
|
next();
|
||||||
skip(',');
|
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();
|
next();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1032,11 +1080,14 @@ static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global)
|
|||||||
tcc_debug_line(s1);
|
tcc_debug_line(s1);
|
||||||
parse_flags |= PARSE_FLAG_LINEFEED; /* XXX: suppress that hack */
|
parse_flags |= PARSE_FLAG_LINEFEED; /* XXX: suppress that hack */
|
||||||
redo:
|
redo:
|
||||||
|
#if !defined(TCC_TARGET_ARM64)
|
||||||
if (tok == '#') {
|
if (tok == '#') {
|
||||||
/* horrible gas comment */
|
/* horrible gas comment */
|
||||||
while (tok != TOK_LINEFEED)
|
while (tok != TOK_LINEFEED)
|
||||||
next();
|
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);
|
asm_parse_directive(s1, global);
|
||||||
} else if (tok == TOK_PPNUM) {
|
} else if (tok == TOK_PPNUM) {
|
||||||
const char *p;
|
const char *p;
|
||||||
@ -1176,6 +1227,9 @@ static void subst_asm_operands(ASMOperand *operands, int nb_operands,
|
|||||||
if (*str == 'c' || *str == 'n' ||
|
if (*str == 'c' || *str == 'n' ||
|
||||||
*str == 'b' || *str == 'w' || *str == 'h' || *str == 'k' ||
|
*str == 'b' || *str == 'w' || *str == 'h' || *str == 'k' ||
|
||||||
*str == 'q' || *str == 'l' ||
|
*str == 'q' || *str == 'l' ||
|
||||||
|
#ifdef TCC_TARGET_ARM64
|
||||||
|
*str == 'x' || *str == 's' || *str == 'd' || *str == 'Z' ||
|
||||||
|
#endif
|
||||||
#ifdef TCC_TARGET_RISCV64
|
#ifdef TCC_TARGET_RISCV64
|
||||||
*str == 'z' ||
|
*str == 'z' ||
|
||||||
#endif
|
#endif
|
||||||
@ -1196,7 +1250,7 @@ static void subst_asm_operands(ASMOperand *operands, int nb_operands,
|
|||||||
sv = *op->vt;
|
sv = *op->vt;
|
||||||
if (op->reg >= 0) {
|
if (op->reg >= 0) {
|
||||||
sv.r = op->reg;
|
sv.r = op->reg;
|
||||||
if ((op->vt->r & VT_VALMASK) == VT_LLOCAL && op->is_memory)
|
if (op->is_memory)
|
||||||
sv.r |= VT_LVAL;
|
sv.r |= VT_LVAL;
|
||||||
}
|
}
|
||||||
subst_asm_operand(out_str, &sv, modifier);
|
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) &&
|
if ((vtop->r & VT_LVAL) &&
|
||||||
((vtop->r & VT_VALMASK) == VT_LLOCAL ||
|
((vtop->r & VT_VALMASK) == VT_LLOCAL ||
|
||||||
(vtop->r & VT_VALMASK) < VT_CONST) &&
|
(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);
|
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) */
|
/* create ro data section (make ro after relocation done with GNU_RELRO) */
|
||||||
rodata_section = new_section(s, rdata, SHT_PROGBITS, shf_RELRO);
|
rodata_section = new_section(s, rdata, SHT_PROGBITS, shf_RELRO);
|
||||||
bss_section = new_section(s, ".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE);
|
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 = new_section(s, ".common", SHT_NOBITS, SHF_PRIVATE);
|
||||||
common_section->sh_num = SHN_COMMON;
|
common_section->sh_num = SHN_COMMON;
|
||||||
|
|
||||||
@ -110,6 +112,21 @@ ST_FUNC void tccelf_new(TCCState *s)
|
|||||||
if (s->elf_entryname)
|
if (s->elf_entryname)
|
||||||
set_global_sym(s, s->elf_entryname, NULL, 0); /* SHN_UNDEF */
|
set_global_sym(s, s->elf_entryname, NULL, 0); /* SHN_UNDEF */
|
||||||
#endif
|
#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)
|
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);
|
dynarray_reset(&s1->priv_sections, &s1->nb_priv_sections);
|
||||||
|
|
||||||
tcc_free(s1->sym_attrs);
|
tcc_free(s1->sym_attrs);
|
||||||
#ifdef TCC_TARGET_RISCV64
|
|
||||||
tcc_free(s1->pcrel_hi_entries);
|
|
||||||
#endif
|
|
||||||
symtab_section = NULL; /* for tccrun.c:rt_printline() */
|
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)
|
if (sym_bind == STB_WEAK)
|
||||||
sym->st_value = 0;
|
sym->st_value = 0;
|
||||||
else
|
else
|
||||||
tcc_error_noabort("undefined symbol '%s'", name);
|
tcc_error_noabort("unresolved reference to '%s'", name);
|
||||||
|
|
||||||
} else if (sh_num < SHN_LORESERVE) {
|
} else if (sh_num < SHN_LORESERVE) {
|
||||||
/* add section base */
|
/* add section base */
|
||||||
@ -1130,10 +1144,6 @@ static void relocate_section(TCCState *s1, Section *s, Section *sr)
|
|||||||
addr_t tgt, addr;
|
addr_t tgt, addr;
|
||||||
int is_dwarf = s->sh_num >= s1->dwlo && s->sh_num < s1->dwhi;
|
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;
|
qrel = (ElfW_Rel *)sr->data;
|
||||||
for_each_elem(sr, 0, rel, ElfW_Rel) {
|
for_each_elem(sr, 0, rel, ElfW_Rel) {
|
||||||
if (s->data == NULL) /* bss */
|
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;
|
addr = s->sh_addr + rel->r_offset;
|
||||||
relocate(s1, rel, type, ptr, addr, tgt);
|
relocate(s1, rel, type, ptr, addr, tgt);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef ELF_OBJ_ONLY
|
#ifndef ELF_OBJ_ONLY
|
||||||
/* if the relocation is allocated, we change its symbol table */
|
/* if the relocation is allocated, we change its symbol table */
|
||||||
if (sr->sh_flags & SHF_ALLOC) {
|
if (sr->sh_flags & SHF_ALLOC) {
|
||||||
@ -1172,6 +1183,10 @@ static void relocate_section(TCCState *s1, Section *s, Section *sr)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef TCC_TARGET_RISCV64
|
||||||
|
dynarray_reset(&s1->pcrel_hi_entries, &s1->nb_pcrel_hi_entries);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* relocate all sections */
|
/* 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 ||
|
if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK ||
|
||||||
!strcmp(name, "_fp_hw")) {
|
!strcmp(name, "_fp_hw")) {
|
||||||
} else {
|
} 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) {
|
if (esym->st_shndx == SHN_UNDEF) {
|
||||||
/* weak symbols can stay undefined */
|
/* weak symbols can stay undefined */
|
||||||
if (ELFW(ST_BIND)(esym->st_info) != STB_WEAK)
|
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)
|
if (k < 0x900)
|
||||||
++d->shnum;
|
++d->shnum;
|
||||||
if (k < 0x700) {
|
if (k < 0x700) {
|
||||||
f = s->sh_flags & (SHF_ALLOC|SHF_WRITE|SHF_EXECINSTR|SHF_TLS);
|
f = s->sh_flags & (SHF_ALLOC|SHF_WRITE|SHF_EXECINSTR);
|
||||||
#if TARGETOS_NetBSD
|
#if TARGETOS_NetBSD
|
||||||
/* NetBSD only supports 2 PT_LOAD sections.
|
/* NetBSD only supports 2 PT_LOAD sections.
|
||||||
See: https://blog.netbsd.org/tnf/entry/the_first_report_on_lld */
|
See: https://blog.netbsd.org/tnf/entry/the_first_report_on_lld */
|
||||||
@ -2340,6 +2355,18 @@ static int layout_sections(TCCState *s1, int *sec_order, struct dyn_inf *d)
|
|||||||
++phnum;
|
++phnum;
|
||||||
if (d->roinf)
|
if (d->roinf)
|
||||||
++phnum;
|
++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->phnum = phnum;
|
||||||
d->phdr = tcc_mallocz(phnum * sizeof(ElfW(Phdr)));
|
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;
|
ph->p_flags |= PF_W;
|
||||||
if (f & SHF_EXECINSTR)
|
if (f & SHF_EXECINSTR)
|
||||||
ph->p_flags |= PF_X;
|
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_offset = file_offset;
|
||||||
ph->p_vaddr = addr;
|
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);
|
fill_phdr(++ph, PT_GNU_EH_FRAME, eh_frame_hdr_section);
|
||||||
if (d->roinf)
|
if (d->roinf)
|
||||||
fill_phdr(++ph, PT_GNU_RELRO, d->roinf)->p_flags |= PF_W;
|
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)
|
if (d->interp)
|
||||||
fill_phdr(&d->phdr[1], PT_INTERP, d->interp);
|
fill_phdr(&d->phdr[1], PT_INTERP, d->interp);
|
||||||
if (phfill) {
|
if (phfill) {
|
||||||
@ -2839,6 +2890,28 @@ static void create_arm_attribute_section(TCCState *s1)
|
|||||||
}
|
}
|
||||||
#endif
|
#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
|
#if TARGETOS_OpenBSD || TARGETOS_NetBSD || TARGETOS_FreeBSD
|
||||||
|
|
||||||
static void fill_bsd_note(Section *s, int type,
|
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 (!s1->static_link) {
|
||||||
if (file_type & TCC_OUTPUT_EXE) {
|
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 */
|
/* add interpreter section only if executable */
|
||||||
interp = new_section(s1, ".interp", SHT_PROGBITS, SHF_ALLOC);
|
interp = new_section(s1, ".interp", SHT_PROGBITS, SHF_ALLOC);
|
||||||
interp->sh_addralign = 1;
|
interp->sh_addralign = 1;
|
||||||
ptr = section_ptr_add(interp, 1 + strlen(elfint));
|
put_elf_str(interp, s1->elfint);
|
||||||
strcpy(ptr, elfint);
|
|
||||||
dyninf.interp = interp;
|
dyninf.interp = interp;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3103,10 +3168,13 @@ static void alloc_sec_names(TCCState *s1, int is_obj)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Output an elf .o file */
|
/* 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;
|
Section *s;
|
||||||
int i, ret, file_offset;
|
int i, ret, file_offset;
|
||||||
|
#ifdef TCC_TARGET_RISCV64
|
||||||
|
create_riscv_attribute_section(s1);
|
||||||
|
#endif
|
||||||
/* Allocate strings for section names */
|
/* Allocate strings for section names */
|
||||||
alloc_sec_names(s1, 1);
|
alloc_sec_names(s1, 1);
|
||||||
file_offset = (sizeof (ElfW(Ehdr)) + 3) & -4;
|
file_offset = (sizeof (ElfW(Ehdr)) + 3) & -4;
|
||||||
@ -3303,6 +3371,8 @@ invalid:
|
|||||||
continue;
|
continue;
|
||||||
if (sh->sh_type != s->sh_type
|
if (sh->sh_type != s->sh_type
|
||||||
&& strcmp (s->name, ".eh_frame")
|
&& 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);
|
tcc_error_noabort("section type conflict: %s %02x <> %02x", s->name, sh->sh_type, s->sh_type);
|
||||||
goto the_end;
|
goto the_end;
|
||||||
|
|||||||
241
tccgen.c
241
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 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 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_var; /* true if current function is variadic (used by return instruction) */
|
||||||
ST_DATA int func_vc;
|
ST_DATA int func_vc; /* stack address for implicit struct return storage */
|
||||||
ST_DATA int func_ind;
|
ST_DATA int func_ind; /* function start address */
|
||||||
|
static int func_old;
|
||||||
ST_DATA const char *funcname;
|
ST_DATA const char *funcname;
|
||||||
ST_DATA CType int_type, func_old_type, char_type, char_pointer_type;
|
ST_DATA CType int_type, func_old_type, char_type, char_pointer_type;
|
||||||
static CString initstr;
|
static CString initstr;
|
||||||
@ -322,12 +323,6 @@ ST_FUNC int ieee_finite(double d)
|
|||||||
return ((unsigned)((p[1] | 0x800fffff) + 1)) >> 31;
|
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)
|
ST_FUNC void test_lvalue(void)
|
||||||
{
|
{
|
||||||
if (!(vtop->r & VT_LVAL))
|
if (!(vtop->r & VT_LVAL))
|
||||||
@ -531,6 +526,8 @@ ST_FUNC void put_extern_sym2(Sym *sym, int sh_num,
|
|||||||
sym_type = STT_NOTYPE;
|
sym_type = STT_NOTYPE;
|
||||||
if (IS_ASM_FUNC(t))
|
if (IS_ASM_FUNC(t))
|
||||||
sym_type = STT_FUNC;
|
sym_type = STT_FUNC;
|
||||||
|
} else if (t & VT_TLS) {
|
||||||
|
sym_type = STT_TLS;
|
||||||
} else {
|
} else {
|
||||||
sym_type = STT_OBJECT;
|
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 */
|
/* make sure that type->ref is on global stack */
|
||||||
move_ref_to_global(s);
|
move_ref_to_global(s);
|
||||||
/* put into local scope */
|
/* put into local scope */
|
||||||
s = sym_copy(s, &local_stack);
|
sym_copy(s, &local_stack);
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
@ -1906,6 +1903,8 @@ ST_FUNC int gv(int rc)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
bt = vtop->type.t & VT_BTYPE;
|
bt = vtop->type.t & VT_BTYPE;
|
||||||
|
if (bt == VT_VOID || bt == VT_STRUCT) /* should not happen */
|
||||||
|
return vtop->r;
|
||||||
|
|
||||||
#ifdef TCC_TARGET_RISCV64
|
#ifdef TCC_TARGET_RISCV64
|
||||||
/* XXX mega hack */
|
/* XXX mega hack */
|
||||||
@ -2521,11 +2520,17 @@ void gen_negf(int op)
|
|||||||
operation. We implement this with bit manipulation and have
|
operation. We implement this with bit manipulation and have
|
||||||
to do some type reinterpretation for this, which TCC can do
|
to do some type reinterpretation for this, which TCC can do
|
||||||
only via memory. */
|
only via memory. */
|
||||||
|
|
||||||
int align, size, bt;
|
int align, size, bt;
|
||||||
|
|
||||||
size = type_size(&vtop->type, &align);
|
size = type_size(&vtop->type, &align);
|
||||||
bt = vtop->type.t & VT_BTYPE;
|
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)));
|
save_reg(gv(RC_TYPE(bt)));
|
||||||
vdup();
|
vdup();
|
||||||
incr_bf_adr(size - 1);
|
incr_bf_adr(size - 1);
|
||||||
@ -2534,6 +2539,8 @@ void gen_negf(int op)
|
|||||||
gen_op('^');
|
gen_op('^');
|
||||||
vstore();
|
vstore();
|
||||||
vpop();
|
vpop();
|
||||||
|
gv2:
|
||||||
|
gv(RC_TYPE(bt)); /* -n is not a lvalue */
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -2919,7 +2926,8 @@ static int combine_types(CType *dest, SValue *op1, SValue *op2, int op)
|
|||||||
type.ref = NULL;
|
type.ref = NULL;
|
||||||
|
|
||||||
if (bt1 == VT_VOID || bt2 == VT_VOID) {
|
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 */
|
/* NOTE: as an extension, we accept void on only one side */
|
||||||
type.t = VT_VOID;
|
type.t = VT_VOID;
|
||||||
} else if (bt1 == VT_PTR || bt2 == VT_PTR) {
|
} else if (bt1 == VT_PTR || bt2 == VT_PTR) {
|
||||||
@ -3097,9 +3105,7 @@ op_err:
|
|||||||
#endif
|
#endif
|
||||||
type1 = vtop[-1].type;
|
type1 = vtop[-1].type;
|
||||||
vpush_type_size(pointed_type(&vtop[-1].type), &align);
|
vpush_type_size(pointed_type(&vtop[-1].type), &align);
|
||||||
if (!(vtop[-1].type.t & VT_UNSIGNED)) {
|
vtop->type.t &= ~VT_UNSIGNED;
|
||||||
gen_cast_s(VT_PTRDIFF_T);
|
|
||||||
}
|
|
||||||
gen_op('*');
|
gen_op('*');
|
||||||
#ifdef CONFIG_TCC_BCHECK
|
#ifdef CONFIG_TCC_BCHECK
|
||||||
if (tcc_state->do_bounds_check && !CONST_WANTED) {
|
if (tcc_state->do_bounds_check && !CONST_WANTED) {
|
||||||
@ -3168,7 +3174,7 @@ op_err:
|
|||||||
}
|
}
|
||||||
// Make sure that we have converted to an rvalue:
|
// Make sure that we have converted to an rvalue:
|
||||||
if (vtop->r & VT_LVAL)
|
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
|
#if defined TCC_TARGET_ARM64 || defined TCC_TARGET_RISCV64 || defined TCC_TARGET_ARM
|
||||||
@ -3273,20 +3279,15 @@ again:
|
|||||||
df = is_float(dbt);
|
df = is_float(dbt);
|
||||||
dbt_bt = dbt & VT_BTYPE;
|
dbt_bt = dbt & VT_BTYPE;
|
||||||
sbt_bt = sbt & VT_BTYPE;
|
sbt_bt = sbt & VT_BTYPE;
|
||||||
if (dbt_bt == VT_VOID)
|
if (dbt_bt == VT_VOID) {
|
||||||
goto done;
|
goto done;
|
||||||
|
}
|
||||||
if (sbt_bt == VT_VOID) {
|
if (sbt_bt == VT_VOID) {
|
||||||
error:
|
error:
|
||||||
cast_error(&vtop->type, type);
|
cast_error(&vtop->type, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
c = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST;
|
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) {
|
if (c) {
|
||||||
/* constant case: we can do it now */
|
/* constant case: we can do it now */
|
||||||
/* XXX: in ISOC, cannot do it if error in convert */
|
/* XXX: in ISOC, cannot do it if error in convert */
|
||||||
@ -3353,8 +3354,11 @@ error:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* cannot generate code for global or static initializers */
|
/* 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;
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
/* non constant case: generate code */
|
/* non constant case: generate code */
|
||||||
if (dbt == VT_BOOL) {
|
if (dbt == VT_BOOL) {
|
||||||
@ -3463,11 +3467,11 @@ error:
|
|||||||
|
|
||||||
if (ds >= ss)
|
if (ds >= ss)
|
||||||
goto done;
|
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) {
|
if (ss == 4) {
|
||||||
gen_cvt_csti(dbt);
|
gen_cvt_csti(dbt);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
bits = (ss - ds) * 8;
|
bits = (ss - ds) * 8;
|
||||||
/* for unsigned, gen_op will convert SAR to SHR */
|
/* for unsigned, gen_op will convert SAR to SHR */
|
||||||
@ -4745,6 +4749,8 @@ static int parse_btype(CType *type, AttributeDef *ad, int ignore_label)
|
|||||||
} else {
|
} else {
|
||||||
if (bt != -1 || (st != -1 && u != VT_INT))
|
if (bt != -1 || (st != -1 && u != VT_INT))
|
||||||
goto tmbt;
|
goto tmbt;
|
||||||
|
if ((t & VT_DEFSIGN) && (u == VT_VOID || u > VT_LLONG))
|
||||||
|
goto tmbt;
|
||||||
bt = u;
|
bt = u;
|
||||||
}
|
}
|
||||||
if (u != VT_INT)
|
if (u != VT_INT)
|
||||||
@ -4927,7 +4933,12 @@ static int parse_btype(CType *type, AttributeDef *ad, int ignore_label)
|
|||||||
}
|
}
|
||||||
goto basic_type2;
|
goto basic_type2;
|
||||||
case TOK_THREAD_LOCAL:
|
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:
|
default:
|
||||||
if (typespec_found)
|
if (typespec_found)
|
||||||
goto the_end;
|
goto the_end;
|
||||||
@ -5627,6 +5638,7 @@ ST_FUNC void unary(void)
|
|||||||
case TOK_CLDOUBLE:
|
case TOK_CLDOUBLE:
|
||||||
#ifdef TCC_USING_DOUBLE_FOR_LDOUBLE
|
#ifdef TCC_USING_DOUBLE_FOR_LDOUBLE
|
||||||
t = VT_DOUBLE | VT_LONG;
|
t = VT_DOUBLE | VT_LONG;
|
||||||
|
tokc.d = tokc.ld;
|
||||||
#else
|
#else
|
||||||
t = VT_LDOUBLE;
|
t = VT_LDOUBLE;
|
||||||
#endif
|
#endif
|
||||||
@ -5941,6 +5953,8 @@ ST_FUNC void unary(void)
|
|||||||
vtop->type = type;
|
vtop->type = type;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef TCC_TARGET_ARM64
|
||||||
case TOK___arm64_clear_cache: {
|
case TOK___arm64_clear_cache: {
|
||||||
parse_builtin_params(0, "ee");
|
parse_builtin_params(0, "ee");
|
||||||
gen_clear_cache();
|
gen_clear_cache();
|
||||||
@ -5949,6 +5963,17 @@ ST_FUNC void unary(void)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#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 */
|
/* atomic operations */
|
||||||
case TOK___atomic_store:
|
case TOK___atomic_store:
|
||||||
@ -6104,6 +6129,7 @@ special_math_val:
|
|||||||
tcc_error("'%s' undeclared", name);
|
tcc_error("'%s' undeclared", name);
|
||||||
/* for simple function calls, we tolerate undeclared
|
/* for simple function calls, we tolerate undeclared
|
||||||
external reference to int() function */
|
external reference to int() function */
|
||||||
|
if (!func_old)
|
||||||
tcc_warning_c(warn_implicit_function_declaration)(
|
tcc_warning_c(warn_implicit_function_declaration)(
|
||||||
"implicit declaration of function '%s'", name);
|
"implicit declaration of function '%s'", name);
|
||||||
s = external_global_sym(t, &func_old_type);
|
s = external_global_sym(t, &func_old_type);
|
||||||
@ -6158,7 +6184,8 @@ special_math_val:
|
|||||||
gen_op('+');
|
gen_op('+');
|
||||||
/* change type to field type, and set to lvalue */
|
/* change type to field type, and set to lvalue */
|
||||||
vtop->type = s->type;
|
vtop->type = s->type;
|
||||||
vtop->type.t |= qualifiers;
|
if (qualifiers)
|
||||||
|
parse_btype_qualify(&vtop->type, qualifiers);
|
||||||
/* an array is never an lvalue */
|
/* an array is never an lvalue */
|
||||||
if (!(vtop->type.t & VT_ARRAY)) {
|
if (!(vtop->type.t & VT_ARRAY)) {
|
||||||
vtop->r |= VT_LVAL;
|
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
|
/* keep structs lvalue by transforming `(expr ? a : b)` to `*(expr ? &a : &b)` so
|
||||||
that `(expr ? a : b).mem` does not error with "lvalue expected" */
|
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 */
|
/* now we convert second operand */
|
||||||
if (c != 1) {
|
if (c != 1) {
|
||||||
@ -6660,8 +6687,7 @@ static void expr_cond(void)
|
|||||||
if (islv) {
|
if (islv) {
|
||||||
mk_pointer(&vtop->type);
|
mk_pointer(&vtop->type);
|
||||||
gaddrof();
|
gaddrof();
|
||||||
} else if (VT_STRUCT == (vtop->type.t & VT_BTYPE))
|
}
|
||||||
gaddrof();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = RC_TYPE(type.t);
|
rc = RC_TYPE(type.t);
|
||||||
@ -6672,7 +6698,8 @@ static void expr_cond(void)
|
|||||||
|
|
||||||
tt = r2 = 0;
|
tt = r2 = 0;
|
||||||
if (c < 0) {
|
if (c < 0) {
|
||||||
r2 = gv(rc);
|
if (type.t != VT_VOID)
|
||||||
|
r2 = gv(rc);
|
||||||
tt = gjmp(0);
|
tt = gjmp(0);
|
||||||
}
|
}
|
||||||
gsym(u);
|
gsym(u);
|
||||||
@ -6687,14 +6714,15 @@ static void expr_cond(void)
|
|||||||
if (islv) {
|
if (islv) {
|
||||||
mk_pointer(&vtop->type);
|
mk_pointer(&vtop->type);
|
||||||
gaddrof();
|
gaddrof();
|
||||||
} else if (VT_STRUCT == (vtop->type.t & VT_BTYPE))
|
}
|
||||||
gaddrof();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c < 0) {
|
if (c < 0) {
|
||||||
r1 = gv(rc);
|
if (type.t != VT_VOID) {
|
||||||
move_reg(r2, r1, islv ? VT_PTR : type.t);
|
r1 = gv(rc);
|
||||||
vtop->r = r2;
|
move_reg(r2, r1, islv ? VT_PTR : type.t);
|
||||||
|
vtop->r = r2;
|
||||||
|
}
|
||||||
gsym(tt);
|
gsym(tt);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6737,7 +6765,8 @@ ST_FUNC void gexpr(void)
|
|||||||
|
|
||||||
/* make builtin_constant_p((1,2)) return 0 (like on gcc) */
|
/* make builtin_constant_p((1,2)) return 0 (like on gcc) */
|
||||||
if ((vtop->r & VT_VALMASK) == VT_CONST && nocode_wanted && !CONST_WANTED)
|
if ((vtop->r & VT_VALMASK) == VT_CONST && nocode_wanted && !CONST_WANTED)
|
||||||
gv(RC_TYPE(vtop->type.t));
|
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)
|
if ((func_vt.t & VT_BTYPE) == VT_VOID)
|
||||||
return;
|
return;
|
||||||
if (!strcmp (funcname, "main")
|
if ((!strcmp(funcname, "main") || func_old)
|
||||||
&& (func_vt.t & VT_BTYPE) == VT_INT) {
|
&& (func_vt.t & VT_BTYPE) == VT_INT) {
|
||||||
/* main returns 0 by default */
|
/* main returns 0 by default */
|
||||||
vpushi(0);
|
vpushi(0);
|
||||||
gen_assign_cast(&func_vt);
|
|
||||||
gfunc_return(&func_vt);
|
gfunc_return(&func_vt);
|
||||||
} else {
|
} else {
|
||||||
tcc_warning("function might return no value: '%s'", funcname);
|
tcc_warning("function might return no value: '%s'", funcname);
|
||||||
@ -7234,6 +7262,8 @@ again:
|
|||||||
tcc_warning("void function returns a value");
|
tcc_warning("void function returns a value");
|
||||||
vtop--;
|
vtop--;
|
||||||
}
|
}
|
||||||
|
} else if (b && func_old && (func_vt.t & VT_BTYPE) == VT_INT) {
|
||||||
|
vpushi(0);
|
||||||
} else if (b) {
|
} else if (b) {
|
||||||
tcc_warning("'return' with no value");
|
tcc_warning("'return' with no value");
|
||||||
b = 0;
|
b = 0;
|
||||||
@ -7758,6 +7788,71 @@ static int decl_designator(init_params *p, CType *type, unsigned long c,
|
|||||||
return al;
|
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 */
|
/* 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)
|
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;
|
ptr = sec->data + c;
|
||||||
val = vtop->c.i;
|
val = vtop->c.i;
|
||||||
|
|
||||||
/* XXX: make code faster ? */
|
if ((vtop->r & (VT_SYM|VT_CONST)) == (VT_SYM|VT_CONST)
|
||||||
if ((vtop->r & (VT_SYM|VT_CONST)) == (VT_SYM|VT_CONST) &&
|
&& vtop->sym->v >= SYM_FIRST_ANOM
|
||||||
vtop->sym->v >= SYM_FIRST_ANOM &&
|
&& ((vtop->r & VT_LVAL) /* compound literal */
|
||||||
/* XXX This rejects compound literals like
|
|| bt == VT_STRUCT /* designator */
|
||||||
'(void *){ptr}'. The problem is that '&sym' is
|
)) {
|
||||||
represented the same way, which would be ruled out
|
/* memcpy stuff over. */
|
||||||
by the SYM_FIRST_ANOM check above, but also '"string"'
|
|
||||||
in 'char *p = "string"' is represented the same
|
|
||||||
with the type being VT_PTR and the symbol being an
|
|
||||||
anonymous one. That is, there's no difference in vtop
|
|
||||||
between '(void *){x}' and '&(void *){x}'. Ignore
|
|
||||||
pointer typed entities here. Hopefully no real code
|
|
||||||
will ever use compound literals with scalar type. */
|
|
||||||
(vtop->type.t & VT_BTYPE) != VT_PTR) {
|
|
||||||
/* These come from compound literals, memcpy stuff over. */
|
|
||||||
Section *ssec;
|
Section *ssec;
|
||||||
ElfSym *esym;
|
ElfSym *esym;
|
||||||
ElfW_Rel *rel;
|
ElfW_Rel *rel;
|
||||||
@ -7879,34 +7965,7 @@ static void init_putv(init_params *p, CType *type, unsigned long c)
|
|||||||
write64le(ptr, val);
|
write64le(ptr, val);
|
||||||
break;
|
break;
|
||||||
case VT_LDOUBLE:
|
case VT_LDOUBLE:
|
||||||
#if defined TCC_IS_NATIVE_387
|
write_ldouble(ptr, &vtop->c.ld);
|
||||||
/* Host and target platform may be different but both have x87.
|
|
||||||
On windows, tcc does not use VT_LDOUBLE, except when it is a
|
|
||||||
cross compiler. In this case a mingw gcc as host compiler
|
|
||||||
comes here with 10-byte long doubles, while msvc or tcc won't.
|
|
||||||
tcc itself can still translate by asm.
|
|
||||||
In any case we avoid possibly random bytes 11 and 12.
|
|
||||||
*/
|
|
||||||
if (sizeof (long double) >= 10)
|
|
||||||
memcpy(ptr, &vtop->c.ld, 10);
|
|
||||||
#ifdef __TINYC__
|
|
||||||
else if (sizeof (long double) == sizeof (double))
|
|
||||||
__asm__("fldl %1\nfstpt %0\n" : "=m" (*ptr) : "m" (vtop->c.ld));
|
|
||||||
#endif
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
/* For other platforms it should work natively, but may not work
|
|
||||||
for cross compilers */
|
|
||||||
if (sizeof(long double) == LDOUBLE_SIZE)
|
|
||||||
memcpy(ptr, &vtop->c.ld, LDOUBLE_SIZE);
|
|
||||||
else if (sizeof(double) == LDOUBLE_SIZE)
|
|
||||||
*(double*)ptr = (double)vtop->c.ld;
|
|
||||||
else if (0 == memcmp(ptr, &vtop->c.ld, LDOUBLE_SIZE))
|
|
||||||
; /* nothing to do for 0.0 */
|
|
||||||
#ifndef TCC_CROSS_TEST
|
|
||||||
else
|
|
||||||
tcc_error("can't cross compile long double constants");
|
|
||||||
#endif
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#if PTR_SIZE == 8
|
#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 {
|
} else {
|
||||||
|
|
||||||
do_init_array:
|
do_init_array:
|
||||||
@ -8336,7 +8397,12 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
|
|||||||
CType *tp = type;
|
CType *tp = type;
|
||||||
while ((tp->t & (VT_BTYPE|VT_ARRAY)) == (VT_PTR|VT_ARRAY))
|
while ((tp->t & (VT_BTYPE|VT_ARRAY)) == (VT_PTR|VT_ARRAY))
|
||||||
tp = &tp->ref->type;
|
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;
|
sec = rodata_section;
|
||||||
} else if (has_init) {
|
} else if (has_init) {
|
||||||
sec = data_section;
|
sec = data_section;
|
||||||
@ -8520,6 +8586,7 @@ static void gen_function(Sym *sym)
|
|||||||
func_ind = ind;
|
func_ind = ind;
|
||||||
func_vt = sym->type.ref->type;
|
func_vt = sym->type.ref->type;
|
||||||
func_var = sym->type.ref->f.func_type == FUNC_ELLIPSIS;
|
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 */
|
/* NOTE: we patch the symbol size later */
|
||||||
put_extern_sym(sym, cur_text_section, ind, 0);
|
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);
|
long int strtol(const char *nptr, char **endptr, int base);
|
||||||
unsigned long int strtoul(const char *nptr, char **endptr, int base);
|
unsigned long int strtoul(const char *nptr, char **endptr, int base);
|
||||||
void exit(int);
|
void exit(int);
|
||||||
|
void *alloca(size_t);
|
||||||
|
|
||||||
/* stdio.h */
|
/* stdio.h */
|
||||||
typedef struct __FILE FILE;
|
typedef struct __FILE FILE;
|
||||||
@ -39,6 +40,7 @@ int getchar(void);
|
|||||||
char *gets(char *s);
|
char *gets(char *s);
|
||||||
int ungetc(int c, FILE *stream);
|
int ungetc(int c, FILE *stream);
|
||||||
int fflush(FILE *stream);
|
int fflush(FILE *stream);
|
||||||
|
int puts(const char *s);
|
||||||
int putchar (int c);
|
int putchar (int c);
|
||||||
|
|
||||||
int printf(const char *format, ...);
|
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));
|
goti = tcc_realloc(goti, (mo->n_got + 1) * sizeof(*goti));
|
||||||
if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) {
|
if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) {
|
||||||
if (sym->st_shndx == SHN_UNDEF)
|
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);
|
(char *) symtab_section->link->data + sym->st_name);
|
||||||
goti[mo->n_got++] = INDIRECT_SYMBOL_LOCAL;
|
goti[mo->n_got++] = INDIRECT_SYMBOL_LOCAL;
|
||||||
} else {
|
} else {
|
||||||
@ -859,7 +859,7 @@ static void check_relocs(TCCState *s1, struct macho *mo)
|
|||||||
goti = tcc_realloc(goti, (mo->n_got + 1) * sizeof(*goti));
|
goti = tcc_realloc(goti, (mo->n_got + 1) * sizeof(*goti));
|
||||||
if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) {
|
if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) {
|
||||||
if (sym->st_shndx == SHN_UNDEF)
|
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);
|
(char *) symtab_section->link->data + sym->st_name);
|
||||||
goti[mo->n_got++] = INDIRECT_SYMBOL_LOCAL;
|
goti[mo->n_got++] = INDIRECT_SYMBOL_LOCAL;
|
||||||
} else {
|
} else {
|
||||||
@ -1042,7 +1042,7 @@ static int check_symbols(TCCState *s1, struct macho *mo)
|
|||||||
sym->st_shndx = SHN_FROMDLL;
|
sym->st_shndx = SHN_FROMDLL;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
tcc_error_noabort("undefined symbol '%s'", name);
|
tcc_error_noabort("unresolved reference to '%s'", name);
|
||||||
ret = -1;
|
ret = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1058,6 +1058,7 @@ static void convert_symbol(TCCState *s1, struct macho *mo, struct nlist_64 *pn)
|
|||||||
case STT_NOTYPE:
|
case STT_NOTYPE:
|
||||||
case STT_OBJECT:
|
case STT_OBJECT:
|
||||||
case STT_FUNC:
|
case STT_FUNC:
|
||||||
|
case STT_TLS:
|
||||||
case STT_SECTION:
|
case STT_SECTION:
|
||||||
n.n_type = N_SECT;
|
n.n_type = N_SECT;
|
||||||
break;
|
break;
|
||||||
|
|||||||
247
tccpe.c
247
tccpe.c
@ -27,6 +27,8 @@
|
|||||||
#define stricmp strcasecmp
|
#define stricmp strcasecmp
|
||||||
#define strnicmp strncasecmp
|
#define strnicmp strncasecmp
|
||||||
#include <sys/stat.h> /* chmod() */
|
#include <sys/stat.h> /* chmod() */
|
||||||
|
#else
|
||||||
|
#include <process.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef TCC_TARGET_X86_64
|
#ifdef TCC_TARGET_X86_64
|
||||||
@ -50,6 +52,16 @@
|
|||||||
# define IMAGE_FILE_MACHINE 0x01C0
|
# define IMAGE_FILE_MACHINE 0x01C0
|
||||||
# define RSRC_RELTYPE 7 /* ??? (not tested) */
|
# 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
|
#elif defined TCC_TARGET_I386
|
||||||
# define ADDR3264 DWORD
|
# define ADDR3264 DWORD
|
||||||
# define PE_IMAGE_REL IMAGE_REL_BASED_HIGHLOW
|
# define PE_IMAGE_REL IMAGE_REL_BASED_HIGHLOW
|
||||||
@ -126,7 +138,7 @@ typedef struct _IMAGE_OPTIONAL_HEADER {
|
|||||||
DWORD SizeOfUninitializedData;
|
DWORD SizeOfUninitializedData;
|
||||||
DWORD AddressOfEntryPoint;
|
DWORD AddressOfEntryPoint;
|
||||||
DWORD BaseOfCode;
|
DWORD BaseOfCode;
|
||||||
#ifndef TCC_TARGET_X86_64
|
#if !defined(TCC_TARGET_X86_64) && !defined(TCC_TARGET_ARM64)
|
||||||
DWORD BaseOfData;
|
DWORD BaseOfData;
|
||||||
#endif
|
#endif
|
||||||
/* NT additional fields. */
|
/* NT additional fields. */
|
||||||
@ -225,6 +237,19 @@ typedef struct _IMAGE_BASE_RELOCATION {
|
|||||||
|
|
||||||
#define IMAGE_SIZEOF_BASE_RELOCATION 8
|
#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_ABSOLUTE 0
|
||||||
#define IMAGE_REL_BASED_HIGH 1
|
#define IMAGE_REL_BASED_HIGH 1
|
||||||
#define IMAGE_REL_BASED_LOW 2
|
#define IMAGE_REL_BASED_LOW 2
|
||||||
@ -250,6 +275,24 @@ typedef struct _IMAGE_BASE_RELOCATION {
|
|||||||
#endif /* ndef IMAGE_NT_SIGNATURE */
|
#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
|
#ifndef IMAGE_REL_BASED_DIR64
|
||||||
# define IMAGE_REL_BASED_DIR64 10
|
# define IMAGE_REL_BASED_DIR64 10
|
||||||
#endif
|
#endif
|
||||||
@ -261,7 +304,7 @@ struct pe_header
|
|||||||
BYTE dosstub[0x40];
|
BYTE dosstub[0x40];
|
||||||
DWORD nt_sig;
|
DWORD nt_sig;
|
||||||
IMAGE_FILE_HEADER filehdr;
|
IMAGE_FILE_HEADER filehdr;
|
||||||
#ifdef TCC_TARGET_X86_64
|
#if defined(TCC_TARGET_X86_64) || defined(TCC_TARGET_ARM64)
|
||||||
IMAGE_OPTIONAL_HEADER64 opthdr;
|
IMAGE_OPTIONAL_HEADER64 opthdr;
|
||||||
#else
|
#else
|
||||||
#ifdef _WIN64
|
#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
|
/* Run cv2pdb, available at https://github.com/rainers/cv2pdb. It reads
|
||||||
and strips the dwarf info and creates a <exename>.pdb file instead */
|
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)
|
static void pe_create_pdb(TCCState *s1, const char *exename)
|
||||||
{
|
{
|
||||||
char buf[300]; int r;
|
size_t len = strlen(exename);
|
||||||
snprintf(buf, sizeof buf, "cv2pdb.exe %s", exename);
|
char *pdbfile = tcc_malloc(len + sizeof(".pdb"));
|
||||||
r = system(buf);
|
intptr_t r;
|
||||||
strcpy(tcc_fileextension(strcpy(buf, exename)), ".pdb");
|
|
||||||
|
strcpy(pdbfile, exename);
|
||||||
|
strcpy(tcc_fileextension(pdbfile), ".pdb");
|
||||||
|
r = pe_run_cv2pdb(exename);
|
||||||
if (r) {
|
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) {
|
} 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; */
|
0x00E0, /*WORD SizeOfOptionalHeader; */
|
||||||
0x010F, /*WORD Characteristics; */
|
0x010F, /*WORD Characteristics; */
|
||||||
#define CHARACTERISTICS_DLL 0x230F
|
#define CHARACTERISTICS_DLL 0x230F
|
||||||
|
#elif defined(TCC_TARGET_ARM64)
|
||||||
|
0x00F0, /*WORD SizeOfOptionalHeader; */
|
||||||
|
0x0022 /*WORD Characteristics; */
|
||||||
|
#define CHARACTERISTICS_DLL 0x2022
|
||||||
#endif
|
#endif
|
||||||
},{
|
},{
|
||||||
/* IMAGE_OPTIONAL_HEADER opthdr */
|
/* IMAGE_OPTIONAL_HEADER opthdr */
|
||||||
/* Standard fields. */
|
/* Standard fields. */
|
||||||
#ifdef TCC_TARGET_X86_64
|
#if defined(TCC_TARGET_X86_64) || defined(TCC_TARGET_ARM64)
|
||||||
0x020B, /*WORD Magic; */
|
0x020B, /*WORD Magic; */
|
||||||
#else
|
#else
|
||||||
0x010B, /*WORD Magic; */
|
0x010B, /*WORD Magic; */
|
||||||
@ -621,23 +706,35 @@ static int pe_write(struct pe_info *pe)
|
|||||||
0x00000000, /*DWORD SizeOfUninitializedData; */
|
0x00000000, /*DWORD SizeOfUninitializedData; */
|
||||||
0x00000000, /*DWORD AddressOfEntryPoint; */
|
0x00000000, /*DWORD AddressOfEntryPoint; */
|
||||||
0x00000000, /*DWORD BaseOfCode; */
|
0x00000000, /*DWORD BaseOfCode; */
|
||||||
#ifndef TCC_TARGET_X86_64
|
#if !defined(TCC_TARGET_X86_64) && !defined(TCC_TARGET_ARM64)
|
||||||
0x00000000, /*DWORD BaseOfData; */
|
0x00000000, /*DWORD BaseOfData; */
|
||||||
#endif
|
#endif
|
||||||
/* NT additional fields. */
|
/* NT additional fields. */
|
||||||
#if defined(TCC_TARGET_ARM)
|
#if defined(TCC_TARGET_ARM)
|
||||||
0x00100000, /*DWORD ImageBase; */
|
0x00100000, /*DWORD ImageBase; */
|
||||||
|
#elif defined(TCC_TARGET_ARM64)
|
||||||
|
0x140000000ULL, /*ULONGLONG ImageBase; */
|
||||||
#else
|
#else
|
||||||
0x00400000, /*DWORD ImageBase; */
|
0x00400000, /*DWORD ImageBase; */
|
||||||
#endif
|
#endif
|
||||||
0x00001000, /*DWORD SectionAlignment; */
|
0x00001000, /*DWORD SectionAlignment; */
|
||||||
0x00000200, /*DWORD FileAlignment; */
|
0x00000200, /*DWORD FileAlignment; */
|
||||||
|
#if defined(TCC_TARGET_ARM64)
|
||||||
|
0x0006, /*WORD MajorOperatingSystemVersion; */
|
||||||
|
0x0002, /*WORD MinorOperatingSystemVersion; */
|
||||||
|
#else
|
||||||
0x0004, /*WORD MajorOperatingSystemVersion; */
|
0x0004, /*WORD MajorOperatingSystemVersion; */
|
||||||
0x0000, /*WORD MinorOperatingSystemVersion; */
|
0x0000, /*WORD MinorOperatingSystemVersion; */
|
||||||
|
#endif
|
||||||
0x0000, /*WORD MajorImageVersion; */
|
0x0000, /*WORD MajorImageVersion; */
|
||||||
0x0000, /*WORD MinorImageVersion; */
|
0x0000, /*WORD MinorImageVersion; */
|
||||||
|
#if defined(TCC_TARGET_ARM64)
|
||||||
|
0x0006, /*WORD MajorSubsystemVersion; */
|
||||||
|
0x0002, /*WORD MinorSubsystemVersion; */
|
||||||
|
#else
|
||||||
0x0004, /*WORD MajorSubsystemVersion; */
|
0x0004, /*WORD MajorSubsystemVersion; */
|
||||||
0x0000, /*WORD MinorSubsystemVersion; */
|
0x0000, /*WORD MinorSubsystemVersion; */
|
||||||
|
#endif
|
||||||
0x00000000, /*DWORD Win32VersionValue; */
|
0x00000000, /*DWORD Win32VersionValue; */
|
||||||
0x00000000, /*DWORD SizeOfImage; */
|
0x00000000, /*DWORD SizeOfImage; */
|
||||||
0x00000200, /*DWORD SizeOfHeaders; */
|
0x00000200, /*DWORD SizeOfHeaders; */
|
||||||
@ -702,7 +799,7 @@ static int pe_write(struct pe_info *pe)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case sec_data:
|
case sec_data:
|
||||||
#ifndef TCC_TARGET_X86_64
|
#if !defined(TCC_TARGET_X86_64) && !defined(TCC_TARGET_ARM64)
|
||||||
if (!pe_header.opthdr.BaseOfData)
|
if (!pe_header.opthdr.BaseOfData)
|
||||||
pe_header.opthdr.BaseOfData = addr;
|
pe_header.opthdr.BaseOfData = addr;
|
||||||
#endif
|
#endif
|
||||||
@ -764,11 +861,14 @@ static int pe_write(struct pe_info *pe)
|
|||||||
pe_header.opthdr.SizeOfHeaders = pe->sizeofheaders;
|
pe_header.opthdr.SizeOfHeaders = pe->sizeofheaders;
|
||||||
pe_header.opthdr.ImageBase = pe->imagebase;
|
pe_header.opthdr.ImageBase = pe->imagebase;
|
||||||
pe_header.opthdr.Subsystem = pe->subsystem;
|
pe_header.opthdr.Subsystem = pe->subsystem;
|
||||||
|
pe_header.opthdr.DllCharacteristics = pe_get_dll_characteristics(s1);
|
||||||
if (s1->pe_stack_size)
|
if (s1->pe_stack_size)
|
||||||
pe_header.opthdr.SizeOfStackReserve = s1->pe_stack_size;
|
pe_header.opthdr.SizeOfStackReserve = s1->pe_stack_size;
|
||||||
if (PE_DLL == pe->type)
|
if (PE_DLL == pe->type)
|
||||||
pe_header.filehdr.Characteristics = CHARACTERISTICS_DLL;
|
pe_header.filehdr.Characteristics = CHARACTERISTICS_DLL;
|
||||||
pe_header.filehdr.Characteristics |= s1->pe_characteristics;
|
pe_header.filehdr.Characteristics |= s1->pe_characteristics;
|
||||||
|
if (pe->reloc)
|
||||||
|
pe_header.filehdr.Characteristics &= ~PE_IMAGE_FILE_RELOCS_STRIPPED;
|
||||||
|
|
||||||
if (pe->coffsym) {
|
if (pe->coffsym) {
|
||||||
pe_add_coffsym(pe);
|
pe_add_coffsym(pe);
|
||||||
@ -1191,7 +1291,8 @@ static int pe_assign_addresses (struct pe_info *pe)
|
|||||||
Section *s;
|
Section *s;
|
||||||
TCCState *s1 = pe->s1;
|
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->reloc = new_section(s1, ".reloc", SHT_PROGBITS, 0);
|
||||||
//pe->thunk = new_section(s1, ".iedat", SHT_PROGBITS, SHF_ALLOC);
|
//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]
|
write32le(p + 4, 0xE59CF000); // arm code ldr pc, [ip]
|
||||||
put_elf_reloc(symtab_section, text_section,
|
put_elf_reloc(symtab_section, text_section,
|
||||||
offset + 8, R_XXX_THUNKFIX, is->iat_index); // offset to IAT position
|
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
|
#else
|
||||||
p = section_ptr_add(text_section, 8);
|
p = section_ptr_add(text_section, 8);
|
||||||
write16le(p, 0x25FF);
|
write16le(p, 0x25FF);
|
||||||
@ -1611,7 +1724,7 @@ static int get_dllexports(int fd, char **pp)
|
|||||||
if (IMAGE_DIRECTORY_ENTRY_EXPORT >= oh.NumberOfRvaAndSizes)
|
if (IMAGE_DIRECTORY_ENTRY_EXPORT >= oh.NumberOfRvaAndSizes)
|
||||||
goto the_end_0;
|
goto the_end_0;
|
||||||
addr = oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
|
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;
|
IMAGE_OPTIONAL_HEADER64 oh;
|
||||||
sec_hdroffset = opt_hdroffset + sizeof oh;
|
sec_hdroffset = opt_hdroffset + sizeof oh;
|
||||||
if (!read_mem(fd, opt_hdroffset, &oh, 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
|
#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) {
|
if (NULL == s1->uw_pdata) {
|
||||||
s1->uw_pdata = find_section(s1, ".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;
|
DWORD UnwindData;
|
||||||
} *p;
|
} *p;
|
||||||
|
|
||||||
d = pe_add_uwwind_info(s1);
|
d = pe_add_unwind_info(s1);
|
||||||
pd = s1->uw_pdata;
|
pd = s1->uw_pdata;
|
||||||
o = pd->data_offset;
|
o = pd->data_offset;
|
||||||
p = section_ptr_add(pd, sizeof *p);
|
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)
|
for (n = o + sizeof *p; o < n; o += sizeof p->BeginAddress)
|
||||||
put_elf_reloc(symtab_section, pd, o, R_XXX_RELATIVE, s1->uw_sym);
|
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
|
#endif
|
||||||
/* ------------------------------------------------------------- */
|
/* ------------------------------------------------------------- */
|
||||||
#ifdef TCC_TARGET_X86_64
|
#if defined(TCC_TARGET_X86_64) || defined(TCC_TARGET_ARM64)
|
||||||
#define PE_STDSYM(n,s) n
|
#define PE_STDSYM(n,s) n
|
||||||
#else
|
#else
|
||||||
#define PE_STDSYM(n,s) "_" n s
|
#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)
|
ST_FUNC int pe_setsubsy(TCCState *s1, const char *arg)
|
||||||
{
|
{
|
||||||
static const struct subsy { const char* p; int v; } x[] = {
|
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 },
|
{ "native", 1 },
|
||||||
{ "gui", 2 },
|
{ "gui", 2 },
|
||||||
{ "windows", 2 },
|
{ "windows", 2 },
|
||||||
@ -2020,10 +2209,16 @@ static void pe_set_options(TCCState * s1, struct pe_info *pe)
|
|||||||
{
|
{
|
||||||
if (PE_DLL == pe->type) {
|
if (PE_DLL == pe->type) {
|
||||||
/* XXX: check if is correct for arm-pe target */
|
/* XXX: check if is correct for arm-pe target */
|
||||||
|
#if defined(TCC_TARGET_ARM64)
|
||||||
|
pe->imagebase = 0x180000000ULL;
|
||||||
|
#else
|
||||||
pe->imagebase = 0x10000000;
|
pe->imagebase = 0x10000000;
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
#if defined(TCC_TARGET_ARM)
|
#if defined(TCC_TARGET_ARM)
|
||||||
pe->imagebase = 0x00010000;
|
pe->imagebase = 0x00010000;
|
||||||
|
#elif defined(TCC_TARGET_ARM64)
|
||||||
|
pe->imagebase = 0x140000000ULL;
|
||||||
#else
|
#else
|
||||||
pe->imagebase = 0x00400000;
|
pe->imagebase = 0x00400000;
|
||||||
#endif
|
#endif
|
||||||
@ -2080,29 +2275,33 @@ ST_FUNC int pe_output_file(TCCState *s1, const char *filename)
|
|||||||
resolve_common_syms(s1);
|
resolve_common_syms(s1);
|
||||||
pe_set_options(s1, &pe);
|
pe_set_options(s1, &pe);
|
||||||
pe_check_symbols(&pe);
|
pe_check_symbols(&pe);
|
||||||
|
|
||||||
if (s1->nb_errors)
|
if (s1->nb_errors)
|
||||||
;
|
goto done;
|
||||||
else if (filename) {
|
if (filename) {
|
||||||
pe_assign_addresses(&pe);
|
pe_assign_addresses(&pe);
|
||||||
relocate_syms(s1, s1->symtab, 0);
|
relocate_syms(s1, s1->symtab, 0);
|
||||||
|
if (s1->nb_errors)
|
||||||
|
goto done;
|
||||||
s1->pe_imagebase = pe.imagebase;
|
s1->pe_imagebase = pe.imagebase;
|
||||||
relocate_sections(s1);
|
relocate_sections(s1);
|
||||||
pe.start_addr = (DWORD)
|
pe.start_addr = (DWORD)
|
||||||
(get_sym_addr(s1, pe.start_symbol, 1, 1) - pe.imagebase);
|
(get_sym_addr(s1, pe.start_symbol, 1, 1) - pe.imagebase);
|
||||||
if (0 == s1->nb_errors)
|
if (s1->nb_errors)
|
||||||
pe_write(&pe);
|
goto done;
|
||||||
dynarray_reset(&pe.sec_info, &pe.sec_count);
|
pe_write(&pe);
|
||||||
} else {
|
} else {
|
||||||
|
/* -run */
|
||||||
#ifdef TCC_IS_NATIVE
|
#ifdef TCC_IS_NATIVE
|
||||||
pe.thunk = data_section;
|
pe.thunk = data_section;
|
||||||
pe_build_imports(&pe);
|
pe_build_imports(&pe);
|
||||||
s1->run_main = pe.start_symbol;
|
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");
|
s1->uw_pdata = find_section(s1, ".pdata");
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
done:
|
||||||
|
dynarray_reset(&pe.sec_info, &pe.sec_count);
|
||||||
pe_free_imports(&pe);
|
pe_free_imports(&pe);
|
||||||
#if PE_PRINT_SECTIONS
|
#if PE_PRINT_SECTIONS
|
||||||
if (g_debug & 8)
|
if (g_debug & 8)
|
||||||
|
|||||||
95
tccpp.c
95
tccpp.c
@ -942,11 +942,11 @@ redo_start:
|
|||||||
else if (parse_flags & PARSE_FLAG_ASM_FILE)
|
else if (parse_flags & PARSE_FLAG_ASM_FILE)
|
||||||
p = parse_line_comment(p - 1);
|
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)
|
else if (parse_flags & PARSE_FLAG_ASM_FILE)
|
||||||
p = parse_line_comment(p - 1);
|
p = parse_line_comment(p - 1);
|
||||||
#else
|
#else
|
||||||
/* ARM assembly uses '#' for constants */
|
/* ARM/ARM64 assembly uses '#' for constants */
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
_default:
|
_default:
|
||||||
@ -987,11 +987,7 @@ static inline int tok_size(const int *p)
|
|||||||
case TOK_CULLONG:
|
case TOK_CULLONG:
|
||||||
return 1 + 2;
|
return 1 + 2;
|
||||||
case TOK_CLDOUBLE:
|
case TOK_CLDOUBLE:
|
||||||
#ifdef TCC_USING_DOUBLE_FOR_LDOUBLE
|
return 1 + LDOUBLE_WORDS;
|
||||||
return 1 + 8 / 4;
|
|
||||||
#else
|
|
||||||
return 1 + LDOUBLE_SIZE / 4;
|
|
||||||
#endif
|
|
||||||
default:
|
default:
|
||||||
return 1 + 0;
|
return 1 + 0;
|
||||||
}
|
}
|
||||||
@ -1130,22 +1126,12 @@ static void tok_str_add2(TokenString *s, int t, CValue *cv)
|
|||||||
str[len++] = cv->tab[1];
|
str[len++] = cv->tab[1];
|
||||||
break;
|
break;
|
||||||
case TOK_CLDOUBLE:
|
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[0];
|
||||||
str[len++] = cv->tab[1];
|
str[len++] = cv->tab[1];
|
||||||
|
if (LDOUBLE_WORDS >= 3)
|
||||||
str[len++] = cv->tab[2];
|
str[len++] = cv->tab[2];
|
||||||
|
if (LDOUBLE_WORDS >= 4)
|
||||||
str[len++] = cv->tab[3];
|
str[len++] = cv->tab[3];
|
||||||
#else
|
|
||||||
#error add long double size support
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1219,15 +1205,7 @@ static inline void tok_get(int *t, const int **pp, CValue *cv)
|
|||||||
n = 2;
|
n = 2;
|
||||||
goto copy;
|
goto copy;
|
||||||
case TOK_CLDOUBLE:
|
case TOK_CLDOUBLE:
|
||||||
#if LDOUBLE_SIZE == 8 || defined TCC_USING_DOUBLE_FOR_LDOUBLE
|
n = LDOUBLE_WORDS;
|
||||||
n = 2;
|
|
||||||
#elif LDOUBLE_SIZE == 12
|
|
||||||
n = 3;
|
|
||||||
#elif LDOUBLE_SIZE == 16
|
|
||||||
n = 4;
|
|
||||||
#else
|
|
||||||
# error add long double size support
|
|
||||||
#endif
|
|
||||||
copy:
|
copy:
|
||||||
do
|
do
|
||||||
*tab++ = *p++;
|
*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 */
|
/* we use 128 bit (64/112 needed) numbers */
|
||||||
#define BN_SIZE 4
|
#define BN_SIZE 4
|
||||||
#endif
|
|
||||||
|
|
||||||
/* bn = (bn << shift) | or_val */
|
/* bn = (bn << shift) | or_val */
|
||||||
static int bn_lshift(unsigned int *bn, int shift, int 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;
|
int b, t, shift, frac_bits, s, exp_val, ch;
|
||||||
char *q;
|
char *q;
|
||||||
unsigned int bn[BN_SIZE];
|
unsigned int bn[BN_SIZE];
|
||||||
#ifdef TCC_USING_DOUBLE_FOR_LDOUBLE
|
|
||||||
double d;
|
|
||||||
#else
|
|
||||||
long double d;
|
long double d;
|
||||||
#endif
|
|
||||||
|
|
||||||
/* number */
|
/* number */
|
||||||
q = token_buf;
|
q = token_buf;
|
||||||
@ -2388,19 +2357,14 @@ static void parse_number(const char *p)
|
|||||||
ch = *p++;
|
ch = *p++;
|
||||||
}
|
}
|
||||||
exp_val = exp_val * s;
|
exp_val = exp_val * s;
|
||||||
|
|
||||||
/* now we can generate the number */
|
/* now we can generate the number */
|
||||||
/* XXX: should patch directly float 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 +
|
d = (long double)bn[3] * 79228162514264337593543950336.0L +
|
||||||
(long double)bn[2] * 18446744073709551616.0L +
|
(long double)bn[2] * 18446744073709551616.0L +
|
||||||
(long double)bn[1] * 4294967296.0L +
|
(long double)bn[1] * 4294967296.0L +
|
||||||
(long double)bn[0];
|
(long double)bn[0];
|
||||||
d = ldexpl(d, exp_val - frac_bits);
|
d = ldexpl(d, exp_val - frac_bits);
|
||||||
#endif
|
|
||||||
t = toup(ch);
|
t = toup(ch);
|
||||||
if (t == 'F') {
|
if (t == 'F') {
|
||||||
ch = *p++;
|
ch = *p++;
|
||||||
@ -2410,11 +2374,7 @@ static void parse_number(const char *p)
|
|||||||
} else if (t == 'L') {
|
} else if (t == 'L') {
|
||||||
ch = *p++;
|
ch = *p++;
|
||||||
tok = TOK_CLDOUBLE;
|
tok = TOK_CLDOUBLE;
|
||||||
#ifdef TCC_USING_DOUBLE_FOR_LDOUBLE
|
|
||||||
tokc.d = d;
|
|
||||||
#else
|
|
||||||
tokc.ld = d;
|
tokc.ld = d;
|
||||||
#endif
|
|
||||||
} else {
|
} else {
|
||||||
tok = TOK_CDOUBLE;
|
tok = TOK_CDOUBLE;
|
||||||
tokc.d = (double)d;
|
tokc.d = (double)d;
|
||||||
@ -2464,18 +2424,14 @@ static void parse_number(const char *p)
|
|||||||
} else if (t == 'L') {
|
} else if (t == 'L') {
|
||||||
ch = *p++;
|
ch = *p++;
|
||||||
tok = TOK_CLDOUBLE;
|
tok = TOK_CLDOUBLE;
|
||||||
#ifdef TCC_USING_DOUBLE_FOR_LDOUBLE
|
|
||||||
tokc.d = strtod(token_buf, NULL);
|
|
||||||
#else
|
|
||||||
tokc.ld = strtold(token_buf, NULL);
|
tokc.ld = strtold(token_buf, NULL);
|
||||||
#endif
|
|
||||||
} else {
|
} else {
|
||||||
tok = TOK_CDOUBLE;
|
tok = TOK_CDOUBLE;
|
||||||
tokc.d = strtod(token_buf, NULL);
|
tokc.d = strtod(token_buf, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
unsigned long long n = 0, n1 = 0;
|
unsigned long long n, n1;
|
||||||
int lcount, ucount, ov = 0;
|
int lcount, ucount, ov = 0;
|
||||||
const char *p1;
|
const char *p1;
|
||||||
|
|
||||||
@ -2486,6 +2442,7 @@ static void parse_number(const char *p)
|
|||||||
b = 8;
|
b = 8;
|
||||||
q++;
|
q++;
|
||||||
}
|
}
|
||||||
|
n = 0;
|
||||||
while(1) {
|
while(1) {
|
||||||
t = *q++;
|
t = *q++;
|
||||||
/* no need for checks except for base 10 / 8 errors */
|
/* no need for checks except for base 10 / 8 errors */
|
||||||
@ -2499,14 +2456,11 @@ static void parse_number(const char *p)
|
|||||||
t = t - '0';
|
t = t - '0';
|
||||||
if (t >= b)
|
if (t >= b)
|
||||||
tcc_error("invalid digit");
|
tcc_error("invalid digit");
|
||||||
|
n1 = n;
|
||||||
n = n * b + t;
|
n = n * b + t;
|
||||||
if (!ov) {
|
/* detect overflow */
|
||||||
/* detect overflow */
|
if (n1 >= 0x1000000000000000ULL && n / b != n1)
|
||||||
if (n1 >= 0x1000000000000000ULL && n / b != n1)
|
ov = 1;
|
||||||
ov = 1;
|
|
||||||
else
|
|
||||||
n1 = n;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Determine the characteristics (unsigned and/or 64bit) the type of
|
/* Determine the characteristics (unsigned and/or 64bit) the type of
|
||||||
@ -2556,26 +2510,7 @@ static void parse_number(const char *p)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ov)
|
if (ov)
|
||||||
/* Give a warning with values in case of an overflow. This helps to
|
tcc_warning("integer constant overflow");
|
||||||
spot the 0 too much in 0x8000'0000'0000'0000'0. It may even be
|
|
||||||
better to use a 0x8000'0000'0000'0000 from n1 instead of a 0 from
|
|
||||||
n after the overflow. This is at least undefined behavior.
|
|
||||||
The C99 to C23 standards state:
|
|
||||||
"Each constant shall have a type and the value of a constant
|
|
||||||
shall be in the range of representable values for its type."
|
|
||||||
"If an integer constant cannot be represented by any type ...,
|
|
||||||
then the integer constant has no type."
|
|
||||||
The C++ standards state:
|
|
||||||
"A program is ill-formed if one of its translation units contains
|
|
||||||
an integer-literal that cannot be represented by any of the
|
|
||||||
allowed types." */
|
|
||||||
tcc_warning(
|
|
||||||
b == 8
|
|
||||||
? "integer constant overflow, using %#llo; did you mean %#llo?"
|
|
||||||
: b == 10
|
|
||||||
? "integer constant overflow, using %llu, did you mean %llu?"
|
|
||||||
: "integer constant overflow, using %#llx; did you mean %#llx?",
|
|
||||||
n, n1);
|
|
||||||
|
|
||||||
tok = TOK_CINT;
|
tok = TOK_CINT;
|
||||||
if (lcount) {
|
if (lcount) {
|
||||||
@ -2699,7 +2634,7 @@ maybe_newline:
|
|||||||
p++;
|
p++;
|
||||||
tok = TOK_TWOSHARPS;
|
tok = TOK_TWOSHARPS;
|
||||||
} else {
|
} else {
|
||||||
#if !defined(TCC_TARGET_ARM)
|
#if !defined(TCC_TARGET_ARM) && !defined(TCC_TARGET_ARM64)
|
||||||
if (parse_flags & PARSE_FLAG_ASM_FILE) {
|
if (parse_flags & PARSE_FLAG_ASM_FILE) {
|
||||||
p = parse_line_comment(p - 1);
|
p = parse_line_comment(p - 1);
|
||||||
goto redo_no_start;
|
goto redo_no_start;
|
||||||
|
|||||||
52
tccrun.c
52
tccrun.c
@ -130,8 +130,15 @@ static int rt_mem(TCCState *s1, int size)
|
|||||||
//printf("map %p %p %p\n", ptr, prw, (void*)ptr_diff);
|
//printf("map %p %p %p\n", ptr, prw, (void*)ptr_diff);
|
||||||
size *= 2;
|
size *= 2;
|
||||||
#else
|
#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 */
|
ptr = tcc_malloc(size += PAGESIZE); /* one extra page to align malloc memory */
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
if (!ptr)
|
||||||
|
return tcc_error_noabort("tccrun: could not allocate memory");
|
||||||
s1->run_ptr = ptr;
|
s1->run_ptr = ptr;
|
||||||
s1->run_size = size;
|
s1->run_size = size;
|
||||||
return ptr_diff;
|
return ptr_diff;
|
||||||
@ -188,12 +195,20 @@ ST_FUNC void tcc_run_free(TCCState *s1)
|
|||||||
#ifdef CONFIG_SELINUX
|
#ifdef CONFIG_SELINUX
|
||||||
munmap(ptr, size);
|
munmap(ptr, size);
|
||||||
#else
|
#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 */
|
/* unprotect memory to make it usable for malloc again */
|
||||||
protect_pages((void*)PAGEALIGN(ptr), size - PAGESIZE, 2 /*rw*/);
|
protect_pages((void*)PAGEALIGN(ptr), size - PAGESIZE, 2 /*rw*/);
|
||||||
# ifdef _WIN64
|
# ifdef _WIN64
|
||||||
win64_del_function_table(s1->run_function_table);
|
win64_del_function_table(s1->run_function_table);
|
||||||
# endif
|
# endif
|
||||||
tcc_free(ptr);
|
tcc_free(ptr);
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -287,7 +302,7 @@ static void cleanup_sections(TCCState *s1)
|
|||||||
do {
|
do {
|
||||||
for (i = --f; i < p->nb_secs; i++) {
|
for (i = --f; i < p->nb_secs; i++) {
|
||||||
Section *s = p->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);
|
s->data = tcc_realloc(s->data, s->data_allocated = s->data_offset);
|
||||||
} else {
|
} else {
|
||||||
free_section(s), tcc_free(s), p->secs[i] = NULL;
|
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) */
|
/* 0 = .text rwx other rw (memory >= 2 pages a 4096 bytes) */
|
||||||
/* 1 = .text rx other rw (memory >= 3 pages) */
|
/* 1 = .text rx other rw (memory >= 3 pages) */
|
||||||
/* 2 = .debug .debug ro (optional) */
|
/* 2 = .text rx .rdata ro .data/.bss rw (memory >= 4 pages) */
|
||||||
/* 3 = .text rx .rdata ro .data/.bss rw (memory >= 4 pages) */
|
|
||||||
|
|
||||||
/* Some targets implement secutiry options that do not allow write in
|
/* 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. */
|
The disadvantage of this is that it requires a little bit more memory. */
|
||||||
|
|
||||||
#ifndef CONFIG_RUNMEM_RO
|
#ifndef CONFIG_RUNMEM_RO
|
||||||
@ -344,13 +358,12 @@ redo:
|
|||||||
if (copy == 3)
|
if (copy == 3)
|
||||||
return 0;
|
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;
|
n = 0; addr = 0;
|
||||||
for(i = 1; i < s1->nb_sections; i++) {
|
for(i = 1; i < s1->nb_sections; i++) {
|
||||||
static const char shf[] = {
|
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];
|
s = s1->sections[i];
|
||||||
if (shf[k] != (s->sh_flags & (SHF_ALLOC|SHF_WRITE|SHF_EXECINSTR)))
|
if (shf[k] != (s->sh_flags & (SHF_ALLOC|SHF_WRITE|SHF_EXECINSTR)))
|
||||||
continue;
|
continue;
|
||||||
@ -414,7 +427,11 @@ redo:
|
|||||||
}
|
}
|
||||||
if (protect_pages((void*)addr, n, f) < 0)
|
if (protect_pages((void*)addr, n, f) < 0)
|
||||||
return tcc_error_noabort(
|
return tcc_error_noabort(
|
||||||
|
#ifdef _WIN32
|
||||||
|
"VirtualProtect failed");
|
||||||
|
#else
|
||||||
"mprotect failed (did you mean to configure --with-selinux?)");
|
"mprotect failed (did you mean to configure --with-selinux?)");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -436,6 +453,8 @@ redo:
|
|||||||
|
|
||||||
/* relocate symbols */
|
/* relocate symbols */
|
||||||
relocate_syms(s1, s1->symtab, 1);
|
relocate_syms(s1, s1->symtab, 1);
|
||||||
|
if (s1->nb_errors)
|
||||||
|
goto redo;
|
||||||
/* relocate sections */
|
/* relocate sections */
|
||||||
#ifdef TCC_TARGET_PE
|
#ifdef TCC_TARGET_PE
|
||||||
s1->pe_imagebase = mem;
|
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]))
|
if (mprotect(ptr, length, protect[mode]))
|
||||||
return -1;
|
return -1;
|
||||||
/* XXX: BSD sometimes dump core with bad system call */
|
/* 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) {
|
if (mode == 0 || mode == 3) {
|
||||||
void __clear_cache(void *beginning, void *end);
|
void __clear_cache(void *beginning, void *end);
|
||||||
__clear_cache(ptr, (char *)ptr + length);
|
__clear_cache(ptr, (char *)ptr + length);
|
||||||
@ -487,11 +506,14 @@ static void *win64_add_function_table(TCCState *s1)
|
|||||||
void *p = NULL;
|
void *p = NULL;
|
||||||
if (s1->uw_pdata) {
|
if (s1->uw_pdata) {
|
||||||
p = (void*)s1->uw_pdata->sh_addr;
|
p = (void*)s1->uw_pdata->sh_addr;
|
||||||
RtlAddFunctionTable(
|
if (!RtlAddFunctionTable(
|
||||||
(RUNTIME_FUNCTION*)p,
|
(RUNTIME_FUNCTION*)p,
|
||||||
s1->uw_pdata->data_offset / sizeof (RUNTIME_FUNCTION),
|
s1->uw_pdata->data_offset / sizeof (RUNTIME_FUNCTION),
|
||||||
s1->pe_imagebase
|
s1->pe_imagebase
|
||||||
);
|
)) {
|
||||||
|
tcc_error_noabort("RtlAddFunctionTable failed");
|
||||||
|
p = NULL;
|
||||||
|
}
|
||||||
s1->uw_pdata = NULL;
|
s1->uw_pdata = NULL;
|
||||||
}
|
}
|
||||||
return p;
|
return p;
|
||||||
@ -1201,7 +1223,11 @@ static int rt_error(rt_frame *f, const char *fmt, ...)
|
|||||||
/* translate from ucontext_t* to internal rt_context * */
|
/* translate from ucontext_t* to internal rt_context * */
|
||||||
static void rt_getcontext(ucontext_t *uc, rt_frame *rc)
|
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->ip = uc->Rip;
|
||||||
rc->fp = uc->Rbp;
|
rc->fp = uc->Rbp;
|
||||||
rc->sp = uc->Rsp;
|
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. */
|
/* Generate a stack backtrace when a CPU exception occurs. */
|
||||||
static void set_exception_handler(void)
|
static void set_exception_handler(void)
|
||||||
{
|
{
|
||||||
|
#ifdef _WIN64
|
||||||
|
AddVectoredExceptionHandler(1, cpu_exception_handler);
|
||||||
|
#else
|
||||||
SetUnhandledExceptionFilter(cpu_exception_handler);
|
SetUnhandledExceptionFilter(cpu_exception_handler);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
21
tcctok.h
21
tcctok.h
@ -39,6 +39,7 @@
|
|||||||
DEF(TOK_RESTRICT3, "__restrict__")
|
DEF(TOK_RESTRICT3, "__restrict__")
|
||||||
DEF(TOK_EXTENSION, "__extension__") /* gcc keyword */
|
DEF(TOK_EXTENSION, "__extension__") /* gcc keyword */
|
||||||
DEF(TOK_THREAD_LOCAL, "_Thread_local") /* C11 thread-local storage */
|
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_GENERIC, "_Generic")
|
||||||
DEF(TOK_STATIC_ASSERT, "_Static_assert")
|
DEF(TOK_STATIC_ASSERT, "_Static_assert")
|
||||||
@ -306,8 +307,13 @@
|
|||||||
#if defined TCC_TARGET_PE
|
#if defined TCC_TARGET_PE
|
||||||
DEF(TOK___chkstk, "__chkstk")
|
DEF(TOK___chkstk, "__chkstk")
|
||||||
#endif
|
#endif
|
||||||
#if defined TCC_TARGET_ARM64 || defined TCC_TARGET_RISCV64
|
#ifdef TCC_TARGET_ARM64
|
||||||
DEF(TOK___arm64_clear_cache, "__arm64_clear_cache")
|
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___addtf3, "__addtf3")
|
||||||
DEF(TOK___subtf3, "__subtf3")
|
DEF(TOK___subtf3, "__subtf3")
|
||||||
DEF(TOK___multf3, "__multf3")
|
DEF(TOK___multf3, "__multf3")
|
||||||
@ -402,12 +408,13 @@
|
|||||||
DEF_ASMDIR(endr)
|
DEF_ASMDIR(endr)
|
||||||
DEF_ASMDIR(org)
|
DEF_ASMDIR(org)
|
||||||
DEF_ASMDIR(quad)
|
DEF_ASMDIR(quad)
|
||||||
#if defined(TCC_TARGET_I386)
|
#if PTR_SIZE == 4
|
||||||
DEF_ASMDIR(code16)
|
DEF_ASMDIR(code16)
|
||||||
DEF_ASMDIR(code32)
|
DEF_ASMDIR(code32)
|
||||||
#elif defined(TCC_TARGET_X86_64)
|
#else
|
||||||
DEF_ASMDIR(code64)
|
DEF_ASMDIR(code64)
|
||||||
#elif defined(TCC_TARGET_RISCV64)
|
#endif
|
||||||
|
#if defined(TCC_TARGET_RISCV64)
|
||||||
DEF_ASMDIR(option)
|
DEF_ASMDIR(option)
|
||||||
#endif
|
#endif
|
||||||
DEF_ASMDIR(short)
|
DEF_ASMDIR(short)
|
||||||
@ -421,10 +428,14 @@
|
|||||||
#include "i386-tok.h"
|
#include "i386-tok.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined TCC_TARGET_ARM || defined TCC_TARGET_ARM64
|
#if defined TCC_TARGET_ARM
|
||||||
#include "arm-tok.h"
|
#include "arm-tok.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined TCC_TARGET_ARM64
|
||||||
|
#include "arm64-tok.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined TCC_TARGET_RISCV64
|
#if defined TCC_TARGET_RISCV64
|
||||||
#include "riscv64-tok.h"
|
#include "riscv64-tok.h"
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -13,7 +13,6 @@ TESTS = \
|
|||||||
hello-run \
|
hello-run \
|
||||||
libtest \
|
libtest \
|
||||||
libtest_mt \
|
libtest_mt \
|
||||||
libtest_xor_rex \
|
|
||||||
test3 \
|
test3 \
|
||||||
abitest \
|
abitest \
|
||||||
asm-c-connect-test \
|
asm-c-connect-test \
|
||||||
@ -41,9 +40,6 @@ endif
|
|||||||
ifeq (,$(filter i386 x86_64,$(ARCH)))
|
ifeq (,$(filter i386 x86_64,$(ARCH)))
|
||||||
TESTS := $(filter-out asm-c-connect-test,$(TESTS))
|
TESTS := $(filter-out asm-c-connect-test,$(TESTS))
|
||||||
endif
|
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
|
ifeq ($(OS),Windows_NT) # for libtcc_test to find libtcc.dll
|
||||||
PATH := $(CURDIR)/$(TOP)$(if $(findstring ;,$(PATH)),;,:)$(PATH)
|
PATH := $(CURDIR)/$(TOP)$(if $(findstring ;,$(PATH)),;,:)$(PATH)
|
||||||
endif
|
endif
|
||||||
@ -76,9 +72,9 @@ endif
|
|||||||
RUN_TCC = -run $(TOPSRC)/tcc.c $(TCCFLAGS)
|
RUN_TCC = -run $(TOPSRC)/tcc.c $(TCCFLAGS)
|
||||||
DISAS = objdump -d
|
DISAS = objdump -d
|
||||||
ifdef CONFIG_OSX
|
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
|
else
|
||||||
DUMPTCC = (set -x; $(TOP)/tcc -vv; ldd $(TOP)/tcc; exit 1)
|
DUMPTCC = (set -x; $(TCC_LOCAL) -vv; ldd $(TCC_LOCAL); exit 1)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
all test :
|
all test :
|
||||||
@ -86,6 +82,7 @@ all test :
|
|||||||
@$(TCC_LOCAL) -v
|
@$(TCC_LOCAL) -v
|
||||||
@$(MAKE) --no-print-directory -s clean
|
@$(MAKE) --no-print-directory -s clean
|
||||||
@$(MAKE) --no-print-directory -s -r _all
|
@$(MAKE) --no-print-directory -s -r _all
|
||||||
|
@echo ------- ALL TESTS PASSED --------
|
||||||
|
|
||||||
_all : $(TESTS)
|
_all : $(TESTS)
|
||||||
|
|
||||||
@ -107,17 +104,14 @@ libtcc_test$(EXESUF): libtcc_test.c
|
|||||||
libtcc_test_mt$(EXESUF): libtcc_test_mt.c
|
libtcc_test_mt$(EXESUF): libtcc_test_mt.c
|
||||||
$(CC) -o $@ $< $(CFLAGS) $(-LTCC) $(LIBS)
|
$(CC) -o $@ $< $(CFLAGS) $(-LTCC) $(LIBS)
|
||||||
|
|
||||||
libtcc_test_xor_rex$(EXESUF): libtcc_test_xor_rex.c
|
|
||||||
$(CC) -o $@ $< $(CFLAGS) $(-LTCC) $(LIBS)
|
|
||||||
|
|
||||||
%-dir:
|
%-dir:
|
||||||
@echo ------------ $@ ------------
|
@echo ------------ $@ ------------
|
||||||
$(MAKE) -k -C $*
|
$(MAKE) -k -C $*
|
||||||
|
|
||||||
# test.ref - generate using cc
|
# test.ref - generate using cc
|
||||||
test.ref: tcctest.c
|
test.ref: tcctest.c
|
||||||
$(CC) -o tcctest.gcc $< $(CFLAGS) -w -O0 -std=gnu99 -fno-omit-frame-pointer
|
$(CC) -o tcctest.gcc$(EXESUF) $< $(CFLAGS) -w -O0 -std=gnu99 -fno-omit-frame-pointer
|
||||||
./tcctest.gcc > $@
|
./tcctest.gcc$(EXESUF) > $@
|
||||||
|
|
||||||
# auto test
|
# auto test
|
||||||
test1 test1b: tcctest.c test.ref
|
test1 test1b: tcctest.c test.ref
|
||||||
@ -316,6 +310,7 @@ CROSS-TGTS = \
|
|||||||
arm-NetBSD \
|
arm-NetBSD \
|
||||||
arm-wince \
|
arm-wince \
|
||||||
arm64 \
|
arm64 \
|
||||||
|
arm64-win32 \
|
||||||
arm64-osx \
|
arm64-osx \
|
||||||
arm64-FreeBSD \
|
arm64-FreeBSD \
|
||||||
arm64-NetBSD \
|
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;
|
void *func;
|
||||||
tcc_add_symbol(s, "add", add);
|
tcc_add_symbol(s, "add", add);
|
||||||
|
tcc_add_symbol(s, "printf", printf);
|
||||||
if (tcc_relocate(s) < 0) {
|
if (tcc_relocate(s) < 0) {
|
||||||
fprintf(stderr, __FILE__ ": could not relocate tcc state.\n");
|
fprintf(stderr, __FILE__ ": could not relocate tcc state.\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -337,8 +338,16 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
#include <tcclib.h>
|
#include <tcclib.h>
|
||||||
|
#ifdef _WIN32
|
||||||
unsigned int sleep(unsigned int seconds);
|
# 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)
|
int fib(n)
|
||||||
{
|
{
|
||||||
@ -347,7 +356,7 @@ int fib(n)
|
|||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
sleep(1);
|
sleep_ms(333);
|
||||||
printf(" %d", fib(atoi(argv[1])));
|
printf(" %d", fib(atoi(argv[1])));
|
||||||
return 0;
|
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
|
rm -f *.output
|
||||||
|
|
||||||
02.test : DIFF_OPTS += -w
|
02.test : DIFF_OPTS += -w
|
||||||
|
16.test : DIFF_OPTS += -B
|
||||||
# 15.test : DIFF_OPTS += -I"^XXX:"
|
# 15.test : DIFF_OPTS += -I"^XXX:"
|
||||||
|
|
||||||
# diff options:
|
# diff options:
|
||||||
|
|||||||
@ -32,8 +32,9 @@
|
|||||||
#define XLONG_LONG_FORMAT "%Lx"
|
#define XLONG_LONG_FORMAT "%Lx"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// MinGW has 80-bit rather than 64-bit long double which isn't compatible with TCC or MSVC
|
/* MinGW has 80-bit rather than 64-bit long double which isn't
|
||||||
#if defined(_WIN32) && defined(__GNUC__)
|
compatible with printf in msvcrt */
|
||||||
|
#if defined(_WIN32)
|
||||||
#define LONG_DOUBLE double
|
#define LONG_DOUBLE double
|
||||||
#define LONG_DOUBLE_LITERAL(x) x
|
#define LONG_DOUBLE_LITERAL(x) x
|
||||||
#else
|
#else
|
||||||
@ -81,9 +82,6 @@ typedef __SIZE_TYPE__ uintptr_t;
|
|||||||
#include incname
|
#include incname
|
||||||
#include stringify(funnyname)
|
#include stringify(funnyname)
|
||||||
|
|
||||||
int puts(const char *s);
|
|
||||||
void *alloca(size_t size);
|
|
||||||
|
|
||||||
int fib(int n);
|
int fib(int n);
|
||||||
void num(int n);
|
void num(int n);
|
||||||
void forward_ref(void);
|
void forward_ref(void);
|
||||||
@ -287,6 +285,7 @@ comment
|
|||||||
|
|
||||||
printf("basefromheader %s\n", get_basefile_from_header());
|
printf("basefromheader %s\n", get_basefile_from_header());
|
||||||
printf("base %s\n", __BASE_FILE__);
|
printf("base %s\n", __BASE_FILE__);
|
||||||
|
#if !(defined _WIN32 && CC_NAME == CC_clang)
|
||||||
{
|
{
|
||||||
/* Some compilers (clang) prepend './' to __FILE__ from included
|
/* Some compilers (clang) prepend './' to __FILE__ from included
|
||||||
files. */
|
files. */
|
||||||
@ -295,6 +294,8 @@ comment
|
|||||||
fn += 2;
|
fn += 2;
|
||||||
printf("filefromheader %s\n", fn);
|
printf("filefromheader %s\n", fn);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
printf("file %s\n", __FILE__);
|
printf("file %s\n", __FILE__);
|
||||||
|
|
||||||
/* Check that funnily named include was in fact included */
|
/* Check that funnily named include was in fact included */
|
||||||
@ -1095,8 +1096,10 @@ void struct_test()
|
|||||||
sizeof(struct aligntest2), __alignof__(struct aligntest2));
|
sizeof(struct aligntest2), __alignof__(struct aligntest2));
|
||||||
printf("aligntest3 sizeof=%d alignof=%d\n",
|
printf("aligntest3 sizeof=%d alignof=%d\n",
|
||||||
sizeof(struct aligntest3), __alignof__(struct aligntest3));
|
sizeof(struct aligntest3), __alignof__(struct aligntest3));
|
||||||
|
#if !(defined _WIN32 && CC_NAME == CC_clang)
|
||||||
printf("aligntest4 sizeof=%d alignof=%d\n",
|
printf("aligntest4 sizeof=%d alignof=%d\n",
|
||||||
sizeof(struct aligntest4), __alignof__(struct aligntest4));
|
sizeof(struct aligntest4), __alignof__(struct aligntest4));
|
||||||
|
#endif
|
||||||
printf("aligntest5 sizeof=%d alignof=%d\n",
|
printf("aligntest5 sizeof=%d alignof=%d\n",
|
||||||
sizeof(struct aligntest5), __alignof__(struct aligntest5));
|
sizeof(struct aligntest5), __alignof__(struct aligntest5));
|
||||||
printf("aligntest6 sizeof=%d alignof=%d\n",
|
printf("aligntest6 sizeof=%d alignof=%d\n",
|
||||||
@ -1105,8 +1108,10 @@ void struct_test()
|
|||||||
sizeof(struct aligntest7), __alignof__(struct aligntest7));
|
sizeof(struct aligntest7), __alignof__(struct aligntest7));
|
||||||
printf("aligntest8 sizeof=%d alignof=%d\n",
|
printf("aligntest8 sizeof=%d alignof=%d\n",
|
||||||
sizeof(struct aligntest8), __alignof__(struct aligntest8));
|
sizeof(struct aligntest8), __alignof__(struct aligntest8));
|
||||||
|
#if !(defined _WIN32 && CC_NAME == CC_clang)
|
||||||
printf("aligntest9 sizeof=%d alignof=%d\n",
|
printf("aligntest9 sizeof=%d alignof=%d\n",
|
||||||
sizeof(struct aligntest9), __alignof__(struct aligntest9));
|
sizeof(struct aligntest9), __alignof__(struct aligntest9));
|
||||||
|
#endif
|
||||||
printf("aligntest10 sizeof=%d alignof=%d\n",
|
printf("aligntest10 sizeof=%d alignof=%d\n",
|
||||||
sizeof(struct aligntest10), __alignof__(struct aligntest10));
|
sizeof(struct aligntest10), __alignof__(struct aligntest10));
|
||||||
printf("altest5 sizeof=%d alignof=%d\n",
|
printf("altest5 sizeof=%d alignof=%d\n",
|
||||||
@ -1117,7 +1122,9 @@ void struct_test()
|
|||||||
sizeof(altest7), __alignof__(altest7));
|
sizeof(altest7), __alignof__(altest7));
|
||||||
|
|
||||||
/* empty structures (GCC extension) */
|
/* empty structures (GCC extension) */
|
||||||
|
#if !(defined _WIN32 && CC_NAME == CC_clang)
|
||||||
printf("sizeof(struct empty) = %d\n", sizeof(struct empty));
|
printf("sizeof(struct empty) = %d\n", sizeof(struct empty));
|
||||||
|
#endif
|
||||||
printf("alignof(struct empty) = %d\n", __alignof__(struct empty));
|
printf("alignof(struct empty) = %d\n", __alignof__(struct empty));
|
||||||
|
|
||||||
printf("Large: sizeof=%d\n", sizeof(ls));
|
printf("Large: sizeof=%d\n", sizeof(ls));
|
||||||
@ -1168,7 +1175,7 @@ void char_short_test()
|
|||||||
var4 = 0x11223344aa998877ULL;
|
var4 = 0x11223344aa998877ULL;
|
||||||
printf("promote char/short assign VA %d %d\n", var3 = var1 + 1, var3 = var4 + 1);
|
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));
|
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
|
/* We can't really express GCC behaviour of return type promotion in
|
||||||
the presence of undefined behaviour (like __csf is). */
|
the presence of undefined behaviour (like __csf is). */
|
||||||
var1 = csf(unsigned char,0x89898989);
|
var1 = csf(unsigned char,0x89898989);
|
||||||
@ -1459,17 +1466,37 @@ static int tab_reinit[10];
|
|||||||
static int tentative_ar[];
|
static int tentative_ar[];
|
||||||
static int tentative_ar[] = {1,2,3};
|
static int tentative_ar[] = {1,2,3};
|
||||||
|
|
||||||
//int cinit1; /* a global variable can be defined several times without error ! */
|
int cinit1; /* a global variable can be defined several times without error ! */
|
||||||
int cinit1;
|
|
||||||
int cinit1;
|
int cinit1;
|
||||||
int cinit1 = 0;
|
int cinit1 = 0;
|
||||||
int *cinit2 = (int []){3, 2, 1};
|
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)
|
void compound_literal_test(void)
|
||||||
{
|
{
|
||||||
int *p, i;
|
int *p, i;
|
||||||
char *q, *q3;
|
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};
|
p = (int []){1, 2, 3};
|
||||||
for(i=0;i<3;i++)
|
for(i=0;i<3;i++)
|
||||||
printf(" %d", p[i]);
|
printf(" %d", p[i]);
|
||||||
@ -2176,15 +2203,6 @@ float strtof(const char *nptr, char **endptr);
|
|||||||
LONG_DOUBLE strtold(const char *nptr, char **endptr);
|
LONG_DOUBLE strtold(const char *nptr, char **endptr);
|
||||||
#endif
|
#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)\
|
#define FTEST(prefix, typename, type, fmt)\
|
||||||
void prefix ## cmp(type a, type b)\
|
void prefix ## cmp(type a, type b)\
|
||||||
{\
|
{\
|
||||||
@ -2240,7 +2258,7 @@ void prefix ## fcast(type a)\
|
|||||||
b = llia;\
|
b = llia;\
|
||||||
printf("lltof: " fmt "\n", b);\
|
printf("lltof: " fmt "\n", b);\
|
||||||
b = llua;\
|
b = llua;\
|
||||||
printf("ulltof: " fmt "\n", b);\
|
if (CC_NAME != CC_clang) printf("ulltof: " fmt "\n", b);\
|
||||||
}\
|
}\
|
||||||
\
|
\
|
||||||
float prefix ## retf(type a) { return a; }\
|
float prefix ## retf(type a) { return a; }\
|
||||||
@ -2300,7 +2318,7 @@ void prefix ## test(void)\
|
|||||||
prefix ## fcast(-2334.6);\
|
prefix ## fcast(-2334.6);\
|
||||||
prefix ## call();\
|
prefix ## call();\
|
||||||
prefix ## signed_zeros();\
|
prefix ## signed_zeros();\
|
||||||
if (enable_nan_test) prefix ## nan();\
|
if (CC_NAME != CC_clang) prefix ## nan();\
|
||||||
}
|
}
|
||||||
|
|
||||||
FTEST(f, float, float, "%f")
|
FTEST(f, float, float, "%f")
|
||||||
@ -2556,8 +2574,8 @@ void longlong_test(void)
|
|||||||
a = ia;
|
a = ia;
|
||||||
b = ua;
|
b = ua;
|
||||||
printf(LONG_LONG_FORMAT " " LONG_LONG_FORMAT "\n", a, b);
|
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)1,
|
||||||
(long long)-2,
|
(long long)-2,
|
||||||
1LL,
|
1LL,
|
||||||
0x1234567812345679);
|
0x1234567812345679);
|
||||||
@ -2867,12 +2885,14 @@ void stdarg_test(void)
|
|||||||
stdarg_for_struct(bob, bob2, bob3, bob4, bob, bob, bob.profile);
|
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_for_libc("stdarg_for_libc: %s %.2f %d\n", "string", 1.23, 456);
|
||||||
stdarg_syntax(1, 17);
|
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(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,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,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,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,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]);
|
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 };
|
int reltab[3] = { 1, 2, 3 };
|
||||||
@ -3289,7 +3309,7 @@ void local_label_test(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* inline assembler test */
|
/* 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;
|
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]);
|
printf ("asm_local_label_diff: %d %d\n", alld_stuff[0], alld_stuff[1]);
|
||||||
}
|
}
|
||||||
#endif
|
#endif //!__APPLE__
|
||||||
#endif
|
#endif //!_WIN32
|
||||||
|
|
||||||
/* This checks that static local variables are available from assembler. */
|
/* This checks that static local variables are available from assembler. */
|
||||||
void asm_local_statics (void)
|
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
|
#elif defined test_switch_W4
|
||||||
#pragma comment(option, "-Wunsupported -Wno-error=implicit-function-declaration -Werror")
|
#pragma comment(option, "-Wunsupported -Wno-error=implicit-function-declaration -Werror")
|
||||||
#endif
|
#endif
|
||||||
void func()
|
void func(void)
|
||||||
{
|
{
|
||||||
char *ccp = "123";
|
char *ccp = "123";
|
||||||
fink();
|
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
|
#endif
|
||||||
|
|||||||
@ -262,3 +262,31 @@ bar 15 12 34
|
|||||||
[test_scope_3]
|
[test_scope_3]
|
||||||
60_errors_and_warnings.c:548: warning: assignment from incompatible pointer type
|
60_errors_and_warnings.c:548: warning: assignment from incompatible pointer type
|
||||||
60_errors_and_warnings.c:549: error: initialization of incomplete 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 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 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_s1(struct s1 a) { printf("%.1s\n", a.x); }
|
||||||
void fa_s2(struct s2 a) { printf("%.2s\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); }
|
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); }
|
{ printf("%.1Lf %.1Lf %.1Lf\n", a.a, a.b, a.c); }
|
||||||
void fa_hfa34(struct hfa34 a)
|
void fa_hfa34(struct hfa34 a)
|
||||||
{ printf("%.1Lf %.1Lf %.1Lf %.1Lf\n", a.a, a.b, a.c, a.d); }
|
{ 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,
|
void fa1(struct s8 a, struct s9 b, struct s10 c, struct s11 d,
|
||||||
struct s12 e, struct s13 f)
|
struct s12 e, struct s13 f)
|
||||||
@ -140,6 +149,8 @@ void arg(void)
|
|||||||
fa_hfa32(hfa32);
|
fa_hfa32(hfa32);
|
||||||
fa_hfa33(hfa33);
|
fa_hfa33(hfa33);
|
||||||
fa_hfa34(hfa34);
|
fa_hfa34(hfa34);
|
||||||
|
fa_hfae12(hfae12);
|
||||||
|
fa_hfae22(hfae22);
|
||||||
fa1(s8, s9, s10, s11, s12, s13);
|
fa1(s8, s9, s10, s11, s12, s13);
|
||||||
fa2(s9, s10, s11, s12, s13, s14);
|
fa2(s9, s10, s11, s12, s13, s14);
|
||||||
fa3(hfa14, hfa23, hfa32);
|
fa3(hfa14, hfa23, hfa32);
|
||||||
@ -178,6 +189,8 @@ struct hfa31 fr_hfa31(void) { return hfa31; }
|
|||||||
struct hfa32 fr_hfa32(void) { return hfa32; }
|
struct hfa32 fr_hfa32(void) { return hfa32; }
|
||||||
struct hfa33 fr_hfa33(void) { return hfa33; }
|
struct hfa33 fr_hfa33(void) { return hfa33; }
|
||||||
struct hfa34 fr_hfa34(void) { return hfa34; }
|
struct hfa34 fr_hfa34(void) { return hfa34; }
|
||||||
|
struct hfae12 fr_hfae12(void) { return hfae12; }
|
||||||
|
struct hfae22 fr_hfae22(void) { return hfae22; }
|
||||||
|
|
||||||
void ret(void)
|
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_hfa32().a, fr_hfa32().b);
|
||||||
printf("%.1Lf %.1Lf\n", fr_hfa33().a, fr_hfa33().c);
|
printf("%.1Lf %.1Lf\n", fr_hfa33().a, fr_hfa33().c);
|
||||||
printf("%.1Lf %.1Lf\n", fr_hfa34().a, fr_hfa34().d);
|
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*
|
void*
|
||||||
|
|||||||
@ -28,6 +28,8 @@ cdefghijklmnopqrs
|
|||||||
32.1 32.1
|
32.1 32.1
|
||||||
33.1 33.2 33.3
|
33.1 33.2 33.3
|
||||||
34.1 34.2 34.3 34.4
|
34.1 34.2 34.3 34.4
|
||||||
|
112.1 112.2
|
||||||
|
122.1 122.2
|
||||||
stu ABC JKL TUV 456 ghi
|
stu ABC JKL TUV 456 ghi
|
||||||
ABC JKL TUV 456 ghi tuv
|
ABC JKL TUV 456 ghi tuv
|
||||||
14.1 14.4 23.1 23.3 32.1 32.2
|
14.1 14.4 23.1 23.3 32.1 32.2
|
||||||
@ -62,6 +64,8 @@ cdefghijklmnopqrs
|
|||||||
32.1 32.2
|
32.1 32.2
|
||||||
33.1 33.3
|
33.1 33.3
|
||||||
34.1 34.4
|
34.1 34.4
|
||||||
|
112.1 112.2
|
||||||
|
122.1 122.2
|
||||||
stdarg:
|
stdarg:
|
||||||
ABCDEFGHI ABCDEFGHI ABCDEFGHI ABCDEFGHI ABCDEFGHI ABCDEFGHI
|
ABCDEFGHI ABCDEFGHI ABCDEFGHI ABCDEFGHI ABCDEFGHI ABCDEFGHI
|
||||||
lmnopqr 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 += 85_asm-outside-function.test # x86 asm
|
||||||
SKIP += 127_asm_goto.test # hardcodes x86 asm
|
SKIP += 127_asm_goto.test # hardcodes x86 asm
|
||||||
endif
|
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)
|
ifeq ($(CONFIG_backtrace),no)
|
||||||
SKIP += 113_btdll.test
|
SKIP += 113_btdll.test
|
||||||
CONFIG_bcheck = no
|
CONFIG_bcheck = no
|
||||||
@ -47,12 +50,29 @@ ifeq (-$(CONFIG_WIN32)-,-yes-)
|
|||||||
SKIP += 114_bound_signal.test # No pthread support
|
SKIP += 114_bound_signal.test # No pthread support
|
||||||
SKIP += 117_builtins.test # win32 port doesn't define __builtins
|
SKIP += 117_builtins.test # win32 port doesn't define __builtins
|
||||||
SKIP += 124_atomic_counter.test # No pthread support
|
SKIP += 124_atomic_counter.test # No pthread support
|
||||||
|
SKIP += 144_tls.test # No pthread support
|
||||||
endif
|
endif
|
||||||
ifneq (,$(filter OpenBSD FreeBSD NetBSD,$(TARGETOS)))
|
ifneq (,$(filter OpenBSD FreeBSD NetBSD,$(TARGETOS)))
|
||||||
SKIP += 106_versym.test # no pthread_condattr_setpshared
|
SKIP += 106_versym.test # no pthread_condattr_setpshared
|
||||||
SKIP += 114_bound_signal.test # libc problem signal/fork
|
SKIP += 114_bound_signal.test # libc problem signal/fork
|
||||||
SKIP += 116_bound_setjmp2.test # No TLS_FUNC/TLS_VAR in bcheck.c
|
SKIP += 116_bound_setjmp2.test # No TLS_FUNC/TLS_VAR in bcheck.c
|
||||||
endif
|
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
|
# Some tests might need arguments
|
||||||
ARGS =
|
ARGS =
|
||||||
@ -62,6 +82,7 @@ ARGS =
|
|||||||
# And some tests don't test the right thing with -run
|
# And some tests don't test the right thing with -run
|
||||||
NORUN =
|
NORUN =
|
||||||
42_function_pointer.test : NORUN = true
|
42_function_pointer.test : NORUN = true
|
||||||
|
# riscv64 asm tests validate encoding, raw regs may crash at runtime
|
||||||
|
|
||||||
# Some tests might need different flags
|
# Some tests might need different flags
|
||||||
FLAGS =
|
FLAGS =
|
||||||
@ -74,8 +95,8 @@ endif
|
|||||||
# These tests run several snippets from the same file one by one
|
# These tests run several snippets from the same file one by one
|
||||||
60_errors_and_warnings.test : FLAGS += -dt
|
60_errors_and_warnings.test : FLAGS += -dt
|
||||||
96_nodata_wanted.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 =
|
||||||
# GEN-ALWAYS += 95_bitfields.expect # does not work
|
# GEN-ALWAYS += 95_bitfields.expect # does not work
|
||||||
|
|
||||||
@ -98,6 +119,10 @@ GEN-ALWAYS =
|
|||||||
# constructor/destructor
|
# constructor/destructor
|
||||||
108_constructor.test: NORUN = true
|
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: FLAGS += -dt -b
|
||||||
112_backtrace.test 113_btdll.test 126_bound_global.test: FILTER += \
|
112_backtrace.test 113_btdll.test 126_bound_global.test: FILTER += \
|
||||||
-e 's;[0-9A-Fa-fx]\{5,\};........;g' \
|
-e 's;[0-9A-Fa-fx]\{5,\};........;g' \
|
||||||
@ -125,6 +150,8 @@ endif
|
|||||||
126_bound_global.test: NORUN = true
|
126_bound_global.test: NORUN = true
|
||||||
128_run_atexit.test: FLAGS += -dt
|
128_run_atexit.test: FLAGS += -dt
|
||||||
132_bound_test.test: FLAGS += -b
|
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 source directory in warnings/errors (out-of-tree builds)
|
||||||
FILTER = 2>&1 | sed -e 's,$(SRC)/,,g'
|
FILTER = 2>&1 | sed -e 's,$(SRC)/,,g'
|
||||||
|
|||||||
@ -5,13 +5,15 @@
|
|||||||
@echo off
|
@echo off
|
||||||
setlocal
|
setlocal
|
||||||
if (%1)==(-clean) goto :cleanup
|
if (%1)==(-clean) goto :cleanup
|
||||||
set CC=gcc
|
set CC=gcc -O2 -Wall
|
||||||
set /p VERSION= < ..\VERSION
|
set /p VERSION= < ..\VERSION
|
||||||
set TCCDIR=
|
set TCCDIR=
|
||||||
set BINDIR=
|
set BINDIR=
|
||||||
set DOC=no
|
set DOC=no
|
||||||
set XCC=no
|
set TX=
|
||||||
|
set SELF=%~nx0
|
||||||
goto :a0
|
goto :a0
|
||||||
|
|
||||||
:a2
|
:a2
|
||||||
shift
|
shift
|
||||||
:a3
|
:a3
|
||||||
@ -27,20 +29,22 @@ if (%1)==(-v) set VERSION=%~2&& goto :a2
|
|||||||
if (%1)==(-i) set TCCDIR=%2&& goto :a2
|
if (%1)==(-i) set TCCDIR=%2&& goto :a2
|
||||||
if (%1)==(-b) set BINDIR=%2&& goto :a2
|
if (%1)==(-b) set BINDIR=%2&& goto :a2
|
||||||
if (%1)==(-d) set DOC=yes&& goto :a3
|
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
|
if (%1)==() goto :p1
|
||||||
|
|
||||||
:usage
|
:usage
|
||||||
echo usage: build-tcc.bat [ options ... ]
|
echo usage: build-tcc.bat [ options ... ]
|
||||||
echo options:
|
echo options:
|
||||||
echo -c prog use prog (gcc/tcc/cl) to compile tcc
|
echo -c prog use prog (gcc/tcc/cl) to compile tcc
|
||||||
echo -c "prog options" use prog with options 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 -v "version" set tcc version
|
||||||
echo -i tccdir install tcc into tccdir
|
echo -i tccdir install tcc into tccdir
|
||||||
echo -b bindir but install tcc.exe and libtcc.dll into bindir
|
echo -b bindir but install tcc.exe and libtcc.dll into bindir
|
||||||
echo -d create tcc-doc.html too (needs makeinfo)
|
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 -clean delete all previously produced files and directories
|
||||||
|
echo supported targets i386 x86_64 arm64
|
||||||
exit /B 1
|
exit /B 1
|
||||||
|
|
||||||
@rem ------------------------------------------------------
|
@rem ------------------------------------------------------
|
||||||
@ -65,6 +69,7 @@ exit /B 0
|
|||||||
if exist %1 rmdir /Q/S %1 && %LOG% %1
|
if exist %1 rmdir /Q/S %1 && %LOG% %1
|
||||||
exit /B 0
|
exit /B 0
|
||||||
|
|
||||||
|
@rem ------------------------------------------------------
|
||||||
:cl
|
:cl
|
||||||
@echo off
|
@echo off
|
||||||
set CMD=cl
|
set CMD=cl
|
||||||
@ -84,36 +89,19 @@ echo on
|
|||||||
@rem main program
|
@rem main program
|
||||||
|
|
||||||
:p1
|
:p1
|
||||||
if not %T%_==_ goto :p2
|
if not _%TX%_==__ set T=%TX%&&set TX=%TX%-win32-
|
||||||
set T=32
|
if _%T%_%PROCESSOR_ARCHITECTURE%_==__x86_ set T=i386
|
||||||
if %PROCESSOR_ARCHITECTURE%_==AMD64_ set T=64
|
if _%T%_%PROCESSOR_ARCHITECTURE%_==__ARM64_ set T=arm64
|
||||||
if %PROCESSOR_ARCHITEW6432%_==AMD64_ set T=64
|
if _%T%_==__ set T=x86_64
|
||||||
:p2
|
if %T%==i386 set D=-DTCC_TARGET_PE -DTCC_TARGET_I386
|
||||||
if "%CC:~-3%"=="gcc" set CC=%CC% -O2 -s -static
|
if %T%==x86_64 set D=-DTCC_TARGET_PE -DTCC_TARGET_X86_64
|
||||||
if (%BINDIR%)==() set BINDIR=%TCCDIR%
|
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
|
@if (%CC:~0,3%)==(gcc) set CC=%CC% -s -static
|
||||||
set D64=-DTCC_TARGET_PE -DTCC_TARGET_X86_64
|
@if (%BINDIR%)==() set BINDIR=%TCCDIR%
|
||||||
set P32=i386-win32
|
|
||||||
set P64=x86_64-win32
|
|
||||||
|
|
||||||
if %T%==64 goto :t64
|
:git_hash
|
||||||
set D=%D32%
|
|
||||||
set P=%P32%
|
|
||||||
set DX=%D64%
|
|
||||||
set PX=%P64%
|
|
||||||
set TX=64
|
|
||||||
goto :p3
|
|
||||||
|
|
||||||
:t64
|
|
||||||
set D=%D64%
|
|
||||||
set P=%P64%
|
|
||||||
set DX=%D32%
|
|
||||||
set PX=%P32%
|
|
||||||
set TX=32
|
|
||||||
goto :p3
|
|
||||||
|
|
||||||
:p3
|
|
||||||
git.exe --version 2>nul
|
git.exe --version 2>nul
|
||||||
if not %ERRORLEVEL%==0 goto :git_done
|
if not %ERRORLEVEL%==0 goto :git_done
|
||||||
for /f %%b in ('git.exe rev-parse --abbrev-ref HEAD') do set GITHASH=%%b
|
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
|
:config.h
|
||||||
echo>..\config.h #define TCC_VERSION "%VERSION%"
|
echo>..\config.h #define TCC_VERSION "%VERSION%"
|
||||||
if not (%GITHASH%)==() echo>> ..\config.h #define TCC_GITHASH "%GITHASH%"
|
@if not "%GITHASH%"=="" echo>>..\config.h #define TCC_GITHASH "%GITHASH%"
|
||||||
@if not (%BINDIR%)==(%TCCDIR%) echo>> ..\config.h #define CONFIG_TCCDIR "%TCCDIR:\=/%"
|
@if not _%BINDIR%_==_%TCCDIR%_ echo>>..\config.h #define CONFIG_TCCDIR "%TCCDIR:\=/%"
|
||||||
if %TX%==64 echo>> ..\config.h #ifdef TCC_TARGET_X86_64
|
@if not _%TX%_==__ @echo>>..\config.h #define CONFIG_TCC_CROSSPREFIX "%TX%"
|
||||||
if %TX%==32 echo>> ..\config.h #ifdef TCC_TARGET_I386
|
|
||||||
echo>> ..\config.h #define CONFIG_TCC_CROSSPREFIX "%PX%-"
|
|
||||||
echo>> ..\config.h #endif
|
|
||||||
|
|
||||||
@rem echo>> ..\config.h #define CONFIG_TCC_PREDEFS 1
|
@rem echo>> ..\config.h #define CONFIG_TCC_PREDEFS 1
|
||||||
@rem %CC% -DC2STR ..\conftest.c -o c2str.exe
|
@rem %CC% -DC2STR ..\conftest.c -o c2str.exe
|
||||||
@rem .\c2str.exe ../include/tccdefs.h ../tccdefs_.h
|
@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
|
@if _%LIBTCC_C%_==__ set LIBTCC_C=..\libtcc.c
|
||||||
@rem if TCC_C was defined then build only tcc.exe
|
@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%
|
%CC% -o tcc.exe %TCC_C% %D%
|
||||||
@if errorlevel 1 goto :the_end
|
@if errorlevel 1 goto :the_end
|
||||||
@goto :compiler_done
|
@goto :compiler_done
|
||||||
|
|
||||||
:compiler_2parts
|
:tcc_cross
|
||||||
@if _%LIBTCC_C%_==__ set LIBTCC_C=..\libtcc.c
|
%CC% -o %TX%tcc.exe ..\tcc.c %D%
|
||||||
%CC% -o libtcc.dll -shared %LIBTCC_C% %D% -DLIBTCC_AS_DLL
|
|
||||||
@if errorlevel 1 goto :the_end
|
|
||||||
%CC% -o tcc.exe ..\tcc.c libtcc.dll %D% -DONE_SOURCE"=0"
|
|
||||||
@if errorlevel 1 goto :the_end
|
|
||||||
if not _%XCC%_==_yes_ goto :compiler_done
|
|
||||||
%CC% -o %PX%-tcc.exe ..\tcc.c %DX%
|
|
||||||
@if errorlevel 1 goto :the_end
|
@if errorlevel 1 goto :the_end
|
||||||
|
@goto :compiler_done
|
||||||
|
|
||||||
:compiler_done
|
:compiler_done
|
||||||
@if (%EXES_ONLY%)==(yes) goto :files_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
|
@if errorlevel 1 goto :the_end
|
||||||
|
|
||||||
:lib
|
:lib
|
||||||
call :make_lib %T% || goto :the_end
|
@call :make_lib %TX% || goto :the_end
|
||||||
@if exist %PX%-tcc.exe call :make_lib %TX% %PX%- || goto :the_end
|
|
||||||
|
|
||||||
:tcc-doc.html
|
:tcc-doc.html
|
||||||
@if not (%DOC%)==(yes) goto :doc-done
|
@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%
|
exit /B %ERRORLEVEL%
|
||||||
|
|
||||||
:make_lib
|
:make_lib
|
||||||
.\tcc -B. -m%1 -c ../lib/libtcc1.c
|
@set LIBTCC1=libtcc1
|
||||||
.\tcc -B. -m%1 -c lib/crt1.c
|
@if _%1_==_arm64_ set LIBTCC1=lib-arm64
|
||||||
.\tcc -B. -m%1 -c lib/crt1w.c
|
.\%1tcc -B. -c ../lib/%LIBTCC1%.c
|
||||||
.\tcc -B. -m%1 -c lib/wincrt1.c
|
.\%1tcc -B. -c lib/crt1.c
|
||||||
.\tcc -B. -m%1 -c lib/wincrt1w.c
|
.\%1tcc -B. -c lib/crt1w.c
|
||||||
.\tcc -B. -m%1 -c lib/dllcrt1.c
|
.\%1tcc -B. -c lib/wincrt1.c
|
||||||
.\tcc -B. -m%1 -c lib/dllmain.c
|
.\%1tcc -B. -c lib/wincrt1w.c
|
||||||
.\tcc -B. -m%1 -c lib/chkstk.S
|
.\%1tcc -B. -c lib/dllcrt1.c
|
||||||
.\tcc -B. -m%1 -c ../lib/alloca.S
|
.\%1tcc -B. -c lib/dllmain.c
|
||||||
.\tcc -B. -m%1 -c ../lib/alloca-bt.S
|
.\%1tcc -B. -c lib/winex.c
|
||||||
.\tcc -B. -m%1 -c ../lib/stdatomic.c
|
.\%1tcc -B. -c lib/chkstk.S
|
||||||
.\tcc -B. -m%1 -c ../lib/atomic.S
|
.\%1tcc -B. -c ../lib/alloca.S
|
||||||
.\tcc -B. -m%1 -c ../lib/builtin.c
|
.\%1tcc -B. -c ../lib/alloca-bt.S
|
||||||
.\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
|
.\%1tcc -B. -c ../lib/stdatomic.c
|
||||||
.\tcc -B. -m%1 -c ../lib/bcheck.c -o lib/%2bcheck.o -bt -I..
|
.\%1tcc -B. -c ../lib/atomic.S
|
||||||
.\tcc -B. -m%1 -c ../lib/bt-exe.c -o lib/%2bt-exe.o
|
.\%1tcc -B. -c ../lib/builtin.c
|
||||||
.\tcc -B. -m%1 -c ../lib/bt-log.c -o lib/%2bt-log.o
|
.\%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
|
||||||
.\tcc -B. -m%1 -c ../lib/bt-dll.c -o lib/%2bt-dll.o
|
.\%1tcc -B. -c ../lib/bcheck.c -o lib/%1bcheck.o -bt -I..
|
||||||
.\tcc -B. -m%1 -c ../lib/runmain.c -o lib/%2runmain.o
|
.\%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%
|
exit /B %ERRORLEVEL%
|
||||||
|
|||||||
@ -70,12 +70,15 @@
|
|||||||
|
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
#define __stdcall
|
#define __stdcall
|
||||||
|
#if defined(__aarch64__)
|
||||||
|
#define _M_ARM64 1
|
||||||
|
#define _ARM64_ 1
|
||||||
|
#else
|
||||||
#define _AMD64_ 1
|
#define _AMD64_ 1
|
||||||
#define __x86_64 1
|
#define __x86_64 1
|
||||||
#define _M_X64 100 /* Visual Studio */
|
#define _M_X64 100 /* Visual Studio */
|
||||||
#define _M_AMD64 100 /* Visual Studio */
|
#define _M_AMD64 100 /* Visual Studio */
|
||||||
#define USE_MINGW_SETJMP_TWO_ARGS
|
#endif
|
||||||
#define mingw_getsp tinyc_getbp
|
|
||||||
#else
|
#else
|
||||||
#define __stdcall __attribute__((__stdcall__))
|
#define __stdcall __attribute__((__stdcall__))
|
||||||
#define _X86_ 1
|
#define _X86_ 1
|
||||||
|
|||||||
@ -124,37 +124,76 @@ extern "C" {
|
|||||||
SETJMP_FLOAT128 Xmm14;
|
SETJMP_FLOAT128 Xmm14;
|
||||||
SETJMP_FLOAT128 Xmm15;
|
SETJMP_FLOAT128 Xmm15;
|
||||||
} _JUMP_BUFFER;
|
} _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
|
#endif
|
||||||
#ifndef _JMP_BUF_DEFINED
|
#ifndef _JMP_BUF_DEFINED
|
||||||
typedef _JBTYPE jmp_buf[_JBLEN];
|
typedef _JBTYPE jmp_buf[_JBLEN];
|
||||||
#define _JMP_BUF_DEFINED
|
#define _JMP_BUF_DEFINED
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void * __cdecl __attribute__ ((__nothrow__)) mingw_getsp(void);
|
#pragma pack(pop)
|
||||||
|
|
||||||
#ifdef USE_MINGW_SETJMP_TWO_ARGS
|
#if defined __aarch64__
|
||||||
#ifndef _INC_SETJMPEX
|
int _setjmpex(jmp_buf _Buf, void *frame);
|
||||||
#define setjmp(BUF) _setjmp((BUF),mingw_getsp())
|
#define setjmp(BUF) _setjmpex((BUF), (char*)__builtin_frame_address(0) + 224)
|
||||||
int __cdecl __attribute__ ((__nothrow__)) _setjmp(jmp_buf _Buf,void *_Ctx);
|
#elif defined __x86_64__
|
||||||
#else
|
int _setjmp(jmp_buf _Buf, void *frame);
|
||||||
#undef setjmp
|
#define setjmp(BUF) _setjmp((BUF), __builtin_frame_address(0))
|
||||||
#define setjmp(BUF) _setjmpex((BUF),mingw_getsp())
|
#else /* __i386__ */
|
||||||
#define setjmpex(BUF) _setjmpex((BUF),mingw_getsp())
|
int _setjmp(jmp_buf _Buf);
|
||||||
int __cdecl __attribute__ ((__nothrow__)) _setjmpex(jmp_buf _Buf,void *_Ctx);
|
#define setjmp _setjmp
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
#ifndef _INC_SETJMPEX
|
|
||||||
#define setjmp _setjmp
|
|
||||||
#endif
|
|
||||||
int __cdecl __attribute__ ((__nothrow__)) setjmp(jmp_buf _Buf);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
__declspec(noreturn) __attribute__ ((__nothrow__)) void __cdecl ms_longjmp(jmp_buf _Buf,int _Value)/* throw(...)*/;
|
__declspec(noreturn) void longjmp(jmp_buf _Buf,int _Value);
|
||||||
__declspec(noreturn) __attribute__ ((__nothrow__)) void __cdecl longjmp(jmp_buf _Buf,int _Value);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#pragma pack(pop)
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -207,6 +207,21 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#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
|
#ifndef _pgmptr
|
||||||
#ifdef _MSVCRT_
|
#ifdef _MSVCRT_
|
||||||
extern char *_pgmptr;
|
extern char *_pgmptr;
|
||||||
|
|||||||
@ -972,7 +972,9 @@ extern "C" {
|
|||||||
LONG WINAPI InterlockedDecrement(LONG volatile *lpAddend);
|
LONG WINAPI InterlockedDecrement(LONG volatile *lpAddend);
|
||||||
LONG WINAPI InterlockedExchange(LONG volatile *Target,LONG Value);
|
LONG WINAPI InterlockedExchange(LONG volatile *Target,LONG Value);
|
||||||
|
|
||||||
|
#ifndef InterlockedExchangePointer
|
||||||
#define InterlockedExchangePointer(Target,Value) (PVOID)InterlockedExchange((PLONG)(Target),(LONG)(Value))
|
#define InterlockedExchangePointer(Target,Value) (PVOID)InterlockedExchange((PLONG)(Target),(LONG)(Value))
|
||||||
|
#endif
|
||||||
|
|
||||||
LONG WINAPI InterlockedExchangeAdd(LONG volatile *Addend,LONG Value);
|
LONG WINAPI InterlockedExchangeAdd(LONG volatile *Addend,LONG Value);
|
||||||
LONG WINAPI InterlockedCompareExchange(LONG volatile *Destination,LONG Exchange,LONG Comperand);
|
LONG WINAPI InterlockedCompareExchange(LONG volatile *Destination,LONG Exchange,LONG Comperand);
|
||||||
@ -1035,6 +1037,7 @@ extern "C" {
|
|||||||
return Old;
|
return Old;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef InterlockedCompareExchangePointer
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
__CRT_INLINE PVOID __cdecl __InlineInterlockedCompareExchangePointer(PVOID volatile *Destination,PVOID ExChange,PVOID Comperand) {
|
__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));
|
return((PVOID)(LONG_PTR)InterlockedCompareExchange((LONG volatile *)Destination,(LONG)(LONG_PTR)ExChange,(LONG)(LONG_PTR)Comperand));
|
||||||
@ -1043,6 +1046,7 @@ extern "C" {
|
|||||||
#else
|
#else
|
||||||
#define InterlockedCompareExchangePointer(Destination,ExChange,Comperand)(PVOID)(LONG_PTR)InterlockedCompareExchange((LONG volatile *)(Destination),(LONG)(LONG_PTR)(ExChange),(LONG)(LONG_PTR)(Comperand))
|
#define InterlockedCompareExchangePointer(Destination,ExChange,Comperand)(PVOID)(LONG_PTR)InterlockedCompareExchange((LONG volatile *)(Destination),(LONG)(LONG_PTR)(ExChange),(LONG)(LONG_PTR)(Comperand))
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#define InterlockedIncrementAcquire InterlockedIncrement
|
#define InterlockedIncrementAcquire InterlockedIncrement
|
||||||
#define InterlockedIncrementRelease InterlockedIncrement
|
#define InterlockedIncrementRelease InterlockedIncrement
|
||||||
@ -1054,9 +1058,13 @@ extern "C" {
|
|||||||
#define InterlockedCompareExchangeRelease InterlockedCompareExchange
|
#define InterlockedCompareExchangeRelease InterlockedCompareExchange
|
||||||
#define InterlockedCompareExchangeAcquire64 InterlockedCompareExchange64
|
#define InterlockedCompareExchangeAcquire64 InterlockedCompareExchange64
|
||||||
#define InterlockedCompareExchangeRelease64 InterlockedCompareExchange64
|
#define InterlockedCompareExchangeRelease64 InterlockedCompareExchange64
|
||||||
|
#ifndef InterlockedCompareExchangePointerAcquire
|
||||||
#define InterlockedCompareExchangePointerAcquire InterlockedCompareExchangePointer
|
#define InterlockedCompareExchangePointerAcquire InterlockedCompareExchangePointer
|
||||||
|
#endif
|
||||||
|
#ifndef InterlockedCompareExchangePointerRelease
|
||||||
#define InterlockedCompareExchangePointerRelease InterlockedCompareExchangePointer
|
#define InterlockedCompareExchangePointerRelease InterlockedCompareExchangePointer
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(_SLIST_HEADER_) && !defined(_NTOSP_)
|
#if defined(_SLIST_HEADER_) && !defined(_NTOSP_)
|
||||||
WINBASEAPI VOID WINAPI InitializeSListHead(PSLIST_HEADER ListHead);
|
WINBASEAPI VOID WINAPI InitializeSListHead(PSLIST_HEADER ListHead);
|
||||||
|
|||||||
@ -21,7 +21,7 @@ extern "C" {
|
|||||||
#define __CRT_UNALIGNED
|
#define __CRT_UNALIGNED
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__ia64__) || defined(__x86_64)
|
#if defined(__ia64__) || defined(__x86_64) || defined(__aarch64__)
|
||||||
#define UNALIGNED __CRT_UNALIGNED
|
#define UNALIGNED __CRT_UNALIGNED
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
#define UNALIGNED64 __CRT_UNALIGNED
|
#define UNALIGNED64 __CRT_UNALIGNED
|
||||||
@ -65,7 +65,7 @@ extern "C" {
|
|||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
#ifdef _AMD64_
|
#ifdef _AMD64_
|
||||||
#define PROBE_ALIGNMENT(_s) TYPE_ALIGNMENT(DWORD)
|
#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))
|
#define PROBE_ALIGNMENT(_s) (TYPE_ALIGNMENT(_s) > TYPE_ALIGNMENT(DWORD) ? TYPE_ALIGNMENT(_s) : TYPE_ALIGNMENT(DWORD))
|
||||||
#else
|
#else
|
||||||
#error No Target Architecture
|
#error No Target Architecture
|
||||||
@ -79,7 +79,7 @@ extern "C" {
|
|||||||
|
|
||||||
#include <basetsd.h>
|
#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)
|
#define DECLSPEC_IMPORT __declspec(dllimport)
|
||||||
#else
|
#else
|
||||||
#define DECLSPEC_IMPORT
|
#define DECLSPEC_IMPORT
|
||||||
@ -321,7 +321,7 @@ typedef DWORD LCID;
|
|||||||
#define Int32x32To64(a,b) (LONGLONG)((LONGLONG)(LONG)(a) *(LONG)(b))
|
#define Int32x32To64(a,b) (LONGLONG)((LONGLONG)(LONG)(a) *(LONG)(b))
|
||||||
#define UInt32x32To64(a,b) (ULONGLONG)((ULONGLONG)(DWORD)(a) *(DWORD)(b))
|
#define UInt32x32To64(a,b) (ULONGLONG)((ULONGLONG)(DWORD)(a) *(DWORD)(b))
|
||||||
#define Int64ShrlMod32(a,b) ((DWORDLONG)(a)>>(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 Int32x32To64(a,b) ((LONGLONG)((LONG)(a)) *(LONGLONG)((LONG)(b)))
|
||||||
#define UInt32x32To64(a,b) ((ULONGLONG)((DWORD)(a)) *(ULONGLONG)((DWORD)(b)))
|
#define UInt32x32To64(a,b) ((ULONGLONG)((DWORD)(a)) *(ULONGLONG)((DWORD)(b)))
|
||||||
#define Int64ShrlMod32(a,b) ((ULONGLONG)(a) >> (b))
|
#define Int64ShrlMod32(a,b) ((ULONGLONG)(a) >> (b))
|
||||||
@ -829,8 +829,6 @@ typedef DWORD LCID;
|
|||||||
typedef ULONG_PTR KSPIN_LOCK;
|
typedef ULONG_PTR KSPIN_LOCK;
|
||||||
typedef KSPIN_LOCK *PKSPIN_LOCK;
|
typedef KSPIN_LOCK *PKSPIN_LOCK;
|
||||||
|
|
||||||
#ifdef _AMD64_
|
|
||||||
|
|
||||||
#if defined(__x86_64) && !defined(RC_INVOKED)
|
#if defined(__x86_64) && !defined(RC_INVOKED)
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
@ -1282,7 +1280,6 @@ typedef DWORD LCID;
|
|||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
|
|
||||||
#define EXCEPTION_READ_FAULT 0
|
#define EXCEPTION_READ_FAULT 0
|
||||||
#define EXCEPTION_WRITE_FAULT 1
|
#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);
|
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"
|
#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 VOID __cdecl RtlRestoreContext (PCONTEXT ContextRecord,struct _EXCEPTION_RECORD *ExceptionRecord);
|
||||||
NTSYSAPI BOOLEAN __cdecl RtlAddFunctionTable(PRUNTIME_FUNCTION FunctionTable,DWORD EntryCount,DWORD64 BaseAddress);
|
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);
|
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_CEF 0x0CEF
|
||||||
#define IMAGE_FILE_MACHINE_EBC 0x0EBC
|
#define IMAGE_FILE_MACHINE_EBC 0x0EBC
|
||||||
#define IMAGE_FILE_MACHINE_AMD64 0x8664
|
#define IMAGE_FILE_MACHINE_AMD64 0x8664
|
||||||
|
#define IMAGE_FILE_MACHINE_ARM64 0xAA64
|
||||||
#define IMAGE_FILE_MACHINE_M32R 0x9041
|
#define IMAGE_FILE_MACHINE_M32R 0x9041
|
||||||
#define IMAGE_FILE_MACHINE_CEE 0xC0EE
|
#define IMAGE_FILE_MACHINE_CEE 0xC0EE
|
||||||
|
|
||||||
@ -3857,10 +4008,16 @@ typedef DWORD LCID;
|
|||||||
#define IMAGE_SUBSYSTEM_EFI_ROM 13
|
#define IMAGE_SUBSYSTEM_EFI_ROM 13
|
||||||
#define IMAGE_SUBSYSTEM_XBOX 14
|
#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_ISOLATION 0x0200
|
||||||
#define IMAGE_DLLCHARACTERISTICS_NO_SEH 0x0400
|
#define IMAGE_DLLCHARACTERISTICS_NO_SEH 0x0400
|
||||||
#define IMAGE_DLLCHARACTERISTICS_NO_BIND 0x0800
|
#define IMAGE_DLLCHARACTERISTICS_NO_BIND 0x0800
|
||||||
|
#define IMAGE_DLLCHARACTERISTICS_APPCONTAINER 0x1000
|
||||||
#define IMAGE_DLLCHARACTERISTICS_WDM_DRIVER 0x2000
|
#define IMAGE_DLLCHARACTERISTICS_WDM_DRIVER 0x2000
|
||||||
|
#define IMAGE_DLLCHARACTERISTICS_GUARD_CF 0x4000
|
||||||
#define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 0x8000
|
#define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 0x8000
|
||||||
|
|
||||||
#define IMAGE_DIRECTORY_ENTRY_EXPORT 0
|
#define IMAGE_DIRECTORY_ENTRY_EXPORT 0
|
||||||
|
|||||||
@ -8,8 +8,32 @@
|
|||||||
#endif
|
#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)
|
.globl _(__chkstk)
|
||||||
_(__chkstk):
|
_(__chkstk):
|
||||||
@ -33,8 +57,7 @@ P0:
|
|||||||
jmp *4(%eax)
|
jmp *4(%eax)
|
||||||
|
|
||||||
/* ---------------------------------------------- */
|
/* ---------------------------------------------- */
|
||||||
#else
|
#else /* __x86_64__ */
|
||||||
/* ---------------------------------------------- */
|
|
||||||
|
|
||||||
.globl _(__chkstk)
|
.globl _(__chkstk)
|
||||||
_(__chkstk):
|
_(__chkstk):
|
||||||
@ -58,16 +81,6 @@ P0:
|
|||||||
mov (%rax),%rcx /* restore ecx */
|
mov (%rax),%rcx /* restore ecx */
|
||||||
jmp *8(%rax)
|
jmp *8(%rax)
|
||||||
|
|
||||||
/* ---------------------------------------------- */
|
|
||||||
/* setjmp/longjmp support */
|
|
||||||
|
|
||||||
.globl _(tinyc_getbp)
|
|
||||||
_(tinyc_getbp):
|
|
||||||
mov %rbp,%rax
|
|
||||||
ret
|
|
||||||
|
|
||||||
/* ---------------------------------------------- */
|
/* ---------------------------------------------- */
|
||||||
#endif
|
#endif
|
||||||
/* ---------------------------------------------- */
|
/* ---------------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -75,10 +75,11 @@ __attribute__((weak)) extern int __run_on_exit();
|
|||||||
int _runtmain(int argc, /* as tcc passed in */ char **argv)
|
int _runtmain(int argc, /* as tcc passed in */ char **argv)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
#ifdef UNICODE
|
#if defined UNICODE || defined __aarch64__
|
||||||
_startupinfo start_info = {0};
|
_startupinfo start_info = {0};
|
||||||
|
__tgetmainargs(&__argc, &__targv, &_tenviron, 0, &start_info);
|
||||||
__tgetmainargs(&__argc, &__targv, &_tenviron, _dowildcard, &start_info);
|
#endif
|
||||||
|
#ifdef UNICODE
|
||||||
/* may be wrong when tcc has received wildcards (*.c) */
|
/* may be wrong when tcc has received wildcards (*.c) */
|
||||||
if (argc < __argc) {
|
if (argc < __argc) {
|
||||||
__targv += __argc - argc;
|
__targv += __argc - argc;
|
||||||
@ -93,6 +94,8 @@ int _runtmain(int argc, /* as tcc passed in */ char **argv)
|
|||||||
#endif
|
#endif
|
||||||
run_ctors(__argc, __targv, _tenviron);
|
run_ctors(__argc, __targv, _tenviron);
|
||||||
ret = _tmain(__argc, __targv, _tenviron);
|
ret = _tmain(__argc, __targv, _tenviron);
|
||||||
|
fflush(stdout);
|
||||||
|
fflush(stderr);
|
||||||
run_dtors();
|
run_dtors();
|
||||||
__run_on_exit(ret);
|
__run_on_exit(ret);
|
||||||
return ret;
|
return ret;
|
||||||
|
|||||||
@ -9,6 +9,7 @@ AllocConsole
|
|||||||
AllocLSCallback
|
AllocLSCallback
|
||||||
AllocSLCallback
|
AllocSLCallback
|
||||||
AreFileApisANSI
|
AreFileApisANSI
|
||||||
|
AttachConsole
|
||||||
BackupRead
|
BackupRead
|
||||||
BackupSeek
|
BackupSeek
|
||||||
BackupWrite
|
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
|
||||||
58
x86_64-gen.c
58
x86_64-gen.c
@ -266,14 +266,6 @@ ST_FUNC void gen_addr32(int r, Sym *sym, int c)
|
|||||||
gen_le32(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 */
|
/* output constant with relocation if 'r & VT_SYM' is true */
|
||||||
ST_FUNC void gen_addrpc32(int r, Sym *sym, int c)
|
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) {
|
} else if ((r & VT_VALMASK) == VT_LOCAL) {
|
||||||
/* currently, we use only ebp as base */
|
/* currently, we use only ebp as base */
|
||||||
if (c == (char)c) {
|
if (c == (signed char)c) {
|
||||||
/* short reference */
|
/* short reference */
|
||||||
o(0x45 | op_reg);
|
o(0x45 | op_reg);
|
||||||
g(c);
|
g(c);
|
||||||
@ -376,7 +368,8 @@ void load(int r, SValue *sv)
|
|||||||
#ifndef TCC_TARGET_PE
|
#ifndef TCC_TARGET_PE
|
||||||
/* we use indirect access via got */
|
/* we use indirect access via got */
|
||||||
if ((fr & VT_VALMASK) == VT_CONST && (fr & VT_SYM) &&
|
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 */
|
/* use the result register as a temporal register */
|
||||||
int tr = r | TREG_MEM;
|
int tr = r | TREG_MEM;
|
||||||
if (is_float(ft)) {
|
if (is_float(ft)) {
|
||||||
@ -393,6 +386,19 @@ void load(int r, SValue *sv)
|
|||||||
v = fr & VT_VALMASK;
|
v = fr & VT_VALMASK;
|
||||||
if (fr & VT_LVAL) {
|
if (fr & VT_LVAL) {
|
||||||
int b, ll;
|
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) {
|
if (v == VT_LLOCAL) {
|
||||||
v1.type.t = VT_PTR;
|
v1.type.t = VT_PTR;
|
||||||
v1.r = VT_LOCAL | VT_LVAL;
|
v1.r = VT_LOCAL | VT_LVAL;
|
||||||
@ -444,8 +450,7 @@ void load(int r, SValue *sv)
|
|||||||
b = 0xdb, r = 5; /* fldt */
|
b = 0xdb, r = 5; /* fldt */
|
||||||
} else if ((ft & VT_TYPE) == VT_BYTE || (ft & VT_TYPE) == VT_BOOL) {
|
} else if ((ft & VT_TYPE) == VT_BYTE || (ft & VT_TYPE) == VT_BOOL) {
|
||||||
b = 0xbe0f; /* movsbl */
|
b = 0xbe0f; /* movsbl */
|
||||||
} else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED) ||
|
} else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED)) {
|
||||||
(ft & VT_TYPE) == (VT_BOOL | VT_UNSIGNED)) {
|
|
||||||
b = 0xb60f; /* movzbl */
|
b = 0xb60f; /* movzbl */
|
||||||
} else if ((ft & VT_TYPE) == VT_SHORT) {
|
} else if ((ft & VT_TYPE) == VT_SHORT) {
|
||||||
b = 0xbf0f; /* movswl */
|
b = 0xbf0f; /* movswl */
|
||||||
@ -540,8 +545,7 @@ void load(int r, SValue *sv)
|
|||||||
o(0x44 + REG_VALUE(r)*8); /* %xmmN */
|
o(0x44 + REG_VALUE(r)*8); /* %xmmN */
|
||||||
o(0xf024);
|
o(0xf024);
|
||||||
} else {
|
} else {
|
||||||
if (!nocode_wanted)
|
assert((v >= TREG_XMM0) && (v <= TREG_XMM7));
|
||||||
assert((v >= TREG_XMM0) && (v <= TREG_XMM7));
|
|
||||||
if ((ft & VT_BTYPE) == VT_FLOAT) {
|
if ((ft & VT_BTYPE) == VT_FLOAT) {
|
||||||
o(0x100ff3);
|
o(0x100ff3);
|
||||||
} else {
|
} else {
|
||||||
@ -551,8 +555,7 @@ void load(int r, SValue *sv)
|
|||||||
o(0xc0 + REG_VALUE(v) + REG_VALUE(r)*8);
|
o(0xc0 + REG_VALUE(v) + REG_VALUE(r)*8);
|
||||||
}
|
}
|
||||||
} else if (r == TREG_ST0) {
|
} else if (r == TREG_ST0) {
|
||||||
if (!nocode_wanted)
|
assert((v >= TREG_XMM0) && (v <= TREG_XMM7));
|
||||||
assert((v >= TREG_XMM0) && (v <= TREG_XMM7));
|
|
||||||
/* gen_cvt_ftof(VT_LDOUBLE); */
|
/* gen_cvt_ftof(VT_LDOUBLE); */
|
||||||
/* movsd %xmmN,-0x10(%rsp) */
|
/* movsd %xmmN,-0x10(%rsp) */
|
||||||
o(0x110ff2);
|
o(0x110ff2);
|
||||||
@ -583,6 +586,20 @@ void store(int r, SValue *v)
|
|||||||
ft &= ~(VT_VOLATILE | VT_CONSTANT);
|
ft &= ~(VT_VOLATILE | VT_CONSTANT);
|
||||||
bt = ft & VT_BTYPE;
|
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
|
#ifndef TCC_TARGET_PE
|
||||||
/* we need to access the variable via got */
|
/* we need to access the variable via got */
|
||||||
if (fr == VT_CONST
|
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)
|
static void gen_offs_sp(int b, int r, int d)
|
||||||
{
|
{
|
||||||
orex(1,0,r & 0x100 ? 0 : r, b);
|
orex(1,0,r & 0x100 ? 0 : r, b);
|
||||||
if (d == (char)d) {
|
if (d == (signed char)d) {
|
||||||
o(0x2444 | (REG_VALUE(r) << 3));
|
o(0x2444 | (REG_VALUE(r) << 3));
|
||||||
g(d);
|
g(d);
|
||||||
} else {
|
} else {
|
||||||
@ -1060,7 +1077,7 @@ void gfunc_epilog(void)
|
|||||||
|
|
||||||
static void gadd_sp(int val)
|
static void gadd_sp(int val)
|
||||||
{
|
{
|
||||||
if (val == (char)val) {
|
if (val == (signed char)val) {
|
||||||
o(0xc48348);
|
o(0xc48348);
|
||||||
g(val);
|
g(val);
|
||||||
} else {
|
} else {
|
||||||
@ -1643,7 +1660,7 @@ void gjmp_addr(int a)
|
|||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
r = a - ind - 2;
|
r = a - ind - 2;
|
||||||
if (r == (char)r) {
|
if (r == (signed char)r) {
|
||||||
g(0xeb);
|
g(0xeb);
|
||||||
g(r);
|
g(r);
|
||||||
} else {
|
} else {
|
||||||
@ -1712,7 +1729,7 @@ void gen_opi(int op)
|
|||||||
r = gv(RC_INT);
|
r = gv(RC_INT);
|
||||||
vswap();
|
vswap();
|
||||||
c = vtop->c.i;
|
c = vtop->c.i;
|
||||||
if (c == (char)c) {
|
if (c == (signed char)c) {
|
||||||
/* XXX: generate inc and dec for smaller code ? */
|
/* XXX: generate inc and dec for smaller code ? */
|
||||||
orex(ll, r, 0, 0x83);
|
orex(ll, r, 0, 0x83);
|
||||||
o(0xc0 | (opc << 3) | REG_VALUE(r));
|
o(0xc0 | (opc << 3) | REG_VALUE(r));
|
||||||
@ -1840,6 +1857,7 @@ void gen_opf(int op)
|
|||||||
o(0x80); /* xor $0x80, $n(rbp) */
|
o(0x80); /* xor $0x80, $n(rbp) */
|
||||||
gen_modrm(6, vtop->r, NULL, vtop->c.i + (bt == VT_DOUBLE ? 7 : 3));
|
gen_modrm(6, vtop->r, NULL, vtop->c.i + (bt == VT_DOUBLE ? 7 : 3));
|
||||||
o(0x80);
|
o(0x80);
|
||||||
|
gv(float_type); /* -n is not a lvalue */
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,7 +13,7 @@
|
|||||||
#define R_NUM R_X86_64_NUM
|
#define R_NUM R_X86_64_NUM
|
||||||
|
|
||||||
#define ELF_START_ADDR 0x400000
|
#define ELF_START_ADDR 0x400000
|
||||||
#define ELF_PAGE_SIZE 0x200000
|
#define ELF_PAGE_SIZE 0x1000
|
||||||
|
|
||||||
#define PCRELATIVE_DLLPLT 1
|
#define PCRELATIVE_DLLPLT 1
|
||||||
#define RELOCATE_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_TLSGD:
|
||||||
case R_X86_64_TLSLD:
|
case R_X86_64_TLSLD:
|
||||||
case R_X86_64_DTPOFF32:
|
case R_X86_64_DTPOFF32:
|
||||||
case R_X86_64_TPOFF32:
|
|
||||||
case R_X86_64_DTPOFF64:
|
case R_X86_64_DTPOFF64:
|
||||||
case R_X86_64_TPOFF64:
|
|
||||||
case R_X86_64_REX_GOTPCRELX:
|
case R_X86_64_REX_GOTPCRELX:
|
||||||
case R_X86_64_PLT32:
|
case R_X86_64_PLT32:
|
||||||
case R_X86_64_PLTOFF64:
|
case R_X86_64_PLTOFF64:
|
||||||
return ALWAYS_GOTPLT_ENTRY;
|
return ALWAYS_GOTPLT_ENTRY;
|
||||||
|
|
||||||
|
case R_X86_64_TPOFF32:
|
||||||
|
case R_X86_64_TPOFF64:
|
||||||
|
return NO_GOTPLT_ENTRY;
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
@ -372,10 +374,30 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
|
|||||||
ElfW(Sym) *sym;
|
ElfW(Sym) *sym;
|
||||||
Section *sec;
|
Section *sec;
|
||||||
int32_t x;
|
int32_t x;
|
||||||
|
addr_t tls_start = 0, tls_end = 0, tls_align = 1;
|
||||||
|
int i;
|
||||||
|
|
||||||
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
|
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
|
||||||
sec = s1->sections[sym->st_shndx];
|
sec = s1->sections[sym->st_shndx];
|
||||||
x = val - sec->sh_addr - sec->data_offset;
|
|
||||||
|
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);
|
add32le(ptr, x);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -385,10 +407,30 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
|
|||||||
ElfW(Sym) *sym;
|
ElfW(Sym) *sym;
|
||||||
Section *sec;
|
Section *sec;
|
||||||
int32_t x;
|
int32_t x;
|
||||||
|
addr_t tls_start = 0, tls_end = 0, tls_align = 1;
|
||||||
|
int i;
|
||||||
|
|
||||||
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
|
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
|
||||||
sec = s1->sections[sym->st_shndx];
|
sec = s1->sections[sym->st_shndx];
|
||||||
x = val - sec->sh_addr - sec->data_offset;
|
|
||||||
|
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);
|
add64le(ptr, x);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user