mirror of
git://repo.or.cz/tinycc.git
synced 2026-06-20 11:54:18 +08:00
Compare commits
No commits in common. "mob" and "release_0_9_20" have entirely different histories.
mob
...
release_0_
51
.cvsignore
Normal file
51
.cvsignore
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
tcc_g
|
||||||
|
tcc
|
||||||
|
tc2.c
|
||||||
|
ex3
|
||||||
|
otcc1.c
|
||||||
|
doc
|
||||||
|
tc3s.c
|
||||||
|
p3.c
|
||||||
|
tc1.c
|
||||||
|
error.c
|
||||||
|
i386-gen1.c
|
||||||
|
test.out2
|
||||||
|
test.out3
|
||||||
|
web.sh
|
||||||
|
memdebug.c
|
||||||
|
bench
|
||||||
|
tcc-newparse.c
|
||||||
|
p1.c
|
||||||
|
Makefile.uClibc
|
||||||
|
boundtest
|
||||||
|
p4.c
|
||||||
|
p5.c
|
||||||
|
prog.ref
|
||||||
|
test.ref
|
||||||
|
a.c
|
||||||
|
p3
|
||||||
|
test.out
|
||||||
|
elf.h
|
||||||
|
stab.h
|
||||||
|
stab.def
|
||||||
|
p2
|
||||||
|
tcc-doc.html
|
||||||
|
ideas
|
||||||
|
tcctest.ref
|
||||||
|
test
|
||||||
|
linux.tcc
|
||||||
|
wintest.c
|
||||||
|
ldtest
|
||||||
|
libtcc_test
|
||||||
|
instr.S
|
||||||
|
p.c
|
||||||
|
p2.c
|
||||||
|
tcctest[1234]
|
||||||
|
test[1234].out
|
||||||
|
.gdb_history
|
||||||
|
tcc.1
|
||||||
|
tcc.pod
|
||||||
|
config.h
|
||||||
|
config.mak
|
||||||
|
config.texi
|
||||||
|
gcctestsuite.sh
|
||||||
143
.github/workflows/build.yml
vendored
143
.github/workflows/build.yml
vendored
@ -1,143 +0,0 @@
|
|||||||
name: build and test
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ mob ]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test-x86_64-linux:
|
|
||||||
runs-on: ubuntu-22.04
|
|
||||||
timeout-minutes: 2
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- name: make & test tcc (x86_64-linux)
|
|
||||||
run: ./configure && make && make test -k
|
|
||||||
|
|
||||||
test-x86_64-osx:
|
|
||||||
runs-on: macos-15-intel
|
|
||||||
timeout-minutes: 2
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- name: make & test tcc (x86_64-osx)
|
|
||||||
run: ./configure && make && make test -k
|
|
||||||
|
|
||||||
test-aarch64-osx:
|
|
||||||
runs-on: macos-15
|
|
||||||
timeout-minutes: 2
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- name: make & test tcc (aarch64-osx)
|
|
||||||
run: ./configure && make && make test -k
|
|
||||||
|
|
||||||
test-x86_64-win32:
|
|
||||||
runs-on: windows-2025
|
|
||||||
timeout-minutes: 6
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- name: build tcc (x86_64-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
|
|
||||||
call build-tcc.bat -c cl -t x86_64
|
|
||||||
- name: test (x86_64-win32)
|
|
||||||
shell: cmd
|
|
||||||
run: |
|
|
||||||
cd tests
|
|
||||||
call test-win32.bat all -k
|
|
||||||
|
|
||||||
test-i386-win32:
|
|
||||||
runs-on: windows-2025
|
|
||||||
timeout-minutes: 6
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- name: build tcc (i386-win32)
|
|
||||||
shell: cmd
|
|
||||||
run: |
|
|
||||||
cd win32
|
|
||||||
for /f "delims=" %%i in ('vswhere.exe -latest -property installationPath') do call "%%i\VC\Auxiliary\Build\vcvarsall.bat" x86
|
|
||||||
call build-tcc.bat -c cl -t i386
|
|
||||||
- name: test (i386-win32)
|
|
||||||
shell: cmd
|
|
||||||
run: |
|
|
||||||
cd tests
|
|
||||||
call test-win32.bat -p c:\mingw32\bin all -k
|
|
||||||
|
|
||||||
test-arm64-win32:
|
|
||||||
runs-on: windows-11-arm
|
|
||||||
timeout-minutes: 6
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- name: build and test (arm64-win32)
|
|
||||||
shell: cmd
|
|
||||||
run: |
|
|
||||||
cd win32
|
|
||||||
for /f "delims=" %%i in ('vswhere.exe -latest -property installationPath') do call "%%i\VC\Auxiliary\Build\vcvarsall.bat" amd64_arm64
|
|
||||||
call build-tcc.bat -c cl -t arm64
|
|
||||||
set "PATH=C:\Program Files\LLVM\bin;%CD%;%PATH%"
|
|
||||||
cd ..\tests
|
|
||||||
call test-win32.bat -c clang all -k
|
|
||||||
|
|
||||||
test-armv7-linux:
|
|
||||||
runs-on: ubuntu-22.04
|
|
||||||
timeout-minutes: 8
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: uraimo/run-on-arch-action@v3
|
|
||||||
name: make & test tcc (armv7-linux)
|
|
||||||
with:
|
|
||||||
arch: armv7
|
|
||||||
distro: ubuntu22.04
|
|
||||||
githubToken: ${{ github.token }}
|
|
||||||
install: |
|
|
||||||
apt-get update -q -y
|
|
||||||
apt-get install -q -y gcc make
|
|
||||||
run: |
|
|
||||||
echo "::endgroup::" # flatten 'run container'
|
|
||||||
./configure && make && make test -k
|
|
||||||
|
|
||||||
test-aarch64-linux:
|
|
||||||
runs-on: ubuntu-22.04
|
|
||||||
timeout-minutes: 8
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: uraimo/run-on-arch-action@v3
|
|
||||||
name: make & test tcc (aarch64-linux)
|
|
||||||
with:
|
|
||||||
arch: aarch64
|
|
||||||
distro: ubuntu24.04
|
|
||||||
githubToken: ${{ github.token }}
|
|
||||||
install: |
|
|
||||||
apt-get update -q -y
|
|
||||||
apt-get install -q -y gcc make
|
|
||||||
run: |
|
|
||||||
echo "::endgroup::" # flatten 'run container'
|
|
||||||
./configure && make && make test -k
|
|
||||||
|
|
||||||
test-riscv64-linux:
|
|
||||||
runs-on: ubuntu-22.04
|
|
||||||
timeout-minutes: 8
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: uraimo/run-on-arch-action@v3
|
|
||||||
name: make & test tcc (riscv64-linux)
|
|
||||||
with:
|
|
||||||
arch: riscv64
|
|
||||||
distro: ubuntu22.04
|
|
||||||
githubToken: ${{ github.token }}
|
|
||||||
install: |
|
|
||||||
apt-get update -q -y
|
|
||||||
apt-get install -q -y gcc make
|
|
||||||
run: |
|
|
||||||
echo "::endgroup::" # flatten 'run container'
|
|
||||||
./configure && make && make test -k
|
|
||||||
|
|
||||||
test-riscv64-linux-native:
|
|
||||||
runs-on: ubuntu-24.04-riscv
|
|
||||||
timeout-minutes: 8
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- name: make & test tcc (riscv64-linux native)
|
|
||||||
run: |
|
|
||||||
uname -m # riscv64
|
|
||||||
./configure && make && make test -k
|
|
||||||
70
.gitignore
vendored
70
.gitignore
vendored
@ -1,70 +0,0 @@
|
|||||||
*~
|
|
||||||
\#*
|
|
||||||
.#*
|
|
||||||
*.o
|
|
||||||
*.a
|
|
||||||
*.exe
|
|
||||||
*.dll
|
|
||||||
*.obj
|
|
||||||
*.pdb
|
|
||||||
*.lib
|
|
||||||
*.exp
|
|
||||||
*.log
|
|
||||||
*.bz2
|
|
||||||
*.zip
|
|
||||||
.gdb_history
|
|
||||||
a.out
|
|
||||||
tcc_g
|
|
||||||
tcc
|
|
||||||
tcc_c
|
|
||||||
tcc_p
|
|
||||||
*-tcc
|
|
||||||
libtcc*.def
|
|
||||||
|
|
||||||
config*.h
|
|
||||||
*_.h
|
|
||||||
config*.mak
|
|
||||||
config.texi
|
|
||||||
conftest*
|
|
||||||
c2str
|
|
||||||
tags
|
|
||||||
TAGS
|
|
||||||
tcc.1
|
|
||||||
*.pod
|
|
||||||
*.tcov
|
|
||||||
tcc-doc.html
|
|
||||||
tcc-doc.info
|
|
||||||
|
|
||||||
win32/doc
|
|
||||||
win32/examples/libtcc_test.c
|
|
||||||
win32/libtcc
|
|
||||||
win32/lib/32
|
|
||||||
win32/lib/64
|
|
||||||
win32/include/float.h
|
|
||||||
win32/include/stdalign.h
|
|
||||||
win32/include/stdarg.h
|
|
||||||
win32/include/stdbool.h
|
|
||||||
win32/include/stddef.h
|
|
||||||
win32/include/stdnoreturn.h
|
|
||||||
win32/include/varargs.h
|
|
||||||
win32/include/tcclib.h
|
|
||||||
win32/include/tccdefs.h
|
|
||||||
win32/include/stdatomic.h
|
|
||||||
win32/include/tgmath.h
|
|
||||||
|
|
||||||
tests/tcctest[1234]
|
|
||||||
tests/tcctest.gcc
|
|
||||||
tests/*.out*
|
|
||||||
tests/*.ref
|
|
||||||
tests/*.txt
|
|
||||||
tests/*.gcc
|
|
||||||
tests/*-cc*
|
|
||||||
tests/*-tcc*
|
|
||||||
tests/libtcc_test
|
|
||||||
tests/libtcc_test_mt
|
|
||||||
tests/asm-c-connect
|
|
||||||
tests/asm-c-connect-sep
|
|
||||||
tests/vla_test
|
|
||||||
tests/hello
|
|
||||||
tests/tests2/fred.txt
|
|
||||||
libtcc.dylib
|
|
||||||
221
Changelog
221
Changelog
@ -1,224 +1,3 @@
|
|||||||
version 0.9.28:
|
|
||||||
|
|
||||||
User interface:
|
|
||||||
- -b : bounds checker much improved (herman ten brugge)
|
|
||||||
- -bt : support for standalone backtraces also (grischka)
|
|
||||||
- -gdwarf : debug format (herman ten brugge)
|
|
||||||
- -M, -MM, and -MMD (Arthur Williams)
|
|
||||||
- -W[no-]error=<option> (Steffen Nurpmeso)
|
|
||||||
|
|
||||||
Platforms:
|
|
||||||
- new RISC-V (riscv64) target (Michael Matz)
|
|
||||||
- native macOS support for x86_64 (Michael Matz, Herman ten Brugge)
|
|
||||||
- arm and riscv64 assemblers (Danny Milosavljevic)
|
|
||||||
- Android support with position independent executables (grischka)
|
|
||||||
|
|
||||||
Features:
|
|
||||||
- _Static_assert() (matthias)
|
|
||||||
- __attribute__ ((cleanup(func))) (matthias)
|
|
||||||
- stdatomic (Dmitry Selyutin)
|
|
||||||
- asm goto ("jmp %l[label]" : : : : label) (Michael Matz)
|
|
||||||
|
|
||||||
Fixes:
|
|
||||||
- ... many, see git shortlog release_0_9_27...release_0_9_27
|
|
||||||
|
|
||||||
Version 0.9.27:
|
|
||||||
|
|
||||||
User interface:
|
|
||||||
- -x[c|a|n] filetype option (Sergey Korshunoff)
|
|
||||||
- -P[1], -dD, -dM preprocessor options (Sergey Korshunoff)
|
|
||||||
- -Wl,-(no-)whole-archive linker option (Reuben Thomas)
|
|
||||||
- -mms-bitfields option (David Mertens)
|
|
||||||
- -include <file> option (Michael Matz)
|
|
||||||
- -mno-sse on x86-64 disables use of SSE instructions
|
|
||||||
- @listfile support (Vlad Vissoultchev)
|
|
||||||
- tcc -ar/-impdef - formerly tiny_xxx tools integrated (grischka)
|
|
||||||
- CPATH, C_INCLUDE_PATH and LIBRARY_PATH environment variables support
|
|
||||||
(Andrew Aladjev, Urs Janssen)
|
|
||||||
|
|
||||||
Platforms:
|
|
||||||
- new AARCH64 (arm64) target (Edmund Grimley Evans)
|
|
||||||
- vastly improved support for ARM hard float calling convention
|
|
||||||
(Thomas Preud'homme, Daniel Glöckner)
|
|
||||||
- provide a runtime library for ARM (Thomas Preud'homme)
|
|
||||||
- many x86_64 ABI fixes incl. XMM register passing and tests (James Lyon)
|
|
||||||
- ABI tests with native compiler using libtcc (James Lyon)
|
|
||||||
- UNICODE startup code supports wmain and wWinMain (YX Hao)
|
|
||||||
- shared libraries for x86_64 (Michael Matz)
|
|
||||||
- Bootstrap native Windows 32/64 compiler using Cygwin+gcc (Christian Jullien)
|
|
||||||
|
|
||||||
Features:
|
|
||||||
- VLA (variable length array) improved (James Lyon, Pip Cet)
|
|
||||||
- import functions by ordinal in .def files on windows (YX Hao)
|
|
||||||
- x86/x86_64 assembler much improved (Michael Matz)
|
|
||||||
- simple dead code suppression (Edmund Grimley Evans, Michael Matz, grischka)
|
|
||||||
- implement round/fmin/fmax etc. math on windows (Avi Halachmi)
|
|
||||||
- #pragma once support (Sergey Korshunoff, Vlad Vissoultchev, ...)
|
|
||||||
- switch/case code improved (Zdenek Pavlas)
|
|
||||||
- ~15% faster by TinyAlloc fast memory allocator (Vlad Vissoultchev)
|
|
||||||
- standard conforming (and GCC compatible) struct initialization
|
|
||||||
(Michael Matz)
|
|
||||||
- bit-field layout made compatible with GCC (Michael Matz)
|
|
||||||
- UTF8 in string literals supported (Zdenek Pavlas)
|
|
||||||
_ _Generic(...) supported (Matthias Gatto)
|
|
||||||
|
|
||||||
Licensing:
|
|
||||||
- TinyCC partly relicensed to MIT license (See RELICENSING file).
|
|
||||||
|
|
||||||
version 0.9.26:
|
|
||||||
|
|
||||||
User interface:
|
|
||||||
- -MD/-MF (automatically generate dependencies for make)
|
|
||||||
- -pthread option (same as -D_REENTRANT -lpthread) (Henry Kroll III)
|
|
||||||
- -m32/-m64 to re-exec cross compiler (Henry Kroll III)
|
|
||||||
- -Wl, Mimic all GNU -option forms supported by ld (Kirill Smelkov)
|
|
||||||
- new LIBTCCAPI tcc_set_options() (grischka)
|
|
||||||
|
|
||||||
Platforms:
|
|
||||||
- Many improvements for x86-64 target (Shinichiro Hamaji, Michael Matz, grischka)
|
|
||||||
- x86-64 assembler (Frederic Feret)
|
|
||||||
- Many improvements for ARM target (Daniel Glöckner, Thomas Preud'homme)
|
|
||||||
- Support WinCE PE ARM (Timo VJ Lahde)
|
|
||||||
- Support ARM hardfloat calling convention (Thomas Preud'homme)
|
|
||||||
- Support SELinux (Security-Enhanced Linux) (Henry Kroll III)
|
|
||||||
- Support Debian GNU/kFreeBSD kernels (Pierre Chifflier)
|
|
||||||
- Support GNU/Hurd kernels (Thomas Preud'homme)
|
|
||||||
- Support OSX (tcc -run only) (Milutin Jovanovic)
|
|
||||||
- Support multiarch configuration (Thomas Preud'homme)
|
|
||||||
- Support out-of-tree build (Akim Demaille)
|
|
||||||
|
|
||||||
Features:
|
|
||||||
- C99 variable length arrays (Thomas Preud'homme & Joe Soroka)
|
|
||||||
- Asm labels for variables and functions (Thomas Preud'homme)
|
|
||||||
- STT_GNU_IFUNC (Indirect functions as externals) (Thomas Preud'homme)
|
|
||||||
- More tests (tests2) (Milutin Jovanovic)
|
|
||||||
|
|
||||||
version 0.9.25:
|
|
||||||
|
|
||||||
- first support for x86-64 target (Shinichiro Hamaji)
|
|
||||||
- support µClibc
|
|
||||||
- split tcc.c into tcc.h libtcc.c tccpp.c tccgen.c tcc.c
|
|
||||||
- improved preprocess output with linenumbers and spaces preserved
|
|
||||||
- tcc_relocate now copies code into user buffer
|
|
||||||
- fix bitfields with non-int types and in unions
|
|
||||||
- improve ARM cross-compiling (Daniel Glöckner)
|
|
||||||
- link stabstr sections from multiple objects
|
|
||||||
- better (still limited) support for multiple TCCStates
|
|
||||||
|
|
||||||
version 0.9.24:
|
|
||||||
|
|
||||||
- added verbosity levels -v, -vv, -vvv
|
|
||||||
- Accept standard input as an inputstream (Hanzac Chen)
|
|
||||||
- Support c89 compilers other than gcc (Hanzac Chen)
|
|
||||||
- -soname linker option (Marc Andre Tanner)
|
|
||||||
- Just warn about unknown directives, ignore quotes in #error/#warning
|
|
||||||
- Define __STDC_VERSION__=199901L (477)
|
|
||||||
- Switch to newer tccpe.c (includes support for resources)
|
|
||||||
- Handle backslashes within #include/#error/#warning
|
|
||||||
- Import changesets (part 4) 428,457,460,467: defines for openbsd etc.
|
|
||||||
- Use _WIN32 for a windows hosted tcc and define it for the PE target,
|
|
||||||
otherwise define __unix / __linux (Detlef Riekenberg)
|
|
||||||
- Import changesets (part 3) 409,410: ARM EABI by Daniel Glöckner
|
|
||||||
- Some in-between fixes:
|
|
||||||
TCC -E no longer hangs with macro calls involving newlines.
|
|
||||||
(next_nomacro1 now advances the read-pointer with TOK_LINEFEED)
|
|
||||||
Global cast (int g_i = 1LL;) no longer crashes tcc.
|
|
||||||
(nocode_wanted is initially 1, and only 0 for gen_function)
|
|
||||||
On win32 now tcc.exe finds 'include' & 'lib' even if itself is in 'bin'.
|
|
||||||
(new function w32_tcc_lib_path removes 'bin' if detected)
|
|
||||||
Added quick build batch file for mingw (win32/build-tcc.bat)
|
|
||||||
Last added case label optimization (455) produced wrong code. Reverted.
|
|
||||||
|
|
||||||
- Import more changesets from Rob Landley's fork (part 2):
|
|
||||||
487: Handle long long constants in gen_opic() (Rob Landley)
|
|
||||||
484: Handle parentheses within __attribute__((...)) (Rob Landley)
|
|
||||||
480: Remove a goto in decl_initializer_alloc (Rob Landley)
|
|
||||||
475: Fix dereferences in inline assembly output (Joshua Phillips)
|
|
||||||
474: Cast ptrs to ints of different sizes correctly (Joshua Phillips)
|
|
||||||
473: Fix size of structs with empty array member (Joshua Phillips)
|
|
||||||
470: No warning for && and || with mixed pointers/integers (Rob Landley)
|
|
||||||
469: Fix symbol visibility problems in the linker (Vincent Pit)
|
|
||||||
468: Allow && and || involving pointer arguments (Rob Landley)
|
|
||||||
455: Optimize case labels with no code in between (Zdenek Pavlas)
|
|
||||||
450: Implement alloca for x86 (grischka)
|
|
||||||
415: Parse unicode escape sequences (Axel Liljencrantz)
|
|
||||||
407: Add a simple va_copy() in stdarg.h (Hasso Tepper)
|
|
||||||
400: Allow typedef names as symbols (Dave Dodge)
|
|
||||||
|
|
||||||
- Import some changesets from Rob Landley's fork (part 1):
|
|
||||||
462: Use LGPL with bcheck.c and il-gen.c
|
|
||||||
458: Fix global compound literals (in unary: case '&':) (Andrew Johnson)
|
|
||||||
456: Use return code from tcc_output_file in main() (Michael Somos)
|
|
||||||
442: Fix indirections with function pointers (***fn)() (grischka)
|
|
||||||
441: Fix LL left shift in libtcc1.c:__shldi3 (grischka)
|
|
||||||
440: Pass structures and function ptrs through ?: (grischka)
|
|
||||||
439: Keep rvalue in bit assignment (bit2 = bit1 = x) (grischka)
|
|
||||||
438: Degrade nonportable pointer assignment to warning (grischka)
|
|
||||||
437: Call 'saveregs()' before jumping with logical and/or/not (grischka)
|
|
||||||
435: Put local static variables into global memory (grischka)
|
|
||||||
432/434: Cast double and ptr to bool (grischka)
|
|
||||||
420: Zero pad x87 tenbyte long doubles (Felix Nawothnig)
|
|
||||||
417: Make 'sizeof' unsigned (Rob Landley)
|
|
||||||
397: Fix save_reg for longlongs (Daniel Glöckner)
|
|
||||||
396: Fix "invalid relocation entry" problem on ubuntu - (Bernhard Fischer)
|
|
||||||
|
|
||||||
- ignore AS_NEEDED ld command
|
|
||||||
- mark executable sections as executable when running in memory
|
|
||||||
- added support for win32 wchar_t (Filip Navara)
|
|
||||||
- segment override prefix support (Filip Navara)
|
|
||||||
- normalized slashes in paths (Filip Navara)
|
|
||||||
- windows style fastcall (Filip Navara)
|
|
||||||
- support for empty input register section in asm (Filip Navara)
|
|
||||||
- anonymous union/struct support (Filip Navara)
|
|
||||||
- fixed parsing of function parameters
|
|
||||||
- workaround for function pointers in conditional expressions (Dave Dodge)
|
|
||||||
- initial '-E' option support to use the C preprocessor alone
|
|
||||||
- discard type qualifiers when comparing function parameters (Dave Dodge)
|
|
||||||
- Bug fix: A long long value used as a test expression ignores the
|
|
||||||
upper 32 bits at runtime (Dave Dodge)
|
|
||||||
- fixed multiple concatenation of PPNUM tokens (initial patch by Dave Dodge)
|
|
||||||
- fixed multiple typedef specifiers handling
|
|
||||||
- fixed sign extension in some type conversions (Dave Dodge)
|
|
||||||
|
|
||||||
version 0.9.23:
|
|
||||||
|
|
||||||
- initial PE executable format for windows version (grischka)
|
|
||||||
- '#pragma pack' support (grischka)
|
|
||||||
- '#include_next' support (Bernhard Fischer)
|
|
||||||
- ignore '-pipe' option
|
|
||||||
- added -f[no-]leading-underscore
|
|
||||||
- preprocessor function macro parsing fix (grischka)
|
|
||||||
|
|
||||||
version 0.9.22:
|
|
||||||
|
|
||||||
- simple memory optimisations: kernel compilation is 30% faster
|
|
||||||
- linker symbol definitions fixes
|
|
||||||
- gcc 3.4 fixes
|
|
||||||
- fixed value stack full error
|
|
||||||
- 'packed' attribute support for variables and structure fields
|
|
||||||
- ignore 'const' and 'volatile' in function prototypes
|
|
||||||
- allow '_Bool' in bit fields
|
|
||||||
|
|
||||||
version 0.9.21:
|
|
||||||
|
|
||||||
- ARM target support (Daniel Glöckner)
|
|
||||||
- added '-funsigned-char, '-fsigned-char' and
|
|
||||||
'-Wimplicit-function-declaration'
|
|
||||||
- fixed assignment of const struct in struct
|
|
||||||
- line comment fix (reported by Bertram Felgenhauer)
|
|
||||||
- initial TMS320C67xx target support (TK)
|
|
||||||
- win32 configure
|
|
||||||
- regparm() attribute
|
|
||||||
- many built-in assembler fixes
|
|
||||||
- added '.org', '.fill' and '.previous' assembler directives
|
|
||||||
- '-fno-common' option
|
|
||||||
- '-Ttext' linker option
|
|
||||||
- section alignment fixes
|
|
||||||
- bit fields fixes
|
|
||||||
- do not generate code for unused inline functions
|
|
||||||
- '-oformat' linker option.
|
|
||||||
- added 'binary' output format.
|
|
||||||
|
|
||||||
version 0.9.20:
|
version 0.9.20:
|
||||||
|
|
||||||
- added '-w' option
|
- added '-w' option
|
||||||
|
|||||||
71
CodingStyle
71
CodingStyle
@ -1,71 +0,0 @@
|
|||||||
|
|
||||||
In general, use the same coding style as the surrounding code.
|
|
||||||
|
|
||||||
However, do not make any unnecessary changes as that complicates
|
|
||||||
the VCS (git) history and makes it harder to merge patches. So
|
|
||||||
do not modify code just to make it conform to a coding style.
|
|
||||||
|
|
||||||
Indentation
|
|
||||||
|
|
||||||
Turn on a "fill tabs with spaces" option in your editor.
|
|
||||||
|
|
||||||
Remove tabs and trailing spaces from any lines that are modified.
|
|
||||||
|
|
||||||
Note that some files are indented with 2 spaces (when they
|
|
||||||
have large indentation) while most are indented with 4 spaces.
|
|
||||||
|
|
||||||
Language
|
|
||||||
|
|
||||||
TCC is mostly implemented in C90. Do not use any non-C90 features
|
|
||||||
that are not already in use.
|
|
||||||
|
|
||||||
Non-C90 features currently in use, as revealed by
|
|
||||||
./configure --extra-cflags="-std=c90 -Wpedantic":
|
|
||||||
|
|
||||||
- long long (including "LL" constants)
|
|
||||||
- inline
|
|
||||||
- very long string constants
|
|
||||||
- assignment between function pointer and 'void *'
|
|
||||||
- "//" comments
|
|
||||||
- empty macro arguments (DEF_ASMTEST in i386-tok.h)
|
|
||||||
- unnamed struct and union fields (in struct Sym), a C11 feature
|
|
||||||
|
|
||||||
Testing
|
|
||||||
|
|
||||||
A simple "make test" is sufficient for some simple changes. However,
|
|
||||||
before committing a change consider performing some of the following
|
|
||||||
additional tests:
|
|
||||||
|
|
||||||
- Build and run "make test" on several architectures.
|
|
||||||
|
|
||||||
- Build with ./configure --enable-cross.
|
|
||||||
|
|
||||||
- If the generation of relocations has been changed, try compiling
|
|
||||||
with TCC and linking with GCC/Clang. If the linker has been
|
|
||||||
modified, try compiling with GCC/Clang and linking with TCC.
|
|
||||||
|
|
||||||
- Test with ASan/UBSan to detect memory corruption and undefined behaviour:
|
|
||||||
|
|
||||||
make clean
|
|
||||||
./configure
|
|
||||||
make
|
|
||||||
make test
|
|
||||||
cp libtcc.a libtcc.a.hide
|
|
||||||
|
|
||||||
make clean
|
|
||||||
./configure --extra-cflags="-fsanitize=address,undefined -g"
|
|
||||||
make
|
|
||||||
cp libtcc.a.hide libtcc.a
|
|
||||||
make test
|
|
||||||
|
|
||||||
- Test with Valgrind to detect some uses of uninitialised values:
|
|
||||||
|
|
||||||
make clean
|
|
||||||
./configure
|
|
||||||
make
|
|
||||||
# On Intel, because Valgrind does floating-point arithmetic differently:
|
|
||||||
( cd tests && gcc -I.. tcctest.c && valgrind -q ./a.out > test.ref )
|
|
||||||
make test TCC="valgrind -q --leak-check=full `pwd`/tcc -B`pwd` -I`pwd`"
|
|
||||||
|
|
||||||
(Because of how VLAs are implemented, invalid reads are expected
|
|
||||||
with 79_vla_continue.)
|
|
||||||
689
Makefile
689
Makefile
@ -1,537 +1,234 @@
|
|||||||
# --------------------------------------------------------------------------
|
|
||||||
#
|
#
|
||||||
# Tiny C Compiler Makefile
|
# Tiny C Compiler Makefile
|
||||||
#
|
#
|
||||||
|
include config.mak
|
||||||
|
|
||||||
ifndef TOP
|
CFLAGS=-O2 -g -Wall
|
||||||
TOP = .
|
LIBS=-ldl
|
||||||
INCLUDED = no
|
CFLAGS_P=$(CFLAGS) -pg -static -DCONFIG_TCC_STATIC
|
||||||
endif
|
LIBS_P=
|
||||||
|
|
||||||
ifeq ($(findstring $(MAKECMDGOALS),clean distclean),)
|
CFLAGS+=-mpreferred-stack-boundary=2
|
||||||
include $(TOP)/config.mak
|
ifeq ($(GCC_MAJOR),2)
|
||||||
endif
|
CFLAGS+=-m386 -malign-functions=0
|
||||||
|
|
||||||
ifeq (-$(GCC_MAJOR)-$(findstring $(GCC_MINOR),56789)-,-4--)
|
|
||||||
CFLAGS += -D_FORTIFY_SOURCE=0
|
|
||||||
endif
|
|
||||||
|
|
||||||
LIBTCC = libtcc.a
|
|
||||||
LIBTCC1 = libtcc1.a
|
|
||||||
LINK_LIBTCC =
|
|
||||||
LIBS =
|
|
||||||
CFLAGS += $(CPPFLAGS)
|
|
||||||
VPATH = $(TOPSRC)
|
|
||||||
-LTCC = $(TOP)/$(LIBTCC)
|
|
||||||
|
|
||||||
ifdef CONFIG_WIN32
|
|
||||||
CFG = -win
|
|
||||||
ifneq ($(CONFIG_static),yes)
|
|
||||||
LIBTCC = libtcc$(DLLSUF)
|
|
||||||
LIBTCCDEF = libtcc.def
|
|
||||||
endif
|
|
||||||
ifneq ($(CONFIG_debug),yes)
|
|
||||||
ifneq ($(CC_NAME),clang)
|
|
||||||
LDFLAGS += -s
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
NATIVE_TARGET = $(if $(findstring arm64,$(ARCH)),arm64-win32,$(ARCH)-win$(if $(findstring arm,$(ARCH)),ce,32))
|
|
||||||
else
|
else
|
||||||
CFG = -unx
|
CFLAGS+=-march=i386 -falign-functions=0
|
||||||
LIBS+=-lm
|
|
||||||
ifneq ($(CONFIG_ldl),no)
|
|
||||||
LIBS+=-ldl
|
|
||||||
endif
|
|
||||||
ifneq ($(CONFIG_pthread),no)
|
|
||||||
LIBS+=-lpthread
|
|
||||||
endif
|
|
||||||
# make libtcc as static or dynamic library?
|
|
||||||
ifeq ($(CONFIG_static),no)
|
|
||||||
LIBTCC=libtcc$(DLLSUF)
|
|
||||||
export LD_LIBRARY_PATH := $(CURDIR)/$(TOP)
|
|
||||||
ifneq ($(CONFIG_rpath),no)
|
|
||||||
ifndef CONFIG_OSX
|
|
||||||
LINK_LIBTCC += -Wl,-rpath,"$(libdir)"
|
|
||||||
else
|
|
||||||
# macOS doesn't support env-vars libdir out of the box - which we need for
|
|
||||||
# `make test' when libtcc.dylib is used (configure --disable-static), so
|
|
||||||
# we bake a relative path into the binary. $libdir is used after install.
|
|
||||||
LINK_LIBTCC += -Wl,-rpath,"@executable_path/$(TOP)" -Wl,-rpath,"$(libdir)"
|
|
||||||
# -current/compatibility_version must not contain letters.
|
|
||||||
MACOS_DYLIB_VERSION := $(firstword $(subst rc, ,$(VERSION)))
|
|
||||||
DYLIBVER += -current_version $(MACOS_DYLIB_VERSION)
|
|
||||||
DYLIBVER += -compatibility_version $(MACOS_DYLIB_VERSION)
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
NATIVE_TARGET = $(ARCH)
|
|
||||||
ifdef CONFIG_OSX
|
|
||||||
NATIVE_TARGET = $(ARCH)-osx
|
|
||||||
ifneq ($(CC_NAME),tcc)
|
|
||||||
LDFLAGS += -flat_namespace
|
|
||||||
ifneq (1,$(shell expr $(GCC_MAJOR) ">=" 15))
|
|
||||||
LDFLAGS += -undefined warning # depreciated in clang >= 15.0
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
export MACOSX_DEPLOYMENT_TARGET := 10.6
|
|
||||||
endif
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
DISAS=objdump -d
|
||||||
|
INSTALL=install
|
||||||
|
|
||||||
# run local version of tcc with local libraries and includes
|
# run local version of tcc with local libraries and includes
|
||||||
TCCFLAGS-unx = -B$(TOP) -I$(TOPSRC)/include -I$(TOPSRC) -I$(TOP)
|
TCC=./tcc -B. -I.
|
||||||
TCCFLAGS-win = -B$(TOPSRC)/win32 -I$(TOPSRC)/include -I$(TOPSRC) -I$(TOP) -L$(TOP)
|
|
||||||
TCCFLAGS = $(TCCFLAGS$(CFG))
|
|
||||||
TCC_LOCAL = $(TOP)/tcc$(EXESUF)
|
|
||||||
TCC = $(TCC_LOCAL) $(TCCFLAGS)
|
|
||||||
|
|
||||||
# run tests with the installed tcc instead
|
all: tcc libtcc1.a bcheck.o tcc-doc.html tcc.1 libtcc.a libtcc_test
|
||||||
ifdef TESTINSTALL
|
|
||||||
TCC_LOCAL = $(bindir)/tcc
|
|
||||||
TCCFLAGS-unx = -I$(TOP)
|
|
||||||
TCCFLAGS-win = -B$(bindir) -I$(TOP)
|
|
||||||
-LTCC = $(libdir)/$(LIBTCC) $(LINK_LIBTCC)
|
|
||||||
endif
|
|
||||||
|
|
||||||
CFLAGS_P = $(CFLAGS) -pg -static -DCONFIG_TCC_STATIC -DTCC_PROFILE
|
Makefile: config.mak
|
||||||
LIBS_P = $(LIBS)
|
|
||||||
LDFLAGS_P = $(LDFLAGS)
|
|
||||||
|
|
||||||
DEF-i386 = -DTCC_TARGET_I386
|
# auto test
|
||||||
DEF-i386-win32 = -DTCC_TARGET_I386 -DTCC_TARGET_PE
|
|
||||||
DEF-i386-OpenBSD = $(DEF-i386) -DTARGETOS_OpenBSD
|
|
||||||
DEF-x86_64 = -DTCC_TARGET_X86_64
|
|
||||||
DEF-x86_64-win32 = -DTCC_TARGET_X86_64 -DTCC_TARGET_PE
|
|
||||||
DEF-x86_64-osx = -DTCC_TARGET_X86_64 -DTCC_TARGET_MACHO
|
|
||||||
DEF-arm-fpa = -DTCC_TARGET_ARM
|
|
||||||
DEF-arm-fpa-ld = -DTCC_TARGET_ARM -DLDOUBLE_SIZE=12
|
|
||||||
DEF-arm-vfp = -DTCC_TARGET_ARM -DTCC_ARM_VFP
|
|
||||||
DEF-arm-eabi = -DTCC_TARGET_ARM -DTCC_ARM_VFP -DTCC_ARM_EABI
|
|
||||||
DEF-arm-eabihf = $(DEF-arm-eabi) -DTCC_ARM_HARDFLOAT
|
|
||||||
DEF-arm = $(DEF-arm-eabihf)
|
|
||||||
DEF-arm-NetBSD = $(DEF-arm-eabihf) -DTARGETOS_NetBSD
|
|
||||||
DEF-arm-wince = $(DEF-arm-eabihf) -DTCC_TARGET_PE
|
|
||||||
DEF-arm64 = -DTCC_TARGET_ARM64
|
|
||||||
DEF-arm64-osx = $(DEF-arm64) -DTCC_TARGET_MACHO
|
|
||||||
DEF-arm64-FreeBSD = $(DEF-arm64) -DTARGETOS_FreeBSD
|
|
||||||
DEF-arm64-NetBSD = $(DEF-arm64) -DTARGETOS_NetBSD
|
|
||||||
DEF-arm64-OpenBSD = $(DEF-arm64) -DTARGETOS_OpenBSD
|
|
||||||
DEF-arm64-win32 = $(DEF-arm64) -DTCC_TARGET_PE
|
|
||||||
DEF-riscv64 = -DTCC_TARGET_RISCV64
|
|
||||||
DEF-c67 = -DTCC_TARGET_C67 -w # disable warnigs
|
|
||||||
DEF-x86_64-FreeBSD = $(DEF-x86_64) -DTARGETOS_FreeBSD
|
|
||||||
DEF-x86_64-NetBSD = $(DEF-x86_64) -DTARGETOS_NetBSD
|
|
||||||
DEF-x86_64-OpenBSD = $(DEF-x86_64) -DTARGETOS_OpenBSD
|
|
||||||
|
|
||||||
ifeq ($(INCLUDED),no)
|
test: test.ref test.out
|
||||||
# --------------------------------------------------------------------------
|
@if diff -u test.ref test.out ; then echo "Auto Test OK"; fi
|
||||||
# running top Makefile
|
|
||||||
|
|
||||||
PROGS = tcc$(EXESUF)
|
tcctest.ref: tcctest.c
|
||||||
TCCLIBS = $(LIBTCCDEF) $(LIBTCC) $(LIBTCC1)
|
$(CC) $(CFLAGS) -I. -o $@ $<
|
||||||
TCCDOCS = tcc.1 tcc-doc.html tcc-doc.info
|
|
||||||
|
|
||||||
all: $(PROGS) $(TCCLIBS) $(TCCDOCS)
|
test.ref: tcctest.ref
|
||||||
|
./tcctest.ref > $@
|
||||||
|
|
||||||
# cross compiler targets to build
|
test.out: tcc tcctest.c
|
||||||
TCC_X = i386 x86_64 i386-win32 x86_64-win32 x86_64-osx arm arm64 arm64-win32 arm-wince c67
|
$(TCC) -run tcctest.c > $@
|
||||||
TCC_X += riscv64 arm64-osx
|
|
||||||
# TCC_X += arm-fpa arm-fpa-ld arm-vfp arm-eabi
|
|
||||||
|
|
||||||
# cross libtcc1.a targets to build
|
run: tcc tcctest.c
|
||||||
LIBTCC1_X = $(filter-out c67,$(TCC_X))
|
$(TCC) -run tcctest.c
|
||||||
|
|
||||||
PROGS_CROSS = $(foreach X,$(TCC_X),$X-tcc$(EXESUF))
|
# iterated test2 (compile tcc then compile tcctest.c !)
|
||||||
LIBTCC1_CROSS = $(foreach X,$(LIBTCC1_X),$X-libtcc1.a)
|
test2: tcc tcc.c tcctest.c test.ref
|
||||||
|
$(TCC) -run tcc.c -B. -I. -run tcctest.c > test.out2
|
||||||
|
@if diff -u test.ref test.out2 ; then echo "Auto Test2 OK"; fi
|
||||||
|
|
||||||
# build cross compilers & libs
|
# iterated test3 (compile tcc then compile tcc then compile tcctest.c !)
|
||||||
cross: $(LIBTCC1_CROSS) $(PROGS_CROSS)
|
test3: tcc tcc.c tcctest.c test.ref
|
||||||
|
$(TCC) -run tcc.c -B. -I. -run tcc.c -B. -I. -run tcctest.c > test.out3
|
||||||
|
@if diff -u test.ref test.out3 ; then echo "Auto Test3 OK"; fi
|
||||||
|
|
||||||
# build specific cross compiler & lib
|
# binary output test
|
||||||
cross-%: %-tcc$(EXESUF) %-libtcc1.a ;
|
test4: tcc test.ref
|
||||||
|
# dynamic output
|
||||||
|
$(TCC) -o tcctest1 tcctest.c
|
||||||
|
./tcctest1 > test1.out
|
||||||
|
@if diff -u test.ref test1.out ; then echo "Dynamic Auto Test OK"; fi
|
||||||
|
# static output
|
||||||
|
$(TCC) -static -o tcctest2 tcctest.c
|
||||||
|
./tcctest2 > test2.out
|
||||||
|
@if diff -u test.ref test2.out ; then echo "Static Auto Test OK"; fi
|
||||||
|
# object + link output
|
||||||
|
$(TCC) -c -o tcctest3.o tcctest.c
|
||||||
|
$(TCC) -o tcctest3 tcctest3.o
|
||||||
|
./tcctest3 > test3.out
|
||||||
|
@if diff -u test.ref test3.out ; then echo "Object Auto Test OK"; fi
|
||||||
|
# dynamic output + bound check
|
||||||
|
$(TCC) -b -o tcctest4 tcctest.c
|
||||||
|
./tcctest4 > test4.out
|
||||||
|
@if diff -u test.ref test4.out ; then echo "BCheck Auto Test OK"; fi
|
||||||
|
|
||||||
install: ; @$(MAKE) --no-print-directory install$(CFG)
|
# memory and bound check auto test
|
||||||
install-strip: ; @$(MAKE) --no-print-directory install$(CFG) CONFIG_strip=yes
|
BOUNDS_OK = 1 4 8 10
|
||||||
uninstall: ; @$(MAKE) --no-print-directory uninstall$(CFG)
|
BOUNDS_FAIL= 2 5 7 9 11 12 13
|
||||||
|
|
||||||
ifdef CONFIG_cross
|
btest: boundtest.c tcc
|
||||||
all : cross
|
@for i in $(BOUNDS_OK); do \
|
||||||
endif
|
if $(TCC) -b -run boundtest.c $$i ; then \
|
||||||
|
/bin/true ; \
|
||||||
|
else\
|
||||||
|
echo Failed positive test $$i ; exit 1 ; \
|
||||||
|
fi ;\
|
||||||
|
done ;\
|
||||||
|
for i in $(BOUNDS_FAIL); do \
|
||||||
|
if $(TCC) -b -run boundtest.c $$i ; then \
|
||||||
|
echo Failed negative test $$i ; exit 1 ;\
|
||||||
|
else\
|
||||||
|
/bin/true ; \
|
||||||
|
fi\
|
||||||
|
done ;\
|
||||||
|
echo Bound test OK
|
||||||
|
|
||||||
# --------------------------------------------
|
# speed test
|
||||||
T = $(or $(CROSS_TARGET),$(NATIVE_TARGET))
|
speed: tcc ex2 ex3
|
||||||
X = $(if $(CROSS_TARGET),$(CROSS_TARGET)-)
|
time ./ex2 1238 2 3 4 10 13 4
|
||||||
|
time ./tcc -I. ./ex2.c 1238 2 3 4 10 13 4
|
||||||
|
time ./ex3 35
|
||||||
|
time ./tcc -I. ./ex3.c 35
|
||||||
|
|
||||||
ifneq ($(T),$(NATIVE_TARGET))
|
ex2: ex2.c
|
||||||
$(if $(DEF-$T),,$(error error: unknown target: '$T'))
|
$(CC) $(CFLAGS) -o $@ $<
|
||||||
ifneq ($(CONFIG_WIN32),yes)
|
|
||||||
DEF-win = -DCONFIG_TCCDIR="\"$(tccdir)/win32\""
|
|
||||||
endif
|
|
||||||
# some default config for cross compilers
|
|
||||||
TRIPLET-i386 = i686-linux-gnu
|
|
||||||
TRIPLET-x86_64 = x86_64-linux-gnu
|
|
||||||
TRIPLET-arm = arm-linux-gnueabihf
|
|
||||||
TRIPLET-arm64 = aarch64-linux-gnu
|
|
||||||
TRIPLET-riscv64 = riscv64-linux-gnu
|
|
||||||
ifneq ($(TRIPLET-$T),)
|
|
||||||
# assume support files in "/usr/<triplet>"
|
|
||||||
ROOT-$T = /usr/$(TRIPLET-$T)
|
|
||||||
INC-$T = {B}/include:{R}/include
|
|
||||||
LIB-$T = {R}/lib:{B}
|
|
||||||
CRT-$T = {R}/lib
|
|
||||||
endif
|
|
||||||
DEFINES += $(DEF-$T)
|
|
||||||
DEFINES += $(if $(ROOT-$T),-DCONFIG_SYSROOT="\"$(ROOT-$T)\"")
|
|
||||||
DEFINES += $(if $(CRT-$T),-DCONFIG_TCC_CRTPREFIX="\"$(CRT-$T)\"")
|
|
||||||
DEFINES += $(if $(LIB-$T),-DCONFIG_TCC_LIBPATHS="\"$(LIB-$T)\"")
|
|
||||||
DEFINES += $(if $(INC-$T),-DCONFIG_TCC_SYSINCLUDEPATHS="\"$(INC-$T)\"")
|
|
||||||
DEFINES += $(if $(ELF-$T),-DCONFIG_TCC_ELFINTERP="\"$(ELF-$T)\"")
|
|
||||||
DEFINES += $(DEF-$(or $(findstring win,$T),unx))
|
|
||||||
DEFINES += -DCONFIG_TCC_CROSSPREFIX="\"$X\""
|
|
||||||
endif
|
|
||||||
|
|
||||||
# include custom configuration (see make help)
|
ex3: ex3.c
|
||||||
-include config-extra.mak
|
$(CC) $(CFLAGS) -o $@ $<
|
||||||
|
|
||||||
# so one can use: make EXTRA-DEFS=...
|
# Native Tiny C Compiler
|
||||||
DEFINES += $(EXTRA-DEFS)
|
|
||||||
|
|
||||||
# find config.h with 'out of tree' builds
|
tcc_g: tcc.c i386-gen.c tccelf.c tccasm.c i386-asm.c tcctok.h libtcc.h i386-asm.h Makefile
|
||||||
DEFINES += -I$(TOP)
|
$(CC) $(CFLAGS) -o $@ $< $(LIBS)
|
||||||
|
|
||||||
CORE_FILES = tcc.c tcctools.c libtcc.c tccpp.c tccgen.c tccdbg.c tccelf.c tccasm.c tccrun.c
|
tcc: tcc_g Makefile
|
||||||
CORE_FILES += tcc.h config.h libtcc.h tcctok.h
|
strip -s -R .comment -R .note -o $@ $<
|
||||||
i386_FILES = $(CORE_FILES) i386-gen.c i386-link.c i386-asm.c i386-asm.h i386-tok.h
|
|
||||||
i386-win32_FILES = $(i386_FILES) tccpe.c
|
|
||||||
x86_64_FILES = $(CORE_FILES) x86_64-gen.c x86_64-link.c i386-asm.c x86_64-asm.h
|
|
||||||
x86_64-win32_FILES = $(x86_64_FILES) tccpe.c
|
|
||||||
x86_64-osx_FILES = $(x86_64_FILES) tccmacho.c
|
|
||||||
arm_FILES = $(CORE_FILES) arm-gen.c arm-link.c arm-asm.c arm-tok.h
|
|
||||||
arm-wince_FILES = $(arm_FILES) tccpe.c
|
|
||||||
arm-fpa_FILES = $(arm_FILES)
|
|
||||||
arm-fpa-ld_FILES = $(arm_FILES)
|
|
||||||
arm-vfp_FILES = $(arm_FILES)
|
|
||||||
arm-eabi_FILES = $(arm_FILES)
|
|
||||||
arm-eabihf_FILES = $(arm_FILES)
|
|
||||||
arm64_FILES = $(CORE_FILES) arm64-gen.c arm64-link.c arm64-asm.c arm64-tok.h
|
|
||||||
arm64-osx_FILES = $(arm64_FILES) tccmacho.c
|
|
||||||
arm64-win32_FILES = $(arm64_FILES) tccpe.c
|
|
||||||
c67_FILES = $(CORE_FILES) c67-gen.c c67-link.c tcccoff.c
|
|
||||||
riscv64_FILES = $(CORE_FILES) riscv64-gen.c riscv64-link.c riscv64-asm.c
|
|
||||||
|
|
||||||
TCCDEFS_H$(subst yes,,$(CONFIG_predefs)) = tccdefs_.h
|
|
||||||
|
|
||||||
# libtcc sources
|
|
||||||
LIBTCC_SRC = $(filter-out tcc.c tcctools.c,$(filter %.c,$($T_FILES)))
|
|
||||||
|
|
||||||
ifeq ($(ONE_SOURCE),yes)
|
|
||||||
LIBTCC_OBJ = $(X)libtcc.o
|
|
||||||
LIBTCC_INC = $($T_FILES)
|
|
||||||
TCC_FILES = $(X)tcc.o
|
|
||||||
$(X)tcc.o $(X)libtcc.o : $(TCCDEFS_H)
|
|
||||||
else
|
|
||||||
LIBTCC_OBJ = $(patsubst %.c,$(X)%.o,$(LIBTCC_SRC))
|
|
||||||
LIBTCC_INC = $(filter %.h %-gen.c %-link.c,$($T_FILES))
|
|
||||||
TCC_FILES = $(X)tcc.o $(LIBTCC_OBJ)
|
|
||||||
$(X)tccpp.o : $(TCCDEFS_H)
|
|
||||||
$(X)libtcc.o : DEFINES += -DONE_SOURCE=0
|
|
||||||
$(CROSS_TARGET)-tcc.o : DEFINES += -DONE_SOURCE=0
|
|
||||||
endif
|
|
||||||
# native tcc always made from tcc.o and libtcc.[so|a]
|
|
||||||
tcc.o : DEFINES += -DONE_SOURCE=0
|
|
||||||
|
|
||||||
GITHASH:=$(shell git rev-parse --abbrev-ref HEAD 2>/dev/null || echo no)
|
|
||||||
ifneq ($(GITHASH),no)
|
|
||||||
GITHASH:=$(shell git log -1 --date=short --pretty='format:%cd $(GITHASH)@%h')
|
|
||||||
GITMODF:=$(shell git diff --quiet || echo '*')
|
|
||||||
DEF_GITHASH:= -DTCC_GITHASH="\"$(GITHASH)$(GITMODF)\""
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(CONFIG_debug),yes)
|
|
||||||
CFLAGS += -g
|
|
||||||
LDFLAGS += -g
|
|
||||||
endif
|
|
||||||
|
|
||||||
# convert "include/tccdefs.h" to "tccdefs_.h"
|
|
||||||
%_.h : include/%.h c2str.exe
|
|
||||||
$S./c2str.exe $< $@
|
|
||||||
|
|
||||||
c2str.exe : conftest.c
|
|
||||||
$S$(CC) -DC2STR $< -o $@
|
|
||||||
|
|
||||||
# target specific object rule
|
|
||||||
$(X)%.o : %.c $(LIBTCC_INC)
|
|
||||||
$S$(CC) -o $@ -c $< $(addsuffix ,$(DEFINES) $(CFLAGS))
|
|
||||||
|
|
||||||
# additional dependencies
|
|
||||||
$(X)tcc.o : tcctools.c
|
|
||||||
$(X)tcc.o : DEFINES += $(DEF_GITHASH)
|
|
||||||
|
|
||||||
# Host Tiny C Compiler
|
|
||||||
tcc$(EXESUF): tcc.o $(LIBTCC)
|
|
||||||
$S$(CC) -o $@ $^ $(addsuffix ,$(LIBS) $(LDFLAGS) $(LINK_LIBTCC))
|
|
||||||
|
|
||||||
# Cross Tiny C Compilers
|
|
||||||
# (the TCCDEFS_H dependency is only necessary for parallel makes,
|
|
||||||
# ala 'make -j x86_64-tcc i386-tcc tcc', which would create multiple
|
|
||||||
# c2str.exe and tccdefs_.h files in parallel, leading to access errors.
|
|
||||||
# This forces it to be made only once. Make normally tracks multiple paths
|
|
||||||
# to the same goals and only remakes it once, but that doesn't work over
|
|
||||||
# sub-makes like in this target)
|
|
||||||
%-tcc$(EXESUF): $(TCCDEFS_H) FORCE
|
|
||||||
@$(MAKE) --no-print-directory $@ CROSS_TARGET=$* ONE_SOURCE=$(or $(ONE_SOURCE),yes)
|
|
||||||
|
|
||||||
$(CROSS_TARGET)-tcc$(EXESUF): $(TCC_FILES)
|
|
||||||
$S$(CC) -o $@ $^ $(LIBS) $(LDFLAGS)
|
|
||||||
|
|
||||||
# profiling version
|
|
||||||
tcc_p$(EXESUF): $($T_FILES)
|
|
||||||
$S$(CC) -o $@ $< $(DEFINES) $(CFLAGS_P) $(LIBS_P) $(LDFLAGS_P)
|
|
||||||
|
|
||||||
# static libtcc library
|
|
||||||
libtcc.a: $(LIBTCC_OBJ)
|
|
||||||
$S$(AR) rcs $@ $^
|
|
||||||
|
|
||||||
ifeq ($(CC_NAME)-$(ARCH),clang-x86_64)
|
|
||||||
# avoid 32-bit relocations in libtcc.a for its usage with tcc -run
|
|
||||||
libtcc.a: override CFLAGS += -fPIC
|
|
||||||
endif
|
|
||||||
|
|
||||||
# dynamic libtcc library
|
|
||||||
libtcc.so: $(LIBTCC_OBJ)
|
|
||||||
$S$(CC) -shared -Wl,-soname,$@ -o $@ $^ $(LIBS) $(LDFLAGS)
|
|
||||||
|
|
||||||
libtcc.so: override CFLAGS += -fPIC
|
|
||||||
libtcc.so: override LDFLAGS += -fPIC
|
|
||||||
|
|
||||||
# OSX dynamic libtcc library
|
|
||||||
libtcc.dylib: $(LIBTCC_OBJ)
|
|
||||||
$S$(CC) -dynamiclib $(DYLIBVER) -install_name @rpath/$@ -o $@ $^ $(LDFLAGS)
|
|
||||||
|
|
||||||
# OSX libtcc.dylib (without rpath/ prefix)
|
|
||||||
libtcc.osx: $(LIBTCC_OBJ)
|
|
||||||
$S$(CC) -shared -install_name libtcc.dylib -o libtcc.dylib $^ $(LDFLAGS)
|
|
||||||
|
|
||||||
# windows dynamic libtcc library
|
|
||||||
libtcc.dll : $(LIBTCC_OBJ)
|
|
||||||
$S$(CC) -shared -o $@ $^ $(LDFLAGS)
|
|
||||||
libtcc.dll : DEFINES += -DLIBTCC_AS_DLL
|
|
||||||
|
|
||||||
# import file for windows libtcc.dll
|
|
||||||
libtcc.def : libtcc.dll tcc$(EXESUF)
|
|
||||||
$S$(XTCC) -impdef $< -o $@
|
|
||||||
XTCC ?= ./tcc$(EXESUF)
|
|
||||||
|
|
||||||
# TinyCC runtime libraries
|
# TinyCC runtime libraries
|
||||||
libtcc1.a : tcc$(EXESUF) FORCE
|
libtcc1.o: libtcc1.c
|
||||||
@$(MAKE) -C lib
|
$(CC) -O2 -Wall -c -o $@ $<
|
||||||
|
|
||||||
# Cross libtcc1.a
|
libtcc1.a: libtcc1.o
|
||||||
%-libtcc1.a : %-tcc$(EXESUF) FORCE
|
$(AR) rcs $@ $^
|
||||||
@$(MAKE) -C lib CROSS_TARGET=$*
|
|
||||||
|
|
||||||
.PRECIOUS: %-libtcc1.a
|
bcheck.o: bcheck.c
|
||||||
FORCE:
|
$(CC) -O2 -Wall -c -o $@ $<
|
||||||
|
|
||||||
# WHICH = which $1 2>/dev/null
|
install: tcc_install libinstall
|
||||||
# some versions of gnu-make do not recognize 'command' as a shell builtin
|
|
||||||
WHICH = sh -c 'command -v $1'
|
|
||||||
|
|
||||||
run-if = $(if $(shell $(call WHICH,$1x)),$S $1 $2,@true||echo "(skipping $@ - no $1)")
|
tcc_install: tcc tcc.1 libtcc1.a bcheck.o
|
||||||
S = $(if $(findstring yes,$(SILENT)),@$(info * $@))
|
$(INSTALL) -m755 tcc $(bindir)
|
||||||
|
$(INSTALL) tcc.1 $(mandir)/man1
|
||||||
# --------------------------------------------------------------------------
|
mkdir -p $(libdir)/tcc
|
||||||
# documentation and man page
|
mkdir -p $(libdir)/tcc/include
|
||||||
tcc-doc.html: tcc-doc.texi
|
$(INSTALL) -m644 libtcc1.a bcheck.o $(libdir)/tcc
|
||||||
$(call run-if,makeinfo,--no-split --html --number-sections -o $@ $<)
|
$(INSTALL) -m644 stdarg.h stddef.h stdbool.h float.h varargs.h \
|
||||||
|
tcclib.h $(libdir)/tcc/include
|
||||||
tcc-doc.info: tcc-doc.texi
|
|
||||||
$(call run-if,makeinfo,$< || true)
|
|
||||||
|
|
||||||
tcc.1 : tcc-doc.pod
|
|
||||||
$(call run-if,pod2man,--section=1 --center="Tiny C Compiler" \
|
|
||||||
--release="$(VERSION)" $< >$@)
|
|
||||||
%.pod : %.texi
|
|
||||||
$(call run-if,perl,$(TOPSRC)/texi2pod.pl $< $@)
|
|
||||||
|
|
||||||
doc : $(TCCDOCS)
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------------
|
|
||||||
# install
|
|
||||||
|
|
||||||
INSTALL = install -m 644
|
|
||||||
INSTALLBIN = install -m 755 $(STRIP_$(CONFIG_strip))
|
|
||||||
STRIP_yes = -s
|
|
||||||
|
|
||||||
LIBTCC1_W = $(filter %-win32-libtcc1.a %-wince-libtcc1.a,$(LIBTCC1_CROSS))
|
|
||||||
LIBTCC1_U = $(filter-out $(LIBTCC1_W),$(wildcard *-libtcc1.a))
|
|
||||||
IB = $(if $1,$(IM) mkdir -p $2 && $(INSTALLBIN) $1 $2)
|
|
||||||
IBw = $(call IB,$(wildcard $1),$2)
|
|
||||||
IF = $(if $1,$(IM) mkdir -p $2 && $(INSTALL) $1 $2)
|
|
||||||
IFw = $(call IF,$(wildcard $1),$2)
|
|
||||||
IR = $(IM) mkdir -p $2 && cp -r $1/. $2
|
|
||||||
IM = @echo "-> $2 : $1" ;
|
|
||||||
BINCHECK = $(if $(wildcard $(PROGS) *-tcc$(EXESUF)),,@echo "Makefile: nothing found to install" && exit 1)
|
|
||||||
|
|
||||||
EXTRA_O = runmain.o bt-exe.o bt-dll.o bt-log.o bcheck.o
|
|
||||||
|
|
||||||
# install progs & libs
|
|
||||||
install-unx:
|
|
||||||
$(call BINCHECK)
|
|
||||||
$(call IBw,$(PROGS) *-tcc,"$(bindir)")
|
|
||||||
$(call IFw,$(LIBTCC1) $(EXTRA_O) $(LIBTCC1_U),"$(tccdir)")
|
|
||||||
$(call IF,$(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h,"$(tccdir)/include")
|
|
||||||
$(call $(if $(findstring .so,$(LIBTCC)),IBw,IFw),$(LIBTCC),"$(libdir)")
|
|
||||||
$(call IF,$(TOPSRC)/libtcc.h,"$(includedir)")
|
|
||||||
$(call IFw,tcc.1,"$(mandir)/man1")
|
|
||||||
$(call IFw,tcc-doc.info,"$(infodir)")
|
|
||||||
$(call IFw,tcc-doc.html,"$(docdir)")
|
|
||||||
ifneq "$(wildcard $(LIBTCC1_W))" ""
|
|
||||||
$(call IFw,$(TOPSRC)/win32/lib/*.def $(LIBTCC1_W),"$(tccdir)/win32/lib")
|
|
||||||
$(call IR,$(TOPSRC)/win32/include,"$(tccdir)/win32/include")
|
|
||||||
$(call IF,$(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h,"$(tccdir)/win32/include")
|
|
||||||
endif
|
|
||||||
|
|
||||||
# uninstall
|
|
||||||
uninstall-unx:
|
|
||||||
@rm -fv $(addprefix "$(bindir)/",$(PROGS) $(PROGS_CROSS))
|
|
||||||
@rm -fv $(addprefix "$(libdir)/", libtcc*.a libtcc*.so libtcc.dylib)
|
|
||||||
@rm -fv $(addprefix "$(includedir)/", libtcc.h)
|
|
||||||
@rm -fv "$(mandir)/man1/tcc.1" "$(infodir)/tcc-doc.info"
|
|
||||||
@rm -fv "$(docdir)/tcc-doc.html"
|
|
||||||
@rm -frv "$(tccdir)"
|
|
||||||
|
|
||||||
# install progs & libs on windows
|
|
||||||
install-win:
|
|
||||||
$(call BINCHECK)
|
|
||||||
$(call IBw,$(PROGS) *-tcc.exe libtcc.dll,"$(bindir)")
|
|
||||||
$(call IF,$(TOPSRC)/win32/lib/*.def,"$(tccdir)/lib")
|
|
||||||
$(call IFw,libtcc1.a $(EXTRA_O) $(LIBTCC1_W),"$(tccdir)/lib")
|
|
||||||
$(call IF,$(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h,"$(tccdir)/include")
|
|
||||||
$(call IR,$(TOPSRC)/win32/include,"$(tccdir)/include")
|
|
||||||
$(call IR,$(TOPSRC)/win32/examples,"$(tccdir)/examples")
|
|
||||||
$(call IF,$(TOPSRC)/tests/libtcc_test.c,"$(tccdir)/examples")
|
|
||||||
$(call IFw,$(TOPSRC)/libtcc.h libtcc.def libtcc.a,"$(libdir)")
|
|
||||||
$(call IFw,$(TOPSRC)/win32/tcc-win32.txt tcc-doc.html,"$(docdir)")
|
|
||||||
ifneq "$(wildcard $(LIBTCC1_U))" ""
|
|
||||||
$(call IFw,$(LIBTCC1_U),"$(tccdir)/lib")
|
|
||||||
$(call IF,$(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h,"$(tccdir)/lib/include")
|
|
||||||
endif
|
|
||||||
|
|
||||||
# uninstall on windows
|
|
||||||
uninstall-win:
|
|
||||||
@rm -fv $(foreach P,libtcc*.dll $(PROGS) *-tcc.exe,"$(bindir)"/$P)
|
|
||||||
@rm -fr $(foreach P,doc examples include lib libtcc,"$(tccdir)"/$P/*)
|
|
||||||
@rm -frv $(foreach P,doc examples include lib libtcc,"$(tccdir)"/$P)
|
|
||||||
|
|
||||||
# the msys-git shell works to configure && make except it does not have install
|
|
||||||
ifeq ($(OS),Windows_NT)
|
|
||||||
ifeq ($(shell $(call WHICH,install) || echo no),no)
|
|
||||||
INSTALL = cp
|
|
||||||
INSTALLBIN = cp
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------------
|
|
||||||
# other stuff
|
|
||||||
|
|
||||||
TAGFILES = *.[ch] include/*.h lib/*.[chS]
|
|
||||||
tags : ; ctags $(TAGFILES)
|
|
||||||
# cannot have both tags and TAGS on windows
|
|
||||||
ETAGS : ; etags $(TAGFILES)
|
|
||||||
|
|
||||||
# create release tarball from *current* git branch (including tcc-doc.html
|
|
||||||
# and converting two files to CRLF)
|
|
||||||
TCC-VERSION = tcc-$(VERSION)
|
|
||||||
TCC-VERSION = tinycc-mob-$(shell git rev-parse --short=7 HEAD)
|
|
||||||
tar: tcc-doc.html
|
|
||||||
mkdir -p $(TCC-VERSION)
|
|
||||||
( cd $(TCC-VERSION) && git --git-dir ../.git checkout -f )
|
|
||||||
cp tcc-doc.html $(TCC-VERSION)
|
|
||||||
for f in tcc-win32.txt build-tcc.bat ; do \
|
|
||||||
cat win32/$$f | sed 's,\(.*\),\1\r,g' > $(TCC-VERSION)/win32/$$f ; \
|
|
||||||
done
|
|
||||||
tar cjf $(TCC-VERSION).tar.bz2 $(TCC-VERSION)
|
|
||||||
rm -rf $(TCC-VERSION)
|
|
||||||
git reset
|
|
||||||
|
|
||||||
config.mak:
|
|
||||||
$(if $(wildcard $@),,@echo "Please run ./configure." && exit 1)
|
|
||||||
|
|
||||||
# run all tests
|
|
||||||
test:
|
|
||||||
@$(MAKE) -C tests
|
|
||||||
# run test(s) from tests2 subdir (see make help)
|
|
||||||
tests2.%:
|
|
||||||
@$(MAKE) -C tests/tests2 $@
|
|
||||||
# run test(s) from testspp subdir (see make help)
|
|
||||||
testspp.%:
|
|
||||||
@$(MAKE) -C tests/pp $@
|
|
||||||
# run tests with code coverage
|
|
||||||
tcov-tes% : tcc_c$(EXESUF)
|
|
||||||
@rm -f $<.tcov
|
|
||||||
@$(MAKE) --no-print-directory TCC_LOCAL=$(CURDIR)/$< tes$*
|
|
||||||
tcc_c$(EXESUF): $($T_FILES)
|
|
||||||
$S$(TCC) tcc.c -o $@ -ftest-coverage $(DEFINES) $(LIBS)
|
|
||||||
# run tests with sanitize option
|
|
||||||
sani-tes% : tcc_s$(EXESUF)
|
|
||||||
@$(MAKE) --no-print-directory TCC_LOCAL=$(CURDIR)/$< tes$*
|
|
||||||
tcc_s$(EXESUF): $($T_FILES)
|
|
||||||
$S$(CC) tcc.c -o $@ -fsanitize=address,undefined $(DEFINES) $(CFLAGS) $(LDFLAGS) $(LIBS)
|
|
||||||
# test the installed tcc instead
|
|
||||||
test-install: $(TCCDEFS_H)
|
|
||||||
@$(MAKE) -C tests TESTINSTALL=yes #_all
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
@rm -f tcc *-tcc tcc_p tcc_c tcc_s
|
rm -f *~ *.o tcc tcc1 tcct tcc_g tcctest.ref *.bin *.i ex2 \
|
||||||
@rm -f tags ETAGS *.o *.a *.so* *.out *.log lib*.def *.exe *.dll
|
core gmon.out test.out test.ref a.out tcc_p \
|
||||||
@rm -f a.out *.dylib *_.h *.pod *.tcov
|
*.exe tcc-doc.html tcc.pod tcc.1 libtcc.a libtcc_test \
|
||||||
@$(MAKE) -s -C lib $@
|
tcctest[1234] test[1234].out
|
||||||
@$(MAKE) -s -C tests $@
|
|
||||||
|
|
||||||
distclean: clean
|
distclean: clean
|
||||||
@rm -vf config.h config.mak config.texi
|
rm -f config.h config.mak config.texi
|
||||||
@rm -vf $(TCCDOCS)
|
|
||||||
|
|
||||||
.PHONY: all clean test tar tags ETAGS doc distclean install uninstall FORCE
|
# win32 TCC
|
||||||
|
tcc_g.exe: tcc.c i386-gen.c bcheck.c Makefile
|
||||||
|
i386-mingw32msvc-gcc $(CFLAGS) -DCONFIG_TCC_STATIC -o $@ $<
|
||||||
|
|
||||||
help:
|
tcc.exe: tcc_g.exe
|
||||||
@echo "make"
|
i386-mingw32msvc-strip -o $@ $<
|
||||||
@echo " build native compiler (from separate objects)"
|
|
||||||
@echo "make ONE_SOURCE=no/yes SILENT=no/yes"
|
|
||||||
@echo " force building from separate/one object(s), less/more silently"
|
|
||||||
@echo "make cross-TARGET"
|
|
||||||
@echo " build one specific cross compiler for 'TARGET'. Currently supported:"
|
|
||||||
@echo " $(wordlist 1,8,$(TCC_X))"
|
|
||||||
@echo " $(wordlist 9,99,$(TCC_X))"
|
|
||||||
@echo "make cross"
|
|
||||||
@echo " build all cross compilers"
|
|
||||||
@echo "make test"
|
|
||||||
@echo " run all tests"
|
|
||||||
@echo "make tests2.all / make tests2.37 / make tests2.37+"
|
|
||||||
@echo " run all/single test(s) from tests2, optionally update .expect"
|
|
||||||
@echo "make testspp.all / make testspp.17"
|
|
||||||
@echo " run all/single test(s) from tests/pp"
|
|
||||||
@echo "make tcov-test / tcov-tests2.37 / tcov-testspp.17"
|
|
||||||
@echo " run tests as above with code coverage. After test(s) see tcc_c$(EXESUF).tcov"
|
|
||||||
@echo "make sani-test / sani-tests2.37 / sani-testspp.17"
|
|
||||||
@echo " run tests as above with sanitize option."
|
|
||||||
@echo "make test-install"
|
|
||||||
@echo " run tests with the installed tcc"
|
|
||||||
@echo "Other supported make targets:"
|
|
||||||
@echo " install install-strip uninstall doc [dist]clean tags ETAGS tar help"
|
|
||||||
@echo "Custom configuration:"
|
|
||||||
@echo " The makefile includes a file 'config-extra.mak' if it is present."
|
|
||||||
@echo " This file may contain some custom configuration. For example to"
|
|
||||||
@echo " configure the search paths for a cross-compiler, assuming the"
|
|
||||||
@echo " support files in /usr/i686-linux-gnu:"
|
|
||||||
@echo " ROOT-i386 = /usr/i686-linux-gnu"
|
|
||||||
@echo " CRT-i386 = {R}/lib"
|
|
||||||
@echo " LIB-i386 = {B}:{R}/lib"
|
|
||||||
@echo " INC-i386 = {B}/include:{R}/include (*)"
|
|
||||||
@echo " DEF-i386 += -D__linux__"
|
|
||||||
@echo " Or also, for the cross platform files in /usr/<triplet>"
|
|
||||||
@echo " TRIPLET-i386 = i686-linux-gnu"
|
|
||||||
@echo " (*) tcc replaces {B} by 'tccdir' and {R} by 'CONFIG_SYSROOT'"
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------------
|
# profiling version
|
||||||
endif # ($(INCLUDED),no)
|
tcc_p: tcc.c Makefile
|
||||||
|
$(CC) $(CFLAGS_P) -o $@ $< $(LIBS_P)
|
||||||
|
|
||||||
|
# libtcc generation and example
|
||||||
|
libinstall: libtcc.a
|
||||||
|
$(INSTALL) -m644 libtcc.a $(libdir)
|
||||||
|
$(INSTALL) -m644 libtcc.h $(includedir)
|
||||||
|
|
||||||
|
libtcc.o: tcc.c i386-gen.c bcheck.c Makefile
|
||||||
|
$(CC) $(CFLAGS) -DLIBTCC -c -o $@ $<
|
||||||
|
|
||||||
|
libtcc.a: libtcc.o
|
||||||
|
$(AR) rcs $@ $^
|
||||||
|
|
||||||
|
libtcc_test: libtcc_test.c libtcc.a
|
||||||
|
$(CC) $(CFLAGS) -I. -o $@ $< -L. -ltcc -ldl
|
||||||
|
|
||||||
|
libtest: libtcc_test
|
||||||
|
./libtcc_test
|
||||||
|
|
||||||
|
# targets for development
|
||||||
|
|
||||||
|
%.bin: %.c tcc
|
||||||
|
$(TCC) -g -o $@ $<
|
||||||
|
$(DISAS) $@
|
||||||
|
|
||||||
|
instr: instr.o
|
||||||
|
objdump -d instr.o
|
||||||
|
|
||||||
|
# tiny assembler testing
|
||||||
|
|
||||||
|
asmtest.ref: asmtest.S
|
||||||
|
$(CC) -c -o asmtest.ref.o asmtest.S
|
||||||
|
objdump -D asmtest.ref.o > $@
|
||||||
|
|
||||||
|
# XXX: we compute tcc.c to go faster during development !
|
||||||
|
asmtest.out: asmtest.S tcc
|
||||||
|
# ./tcc tcc.c -c asmtest.S
|
||||||
|
#asmtest.out: asmtest.S tcc
|
||||||
|
./tcc -c asmtest.S
|
||||||
|
objdump -D asmtest.o > $@
|
||||||
|
|
||||||
|
asmtest: asmtest.out asmtest.ref
|
||||||
|
@if diff -u --ignore-matching-lines="file format" asmtest.ref asmtest.out ; then echo "ASM Auto Test OK"; fi
|
||||||
|
|
||||||
|
instr.o: instr.S
|
||||||
|
$(CC) -O2 -Wall -g -c -o $@ $<
|
||||||
|
|
||||||
|
cache: tcc_g
|
||||||
|
cachegrind ./tcc_g -o /tmp/linpack -lm bench/linpack.c
|
||||||
|
vg_annotate tcc.c > /tmp/linpack.cache.log
|
||||||
|
|
||||||
|
# documentation and man page
|
||||||
|
tcc-doc.html: tcc-doc.texi
|
||||||
|
texi2html -monolithic -number $<
|
||||||
|
|
||||||
|
tcc.1: tcc-doc.texi
|
||||||
|
./texi2pod.pl $< tcc.pod
|
||||||
|
pod2man --section=1 --center=" " --release=" " tcc.pod > $@
|
||||||
|
|
||||||
|
FILES= Makefile Makefile.uClibc configure VERSION \
|
||||||
|
README TODO COPYING \
|
||||||
|
Changelog tcc-doc.texi tcc-doc.html \
|
||||||
|
tcc.1 \
|
||||||
|
tcc.c i386-gen.c tccelf.c tcctok.h tccasm.c i386-asm.c i386-asm.h\
|
||||||
|
bcheck.c libtcc1.c \
|
||||||
|
elf.h stab.h stab.def \
|
||||||
|
stddef.h stdarg.h stdbool.h float.h varargs.h \
|
||||||
|
tcclib.h libtcc.h libtcc_test.c \
|
||||||
|
ex1.c ex2.c ex3.c ex4.c ex5.c \
|
||||||
|
tcctest.c boundtest.c gcctestsuite.sh texi2pod.pl
|
||||||
|
|
||||||
|
FILE=tcc-$(VERSION)
|
||||||
|
|
||||||
|
tar:
|
||||||
|
rm -rf /tmp/$(FILE)
|
||||||
|
mkdir -p /tmp/$(FILE)
|
||||||
|
cp -P $(FILES) /tmp/$(FILE)
|
||||||
|
( cd /tmp ; tar zcvf ~/$(FILE).tar.gz $(FILE) )
|
||||||
|
rm -rf /tmp/$(FILE)
|
||||||
|
|||||||
27
README
27
README
@ -7,18 +7,19 @@ Features:
|
|||||||
- SMALL! You can compile and execute C code everywhere, for example on
|
- SMALL! You can compile and execute C code everywhere, for example on
|
||||||
rescue disks.
|
rescue disks.
|
||||||
|
|
||||||
- FAST! tcc generates machine code for i386, x86_64, arm, aarch64 or
|
- FAST! tcc generates optimized x86 code. No byte code
|
||||||
riscv64. Compiles and links about 10 times faster than 'gcc -O0'.
|
overhead. Compile, assemble and link about 7 times faster than 'gcc
|
||||||
|
-O0'.
|
||||||
|
|
||||||
- UNLIMITED! Any C dynamic library can be used directly. TCC is
|
- UNLIMITED! Any C dynamic library can be used directly. TCC is
|
||||||
heading toward full ISOC99 compliance. TCC can of course compile
|
heading torward full ISOC99 compliance. TCC can of course compile
|
||||||
itself.
|
itself.
|
||||||
|
|
||||||
- SAFE! tcc includes an optional memory and bound checker. Bound
|
- SAFE! tcc includes an optional memory and bound checker. Bound
|
||||||
checked code can be mixed freely with standard code.
|
checked code can be mixed freely with standard code.
|
||||||
|
|
||||||
- Compile and execute C source directly. No linking or assembly
|
- Compile and execute C source directly. No linking or assembly
|
||||||
necessary. Full C preprocessor included.
|
necessary. Full C preprocessor included.
|
||||||
|
|
||||||
- C script supported : just add '#!/usr/local/bin/tcc -run' at the first
|
- C script supported : just add '#!/usr/local/bin/tcc -run' at the first
|
||||||
line of your C source, and execute it directly from the command
|
line of your C source, and execute it directly from the command
|
||||||
@ -27,19 +28,17 @@ Features:
|
|||||||
Documentation:
|
Documentation:
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
1) Installation on Linux, BSD variants or macOS hosts:
|
1) Installation
|
||||||
|
|
||||||
|
*** TCC currently only works on Linux x86 with glibc >= 2.1 ***.
|
||||||
|
|
||||||
./configure
|
./configure
|
||||||
make
|
make
|
||||||
make test
|
make test
|
||||||
make install
|
make install
|
||||||
|
|
||||||
Notes: On BSD hosts, gmake should be used instead of make.
|
By default, tcc is installed in /usr/local/bin.
|
||||||
For Windows read tcc-win32.txt.
|
./configure --help shows configuration options.
|
||||||
|
|
||||||
makeinfo must be installed to compile the doc. By default, tcc is
|
|
||||||
installed in /usr/local/bin. ./configure --help shows configuration
|
|
||||||
options.
|
|
||||||
|
|
||||||
|
|
||||||
2) Introduction
|
2) Introduction
|
||||||
@ -68,8 +67,7 @@ operations given a list of numbers (benchmark).
|
|||||||
ex3.c: compute fibonacci numbers (benchmark).
|
ex3.c: compute fibonacci numbers (benchmark).
|
||||||
|
|
||||||
ex4.c: more complicated: X11 program. Very complicated test in fact
|
ex4.c: more complicated: X11 program. Very complicated test in fact
|
||||||
because standard headers are being used ! As for ex1.c, can also be launched
|
because standard headers are being used !
|
||||||
directly as a script: './ex4.c'.
|
|
||||||
|
|
||||||
ex5.c: 'hello world' with standard glibc headers.
|
ex5.c: 'hello world' with standard glibc headers.
|
||||||
|
|
||||||
@ -81,8 +79,7 @@ when doing 'make test'.
|
|||||||
|
|
||||||
4) Full Documentation
|
4) Full Documentation
|
||||||
|
|
||||||
Please read tcc-doc.html to have all the features of TCC. Additional
|
Please read tcc-doc.html to have all the features of TCC.
|
||||||
information for the Windows port is in tcc-win32.txt.
|
|
||||||
|
|
||||||
License:
|
License:
|
||||||
-------
|
-------
|
||||||
|
|||||||
67
RELICENSING
67
RELICENSING
@ -1,67 +0,0 @@
|
|||||||
|
|
||||||
Relicensing TinyCC
|
|
||||||
------------------
|
|
||||||
|
|
||||||
The authors listed below hereby confirm their agreement to relicense TinyCC
|
|
||||||
including their past contributions under the following terms:
|
|
||||||
|
|
||||||
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
|
||||||
* in the Software without restriction, including without limitation the rights
|
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
||||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
* THE SOFTWARE.
|
|
||||||
|
|
||||||
|
|
||||||
Author (name) I agree (YES/NO) Files/Features (optional)
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
Adam Sampson YES makefiles
|
|
||||||
Daniel Glöckner NO arm-gen.c
|
|
||||||
Daniel Glöckner YES not arm-gen.c
|
|
||||||
Danny Milosavljevic YES arm-asm.c riscv64-asm.c
|
|
||||||
Edmund Grimley Evans YES arm64
|
|
||||||
Fabrice Bellard YES original author
|
|
||||||
Frédéric Féret YES x86 64/16 bit asm
|
|
||||||
grischka YES tccpe.c
|
|
||||||
Henry Kroll YES
|
|
||||||
Herman ten Brugge YES
|
|
||||||
Joe Soroka YES
|
|
||||||
Kirill Smelkov YES
|
|
||||||
mingodad YES
|
|
||||||
Pip Cet YES
|
|
||||||
Shinichiro Hamaji YES x86_64-gen.c
|
|
||||||
Steffen Nurpmeso YES
|
|
||||||
Vincent Lefèvre YES
|
|
||||||
Thomas Preud'homme YES arm-gen.c
|
|
||||||
Timo VJ Lähde (Timppa) ? tiny_libmaker.c
|
|
||||||
TK ? tcccoff.c c67-gen.c
|
|
||||||
Tyge Løvset YES tgmath.h, Windows tcc_libm.h math.h
|
|
||||||
Urs Janssen YES
|
|
||||||
waddlesplash YES
|
|
||||||
Christian Jullien YES Windows Cygwin build and tests
|
|
||||||
Reimar Döffinger YES
|
|
||||||
noneofyourbusiness YES
|
|
||||||
Cyan Ogilvie YES
|
|
||||||
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
Please add yourself to the list above (rsp. replace the question mark)
|
|
||||||
and (after fetching the latest version) commit to the "mob" branch with
|
|
||||||
commit message:
|
|
||||||
|
|
||||||
Relicensing TinyCC
|
|
||||||
|
|
||||||
Thanks.
|
|
||||||
113
TODO
113
TODO
@ -1,73 +1,55 @@
|
|||||||
TODO list:
|
TODO list:
|
||||||
|
|
||||||
Releases:
|
- cast bug (Peter Wang)
|
||||||
|
- define incomplete type if defined several times (Peter Wang).
|
||||||
- release tcc on a regular basis
|
- long long constant evaluation
|
||||||
- testing repo.or.cz
|
- configure --cc=tcc (still one bug in libtcc1.c)
|
||||||
|
- disable-asm and disable-bcheck options
|
||||||
Bugs:
|
- test binutils/gcc compile
|
||||||
|
- add alloca(), __builtin_expect()
|
||||||
- i386 fastcall is mostly wrong
|
- gcc '-E' option.
|
||||||
- FPU st(0) is left unclean (kwisatz haderach). Incompatible with
|
- optimize VT_LOCAL + const
|
||||||
optimized gcc/msc code
|
- tci patch + argument.
|
||||||
|
- '-b' bug.
|
||||||
|
- atexit (Nigel Horne)
|
||||||
|
- see -lxxx bug (Michael Charity).
|
||||||
|
- handle inline functions as macros.
|
||||||
- see transparent union pb in /urs/include/sys/socket.h
|
- see transparent union pb in /urs/include/sys/socket.h
|
||||||
- precise behaviour of typeof with arrays ? (__put_user macro)
|
- precise behaviour of typeof with arrays ? (__put_user macro)
|
||||||
|
- #include_next support for /usr/include/limits ?
|
||||||
but should suffice for most cases)
|
but should suffice for most cases)
|
||||||
- handle '? x, y : z' in unsized variable initialization (',' is
|
- handle '? x, y : z' in unsized variable initialization (',' is
|
||||||
considered incorrectly as separator in preparser)
|
considered incorrectly as separator in preparser)
|
||||||
- transform functions to function pointers in function parameters
|
- function pointers/lvalues in ? : (linux kernel net/core/dev.c)
|
||||||
(net/ipv4/ip_output.c)
|
- transform functions to function pointers in function parameters (net/ipv4/ip_output.c)
|
||||||
- fix function pointer type display
|
- fix function pointer type display
|
||||||
|
- fix bound exit on RedHat 7.3
|
||||||
|
- check lcc test suite -> fix bitfield binary operations
|
||||||
- check section alignment in C
|
- check section alignment in C
|
||||||
- fix invalid cast in comparison 'if (v == (int8_t)v)'
|
- fix invalid cast in comparison 'if (v == (int8_t)v)'
|
||||||
|
- packed attribute
|
||||||
- finish varargs.h support (gcc 3.2 testsuite issue)
|
- finish varargs.h support (gcc 3.2 testsuite issue)
|
||||||
- fix static functions declared inside block
|
- fix static functions declared inside block
|
||||||
- fix multiple unions init
|
- C99: add variable size arrays (gcc 3.2 testsuite issue)
|
||||||
- make libtcc fully reentrant (except for the compilation stage itself).
|
|
||||||
- struct/union/enum definitions in nested scopes (see also Debian bug #770657)
|
|
||||||
- __STDC_IEC_559__: float f(void) { static float x = 0.0 / 0.0; return x; }
|
|
||||||
- memory may be leaked after errors (longjmp).
|
|
||||||
|
|
||||||
Portability:
|
|
||||||
|
|
||||||
- it is assumed that int is 32-bit and sizeof(int) == 4
|
|
||||||
- int is used when host or target size_t would make more sense
|
|
||||||
- TCC handles target floating-point (fp) values using the host's fp
|
|
||||||
arithmetic, which is simple and fast but may lead to exceptions
|
|
||||||
and inaccuracy and wrong representations when cross-compiling
|
|
||||||
|
|
||||||
Linking:
|
|
||||||
|
|
||||||
- static linking (-static) does sort of work
|
|
||||||
works with musl libc
|
|
||||||
glibc requires libc.so even when statically linked (very bad, but not
|
|
||||||
up to tcc)
|
|
||||||
|
|
||||||
Bound checking:
|
|
||||||
|
|
||||||
- fix bound exit on RedHat 7.3
|
|
||||||
- setjmp is not supported properly in bound checking.
|
|
||||||
- fix bound check code with '&' on local variables (currently done
|
|
||||||
only for local arrays).
|
|
||||||
- bound checking and float/long long/struct copy code. bound
|
|
||||||
checking and symbol + offset optimization
|
|
||||||
|
|
||||||
Missing features:
|
|
||||||
|
|
||||||
- disable-asm and disable-bcheck options
|
|
||||||
- __builtin_expect()
|
|
||||||
- atexit (Nigel Horne)
|
|
||||||
- C99: add complex types (gcc 3.2 testsuite issue)
|
- C99: add complex types (gcc 3.2 testsuite issue)
|
||||||
- postfix compound literals (see 20010124-1.c)
|
- postfix compound literals (see 20010124-1.c)
|
||||||
- interactive mode / integrated debugger
|
- fix multiple unions init
|
||||||
|
- setjmp is not supported properly in bound checking.
|
||||||
|
- better local variables handling (needed for other targets)
|
||||||
|
- fix bound check code with '&' on local variables (currently done
|
||||||
|
only for local arrays).
|
||||||
|
- sizeof, alignof, typeof can still generate code in some cases.
|
||||||
|
- bound checking and float/long long/struct copy code. bound
|
||||||
|
checking and symbol + offset optimization
|
||||||
|
- Fix the remaining libtcc memory leaks.
|
||||||
|
- make libtcc fully reentrant (except for the compilation stage itself).
|
||||||
|
- '-MD' option
|
||||||
|
|
||||||
Optimizations:
|
Optimizations:
|
||||||
|
|
||||||
- suppress specific anonymous symbol handling
|
- suppress specific anonymous symbol handling
|
||||||
- more parse optimizations (=even faster compilation)
|
- more parse optimizations (=even faster compilation)
|
||||||
- memory alloc optimizations (=even faster compilation)
|
- memory alloc optimizations (=even faster compilation)
|
||||||
- optimize VT_LOCAL + const
|
|
||||||
- better local variables handling (needed for other targets)
|
|
||||||
|
|
||||||
Not critical:
|
Not critical:
|
||||||
|
|
||||||
@ -75,34 +57,19 @@ Not critical:
|
|||||||
normative example - only relevant when using gotos! -> must add
|
normative example - only relevant when using gotos! -> must add
|
||||||
boolean variable to tell if compound literal was already
|
boolean variable to tell if compound literal was already
|
||||||
initialized).
|
initialized).
|
||||||
- add PowerPC generator and improve codegen for RISC (need
|
- add PowerPC or ARM code generator and improve codegen for RISC (need
|
||||||
to suppress VT_LOCAL and use a base register instead).
|
to suppress VT_LOCAL and use a base register instead).
|
||||||
|
- interactive mode / integrated debugger
|
||||||
- fix preprocessor symbol redefinition
|
- fix preprocessor symbol redefinition
|
||||||
|
- better constant opt (&&, ||, ?:)
|
||||||
- add portable byte code generator and interpreter for other
|
- add portable byte code generator and interpreter for other
|
||||||
unsupported architectures.
|
unsupported architectures.
|
||||||
- C++: variable declaration in for, minimal 'class' support.
|
- C++: variable declaration in for, minimal 'class' support.
|
||||||
- win32: __intxx. use resolve for bchecked malloc et al.
|
- win32: add __stdcall, __intxx. use resolve for bchecked malloc et
|
||||||
check exception code (exception filter func).
|
al. check GetModuleHandle for dlls. check exception code (exception
|
||||||
|
filter func).
|
||||||
- handle void (__attribute__() *ptr)()
|
- handle void (__attribute__() *ptr)()
|
||||||
- VLAs are implemented in a way that is not compatible with signals:
|
|
||||||
http://lists.gnu.org/archive/html/tinycc-devel/2015-11/msg00018.html
|
|
||||||
|
|
||||||
Fixed (probably):
|
|
||||||
|
|
||||||
- bug with defines:
|
|
||||||
#define spin_lock(lock) do { } while (0)
|
|
||||||
#define wq_spin_lock spin_lock
|
|
||||||
#define TEST() wq_spin_lock(a)
|
|
||||||
- typedefs can be structure fields
|
|
||||||
- see bugfixes.diff + improvement.diff from Daniel Glockner
|
|
||||||
- long long constant evaluation
|
|
||||||
- add alloca()
|
|
||||||
- gcc '-E' option.
|
|
||||||
- #include_next support for /usr/include/limits ?
|
|
||||||
- function pointers/lvalues in ? : (linux kernel net/core/dev.c)
|
|
||||||
- win32: add __stdcall, check GetModuleHandle for dlls.
|
|
||||||
- macro substitution with nested definitions (ShangHongzhang)
|
|
||||||
- with "-run" and libtcc, a PLT is now built.
|
|
||||||
- '-E' option was improved
|
|
||||||
- packed attribute is now supported
|
|
||||||
- ARM and ARM64 code generators have been added.
|
|
||||||
|
|||||||
68
USES
68
USES
@ -1,68 +0,0 @@
|
|||||||
The following software are known to use or support tcc builds.
|
|
||||||
Feel free to complete this list (*).
|
|
||||||
|
|
||||||
Name Short Description
|
|
||||||
---- -----------------
|
|
||||||
bigz An infinite precision Z & Q library.
|
|
||||||
gawk GNU awk.
|
|
||||||
gmp Library for arbitrary precision arithmetic.
|
|
||||||
gnumake GNU makefile.
|
|
||||||
gnu mes using tinycc to bootstrap a system
|
|
||||||
mpfr Multiple-precision floating-point library.
|
|
||||||
mpc Complex floating-point library with exact rounding.
|
|
||||||
mpv A free, open source, and cross-platform media player.
|
|
||||||
openlisp ISLISP ISO/IEC 13816 Lisp interpreter and compiler.
|
|
||||||
s-nail BSD Mail/POSIX mailx: send and receive Internet mail.
|
|
||||||
sqlite Embbedable SQL engine.
|
|
||||||
st Simple Terminal.
|
|
||||||
tcc Tiny CC which compiles itself.
|
|
||||||
zlib Lossless data-compression library.
|
|
||||||
|
|
||||||
(*) This list is ordered by name.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Forks & Experiments
|
|
||||||
-------------------
|
|
||||||
|
|
||||||
arm-thumb target
|
|
||||||
by Erlend Sveen <erlend.sveen@hotmail.com>
|
|
||||||
https://git.erlendjs.no/erlendjs/tinycc.git
|
|
||||||
|
|
||||||
riscv32 target
|
|
||||||
by Sam Ellicott <sellicott@cedarville.edu>
|
|
||||||
https://github.com/sellicott/tcc-riscv32.git
|
|
||||||
|
|
||||||
Transputer target
|
|
||||||
by David Smith <agentdavo@mac.com>
|
|
||||||
https://github.com/agentdavo/tinycc-transputer
|
|
||||||
|
|
||||||
tcc-65816 - Tiny C Compiler for 65816 CPU (based on V0.9.23) from SNES-SDK
|
|
||||||
https://github.com/nArnoSNES/tcc-65816
|
|
||||||
|
|
||||||
PE-UEFI arm64
|
|
||||||
by Andrei Warkentin <andrey.warkentin@gmail.com>
|
|
||||||
https://github.com/andreiw/tinycc/
|
|
||||||
|
|
||||||
TCCLS - global register allocator (proof of concept)
|
|
||||||
by Sebastian Falbesoner <sebastian.falbesoner@gmail.com>
|
|
||||||
https://bitbucket.org/theStack/tccls_poc.git
|
|
||||||
|
|
||||||
softfloat
|
|
||||||
by Giovanni Mascellani <gio@debian.org>
|
|
||||||
https://gitlab.com/giomasce/tinycc.git
|
|
||||||
|
|
||||||
optimize 386
|
|
||||||
by Jason Hood <jadoxa@yahoo.com.au>
|
|
||||||
|
|
||||||
tcctcl : tcl binding
|
|
||||||
https://code.google.com/archive/p/tcltcc/
|
|
||||||
|
|
||||||
tcc4tcl : tcl binding
|
|
||||||
https://chiselapp.com/user/rkeene/repository/tcc4tcl/index
|
|
||||||
|
|
||||||
lua-tcc : allows a Lua script to compile C code
|
|
||||||
https://github.com/javierguerragiraldez/lua-tcc
|
|
||||||
|
|
||||||
tcclua : semi-high-level bindings for `libtcc`
|
|
||||||
https://github.com/nucular/tcclua/blob/master/tcc.lua
|
|
||||||
472
arm-link.c
472
arm-link.c
@ -1,472 +0,0 @@
|
|||||||
#ifdef TARGET_DEFS_ONLY
|
|
||||||
|
|
||||||
#define EM_TCC_TARGET EM_ARM
|
|
||||||
|
|
||||||
/* relocation type for 32 bit data relocation */
|
|
||||||
#define R_DATA_32 R_ARM_ABS32
|
|
||||||
#define R_DATA_PTR R_ARM_ABS32
|
|
||||||
#define R_JMP_SLOT R_ARM_JUMP_SLOT
|
|
||||||
#define R_GLOB_DAT R_ARM_GLOB_DAT
|
|
||||||
#define R_COPY R_ARM_COPY
|
|
||||||
#define R_RELATIVE R_ARM_RELATIVE
|
|
||||||
|
|
||||||
#define R_NUM R_ARM_NUM
|
|
||||||
|
|
||||||
#define ELF_START_ADDR 0x00010000
|
|
||||||
#define ELF_PAGE_SIZE 0x10000
|
|
||||||
|
|
||||||
#define PCRELATIVE_DLLPLT 1
|
|
||||||
#define RELOCATE_DLLPLT 1
|
|
||||||
|
|
||||||
#else /* !TARGET_DEFS_ONLY */
|
|
||||||
|
|
||||||
#include "tcc.h"
|
|
||||||
|
|
||||||
#ifdef NEED_RELOC_TYPE
|
|
||||||
/* Returns 1 for a code relocation, 0 for a data relocation. For unknown
|
|
||||||
relocations, returns -1. */
|
|
||||||
ST_FUNC int code_reloc (int reloc_type)
|
|
||||||
{
|
|
||||||
switch (reloc_type) {
|
|
||||||
case R_ARM_MOVT_ABS:
|
|
||||||
case R_ARM_MOVW_ABS_NC:
|
|
||||||
case R_ARM_THM_MOVT_ABS:
|
|
||||||
case R_ARM_THM_MOVW_ABS_NC:
|
|
||||||
case R_ARM_ABS32:
|
|
||||||
case R_ARM_REL32:
|
|
||||||
case R_ARM_GOTPC:
|
|
||||||
case R_ARM_GOTOFF:
|
|
||||||
case R_ARM_GOT32:
|
|
||||||
case R_ARM_GOT_PREL:
|
|
||||||
case R_ARM_COPY:
|
|
||||||
case R_ARM_GLOB_DAT:
|
|
||||||
case R_ARM_NONE:
|
|
||||||
case R_ARM_TARGET1:
|
|
||||||
case R_ARM_MOVT_PREL:
|
|
||||||
case R_ARM_MOVW_PREL_NC:
|
|
||||||
case R_ARM_TLS_LE32:
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case R_ARM_PC24:
|
|
||||||
case R_ARM_CALL:
|
|
||||||
case R_ARM_JUMP24:
|
|
||||||
case R_ARM_PLT32:
|
|
||||||
case R_ARM_THM_PC22:
|
|
||||||
case R_ARM_THM_JUMP24:
|
|
||||||
case R_ARM_PREL31:
|
|
||||||
case R_ARM_V4BX:
|
|
||||||
case R_ARM_JUMP_SLOT:
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Returns an enumerator to describe whether and when the relocation needs a
|
|
||||||
GOT and/or PLT entry to be created. See tcc.h for a description of the
|
|
||||||
different values. */
|
|
||||||
ST_FUNC int gotplt_entry_type (int reloc_type)
|
|
||||||
{
|
|
||||||
switch (reloc_type) {
|
|
||||||
case R_ARM_NONE:
|
|
||||||
case R_ARM_COPY:
|
|
||||||
case R_ARM_GLOB_DAT:
|
|
||||||
case R_ARM_JUMP_SLOT:
|
|
||||||
case R_ARM_TLS_LE32:
|
|
||||||
return NO_GOTPLT_ENTRY;
|
|
||||||
|
|
||||||
case R_ARM_PC24:
|
|
||||||
case R_ARM_CALL:
|
|
||||||
case R_ARM_JUMP24:
|
|
||||||
case R_ARM_PLT32:
|
|
||||||
case R_ARM_THM_PC22:
|
|
||||||
case R_ARM_THM_JUMP24:
|
|
||||||
case R_ARM_MOVT_ABS:
|
|
||||||
case R_ARM_MOVW_ABS_NC:
|
|
||||||
case R_ARM_THM_MOVT_ABS:
|
|
||||||
case R_ARM_THM_MOVW_ABS_NC:
|
|
||||||
case R_ARM_PREL31:
|
|
||||||
case R_ARM_ABS32:
|
|
||||||
case R_ARM_REL32:
|
|
||||||
case R_ARM_V4BX:
|
|
||||||
case R_ARM_TARGET1:
|
|
||||||
case R_ARM_MOVT_PREL:
|
|
||||||
case R_ARM_MOVW_PREL_NC:
|
|
||||||
return AUTO_GOTPLT_ENTRY;
|
|
||||||
|
|
||||||
case R_ARM_GOTPC:
|
|
||||||
case R_ARM_GOTOFF:
|
|
||||||
return BUILD_GOT_ONLY;
|
|
||||||
|
|
||||||
case R_ARM_GOT32:
|
|
||||||
case R_ARM_GOT_PREL:
|
|
||||||
return ALWAYS_GOTPLT_ENTRY;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef NEED_BUILD_GOT
|
|
||||||
ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_attr *attr)
|
|
||||||
{
|
|
||||||
Section *plt = s1->plt;
|
|
||||||
uint8_t *p;
|
|
||||||
unsigned plt_offset;
|
|
||||||
|
|
||||||
/* when building a DLL, GOT entry accesses must be done relative to
|
|
||||||
start of GOT (see x86_64 example above) */
|
|
||||||
|
|
||||||
/* empty PLT: create PLT0 entry that push address of call site and
|
|
||||||
jump to ld.so resolution routine (GOT + 8) */
|
|
||||||
if (plt->data_offset == 0) {
|
|
||||||
p = section_ptr_add(plt, 20);
|
|
||||||
write32le(p, 0xe52de004); /* push {lr} */
|
|
||||||
write32le(p+4, 0xe59fe004); /* ldr lr, [pc, #4] */
|
|
||||||
write32le(p+8, 0xe08fe00e); /* add lr, pc, lr */
|
|
||||||
write32le(p+12, 0xe5bef008); /* ldr pc, [lr, #8]! */
|
|
||||||
/* p+16 is set in relocate_plt */
|
|
||||||
}
|
|
||||||
plt_offset = plt->data_offset;
|
|
||||||
|
|
||||||
if (attr->plt_thumb_stub) {
|
|
||||||
p = section_ptr_add(plt, 4);
|
|
||||||
write32le(p, 0x4778); /* bx pc */
|
|
||||||
write32le(p+2, 0x46c0); /* nop */
|
|
||||||
}
|
|
||||||
p = section_ptr_add(plt, 16);
|
|
||||||
/* save GOT offset for relocate_plt */
|
|
||||||
write32le(p + 4, got_offset);
|
|
||||||
return plt_offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* relocate the PLT: compute addresses and offsets in the PLT now that final
|
|
||||||
address for PLT and GOT are known (see fill_program_header) */
|
|
||||||
ST_FUNC void relocate_plt(TCCState *s1)
|
|
||||||
{
|
|
||||||
uint8_t *p, *p_end;
|
|
||||||
|
|
||||||
if (!s1->plt)
|
|
||||||
return;
|
|
||||||
|
|
||||||
p = s1->plt->data;
|
|
||||||
p_end = p + s1->plt->data_offset;
|
|
||||||
|
|
||||||
if (p < p_end) {
|
|
||||||
int x = s1->got->sh_addr - s1->plt->sh_addr - 12;
|
|
||||||
write32le(s1->plt->data + 16, x - 4);
|
|
||||||
p += 20;
|
|
||||||
while (p < p_end) {
|
|
||||||
unsigned off = x + read32le(p + 4) + (s1->plt->data - p) + 4;
|
|
||||||
if (read32le(p) == 0x46c04778) /* PLT Thumb stub present */
|
|
||||||
p += 4;
|
|
||||||
write32le(p, 0xe28fc200 | ((off >> 28) & 0xf)); // add ip, pc, #0xN0000000
|
|
||||||
write32le(p + 4, 0xe28cc600 | ((off >> 20) & 0xff)); // add ip, pc, #0xNN00000
|
|
||||||
write32le(p + 8, 0xe28cca00 | ((off >> 12) & 0xff)); // add ip, ip, #0xNN000
|
|
||||||
write32le(p + 12, 0xe5bcf000 | (off & 0xfff)); // ldr pc, [ip, #0xNNN]!
|
|
||||||
p += 16;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s1->plt->reloc) {
|
|
||||||
ElfW_Rel *rel;
|
|
||||||
p = s1->got->data;
|
|
||||||
for_each_elem(s1->plt->reloc, 0, rel, ElfW_Rel) {
|
|
||||||
write32le(p + rel->r_offset, s1->plt->sh_addr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val)
|
|
||||||
{
|
|
||||||
ElfW(Sym) *sym;
|
|
||||||
int sym_index, esym_index;
|
|
||||||
|
|
||||||
sym_index = ELFW(R_SYM)(rel->r_info);
|
|
||||||
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
|
|
||||||
|
|
||||||
switch(type) {
|
|
||||||
case R_ARM_PC24:
|
|
||||||
case R_ARM_CALL:
|
|
||||||
case R_ARM_JUMP24:
|
|
||||||
case R_ARM_PLT32:
|
|
||||||
{
|
|
||||||
int x, is_thumb, is_call, h, blx_avail, is_bl, th_ko;
|
|
||||||
unsigned code = read32le(ptr);
|
|
||||||
x = code & 0x00ffffff;
|
|
||||||
#ifdef DEBUG_RELOC
|
|
||||||
printf ("reloc %d: x=0x%x val=0x%x ", type, x, val);
|
|
||||||
#endif
|
|
||||||
code &= 0xff000000;
|
|
||||||
x <<= 2;
|
|
||||||
if (x & 0x2000000)
|
|
||||||
x -= 0x4000000;
|
|
||||||
blx_avail = (CONFIG_TCC_CPUVER >= 5);
|
|
||||||
is_thumb = val & 1;
|
|
||||||
is_bl = code == 0xeb000000;
|
|
||||||
is_call = (type == R_ARM_CALL || (type == R_ARM_PC24 && is_bl));
|
|
||||||
x += val - addr;
|
|
||||||
#ifdef DEBUG_RELOC
|
|
||||||
printf (" newx=0x%x name=%s\n", x,
|
|
||||||
(char *) symtab_section->link->data + sym->st_name);
|
|
||||||
#endif
|
|
||||||
h = x & 2;
|
|
||||||
th_ko = (x & 3) && (!blx_avail || !is_call);
|
|
||||||
if (th_ko || x >= 0x2000000 || x < -0x2000000)
|
|
||||||
tcc_error_noabort("can't relocate value at %x,%d",addr, type);
|
|
||||||
x >>= 2;
|
|
||||||
x &= 0xffffff;
|
|
||||||
/* Only reached if blx is avail and it is a call */
|
|
||||||
if (is_thumb) {
|
|
||||||
x |= h << 24;
|
|
||||||
code = 0xfa000000; /* bl -> blx */
|
|
||||||
}
|
|
||||||
write32le(ptr, code | x);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
/* Since these relocations only concern Thumb-2 and blx instruction was
|
|
||||||
introduced before Thumb-2, we can assume blx is available and not
|
|
||||||
guard its use */
|
|
||||||
case R_ARM_THM_PC22:
|
|
||||||
case R_ARM_THM_JUMP24:
|
|
||||||
{
|
|
||||||
int x, hi, lo, s, j1, j2, i1, i2, imm10, imm11;
|
|
||||||
int to_thumb, is_call, to_plt, blx_bit = 1 << 12;
|
|
||||||
Section *plt;
|
|
||||||
|
|
||||||
/* weak reference */
|
|
||||||
if (sym->st_shndx == SHN_UNDEF &&
|
|
||||||
ELFW(ST_BIND)(sym->st_info) == STB_WEAK)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Get initial offset */
|
|
||||||
hi = read16le(ptr);
|
|
||||||
lo = read16le(ptr+2);
|
|
||||||
s = (hi >> 10) & 1;
|
|
||||||
j1 = (lo >> 13) & 1;
|
|
||||||
j2 = (lo >> 11) & 1;
|
|
||||||
i1 = (j1 ^ s) ^ 1;
|
|
||||||
i2 = (j2 ^ s) ^ 1;
|
|
||||||
imm10 = hi & 0x3ff;
|
|
||||||
imm11 = lo & 0x7ff;
|
|
||||||
x = (s << 24) | (i1 << 23) | (i2 << 22) |
|
|
||||||
(imm10 << 12) | (imm11 << 1);
|
|
||||||
if (x & 0x01000000)
|
|
||||||
x -= 0x02000000;
|
|
||||||
|
|
||||||
/* Relocation infos */
|
|
||||||
to_thumb = val & 1;
|
|
||||||
plt = s1->plt;
|
|
||||||
to_plt = (val >= plt->sh_addr) &&
|
|
||||||
(val < plt->sh_addr + plt->data_offset);
|
|
||||||
is_call = (type == R_ARM_THM_PC22);
|
|
||||||
|
|
||||||
if (!to_thumb && !to_plt && !is_call) {
|
|
||||||
int index;
|
|
||||||
uint8_t *p;
|
|
||||||
char *name, buf[1024];
|
|
||||||
Section *text;
|
|
||||||
|
|
||||||
name = (char *) symtab_section->link->data + sym->st_name;
|
|
||||||
text = s1->sections[sym->st_shndx];
|
|
||||||
/* Modify reloc to target a thumb stub to switch to ARM */
|
|
||||||
snprintf(buf, sizeof(buf), "%s_from_thumb", name);
|
|
||||||
index = put_elf_sym(symtab_section,
|
|
||||||
text->data_offset + 1,
|
|
||||||
sym->st_size, sym->st_info, 0,
|
|
||||||
sym->st_shndx, buf);
|
|
||||||
to_thumb = 1;
|
|
||||||
val = text->data_offset + 1;
|
|
||||||
rel->r_info = ELFW(R_INFO)(index, type);
|
|
||||||
/* Create a thumb stub function to switch to ARM mode */
|
|
||||||
put_elf_reloc(symtab_section, text,
|
|
||||||
text->data_offset + 4, R_ARM_JUMP24,
|
|
||||||
sym_index);
|
|
||||||
p = section_ptr_add(text, 8);
|
|
||||||
write32le(p, 0x4778); /* bx pc */
|
|
||||||
write32le(p+2, 0x46c0); /* nop */
|
|
||||||
write32le(p+4, 0xeafffffe); /* b $sym */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Compute final offset */
|
|
||||||
x += val - addr;
|
|
||||||
if (!to_thumb && is_call) {
|
|
||||||
blx_bit = 0; /* bl -> blx */
|
|
||||||
x = (x + 3) & -4; /* Compute offset from aligned PC */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check that relocation is possible
|
|
||||||
* offset must not be out of range
|
|
||||||
* if target is to be entered in arm mode:
|
|
||||||
- bit 1 must not set
|
|
||||||
- instruction must be a call (bl) or a jump to PLT */
|
|
||||||
if (!to_thumb || x >= 0x1000000 || x < -0x1000000)
|
|
||||||
if (to_thumb || (val & 2) || (!is_call && !to_plt))
|
|
||||||
tcc_error_noabort("can't relocate value at %x,%d",addr, type);
|
|
||||||
|
|
||||||
/* Compute and store final offset */
|
|
||||||
s = (x >> 24) & 1;
|
|
||||||
i1 = (x >> 23) & 1;
|
|
||||||
i2 = (x >> 22) & 1;
|
|
||||||
j1 = s ^ (i1 ^ 1);
|
|
||||||
j2 = s ^ (i2 ^ 1);
|
|
||||||
imm10 = (x >> 12) & 0x3ff;
|
|
||||||
imm11 = (x >> 1) & 0x7ff;
|
|
||||||
write16le(ptr, (hi & 0xf800) |
|
|
||||||
(s << 10) | imm10);
|
|
||||||
write16le(ptr+2, (lo & 0xc000) |
|
|
||||||
(j1 << 13) | blx_bit | (j2 << 11) |
|
|
||||||
imm11);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
case R_ARM_MOVT_ABS:
|
|
||||||
case R_ARM_MOVW_ABS_NC:
|
|
||||||
{
|
|
||||||
int x, imm4, imm12;
|
|
||||||
if (type == R_ARM_MOVT_ABS)
|
|
||||||
val >>= 16;
|
|
||||||
imm12 = val & 0xfff;
|
|
||||||
imm4 = (val >> 12) & 0xf;
|
|
||||||
x = (imm4 << 16) | imm12;
|
|
||||||
if (type == R_ARM_THM_MOVT_ABS)
|
|
||||||
write32le(ptr, read32le(ptr) | x);
|
|
||||||
else
|
|
||||||
add32le(ptr, x);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
case R_ARM_MOVT_PREL:
|
|
||||||
case R_ARM_MOVW_PREL_NC:
|
|
||||||
{
|
|
||||||
int insn = read32le(ptr);
|
|
||||||
int addend = ((insn >> 4) & 0xf000) | (insn & 0xfff);
|
|
||||||
|
|
||||||
addend = (addend ^ 0x8000) - 0x8000;
|
|
||||||
val += addend - addr;
|
|
||||||
if (type == R_ARM_MOVT_PREL)
|
|
||||||
val >>= 16;
|
|
||||||
write32le(ptr, (insn & 0xfff0f000) |
|
|
||||||
((val & 0xf000) << 4) | (val & 0xfff));
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
case R_ARM_THM_MOVT_ABS:
|
|
||||||
case R_ARM_THM_MOVW_ABS_NC:
|
|
||||||
{
|
|
||||||
int x, i, imm4, imm3, imm8;
|
|
||||||
if (type == R_ARM_THM_MOVT_ABS)
|
|
||||||
val >>= 16;
|
|
||||||
imm8 = val & 0xff;
|
|
||||||
imm3 = (val >> 8) & 0x7;
|
|
||||||
i = (val >> 11) & 1;
|
|
||||||
imm4 = (val >> 12) & 0xf;
|
|
||||||
x = (imm3 << 28) | (imm8 << 16) | (i << 10) | imm4;
|
|
||||||
if (type == R_ARM_THM_MOVT_ABS)
|
|
||||||
write32le(ptr, read32le(ptr) | x);
|
|
||||||
else
|
|
||||||
add32le(ptr, x);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
case R_ARM_PREL31:
|
|
||||||
{
|
|
||||||
int x;
|
|
||||||
x = read32le(ptr) & 0x7fffffff;
|
|
||||||
write32le(ptr, read32le(ptr) & 0x80000000);
|
|
||||||
x = (x * 2) / 2;
|
|
||||||
x += val - addr;
|
|
||||||
if((x^(x>>1))&0x40000000)
|
|
||||||
tcc_error_noabort("can't relocate value at %x,%d",addr, type);
|
|
||||||
write32le(ptr, read32le(ptr) | (x & 0x7fffffff));
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
case R_ARM_ABS32:
|
|
||||||
case R_ARM_TARGET1:
|
|
||||||
if (s1->output_type & TCC_OUTPUT_DYN) {
|
|
||||||
esym_index = get_sym_attr(s1, sym_index, 0)->dyn_index;
|
|
||||||
qrel->r_offset = rel->r_offset;
|
|
||||||
if (esym_index) {
|
|
||||||
qrel->r_info = ELFW(R_INFO)(esym_index, R_ARM_ABS32);
|
|
||||||
qrel++;
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
qrel->r_info = ELFW(R_INFO)(0, R_ARM_RELATIVE);
|
|
||||||
qrel++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
add32le(ptr, val);
|
|
||||||
return;
|
|
||||||
case R_ARM_REL32:
|
|
||||||
add32le(ptr, val - addr);
|
|
||||||
return;
|
|
||||||
case R_ARM_GOTPC:
|
|
||||||
add32le(ptr, s1->got->sh_addr - addr);
|
|
||||||
return;
|
|
||||||
case R_ARM_GOTOFF:
|
|
||||||
add32le(ptr, val - s1->got->sh_addr);
|
|
||||||
return;
|
|
||||||
case R_ARM_GOT32:
|
|
||||||
/* we load the got offset */
|
|
||||||
add32le(ptr, get_sym_attr(s1, sym_index, 0)->got_offset);
|
|
||||||
return;
|
|
||||||
case R_ARM_GOT_PREL:
|
|
||||||
/* we load the pc relative got offset */
|
|
||||||
add32le(ptr, s1->got->sh_addr +
|
|
||||||
get_sym_attr(s1, sym_index, 0)->got_offset -
|
|
||||||
addr);
|
|
||||||
return;
|
|
||||||
case R_ARM_COPY:
|
|
||||||
return;
|
|
||||||
case R_ARM_V4BX:
|
|
||||||
/* trade Thumb support for ARMv4 support */
|
|
||||||
if ((0x0ffffff0 & read32le(ptr)) == 0x012FFF10)
|
|
||||||
write32le(ptr, read32le(ptr) ^ 0xE12FFF10 ^ 0xE1A0F000); /* BX Rm -> MOV PC, Rm */
|
|
||||||
return;
|
|
||||||
case R_ARM_GLOB_DAT:
|
|
||||||
case R_ARM_JUMP_SLOT:
|
|
||||||
write32le(ptr, val);
|
|
||||||
return;
|
|
||||||
case R_ARM_NONE:
|
|
||||||
/* Nothing to do. Normally used to indicate a dependency
|
|
||||||
on a certain symbol (like for exception handling under EABI). */
|
|
||||||
return;
|
|
||||||
case R_ARM_RELATIVE:
|
|
||||||
#ifdef TCC_TARGET_PE
|
|
||||||
add32le(ptr, val - s1->pe_imagebase);
|
|
||||||
#endif
|
|
||||||
/* do nothing */
|
|
||||||
return;
|
|
||||||
case R_ARM_TLS_LE32:
|
|
||||||
{
|
|
||||||
ElfW(Sym) *sym;
|
|
||||||
Section *sec;
|
|
||||||
int32_t x;
|
|
||||||
addr_t tls_start = 0, tls_end = 0, tls_align = 1;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
|
|
||||||
sec = s1->sections[sym->st_shndx];
|
|
||||||
|
|
||||||
for (i = 1; i < s1->nb_sections; i++) {
|
|
||||||
Section *s = s1->sections[i];
|
|
||||||
if (s->sh_flags & SHF_TLS && s->sh_size) {
|
|
||||||
if (!tls_start || s->sh_addr < tls_start)
|
|
||||||
tls_start = s->sh_addr;
|
|
||||||
if (s->sh_addr + s->sh_size > tls_end)
|
|
||||||
tls_end = s->sh_addr + s->sh_size;
|
|
||||||
if (s->sh_addralign > tls_align)
|
|
||||||
tls_align = s->sh_addralign;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (tls_end > tls_start) {
|
|
||||||
x = val - tls_start + 8;
|
|
||||||
} else {
|
|
||||||
x = val - sec->sh_addr - sec->data_offset + 8;
|
|
||||||
}
|
|
||||||
add32le(ptr, x);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
default:
|
|
||||||
fprintf(stderr,"FIXME: handle reloc type %d at %x [%p] to %x\n",
|
|
||||||
type, (unsigned)addr, ptr, (unsigned)val);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* !TARGET_DEFS_ONLY */
|
|
||||||
406
arm-tok.h
406
arm-tok.h
@ -1,406 +0,0 @@
|
|||||||
/* ------------------------------------------------------------------ */
|
|
||||||
/* WARNING: relative order of tokens is important. */
|
|
||||||
|
|
||||||
/* register */
|
|
||||||
|
|
||||||
DEF_ASM(r0)
|
|
||||||
DEF_ASM(r1)
|
|
||||||
DEF_ASM(r2)
|
|
||||||
DEF_ASM(r3)
|
|
||||||
DEF_ASM(r4)
|
|
||||||
DEF_ASM(r5)
|
|
||||||
DEF_ASM(r6)
|
|
||||||
DEF_ASM(r7)
|
|
||||||
DEF_ASM(r8)
|
|
||||||
DEF_ASM(r9)
|
|
||||||
DEF_ASM(r10)
|
|
||||||
DEF_ASM(r11) /* fp */
|
|
||||||
DEF_ASM(r12) /* ip[c] */
|
|
||||||
DEF_ASM(r13) /* sp */
|
|
||||||
DEF_ASM(r14) /* lr */
|
|
||||||
DEF_ASM(r15) /* pc */
|
|
||||||
|
|
||||||
/* synonym register names */
|
|
||||||
|
|
||||||
DEF_ASM(a1) /* argument/result/scratch register 1: alias for r0 */
|
|
||||||
DEF_ASM(a2) /* argument/result/scratch register 2: alias for r1 */
|
|
||||||
DEF_ASM(a3) /* argument/result/scratch register 3: alias for r2 */
|
|
||||||
DEF_ASM(a4) /* argument/result/scratch register 4: alias for r3 */
|
|
||||||
|
|
||||||
DEF_ASM(v1) /* variable register 1: alias for r4 */
|
|
||||||
DEF_ASM(v2) /* variable register 2: alias for r5 */
|
|
||||||
DEF_ASM(v3) /* variable register 3: alias for r6 */
|
|
||||||
DEF_ASM(v4) /* variable register 4: alias for r7 */
|
|
||||||
DEF_ASM(v5) /* ARM state variable register 5: alias for r8 */
|
|
||||||
DEF_ASM(v6) /* ARM state variable register 6: alias for r9 */
|
|
||||||
DEF_ASM(v7) /* ARM state variable register 7: alias for r10 */
|
|
||||||
DEF_ASM(v8) /* ARM state variable register 8: alias for r11 */
|
|
||||||
|
|
||||||
/* special register names */
|
|
||||||
|
|
||||||
DEF_ASM(sb) /* alias for r9 */
|
|
||||||
DEF_ASM(sl) /* alias for r10 */
|
|
||||||
DEF_ASM(fp) /* alias for r11 */
|
|
||||||
DEF_ASM(ip) /* alias for r12 */
|
|
||||||
DEF_ASM(sp) /* alias for r13 */
|
|
||||||
DEF_ASM(lr) /* alias for r14 */
|
|
||||||
DEF_ASM(pc) /* alias for r15 */
|
|
||||||
|
|
||||||
/* coprocessors */
|
|
||||||
|
|
||||||
DEF_ASM(p0)
|
|
||||||
DEF_ASM(p1)
|
|
||||||
DEF_ASM(p2)
|
|
||||||
DEF_ASM(p3)
|
|
||||||
DEF_ASM(p4)
|
|
||||||
DEF_ASM(p5)
|
|
||||||
DEF_ASM(p6)
|
|
||||||
DEF_ASM(p7)
|
|
||||||
DEF_ASM(p8)
|
|
||||||
DEF_ASM(p9)
|
|
||||||
DEF_ASM(p10)
|
|
||||||
DEF_ASM(p11)
|
|
||||||
DEF_ASM(p12)
|
|
||||||
DEF_ASM(p13)
|
|
||||||
DEF_ASM(p14)
|
|
||||||
DEF_ASM(p15)
|
|
||||||
|
|
||||||
/* coprocessor registers */
|
|
||||||
|
|
||||||
DEF_ASM(c0)
|
|
||||||
DEF_ASM(c1)
|
|
||||||
DEF_ASM(c2)
|
|
||||||
DEF_ASM(c3)
|
|
||||||
DEF_ASM(c4)
|
|
||||||
DEF_ASM(c5)
|
|
||||||
DEF_ASM(c6)
|
|
||||||
DEF_ASM(c7)
|
|
||||||
DEF_ASM(c8)
|
|
||||||
DEF_ASM(c9)
|
|
||||||
DEF_ASM(c10)
|
|
||||||
DEF_ASM(c11)
|
|
||||||
DEF_ASM(c12)
|
|
||||||
DEF_ASM(c13)
|
|
||||||
DEF_ASM(c14)
|
|
||||||
DEF_ASM(c15)
|
|
||||||
|
|
||||||
/* single-precision VFP registers */
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
/* double-precision VFP registers */
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
/* VFP status registers */
|
|
||||||
|
|
||||||
DEF_ASM(fpsid)
|
|
||||||
DEF_ASM(fpscr)
|
|
||||||
DEF_ASM(fpexc)
|
|
||||||
|
|
||||||
/* VFP magical ARM register */
|
|
||||||
|
|
||||||
DEF_ASM(apsr_nzcv)
|
|
||||||
|
|
||||||
/* data processing directives */
|
|
||||||
|
|
||||||
DEF_ASM(asl)
|
|
||||||
|
|
||||||
/* instructions that have no condition code */
|
|
||||||
|
|
||||||
DEF_ASM(cdp2)
|
|
||||||
DEF_ASM(ldc2)
|
|
||||||
DEF_ASM(ldc2l)
|
|
||||||
DEF_ASM(stc2)
|
|
||||||
DEF_ASM(stc2l)
|
|
||||||
|
|
||||||
#define ARM_INSTRUCTION_GROUP(tok) ((((tok) - TOK_ASM_nopeq) & 0xFFFFFFF0) + TOK_ASM_nopeq)
|
|
||||||
|
|
||||||
/* Note: condition code is 4 bits */
|
|
||||||
#define DEF_ASM_CONDED(x) \
|
|
||||||
DEF(TOK_ASM_ ## x ## eq, #x "eq") \
|
|
||||||
DEF(TOK_ASM_ ## x ## ne, #x "ne") \
|
|
||||||
DEF(TOK_ASM_ ## x ## cs, #x "cs") \
|
|
||||||
DEF(TOK_ASM_ ## x ## cc, #x "cc") \
|
|
||||||
DEF(TOK_ASM_ ## x ## mi, #x "mi") \
|
|
||||||
DEF(TOK_ASM_ ## x ## pl, #x "pl") \
|
|
||||||
DEF(TOK_ASM_ ## x ## vs, #x "vs") \
|
|
||||||
DEF(TOK_ASM_ ## x ## vc, #x "vc") \
|
|
||||||
DEF(TOK_ASM_ ## x ## hi, #x "hi") \
|
|
||||||
DEF(TOK_ASM_ ## x ## ls, #x "ls") \
|
|
||||||
DEF(TOK_ASM_ ## x ## ge, #x "ge") \
|
|
||||||
DEF(TOK_ASM_ ## x ## lt, #x "lt") \
|
|
||||||
DEF(TOK_ASM_ ## x ## gt, #x "gt") \
|
|
||||||
DEF(TOK_ASM_ ## x ## le, #x "le") \
|
|
||||||
DEF(TOK_ASM_ ## x, #x) \
|
|
||||||
DEF(TOK_ASM_ ## x ## rsvd, #x "rsvd")
|
|
||||||
|
|
||||||
/* Note: condition code is 4 bits */
|
|
||||||
#define DEF_ASM_CONDED_WITH_SUFFIX(x, y) \
|
|
||||||
DEF(TOK_ASM_ ## x ## eq ## _ ## y, #x "eq." #y) \
|
|
||||||
DEF(TOK_ASM_ ## x ## ne ## _ ## y, #x "ne." #y) \
|
|
||||||
DEF(TOK_ASM_ ## x ## cs ## _ ## y, #x "cs." #y) \
|
|
||||||
DEF(TOK_ASM_ ## x ## cc ## _ ## y, #x "cc." #y) \
|
|
||||||
DEF(TOK_ASM_ ## x ## mi ## _ ## y, #x "mi." #y) \
|
|
||||||
DEF(TOK_ASM_ ## x ## pl ## _ ## y, #x "pl." #y) \
|
|
||||||
DEF(TOK_ASM_ ## x ## vs ## _ ## y, #x "vs." #y) \
|
|
||||||
DEF(TOK_ASM_ ## x ## vc ## _ ## y, #x "vc." #y) \
|
|
||||||
DEF(TOK_ASM_ ## x ## hi ## _ ## y, #x "hi." #y) \
|
|
||||||
DEF(TOK_ASM_ ## x ## ls ## _ ## y, #x "ls." #y) \
|
|
||||||
DEF(TOK_ASM_ ## x ## ge ## _ ## y, #x "ge." #y) \
|
|
||||||
DEF(TOK_ASM_ ## x ## lt ## _ ## y, #x "lt." #y) \
|
|
||||||
DEF(TOK_ASM_ ## x ## gt ## _ ## y, #x "gt." #y) \
|
|
||||||
DEF(TOK_ASM_ ## x ## le ## _ ## y, #x "le." #y) \
|
|
||||||
DEF(TOK_ASM_ ## x ## _ ## y, #x "." #y) \
|
|
||||||
DEF(TOK_ASM_ ## x ## rsvd ## _ ## y, #x "rsvd." #y)
|
|
||||||
|
|
||||||
#define DEF_ASM_CONDED_VFP_F32_F64(x) \
|
|
||||||
DEF_ASM_CONDED_WITH_SUFFIX(x, f32) \
|
|
||||||
DEF_ASM_CONDED_WITH_SUFFIX(x, f64)
|
|
||||||
|
|
||||||
#define DEF_ASM_CONDED_WITH_TWO_SUFFIXES(x, y, z) \
|
|
||||||
DEF(TOK_ASM_ ## x ## eq ## _ ## y ## _ ## z, #x "eq." #y "." #z) \
|
|
||||||
DEF(TOK_ASM_ ## x ## ne ## _ ## y ## _ ## z, #x "ne." #y "." #z) \
|
|
||||||
DEF(TOK_ASM_ ## x ## cs ## _ ## y ## _ ## z, #x "cs." #y "." #z) \
|
|
||||||
DEF(TOK_ASM_ ## x ## cc ## _ ## y ## _ ## z, #x "cc." #y "." #z) \
|
|
||||||
DEF(TOK_ASM_ ## x ## mi ## _ ## y ## _ ## z, #x "mi." #y "." #z) \
|
|
||||||
DEF(TOK_ASM_ ## x ## pl ## _ ## y ## _ ## z, #x "pl." #y "." #z) \
|
|
||||||
DEF(TOK_ASM_ ## x ## vs ## _ ## y ## _ ## z, #x "vs." #y "." #z) \
|
|
||||||
DEF(TOK_ASM_ ## x ## vc ## _ ## y ## _ ## z, #x "vc." #y "." #z) \
|
|
||||||
DEF(TOK_ASM_ ## x ## hi ## _ ## y ## _ ## z, #x "hi." #y "." #z) \
|
|
||||||
DEF(TOK_ASM_ ## x ## ls ## _ ## y ## _ ## z, #x "ls." #y "." #z) \
|
|
||||||
DEF(TOK_ASM_ ## x ## ge ## _ ## y ## _ ## z, #x "ge." #y "." #z) \
|
|
||||||
DEF(TOK_ASM_ ## x ## lt ## _ ## y ## _ ## z, #x "lt." #y "." #z) \
|
|
||||||
DEF(TOK_ASM_ ## x ## gt ## _ ## y ## _ ## z, #x "gt." #y "." #z) \
|
|
||||||
DEF(TOK_ASM_ ## x ## le ## _ ## y ## _ ## z, #x "le." #y "." #z) \
|
|
||||||
DEF(TOK_ASM_ ## x ## _ ## y ## _ ## z, #x "." #y "." #z) \
|
|
||||||
DEF(TOK_ASM_ ## x ## rsvd ## _ ## y ## _ ## z, #x "rsvd." #y "." #z)
|
|
||||||
|
|
||||||
/* Note: add new tokens after nop (MUST always use DEF_ASM_CONDED) */
|
|
||||||
|
|
||||||
DEF_ASM_CONDED(nop)
|
|
||||||
DEF_ASM_CONDED(wfe)
|
|
||||||
DEF_ASM_CONDED(wfi)
|
|
||||||
DEF_ASM_CONDED(swi)
|
|
||||||
DEF_ASM_CONDED(svc)
|
|
||||||
|
|
||||||
/* misc */
|
|
||||||
DEF_ASM_CONDED(clz)
|
|
||||||
|
|
||||||
/* size conversion */
|
|
||||||
|
|
||||||
DEF_ASM_CONDED(sxtb)
|
|
||||||
DEF_ASM_CONDED(sxth)
|
|
||||||
DEF_ASM_CONDED(uxtb)
|
|
||||||
DEF_ASM_CONDED(uxth)
|
|
||||||
DEF_ASM_CONDED(movt)
|
|
||||||
DEF_ASM_CONDED(movw)
|
|
||||||
|
|
||||||
/* multiplication */
|
|
||||||
|
|
||||||
DEF_ASM_CONDED(mul)
|
|
||||||
DEF_ASM_CONDED(muls)
|
|
||||||
DEF_ASM_CONDED(mla)
|
|
||||||
DEF_ASM_CONDED(mlas)
|
|
||||||
DEF_ASM_CONDED(smull)
|
|
||||||
DEF_ASM_CONDED(smulls)
|
|
||||||
DEF_ASM_CONDED(umull)
|
|
||||||
DEF_ASM_CONDED(umulls)
|
|
||||||
DEF_ASM_CONDED(smlal)
|
|
||||||
DEF_ASM_CONDED(smlals)
|
|
||||||
DEF_ASM_CONDED(umlal)
|
|
||||||
DEF_ASM_CONDED(umlals)
|
|
||||||
DEF_ASM_CONDED(mls)
|
|
||||||
DEF_ASM_CONDED(udiv)
|
|
||||||
DEF_ASM_CONDED(sdiv)
|
|
||||||
|
|
||||||
/* load/store */
|
|
||||||
|
|
||||||
DEF_ASM_CONDED(ldr)
|
|
||||||
DEF_ASM_CONDED(ldrb)
|
|
||||||
DEF_ASM_CONDED(str)
|
|
||||||
DEF_ASM_CONDED(strb)
|
|
||||||
DEF_ASM_CONDED(ldrex)
|
|
||||||
DEF_ASM_CONDED(ldrexb)
|
|
||||||
DEF_ASM_CONDED(ldrexh)
|
|
||||||
DEF_ASM_CONDED(strex)
|
|
||||||
DEF_ASM_CONDED(strexb)
|
|
||||||
DEF_ASM_CONDED(strexh)
|
|
||||||
DEF_ASM_CONDED(ldrh)
|
|
||||||
DEF_ASM_CONDED(ldrsh)
|
|
||||||
DEF_ASM_CONDED(ldrsb)
|
|
||||||
DEF_ASM_CONDED(strh)
|
|
||||||
|
|
||||||
DEF_ASM_CONDED(stmda)
|
|
||||||
DEF_ASM_CONDED(ldmda)
|
|
||||||
DEF_ASM_CONDED(stm)
|
|
||||||
DEF_ASM_CONDED(ldm)
|
|
||||||
DEF_ASM_CONDED(stmia)
|
|
||||||
DEF_ASM_CONDED(ldmia)
|
|
||||||
DEF_ASM_CONDED(stmdb)
|
|
||||||
DEF_ASM_CONDED(ldmdb)
|
|
||||||
DEF_ASM_CONDED(stmib)
|
|
||||||
DEF_ASM_CONDED(ldmib)
|
|
||||||
|
|
||||||
DEF_ASM_CONDED(ldc)
|
|
||||||
DEF_ASM_CONDED(ldcl)
|
|
||||||
DEF_ASM_CONDED(stc)
|
|
||||||
DEF_ASM_CONDED(stcl)
|
|
||||||
|
|
||||||
/* instruction macros */
|
|
||||||
|
|
||||||
DEF_ASM_CONDED(push)
|
|
||||||
DEF_ASM_CONDED(pop)
|
|
||||||
|
|
||||||
/* branches */
|
|
||||||
|
|
||||||
DEF_ASM_CONDED(b)
|
|
||||||
DEF_ASM_CONDED(bl)
|
|
||||||
DEF_ASM_CONDED(bx)
|
|
||||||
DEF_ASM_CONDED(blx)
|
|
||||||
|
|
||||||
/* data processing instructions; order is important */
|
|
||||||
|
|
||||||
DEF_ASM_CONDED(and)
|
|
||||||
DEF_ASM_CONDED(ands)
|
|
||||||
DEF_ASM_CONDED(eor)
|
|
||||||
DEF_ASM_CONDED(eors)
|
|
||||||
DEF_ASM_CONDED(sub)
|
|
||||||
DEF_ASM_CONDED(subs)
|
|
||||||
DEF_ASM_CONDED(rsb)
|
|
||||||
DEF_ASM_CONDED(rsbs)
|
|
||||||
DEF_ASM_CONDED(add)
|
|
||||||
DEF_ASM_CONDED(adds)
|
|
||||||
DEF_ASM_CONDED(adc)
|
|
||||||
DEF_ASM_CONDED(adcs)
|
|
||||||
DEF_ASM_CONDED(sbc)
|
|
||||||
DEF_ASM_CONDED(sbcs)
|
|
||||||
DEF_ASM_CONDED(rsc)
|
|
||||||
DEF_ASM_CONDED(rscs)
|
|
||||||
DEF_ASM_CONDED(tst)
|
|
||||||
DEF_ASM_CONDED(tsts) // necessary here--but not useful to the user
|
|
||||||
DEF_ASM_CONDED(teq)
|
|
||||||
DEF_ASM_CONDED(teqs) // necessary here--but not useful to the user
|
|
||||||
DEF_ASM_CONDED(cmp)
|
|
||||||
DEF_ASM_CONDED(cmps) // necessary here--but not useful to the user
|
|
||||||
DEF_ASM_CONDED(cmn)
|
|
||||||
DEF_ASM_CONDED(cmns) // necessary here--but not useful to the user
|
|
||||||
DEF_ASM_CONDED(orr)
|
|
||||||
DEF_ASM_CONDED(orrs)
|
|
||||||
DEF_ASM_CONDED(mov)
|
|
||||||
DEF_ASM_CONDED(movs)
|
|
||||||
DEF_ASM_CONDED(bic)
|
|
||||||
DEF_ASM_CONDED(bics)
|
|
||||||
DEF_ASM_CONDED(mvn)
|
|
||||||
DEF_ASM_CONDED(mvns)
|
|
||||||
|
|
||||||
DEF_ASM_CONDED(lsl)
|
|
||||||
DEF_ASM_CONDED(lsls)
|
|
||||||
DEF_ASM_CONDED(lsr)
|
|
||||||
DEF_ASM_CONDED(lsrs)
|
|
||||||
DEF_ASM_CONDED(asr)
|
|
||||||
DEF_ASM_CONDED(asrs)
|
|
||||||
DEF_ASM_CONDED(ror)
|
|
||||||
DEF_ASM_CONDED(rors)
|
|
||||||
DEF_ASM_CONDED(rrx)
|
|
||||||
DEF_ASM_CONDED(rrxs)
|
|
||||||
|
|
||||||
DEF_ASM_CONDED(cdp)
|
|
||||||
DEF_ASM_CONDED(mcr)
|
|
||||||
DEF_ASM_CONDED(mrc)
|
|
||||||
|
|
||||||
// Floating point high-level instructions
|
|
||||||
|
|
||||||
DEF_ASM_CONDED(vldr)
|
|
||||||
DEF_ASM_CONDED(vstr)
|
|
||||||
|
|
||||||
DEF_ASM_CONDED_VFP_F32_F64(vmla)
|
|
||||||
DEF_ASM_CONDED_VFP_F32_F64(vmls)
|
|
||||||
DEF_ASM_CONDED_VFP_F32_F64(vnmls)
|
|
||||||
DEF_ASM_CONDED_VFP_F32_F64(vnmla)
|
|
||||||
DEF_ASM_CONDED_VFP_F32_F64(vmul)
|
|
||||||
DEF_ASM_CONDED_VFP_F32_F64(vnmul)
|
|
||||||
DEF_ASM_CONDED_VFP_F32_F64(vadd)
|
|
||||||
DEF_ASM_CONDED_VFP_F32_F64(vsub)
|
|
||||||
DEF_ASM_CONDED_VFP_F32_F64(vdiv)
|
|
||||||
DEF_ASM_CONDED_VFP_F32_F64(vneg)
|
|
||||||
DEF_ASM_CONDED_VFP_F32_F64(vabs)
|
|
||||||
DEF_ASM_CONDED_VFP_F32_F64(vsqrt)
|
|
||||||
DEF_ASM_CONDED_VFP_F32_F64(vcmp)
|
|
||||||
DEF_ASM_CONDED_VFP_F32_F64(vcmpe)
|
|
||||||
DEF_ASM_CONDED_VFP_F32_F64(vmov)
|
|
||||||
|
|
||||||
DEF_ASM_CONDED_WITH_TWO_SUFFIXES(vcvtr, s32, f64)
|
|
||||||
DEF_ASM_CONDED_WITH_TWO_SUFFIXES(vcvtr, s32, f32)
|
|
||||||
DEF_ASM_CONDED_WITH_TWO_SUFFIXES(vcvtr, u32, f64)
|
|
||||||
DEF_ASM_CONDED_WITH_TWO_SUFFIXES(vcvtr, u32, f32)
|
|
||||||
|
|
||||||
DEF_ASM_CONDED_WITH_TWO_SUFFIXES(vcvt, s32, f64)
|
|
||||||
DEF_ASM_CONDED_WITH_TWO_SUFFIXES(vcvt, s32, f32)
|
|
||||||
DEF_ASM_CONDED_WITH_TWO_SUFFIXES(vcvt, u32, f64)
|
|
||||||
DEF_ASM_CONDED_WITH_TWO_SUFFIXES(vcvt, u32, f32)
|
|
||||||
|
|
||||||
DEF_ASM_CONDED_WITH_TWO_SUFFIXES(vcvt, f64, s32)
|
|
||||||
DEF_ASM_CONDED_WITH_TWO_SUFFIXES(vcvt, f32, s32)
|
|
||||||
DEF_ASM_CONDED_WITH_TWO_SUFFIXES(vcvt, f64, u32)
|
|
||||||
DEF_ASM_CONDED_WITH_TWO_SUFFIXES(vcvt, f32, u32)
|
|
||||||
|
|
||||||
DEF_ASM_CONDED_WITH_TWO_SUFFIXES(vcvt, f64, f32)
|
|
||||||
DEF_ASM_CONDED_WITH_TWO_SUFFIXES(vcvt, f32, f64)
|
|
||||||
|
|
||||||
DEF_ASM_CONDED(vpush)
|
|
||||||
DEF_ASM_CONDED(vpop)
|
|
||||||
DEF_ASM_CONDED(vldm)
|
|
||||||
DEF_ASM_CONDED(vldmia)
|
|
||||||
DEF_ASM_CONDED(vldmdb)
|
|
||||||
DEF_ASM_CONDED(vstm)
|
|
||||||
DEF_ASM_CONDED(vstmia)
|
|
||||||
DEF_ASM_CONDED(vstmdb)
|
|
||||||
DEF_ASM_CONDED(vmsr)
|
|
||||||
DEF_ASM_CONDED(vmrs)
|
|
||||||
2276
arm64-asm.c
2276
arm64-asm.c
File diff suppressed because it is too large
Load Diff
2353
arm64-gen.c
2353
arm64-gen.c
File diff suppressed because it is too large
Load Diff
406
arm64-link.c
406
arm64-link.c
@ -1,406 +0,0 @@
|
|||||||
#ifdef TARGET_DEFS_ONLY
|
|
||||||
|
|
||||||
#define EM_TCC_TARGET EM_AARCH64
|
|
||||||
|
|
||||||
#define R_DATA_32 R_AARCH64_ABS32
|
|
||||||
#define R_DATA_PTR R_AARCH64_ABS64
|
|
||||||
#define R_JMP_SLOT R_AARCH64_JUMP_SLOT
|
|
||||||
#define R_GLOB_DAT R_AARCH64_GLOB_DAT
|
|
||||||
#define R_COPY R_AARCH64_COPY
|
|
||||||
#define R_RELATIVE R_AARCH64_RELATIVE
|
|
||||||
|
|
||||||
#define R_NUM R_AARCH64_NUM
|
|
||||||
|
|
||||||
#define ELF_START_ADDR 0x00400000
|
|
||||||
#define ELF_PAGE_SIZE 0x10000
|
|
||||||
|
|
||||||
#define PCRELATIVE_DLLPLT 1
|
|
||||||
#define RELOCATE_DLLPLT 1
|
|
||||||
|
|
||||||
#else /* !TARGET_DEFS_ONLY */
|
|
||||||
|
|
||||||
#include "tcc.h"
|
|
||||||
|
|
||||||
#ifdef NEED_RELOC_TYPE
|
|
||||||
/* Returns 1 for a code relocation, 0 for a data relocation. For unknown
|
|
||||||
relocations, returns -1. */
|
|
||||||
ST_FUNC int code_reloc (int reloc_type)
|
|
||||||
{
|
|
||||||
switch (reloc_type) {
|
|
||||||
case R_AARCH64_ABS32:
|
|
||||||
case R_AARCH64_ABS64:
|
|
||||||
case R_AARCH64_PREL32:
|
|
||||||
case R_AARCH64_MOVW_UABS_G0_NC:
|
|
||||||
case R_AARCH64_MOVW_UABS_G1_NC:
|
|
||||||
case R_AARCH64_MOVW_UABS_G2_NC:
|
|
||||||
case R_AARCH64_MOVW_UABS_G3:
|
|
||||||
case R_AARCH64_ADR_PREL_PG_HI21:
|
|
||||||
case R_AARCH64_ADD_ABS_LO12_NC:
|
|
||||||
case R_AARCH64_ADR_GOT_PAGE:
|
|
||||||
case R_AARCH64_LD64_GOT_LO12_NC:
|
|
||||||
case R_AARCH64_LDST128_ABS_LO12_NC:
|
|
||||||
case R_AARCH64_LDST64_ABS_LO12_NC:
|
|
||||||
case R_AARCH64_LDST32_ABS_LO12_NC:
|
|
||||||
case R_AARCH64_LDST16_ABS_LO12_NC:
|
|
||||||
case R_AARCH64_LDST8_ABS_LO12_NC:
|
|
||||||
case R_AARCH64_TLSLE_ADD_TPREL_HI12:
|
|
||||||
case R_AARCH64_TLSLE_ADD_TPREL_LO12:
|
|
||||||
case R_AARCH64_GLOB_DAT:
|
|
||||||
case R_AARCH64_COPY:
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case R_AARCH64_JUMP26:
|
|
||||||
case R_AARCH64_CALL26:
|
|
||||||
case R_AARCH64_JUMP_SLOT:
|
|
||||||
case R_AARCH64_CONDBR19:
|
|
||||||
case R_AARCH64_TSTBR14:
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Returns an enumerator to describe whether and when the relocation needs a
|
|
||||||
GOT and/or PLT entry to be created. See tcc.h for a description of the
|
|
||||||
different values. */
|
|
||||||
ST_FUNC int gotplt_entry_type (int reloc_type)
|
|
||||||
{
|
|
||||||
switch (reloc_type) {
|
|
||||||
case R_AARCH64_PREL32:
|
|
||||||
case R_AARCH64_MOVW_UABS_G0_NC:
|
|
||||||
case R_AARCH64_MOVW_UABS_G1_NC:
|
|
||||||
case R_AARCH64_MOVW_UABS_G2_NC:
|
|
||||||
case R_AARCH64_MOVW_UABS_G3:
|
|
||||||
case R_AARCH64_ADR_PREL_PG_HI21:
|
|
||||||
case R_AARCH64_ADD_ABS_LO12_NC:
|
|
||||||
case R_AARCH64_LDST128_ABS_LO12_NC:
|
|
||||||
case R_AARCH64_LDST64_ABS_LO12_NC:
|
|
||||||
case R_AARCH64_LDST32_ABS_LO12_NC:
|
|
||||||
case R_AARCH64_LDST16_ABS_LO12_NC:
|
|
||||||
case R_AARCH64_LDST8_ABS_LO12_NC:
|
|
||||||
case R_AARCH64_GLOB_DAT:
|
|
||||||
case R_AARCH64_JUMP_SLOT:
|
|
||||||
case R_AARCH64_COPY:
|
|
||||||
case R_AARCH64_CONDBR19:
|
|
||||||
case R_AARCH64_TSTBR14:
|
|
||||||
case R_AARCH64_TLSLE_ADD_TPREL_HI12:
|
|
||||||
case R_AARCH64_TLSLE_ADD_TPREL_LO12:
|
|
||||||
return NO_GOTPLT_ENTRY;
|
|
||||||
|
|
||||||
case R_AARCH64_ABS32:
|
|
||||||
case R_AARCH64_ABS64:
|
|
||||||
case R_AARCH64_JUMP26:
|
|
||||||
case R_AARCH64_CALL26:
|
|
||||||
return AUTO_GOTPLT_ENTRY;
|
|
||||||
|
|
||||||
case R_AARCH64_ADR_GOT_PAGE:
|
|
||||||
case R_AARCH64_LD64_GOT_LO12_NC:
|
|
||||||
return ALWAYS_GOTPLT_ENTRY;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef NEED_BUILD_GOT
|
|
||||||
ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_attr *attr)
|
|
||||||
{
|
|
||||||
Section *plt = s1->plt;
|
|
||||||
uint8_t *p;
|
|
||||||
unsigned plt_offset;
|
|
||||||
|
|
||||||
if (plt->data_offset == 0) {
|
|
||||||
section_ptr_add(plt, 32);
|
|
||||||
}
|
|
||||||
plt_offset = plt->data_offset;
|
|
||||||
|
|
||||||
p = section_ptr_add(plt, 16);
|
|
||||||
write32le(p, got_offset);
|
|
||||||
write32le(p + 4, (uint64_t) got_offset >> 32);
|
|
||||||
return plt_offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* relocate the PLT: compute addresses and offsets in the PLT now that final
|
|
||||||
address for PLT and GOT are known (see fill_program_header) */
|
|
||||||
ST_FUNC void relocate_plt(TCCState *s1)
|
|
||||||
{
|
|
||||||
uint8_t *p, *p_end;
|
|
||||||
|
|
||||||
if (!s1->plt)
|
|
||||||
return;
|
|
||||||
|
|
||||||
p = s1->plt->data;
|
|
||||||
p_end = p + s1->plt->data_offset;
|
|
||||||
|
|
||||||
if (p < p_end) {
|
|
||||||
uint64_t plt = s1->plt->sh_addr;
|
|
||||||
uint64_t got = s1->got->sh_addr + 16;
|
|
||||||
uint64_t off = (got >> 12) - (plt >> 12);
|
|
||||||
if ((off + ((uint32_t)1 << 20)) >> 21)
|
|
||||||
tcc_error_noabort("Failed relocating PLT (off=0x%lx, got=0x%lx, plt=0x%lx)", (long)off, (long)got, (long)plt);
|
|
||||||
write32le(p, ARM64_STP_X_PRE | ARM64_RT(16) | ARM64_RT2(30) |
|
|
||||||
ARM64_RN(31) | ARM64_IMM7(-2)); // stp x16,x30,[sp,#-16]!
|
|
||||||
write32le(p + 4, (ARM64_ADRP | ARM64_RD(16) | // adrp x16,...
|
|
||||||
(off & 0x1ffffc) << 3 | (off & 3) << 29));
|
|
||||||
write32le(p + 8, (ARM64_LDR_X | ARM64_RT(17) | ARM64_RN(16) | // ldr x17,[x16,#...]
|
|
||||||
(got & 0xff8) << 7));
|
|
||||||
write32le(p + 12, (ARM64_ADD_IMM | ARM64_SF(1) | ARM64_RD(16) | ARM64_RN(16) | // add x16,x16,#...
|
|
||||||
(got & 0xfff) << 10));
|
|
||||||
write32le(p + 16, ARM64_BR | ARM64_RN(17)); // br x17
|
|
||||||
write32le(p + 20, ARM64_NOP); // nop
|
|
||||||
write32le(p + 24, ARM64_NOP); // nop
|
|
||||||
write32le(p + 28, ARM64_NOP); // nop
|
|
||||||
p += 32;
|
|
||||||
got = s1->got->sh_addr;
|
|
||||||
while (p < p_end) {
|
|
||||||
uint64_t pc = plt + (p - s1->plt->data);
|
|
||||||
uint64_t addr = got + read64le(p);
|
|
||||||
uint64_t off = (addr >> 12) - (pc >> 12);
|
|
||||||
if ((off + ((uint32_t)1 << 20)) >> 21)
|
|
||||||
tcc_error_noabort("Failed relocating PLT (off=0x%lx, addr=0x%lx, pc=0x%lx)", (long)off, (long)addr, (long)pc);
|
|
||||||
write32le(p, (ARM64_ADRP | ARM64_RD(16) | // adrp x16,...
|
|
||||||
(off & 0x1ffffc) << 3 | (off & 3) << 29));
|
|
||||||
write32le(p + 4, (ARM64_LDR_X | ARM64_RT(17) | ARM64_RN(16) | // ldr x17,[x16,#...]
|
|
||||||
(addr & 0xff8) << 7));
|
|
||||||
write32le(p + 8, (ARM64_ADD_IMM | ARM64_SF(1) | ARM64_RD(16) | ARM64_RN(16) | // add x16,x16,#...
|
|
||||||
(addr & 0xfff) << 10));
|
|
||||||
write32le(p + 12, ARM64_BR | ARM64_RN(17)); // br x17
|
|
||||||
p += 16;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s1->plt->reloc) {
|
|
||||||
ElfW_Rel *rel;
|
|
||||||
p = s1->got->data;
|
|
||||||
for_each_elem(s1->plt->reloc, 0, rel, ElfW_Rel) {
|
|
||||||
write64le(p + rel->r_offset, s1->plt->sh_addr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val)
|
|
||||||
{
|
|
||||||
int sym_index = ELFW(R_SYM)(rel->r_info), esym_index;
|
|
||||||
#ifdef DEBUG_RELOC
|
|
||||||
ElfW(Sym) *sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
switch(type) {
|
|
||||||
case R_AARCH64_ABS64:
|
|
||||||
if ((s1->output_type & TCC_OUTPUT_DYN)) {
|
|
||||||
esym_index = get_sym_attr(s1, sym_index, 0)->dyn_index;
|
|
||||||
qrel->r_offset = rel->r_offset;
|
|
||||||
if (esym_index) {
|
|
||||||
qrel->r_info = ELFW(R_INFO)(esym_index, R_AARCH64_ABS64);
|
|
||||||
qrel->r_addend = rel->r_addend;
|
|
||||||
qrel++;
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
qrel->r_info = ELFW(R_INFO)(0, R_AARCH64_RELATIVE);
|
|
||||||
qrel->r_addend = read64le(ptr) + val;
|
|
||||||
qrel++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
add64le(ptr, val);
|
|
||||||
return;
|
|
||||||
case R_AARCH64_ABS32:
|
|
||||||
if (s1->output_type & TCC_OUTPUT_DYN) {
|
|
||||||
/* XXX: this logic may depend on TCC's codegen
|
|
||||||
now TCC uses R_AARCH64_RELATIVE even for a 64bit pointer */
|
|
||||||
qrel->r_offset = rel->r_offset;
|
|
||||||
qrel->r_info = ELFW(R_INFO)(0, R_AARCH64_RELATIVE);
|
|
||||||
/* Use sign extension! */
|
|
||||||
qrel->r_addend = (int)read32le(ptr) + val;
|
|
||||||
qrel++;
|
|
||||||
}
|
|
||||||
add32le(ptr, val);
|
|
||||||
return;
|
|
||||||
case R_AARCH64_PREL32:
|
|
||||||
if (s1->output_type == TCC_OUTPUT_DLL) {
|
|
||||||
/* DLL relocation */
|
|
||||||
esym_index = get_sym_attr(s1, sym_index, 0)->dyn_index;
|
|
||||||
if (esym_index) {
|
|
||||||
qrel->r_offset = rel->r_offset;
|
|
||||||
qrel->r_info = ELFW(R_INFO)(esym_index, R_AARCH64_PREL32);
|
|
||||||
/* Use sign extension! */
|
|
||||||
qrel->r_addend = (int)read32le(ptr) + rel->r_addend;
|
|
||||||
qrel++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
add32le(ptr, val - addr);
|
|
||||||
return;
|
|
||||||
case R_AARCH64_MOVW_UABS_G0_NC:
|
|
||||||
write32le(ptr, ((read32le(ptr) & 0xffe0001f) |
|
|
||||||
(val & 0xffff) << 5));
|
|
||||||
return;
|
|
||||||
case R_AARCH64_MOVW_UABS_G1_NC:
|
|
||||||
write32le(ptr, ((read32le(ptr) & 0xffe0001f) |
|
|
||||||
(val >> 16 & 0xffff) << 5));
|
|
||||||
return;
|
|
||||||
case R_AARCH64_MOVW_UABS_G2_NC:
|
|
||||||
write32le(ptr, ((read32le(ptr) & 0xffe0001f) |
|
|
||||||
(val >> 32 & 0xffff) << 5));
|
|
||||||
return;
|
|
||||||
case R_AARCH64_MOVW_UABS_G3:
|
|
||||||
write32le(ptr, ((read32le(ptr) & 0xffe0001f) |
|
|
||||||
(val >> 48 & 0xffff) << 5));
|
|
||||||
return;
|
|
||||||
case R_AARCH64_ADR_PREL_PG_HI21: {
|
|
||||||
uint64_t off = (val >> 12) - (addr >> 12);
|
|
||||||
#ifdef TCC_TARGET_PE
|
|
||||||
/* Weak undefined symbols resolve to address 0 on PE. ADRP cannot
|
|
||||||
encode that from the default 64-bit image base, so materialize
|
|
||||||
zero directly and let the paired ADD handle any low addend. */
|
|
||||||
if ((off + ((uint64_t)1 << 20)) >> 21) {
|
|
||||||
ElfW(Sym) *sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
|
|
||||||
if (sym->st_shndx == SHN_UNDEF
|
|
||||||
&& ELFW(ST_BIND)(sym->st_info) == STB_WEAK) {
|
|
||||||
write32le(ptr, 0xd2800000 | (read32le(ptr) & 0x1f));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
tcc_error_noabort("R_AARCH64_ADR_PREL_PG_HI21 relocation failed");
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if ((off + ((uint64_t)1 << 20)) >> 21)
|
|
||||||
tcc_error_noabort("R_AARCH64_ADR_PREL_PG_HI21 relocation failed");
|
|
||||||
#endif
|
|
||||||
write32le(ptr, ((read32le(ptr) & 0x9f00001f) |
|
|
||||||
(off & 0x1ffffc) << 3 | (off & 3) << 29));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case R_AARCH64_ADD_ABS_LO12_NC:
|
|
||||||
case R_AARCH64_LDST8_ABS_LO12_NC:
|
|
||||||
write32le(ptr, ((read32le(ptr) & 0xffc003ff) |
|
|
||||||
(val & 0xfff) << 10));
|
|
||||||
return;
|
|
||||||
case R_AARCH64_LDST16_ABS_LO12_NC:
|
|
||||||
write32le(ptr, ((read32le(ptr) & 0xffc003ff) |
|
|
||||||
(val & 0xffe) << 9));
|
|
||||||
return;
|
|
||||||
case R_AARCH64_LDST32_ABS_LO12_NC:
|
|
||||||
write32le(ptr, ((read32le(ptr) & 0xffc003ff) |
|
|
||||||
(val & 0xffc) << 8));
|
|
||||||
return;
|
|
||||||
case R_AARCH64_LDST64_ABS_LO12_NC:
|
|
||||||
write32le(ptr, ((read32le(ptr) & 0xffc003ff) |
|
|
||||||
(val & 0xff8) << 7));
|
|
||||||
return;
|
|
||||||
case R_AARCH64_LDST128_ABS_LO12_NC:
|
|
||||||
write32le(ptr, ((read32le(ptr) & 0xffc003ff) |
|
|
||||||
(val & 0xff0) << 6));
|
|
||||||
return;
|
|
||||||
case R_AARCH64_CONDBR19:
|
|
||||||
/* Conditional branch: 19-bit signed offset, bits 23:5 */
|
|
||||||
#ifdef DEBUG_RELOC
|
|
||||||
printf ("reloc %d @ 0x%lx: val=0x%lx name=%s\n", type, addr, val,
|
|
||||||
(char *) symtab_section->link->data + sym->st_name);
|
|
||||||
#endif
|
|
||||||
if (((val - addr) + ((uint64_t)1 << 20)) & ~(uint64_t)0x1ffffc)
|
|
||||||
tcc_error_noabort("R_AARCH64_CONDBR19 relocation failed"
|
|
||||||
" (val=%lx, addr=%lx)", (long)val, (long)addr);
|
|
||||||
write32le(ptr, ((read32le(ptr) & 0xff00001f) |
|
|
||||||
(((val - addr) >> 2 & 0x7ffff) << 5)));
|
|
||||||
return;
|
|
||||||
case R_AARCH64_TSTBR14:
|
|
||||||
/* Test and branch: 14-bit signed offset, bits 20:5 */
|
|
||||||
#ifdef DEBUG_RELOC
|
|
||||||
printf ("reloc %d @ 0x%lx: val=0x%lx name=%s\n", type, addr, val,
|
|
||||||
(char *) symtab_section->link->data + sym->st_name);
|
|
||||||
#endif
|
|
||||||
if (((val - addr) + ((uint64_t)1 << 15)) & ~(uint64_t)0xfffc)
|
|
||||||
tcc_error_noabort("R_AARCH64_TSTBR14 relocation failed"
|
|
||||||
" (val=%lx, addr=%lx)", (long)val, (long)addr);
|
|
||||||
write32le(ptr, ((read32le(ptr) & 0xfff8001f) |
|
|
||||||
(((val - addr) >> 2 & 0x3fff) << 5)));
|
|
||||||
return;
|
|
||||||
case R_AARCH64_JUMP26:
|
|
||||||
case R_AARCH64_CALL26:
|
|
||||||
{
|
|
||||||
const char *name;
|
|
||||||
#ifdef DEBUG_RELOC
|
|
||||||
printf ("reloc %d @ 0x%lx: val=0x%lx name=%s\n", type, addr, val,
|
|
||||||
(char *) symtab_section->link->data + sym->st_name);
|
|
||||||
#endif
|
|
||||||
if (((val - addr) + ((uint64_t)1 << 27)) & ~(uint64_t)0xffffffc) {
|
|
||||||
#ifdef TCC_TARGET_PE
|
|
||||||
ElfW(Sym) *sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
|
|
||||||
if (sym->st_shndx == SHN_UNDEF
|
|
||||||
&& ELFW(ST_BIND)(sym->st_info) == STB_WEAK) {
|
|
||||||
write32le(ptr, ARM64_NOP); /* nop */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
name = (char *)symtab_section->link->data +
|
|
||||||
((ElfW(Sym) *)symtab_section->data)[sym_index].st_name;
|
|
||||||
tcc_error_noabort("R_AARCH64_(JUMP|CALL)26 relocation failed"
|
|
||||||
" for '%s' (val=%lx, addr=%lx)",
|
|
||||||
name, (long)val, (long)addr);
|
|
||||||
}
|
|
||||||
write32le(ptr, (0x14000000 |
|
|
||||||
(uint32_t)(type == R_AARCH64_CALL26) << 31 |
|
|
||||||
((val - addr) >> 2 & 0x3ffffff)));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case R_AARCH64_ADR_GOT_PAGE: {
|
|
||||||
uint64_t off =
|
|
||||||
(((s1->got->sh_addr +
|
|
||||||
get_sym_attr(s1, sym_index, 0)->got_offset) >> 12) - (addr >> 12));
|
|
||||||
if ((off + ((uint64_t)1 << 20)) >> 21)
|
|
||||||
tcc_error_noabort("R_AARCH64_ADR_GOT_PAGE relocation failed");
|
|
||||||
write32le(ptr, ((read32le(ptr) & 0x9f00001f) |
|
|
||||||
(off & 0x1ffffc) << 3 | (off & 3) << 29));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case R_AARCH64_LD64_GOT_LO12_NC:
|
|
||||||
write32le(ptr,
|
|
||||||
((read32le(ptr) & 0xfff803ff) |
|
|
||||||
((s1->got->sh_addr +
|
|
||||||
get_sym_attr(s1, sym_index, 0)->got_offset) & 0xff8) << 7));
|
|
||||||
return;
|
|
||||||
case R_AARCH64_COPY:
|
|
||||||
return;
|
|
||||||
case R_AARCH64_GLOB_DAT:
|
|
||||||
case R_AARCH64_JUMP_SLOT:
|
|
||||||
/* They don't need addend */
|
|
||||||
#ifdef DEBUG_RELOC
|
|
||||||
printf ("reloc %d @ 0x%lx: val=0x%lx name=%s\n", type, addr,
|
|
||||||
val - rel->r_addend,
|
|
||||||
(char *) symtab_section->link->data + sym->st_name);
|
|
||||||
#endif
|
|
||||||
write64le(ptr, val - rel->r_addend);
|
|
||||||
return;
|
|
||||||
case R_AARCH64_TLSLE_ADD_TPREL_HI12:
|
|
||||||
case R_AARCH64_TLSLE_ADD_TPREL_LO12: {
|
|
||||||
addr_t tls_start = 0;
|
|
||||||
int i;
|
|
||||||
for (i = 1; i < s1->nb_sections; i++) {
|
|
||||||
Section *s = s1->sections[i];
|
|
||||||
if (s->sh_flags & SHF_TLS && s->sh_size) {
|
|
||||||
if (!tls_start || s->sh_addr < tls_start)
|
|
||||||
tls_start = s->sh_addr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* glibc arm64: tp points to tcbhead_t (DTV), TLS data starts after it */
|
|
||||||
int64_t tp_offset = val - tls_start + 16;
|
|
||||||
int64_t imm;
|
|
||||||
if (type == R_AARCH64_TLSLE_ADD_TPREL_HI12)
|
|
||||||
imm = (tp_offset >> 12) & 0xfff;
|
|
||||||
else
|
|
||||||
imm = tp_offset & 0xfff;
|
|
||||||
write32le(ptr, ((read32le(ptr) & 0xffc003ff) | (imm << 10)));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case R_AARCH64_RELATIVE:
|
|
||||||
#ifdef TCC_TARGET_PE
|
|
||||||
add32le(ptr, val - s1->pe_imagebase);
|
|
||||||
#endif
|
|
||||||
/* do nothing */
|
|
||||||
return;
|
|
||||||
default:
|
|
||||||
fprintf(stderr, "FIXME: handle reloc type %x at %x [%p] to %x\n",
|
|
||||||
type, (unsigned)addr, ptr, (unsigned)val);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* !TARGET_DEFS_ONLY */
|
|
||||||
840
arm64-tok.h
840
arm64-tok.h
@ -1,840 +0,0 @@
|
|||||||
/* ------------------------------------------------------------------ */
|
|
||||||
/* ARM64 (AArch64) assembler token definitions for TCC */
|
|
||||||
|
|
||||||
/* General purpose registers - 64-bit */
|
|
||||||
DEF_ASM(x0)
|
|
||||||
DEF_ASM(x1)
|
|
||||||
DEF_ASM(x2)
|
|
||||||
DEF_ASM(x3)
|
|
||||||
DEF_ASM(x4)
|
|
||||||
DEF_ASM(x5)
|
|
||||||
DEF_ASM(x6)
|
|
||||||
DEF_ASM(x7)
|
|
||||||
DEF_ASM(x8)
|
|
||||||
DEF_ASM(x9)
|
|
||||||
DEF_ASM(x10)
|
|
||||||
DEF_ASM(x11)
|
|
||||||
DEF_ASM(x12)
|
|
||||||
DEF_ASM(x13)
|
|
||||||
DEF_ASM(x14)
|
|
||||||
DEF_ASM(x15)
|
|
||||||
DEF_ASM(x16)
|
|
||||||
DEF_ASM(x17)
|
|
||||||
DEF_ASM(x18)
|
|
||||||
DEF_ASM(x19)
|
|
||||||
DEF_ASM(x20)
|
|
||||||
DEF_ASM(x21)
|
|
||||||
DEF_ASM(x22)
|
|
||||||
DEF_ASM(x23)
|
|
||||||
DEF_ASM(x24)
|
|
||||||
DEF_ASM(x25)
|
|
||||||
DEF_ASM(x26)
|
|
||||||
DEF_ASM(x27)
|
|
||||||
DEF_ASM(x28)
|
|
||||||
DEF_ASM(x29)
|
|
||||||
DEF_ASM(x30)
|
|
||||||
|
|
||||||
/* General purpose registers - 32-bit */
|
|
||||||
DEF_ASM(w0)
|
|
||||||
DEF_ASM(w1)
|
|
||||||
DEF_ASM(w2)
|
|
||||||
DEF_ASM(w3)
|
|
||||||
DEF_ASM(w4)
|
|
||||||
DEF_ASM(w5)
|
|
||||||
DEF_ASM(w6)
|
|
||||||
DEF_ASM(w7)
|
|
||||||
DEF_ASM(w8)
|
|
||||||
DEF_ASM(w9)
|
|
||||||
DEF_ASM(w10)
|
|
||||||
DEF_ASM(w11)
|
|
||||||
DEF_ASM(w12)
|
|
||||||
DEF_ASM(w13)
|
|
||||||
DEF_ASM(w14)
|
|
||||||
DEF_ASM(w15)
|
|
||||||
DEF_ASM(w16)
|
|
||||||
DEF_ASM(w17)
|
|
||||||
DEF_ASM(w18)
|
|
||||||
DEF_ASM(w19)
|
|
||||||
DEF_ASM(w20)
|
|
||||||
DEF_ASM(w21)
|
|
||||||
DEF_ASM(w22)
|
|
||||||
DEF_ASM(w23)
|
|
||||||
DEF_ASM(w24)
|
|
||||||
DEF_ASM(w25)
|
|
||||||
DEF_ASM(w26)
|
|
||||||
DEF_ASM(w27)
|
|
||||||
DEF_ASM(w28)
|
|
||||||
DEF_ASM(w29)
|
|
||||||
DEF_ASM(w30)
|
|
||||||
|
|
||||||
/* Special registers */
|
|
||||||
DEF_ASM(sp)
|
|
||||||
DEF_ASM(xzr)
|
|
||||||
DEF_ASM(wzr)
|
|
||||||
|
|
||||||
/* SIMD/FP registers - 128-bit views */
|
|
||||||
DEF_ASM(v0)
|
|
||||||
DEF_ASM(v1)
|
|
||||||
DEF_ASM(v2)
|
|
||||||
DEF_ASM(v3)
|
|
||||||
DEF_ASM(v4)
|
|
||||||
DEF_ASM(v5)
|
|
||||||
DEF_ASM(v6)
|
|
||||||
DEF_ASM(v7)
|
|
||||||
DEF_ASM(v8)
|
|
||||||
DEF_ASM(v9)
|
|
||||||
DEF_ASM(v10)
|
|
||||||
DEF_ASM(v11)
|
|
||||||
DEF_ASM(v12)
|
|
||||||
DEF_ASM(v13)
|
|
||||||
DEF_ASM(v14)
|
|
||||||
DEF_ASM(v15)
|
|
||||||
DEF_ASM(v16)
|
|
||||||
DEF_ASM(v17)
|
|
||||||
DEF_ASM(v18)
|
|
||||||
DEF_ASM(v19)
|
|
||||||
DEF_ASM(v20)
|
|
||||||
DEF_ASM(v21)
|
|
||||||
DEF_ASM(v22)
|
|
||||||
DEF_ASM(v23)
|
|
||||||
DEF_ASM(v24)
|
|
||||||
DEF_ASM(v25)
|
|
||||||
DEF_ASM(v26)
|
|
||||||
DEF_ASM(v27)
|
|
||||||
DEF_ASM(v28)
|
|
||||||
DEF_ASM(v29)
|
|
||||||
DEF_ASM(v30)
|
|
||||||
DEF_ASM(v31)
|
|
||||||
|
|
||||||
/* SIMD/FP registers - 64-bit views (double) */
|
|
||||||
DEF_ASM(d0)
|
|
||||||
DEF_ASM(d1)
|
|
||||||
DEF_ASM(d2)
|
|
||||||
DEF_ASM(d3)
|
|
||||||
DEF_ASM(d4)
|
|
||||||
DEF_ASM(d5)
|
|
||||||
DEF_ASM(d6)
|
|
||||||
DEF_ASM(d7)
|
|
||||||
DEF_ASM(d8)
|
|
||||||
DEF_ASM(d9)
|
|
||||||
DEF_ASM(d10)
|
|
||||||
DEF_ASM(d11)
|
|
||||||
DEF_ASM(d12)
|
|
||||||
DEF_ASM(d13)
|
|
||||||
DEF_ASM(d14)
|
|
||||||
DEF_ASM(d15)
|
|
||||||
DEF_ASM(d16)
|
|
||||||
DEF_ASM(d17)
|
|
||||||
DEF_ASM(d18)
|
|
||||||
DEF_ASM(d19)
|
|
||||||
DEF_ASM(d20)
|
|
||||||
DEF_ASM(d21)
|
|
||||||
DEF_ASM(d22)
|
|
||||||
DEF_ASM(d23)
|
|
||||||
DEF_ASM(d24)
|
|
||||||
DEF_ASM(d25)
|
|
||||||
DEF_ASM(d26)
|
|
||||||
DEF_ASM(d27)
|
|
||||||
DEF_ASM(d28)
|
|
||||||
DEF_ASM(d29)
|
|
||||||
DEF_ASM(d30)
|
|
||||||
DEF_ASM(d31)
|
|
||||||
|
|
||||||
/* SIMD/FP registers - 32-bit views (single) */
|
|
||||||
DEF_ASM(s0)
|
|
||||||
DEF_ASM(s1)
|
|
||||||
DEF_ASM(s2)
|
|
||||||
DEF_ASM(s3)
|
|
||||||
DEF_ASM(s4)
|
|
||||||
DEF_ASM(s5)
|
|
||||||
DEF_ASM(s6)
|
|
||||||
DEF_ASM(s7)
|
|
||||||
DEF_ASM(s8)
|
|
||||||
DEF_ASM(s9)
|
|
||||||
DEF_ASM(s10)
|
|
||||||
DEF_ASM(s11)
|
|
||||||
DEF_ASM(s12)
|
|
||||||
DEF_ASM(s13)
|
|
||||||
DEF_ASM(s14)
|
|
||||||
DEF_ASM(s15)
|
|
||||||
DEF_ASM(s16)
|
|
||||||
DEF_ASM(s17)
|
|
||||||
DEF_ASM(s18)
|
|
||||||
DEF_ASM(s19)
|
|
||||||
DEF_ASM(s20)
|
|
||||||
DEF_ASM(s21)
|
|
||||||
DEF_ASM(s22)
|
|
||||||
DEF_ASM(s23)
|
|
||||||
DEF_ASM(s24)
|
|
||||||
DEF_ASM(s25)
|
|
||||||
DEF_ASM(s26)
|
|
||||||
DEF_ASM(s27)
|
|
||||||
DEF_ASM(s28)
|
|
||||||
DEF_ASM(s29)
|
|
||||||
DEF_ASM(s30)
|
|
||||||
DEF_ASM(s31)
|
|
||||||
|
|
||||||
/* SIMD/FP registers - 16-bit views (half) */
|
|
||||||
DEF_ASM(h0)
|
|
||||||
DEF_ASM(h1)
|
|
||||||
DEF_ASM(h2)
|
|
||||||
DEF_ASM(h3)
|
|
||||||
DEF_ASM(h4)
|
|
||||||
DEF_ASM(h5)
|
|
||||||
DEF_ASM(h6)
|
|
||||||
DEF_ASM(h7)
|
|
||||||
DEF_ASM(h8)
|
|
||||||
DEF_ASM(h9)
|
|
||||||
DEF_ASM(h10)
|
|
||||||
DEF_ASM(h11)
|
|
||||||
DEF_ASM(h12)
|
|
||||||
DEF_ASM(h13)
|
|
||||||
DEF_ASM(h14)
|
|
||||||
DEF_ASM(h15)
|
|
||||||
DEF_ASM(h16)
|
|
||||||
DEF_ASM(h17)
|
|
||||||
DEF_ASM(h18)
|
|
||||||
DEF_ASM(h19)
|
|
||||||
DEF_ASM(h20)
|
|
||||||
DEF_ASM(h21)
|
|
||||||
DEF_ASM(h22)
|
|
||||||
DEF_ASM(h23)
|
|
||||||
DEF_ASM(h24)
|
|
||||||
DEF_ASM(h25)
|
|
||||||
DEF_ASM(h26)
|
|
||||||
DEF_ASM(h27)
|
|
||||||
DEF_ASM(h28)
|
|
||||||
DEF_ASM(h29)
|
|
||||||
DEF_ASM(h30)
|
|
||||||
DEF_ASM(h31)
|
|
||||||
|
|
||||||
/* SIMD/FP registers - 8-bit views (byte) */
|
|
||||||
DEF_ASM(b0)
|
|
||||||
DEF_ASM(b1)
|
|
||||||
DEF_ASM(b2)
|
|
||||||
DEF_ASM(b3)
|
|
||||||
DEF_ASM(b4)
|
|
||||||
DEF_ASM(b5)
|
|
||||||
DEF_ASM(b6)
|
|
||||||
DEF_ASM(b7)
|
|
||||||
DEF_ASM(b8)
|
|
||||||
DEF_ASM(b9)
|
|
||||||
DEF_ASM(b10)
|
|
||||||
DEF_ASM(b11)
|
|
||||||
DEF_ASM(b12)
|
|
||||||
DEF_ASM(b13)
|
|
||||||
DEF_ASM(b14)
|
|
||||||
DEF_ASM(b15)
|
|
||||||
DEF_ASM(b16)
|
|
||||||
DEF_ASM(b17)
|
|
||||||
DEF_ASM(b18)
|
|
||||||
DEF_ASM(b19)
|
|
||||||
DEF_ASM(b20)
|
|
||||||
DEF_ASM(b21)
|
|
||||||
DEF_ASM(b22)
|
|
||||||
DEF_ASM(b23)
|
|
||||||
DEF_ASM(b24)
|
|
||||||
DEF_ASM(b25)
|
|
||||||
DEF_ASM(b26)
|
|
||||||
DEF_ASM(b27)
|
|
||||||
DEF_ASM(b28)
|
|
||||||
DEF_ASM(b29)
|
|
||||||
DEF_ASM(b30)
|
|
||||||
DEF_ASM(b31)
|
|
||||||
|
|
||||||
/* Condition codes */
|
|
||||||
DEF_ASM(eq)
|
|
||||||
DEF_ASM(ne)
|
|
||||||
DEF_ASM(cs)
|
|
||||||
DEF_ASM(hs)
|
|
||||||
DEF_ASM(cc)
|
|
||||||
DEF_ASM(lo)
|
|
||||||
DEF_ASM(mi)
|
|
||||||
DEF_ASM(pl)
|
|
||||||
DEF_ASM(vs)
|
|
||||||
DEF_ASM(vc)
|
|
||||||
DEF_ASM(hi)
|
|
||||||
DEF_ASM(ls)
|
|
||||||
DEF_ASM(ge)
|
|
||||||
DEF_ASM(lt)
|
|
||||||
DEF_ASM(gt)
|
|
||||||
DEF_ASM(le)
|
|
||||||
DEF_ASM(al)
|
|
||||||
|
|
||||||
/* Data processing - arithmetic (no condition suffixes for ARM64) */
|
|
||||||
DEF_ASM(add)
|
|
||||||
DEF_ASM(adds)
|
|
||||||
DEF_ASM(sub)
|
|
||||||
DEF_ASM(subs)
|
|
||||||
DEF_ASM(cmn)
|
|
||||||
DEF_ASM(cmp)
|
|
||||||
DEF_ASM(neg)
|
|
||||||
DEF_ASM(negs)
|
|
||||||
DEF_ASM(adc)
|
|
||||||
DEF_ASM(adcs)
|
|
||||||
DEF_ASM(sbc)
|
|
||||||
DEF_ASM(sbcs)
|
|
||||||
DEF_ASM(ngc)
|
|
||||||
DEF_ASM(ngcs)
|
|
||||||
|
|
||||||
/* Data processing - bitwise */
|
|
||||||
DEF_ASM(and)
|
|
||||||
DEF_ASM(ands)
|
|
||||||
DEF_ASM(bic)
|
|
||||||
DEF_ASM(bics)
|
|
||||||
DEF_ASM(orr)
|
|
||||||
DEF_ASM(orn)
|
|
||||||
DEF_ASM(eor)
|
|
||||||
DEF_ASM(eon)
|
|
||||||
DEF_ASM(mvn)
|
|
||||||
DEF_ASM(mov)
|
|
||||||
|
|
||||||
/* Shifts */
|
|
||||||
DEF_ASM(lsl)
|
|
||||||
DEF_ASM(lsr)
|
|
||||||
DEF_ASM(asr)
|
|
||||||
DEF_ASM(ror)
|
|
||||||
|
|
||||||
/* Multiply/divide */
|
|
||||||
DEF_ASM(mul)
|
|
||||||
DEF_ASM(madd)
|
|
||||||
DEF_ASM(msub)
|
|
||||||
DEF_ASM(smaddl)
|
|
||||||
DEF_ASM(smsubl)
|
|
||||||
DEF_ASM(umaddl)
|
|
||||||
DEF_ASM(umsubl)
|
|
||||||
DEF_ASM(smulh)
|
|
||||||
DEF_ASM(umulh)
|
|
||||||
DEF_ASM(udiv)
|
|
||||||
DEF_ASM(sdiv)
|
|
||||||
|
|
||||||
/* Moves */
|
|
||||||
DEF_ASM(movz)
|
|
||||||
DEF_ASM(movn)
|
|
||||||
DEF_ASM(movk)
|
|
||||||
|
|
||||||
/* Compare/test */
|
|
||||||
DEF_ASM(tst)
|
|
||||||
DEF_ASM(teq)
|
|
||||||
|
|
||||||
/* Branch instructions */
|
|
||||||
DEF_ASM(b)
|
|
||||||
DEF_ASM(bl)
|
|
||||||
DEF_ASM(br)
|
|
||||||
DEF_ASM(blr)
|
|
||||||
DEF_ASM(ret)
|
|
||||||
DEF_ASM(cbz)
|
|
||||||
DEF_ASM(cbnz)
|
|
||||||
DEF_ASM(tbz)
|
|
||||||
DEF_ASM(tbnz)
|
|
||||||
|
|
||||||
/* Conditional branches */
|
|
||||||
DEF_ASM(beq)
|
|
||||||
DEF_ASM(bne)
|
|
||||||
DEF_ASM(bcs)
|
|
||||||
DEF_ASM(bhs)
|
|
||||||
DEF_ASM(bcc)
|
|
||||||
DEF_ASM(blo)
|
|
||||||
DEF_ASM(bmi)
|
|
||||||
DEF_ASM(bpl)
|
|
||||||
DEF_ASM(bvs)
|
|
||||||
DEF_ASM(bvc)
|
|
||||||
DEF_ASM(bhi)
|
|
||||||
DEF_ASM(bls)
|
|
||||||
DEF_ASM(bge)
|
|
||||||
DEF_ASM(blt)
|
|
||||||
DEF_ASM(bgt)
|
|
||||||
DEF_ASM(ble)
|
|
||||||
|
|
||||||
/* Conditional select */
|
|
||||||
DEF_ASM(csel)
|
|
||||||
DEF_ASM(csinc)
|
|
||||||
DEF_ASM(csinv)
|
|
||||||
DEF_ASM(csneg)
|
|
||||||
|
|
||||||
/* Load/Store */
|
|
||||||
DEF_ASM(ldr)
|
|
||||||
DEF_ASM(ldrb)
|
|
||||||
DEF_ASM(ldrh)
|
|
||||||
DEF_ASM(ldrsb)
|
|
||||||
DEF_ASM(ldrsh)
|
|
||||||
DEF_ASM(ldrsw)
|
|
||||||
DEF_ASM(str)
|
|
||||||
DEF_ASM(strb)
|
|
||||||
DEF_ASM(strh)
|
|
||||||
|
|
||||||
/* Load/Store - pair */
|
|
||||||
DEF_ASM(ldp)
|
|
||||||
DEF_ASM(stp)
|
|
||||||
DEF_ASM(ldpsw)
|
|
||||||
|
|
||||||
/* Address generation */
|
|
||||||
DEF_ASM(adr)
|
|
||||||
DEF_ASM(adrp)
|
|
||||||
|
|
||||||
/* System instructions */
|
|
||||||
DEF_ASM(mrs)
|
|
||||||
DEF_ASM(msr)
|
|
||||||
DEF_ASM(nop)
|
|
||||||
DEF_ASM(wfi)
|
|
||||||
DEF_ASM(wfe)
|
|
||||||
DEF_ASM(sev)
|
|
||||||
DEF_ASM(sevl)
|
|
||||||
DEF_ASM(isb)
|
|
||||||
DEF_ASM(dsb)
|
|
||||||
DEF_ASM(dmb)
|
|
||||||
|
|
||||||
/* Hints */
|
|
||||||
DEF_ASM(yield)
|
|
||||||
DEF_ASM(clrex)
|
|
||||||
|
|
||||||
/* Push/pop */
|
|
||||||
DEF_ASM(push)
|
|
||||||
DEF_ASM(pop)
|
|
||||||
|
|
||||||
/* Floating point */
|
|
||||||
DEF_ASM(fmov)
|
|
||||||
DEF_ASM(fadd)
|
|
||||||
DEF_ASM(fsub)
|
|
||||||
DEF_ASM(fmul)
|
|
||||||
DEF_ASM(fnmul)
|
|
||||||
DEF_ASM(fdiv)
|
|
||||||
DEF_ASM(fmax)
|
|
||||||
DEF_ASM(fmin)
|
|
||||||
DEF_ASM(fmaxnm)
|
|
||||||
DEF_ASM(fminnm)
|
|
||||||
DEF_ASM(fsqrt)
|
|
||||||
DEF_ASM(fabs)
|
|
||||||
DEF_ASM(fneg)
|
|
||||||
DEF_ASM(frintn)
|
|
||||||
DEF_ASM(frintp)
|
|
||||||
DEF_ASM(frintm)
|
|
||||||
DEF_ASM(frintz)
|
|
||||||
DEF_ASM(frinta)
|
|
||||||
DEF_ASM(frintx)
|
|
||||||
DEF_ASM(frinti)
|
|
||||||
DEF_ASM(fcmp)
|
|
||||||
DEF_ASM(fcmpe)
|
|
||||||
DEF_ASM(fccmp)
|
|
||||||
DEF_ASM(fccmpe)
|
|
||||||
DEF_ASM(fcvts)
|
|
||||||
DEF_ASM(fcvtd)
|
|
||||||
DEF_ASM(fcvth)
|
|
||||||
DEF_ASM(fcvtx)
|
|
||||||
DEF_ASM(scvtf)
|
|
||||||
DEF_ASM(ucvtf)
|
|
||||||
DEF_ASM(fcvtns)
|
|
||||||
DEF_ASM(fcvtnu)
|
|
||||||
DEF_ASM(fcvtps)
|
|
||||||
DEF_ASM(fcvtpu)
|
|
||||||
|
|
||||||
/* SIMD instructions */
|
|
||||||
DEF_ASM(addv)
|
|
||||||
DEF_ASM(faddp)
|
|
||||||
DEF_ASM(fmaxp)
|
|
||||||
DEF_ASM(fminp)
|
|
||||||
DEF_ASM(fmaxnmp)
|
|
||||||
DEF_ASM(fminnmp)
|
|
||||||
DEF_ASM(addp)
|
|
||||||
DEF_ASM(bif)
|
|
||||||
DEF_ASM(bit)
|
|
||||||
DEF_ASM(bsl)
|
|
||||||
DEF_ASM(dup)
|
|
||||||
DEF_ASM(ext)
|
|
||||||
DEF_ASM(ins)
|
|
||||||
DEF_ASM(movi)
|
|
||||||
DEF_ASM(mvni)
|
|
||||||
DEF_ASM(not)
|
|
||||||
DEF_ASM(shl)
|
|
||||||
DEF_ASM(shll)
|
|
||||||
DEF_ASM(shll2)
|
|
||||||
DEF_ASM(sli)
|
|
||||||
DEF_ASM(sri)
|
|
||||||
DEF_ASM(sqshl)
|
|
||||||
DEF_ASM(sqshlu)
|
|
||||||
DEF_ASM(srshl)
|
|
||||||
DEF_ASM(sshll)
|
|
||||||
DEF_ASM(sshll2)
|
|
||||||
DEF_ASM(sshr)
|
|
||||||
DEF_ASM(ushll)
|
|
||||||
DEF_ASM(ushll2)
|
|
||||||
DEF_ASM(ushr)
|
|
||||||
|
|
||||||
/* Misc */
|
|
||||||
DEF_ASM(bfm)
|
|
||||||
DEF_ASM(sbfm)
|
|
||||||
DEF_ASM(ubfm)
|
|
||||||
DEF_ASM(extr)
|
|
||||||
DEF_ASM(crc32b)
|
|
||||||
DEF_ASM(crc32h)
|
|
||||||
DEF_ASM(crc32w)
|
|
||||||
DEF_ASM(crc32x)
|
|
||||||
DEF_ASM(crc32cb)
|
|
||||||
DEF_ASM(crc32ch)
|
|
||||||
DEF_ASM(crc32cw)
|
|
||||||
DEF_ASM(crc32cx)
|
|
||||||
DEF_ASM(rev)
|
|
||||||
DEF_ASM(rev16)
|
|
||||||
DEF_ASM(rev32)
|
|
||||||
DEF_ASM(rev64)
|
|
||||||
DEF_ASM(clz)
|
|
||||||
DEF_ASM(cls)
|
|
||||||
DEF_ASM(rbit)
|
|
||||||
|
|
||||||
/* Exception generating */
|
|
||||||
DEF_ASM(svc)
|
|
||||||
DEF_ASM(hvc)
|
|
||||||
DEF_ASM(smc)
|
|
||||||
DEF_ASM(brk)
|
|
||||||
DEF_ASM(hlt)
|
|
||||||
DEF_ASM(dcps1)
|
|
||||||
DEF_ASM(dcps2)
|
|
||||||
DEF_ASM(dcps3)
|
|
||||||
|
|
||||||
/* Conditional branches */
|
|
||||||
DEF_ASM(b_eq)
|
|
||||||
DEF_ASM(b_ne)
|
|
||||||
DEF_ASM(b_cs)
|
|
||||||
DEF_ASM(b_cc)
|
|
||||||
DEF_ASM(b_mi)
|
|
||||||
DEF_ASM(b_pl)
|
|
||||||
DEF_ASM(b_vs)
|
|
||||||
DEF_ASM(b_vc)
|
|
||||||
DEF_ASM(b_hi)
|
|
||||||
DEF_ASM(b_ls)
|
|
||||||
DEF_ASM(b_ge)
|
|
||||||
DEF_ASM(b_lt)
|
|
||||||
DEF_ASM(b_gt)
|
|
||||||
DEF_ASM(b_le)
|
|
||||||
|
|
||||||
/* LD/ST exclusive */
|
|
||||||
DEF_ASM(ldxr)
|
|
||||||
DEF_ASM(ldxrb)
|
|
||||||
DEF_ASM(ldxrh)
|
|
||||||
DEF_ASM(stxr)
|
|
||||||
DEF_ASM(stxrb)
|
|
||||||
DEF_ASM(stxrh)
|
|
||||||
DEF_ASM(ldaxr)
|
|
||||||
DEF_ASM(ldaxrb)
|
|
||||||
DEF_ASM(ldaxrh)
|
|
||||||
DEF_ASM(stlxr)
|
|
||||||
DEF_ASM(stlxrb)
|
|
||||||
DEF_ASM(stlxrh)
|
|
||||||
|
|
||||||
/* LD/ST acquire-release */
|
|
||||||
DEF_ASM(ldar)
|
|
||||||
DEF_ASM(ldarb)
|
|
||||||
DEF_ASM(ldarh)
|
|
||||||
DEF_ASM(stlr)
|
|
||||||
DEF_ASM(stlrb)
|
|
||||||
DEF_ASM(stlrh)
|
|
||||||
DEF_ASM(ldalr)
|
|
||||||
DEF_ASM(ldalrb)
|
|
||||||
DEF_ASM(ldalrh)
|
|
||||||
DEF_ASM(stllr)
|
|
||||||
DEF_ASM(stllrb)
|
|
||||||
DEF_ASM(stllrh)
|
|
||||||
|
|
||||||
/* LD/ST unscaled immediate */
|
|
||||||
DEF_ASM(ldur)
|
|
||||||
DEF_ASM(ldurb)
|
|
||||||
DEF_ASM(ldurh)
|
|
||||||
DEF_ASM(ldursb)
|
|
||||||
DEF_ASM(ldursh)
|
|
||||||
DEF_ASM(ldursw)
|
|
||||||
DEF_ASM(stur)
|
|
||||||
DEF_ASM(sturb)
|
|
||||||
DEF_ASM(sturh)
|
|
||||||
|
|
||||||
/* Vector load/store */
|
|
||||||
DEF_ASM(ld1)
|
|
||||||
DEF_ASM(st1)
|
|
||||||
DEF_ASM(ld2)
|
|
||||||
DEF_ASM(st2)
|
|
||||||
DEF_ASM(ld3)
|
|
||||||
DEF_ASM(st3)
|
|
||||||
DEF_ASM(ld4)
|
|
||||||
DEF_ASM(st4)
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------ */
|
|
||||||
/* ARM64 instruction opcode constants and encoding helpers */
|
|
||||||
/* ------------------------------------------------------------------ */
|
|
||||||
|
|
||||||
/* Data processing - immediate */
|
|
||||||
#define ARM64_ADD_IMM 0x11000000U
|
|
||||||
#define ARM64_ADDS_IMM 0x2B000000U
|
|
||||||
#define ARM64_SUB_IMM 0x51000000U
|
|
||||||
#define ARM64_SUBS_IMM 0x6B000000U
|
|
||||||
|
|
||||||
/* Data processing - register */
|
|
||||||
#define ARM64_ADD_REG 0x0B000000U
|
|
||||||
#define ARM64_ADDS_REG 0x2B000000U
|
|
||||||
#define ARM64_SUB_REG 0x4B000000U
|
|
||||||
#define ARM64_SUBS_REG 0x6B000000U
|
|
||||||
#define ARM64_AND_REG 0x0A000000U
|
|
||||||
#define ARM64_ANDS_REG 0x6A000000U
|
|
||||||
#define ARM64_ORR_REG 0x2A000000U
|
|
||||||
#define ARM64_EOR_REG 0x4A000000U
|
|
||||||
#define ARM64_MUL_REG 0x1B000000U /* Base opcode, Rm/Rn/Rd must be filled in */
|
|
||||||
|
|
||||||
/* Move wide immediate */
|
|
||||||
#define ARM64_MOVZ 0x52800000U
|
|
||||||
#define ARM64_MOVN 0x12800000U
|
|
||||||
#define ARM64_MOVK 0xF2800000U
|
|
||||||
/* ARM64_MOVI_W/X removed: MOVI is a SIMD&FP instruction, not general-purpose */
|
|
||||||
/* Use MOVZ/MOVN/MOVK for general-purpose, or SIMD MOVI variants (0x0F000400, etc.) */
|
|
||||||
|
|
||||||
/* MOVZ/MOVN 64-bit base opcodes */
|
|
||||||
#define ARM64_MOVZ64 0xD2800000U /* MOVZ (64-bit), use with ARM64_HW() */
|
|
||||||
#define ARM64_MOVN64 0x92800000U /* MOVN (64-bit), use with ARM64_HW() */
|
|
||||||
|
|
||||||
/* Move wide immediate shift field (LSL #0/16/32/48 encoded as hw*16) */
|
|
||||||
#define ARM64_HW(v) (((uint32_t)(v) & 3) << 21)
|
|
||||||
|
|
||||||
/* Load/store register (unsigned immediate) */
|
|
||||||
#define ARM64_LDR_X 0xF9400000U
|
|
||||||
#define ARM64_LDR_W 0xB9400000U
|
|
||||||
#define ARM64_LDR_B 0x39400000U
|
|
||||||
#define ARM64_LDR_H 0x79400000U
|
|
||||||
#define ARM64_LDR_D 0xFD400000U
|
|
||||||
#define ARM64_LDR_S 0xBD400000U
|
|
||||||
#define ARM64_STR_X 0xF9000000U
|
|
||||||
#define ARM64_STR_W 0xB9000000U
|
|
||||||
#define ARM64_STR_B 0x39000000U
|
|
||||||
#define ARM64_STR_H 0x79000000U
|
|
||||||
#define ARM64_STR_D 0xFD000000U
|
|
||||||
#define ARM64_STR_S 0xBD000000U
|
|
||||||
|
|
||||||
/* Load/store register (unscaled immediate) */
|
|
||||||
#define ARM64_LDUR_X 0xF8400000U
|
|
||||||
#define ARM64_LDUR_W 0xB8400000U
|
|
||||||
#define ARM64_LDUR_B 0x38400000U
|
|
||||||
#define ARM64_LDUR_H 0x78400000U
|
|
||||||
#define ARM64_STUR_X 0xF8000000U
|
|
||||||
#define ARM64_STUR_W 0xB8000000U
|
|
||||||
#define ARM64_STUR_B 0x38000000U
|
|
||||||
#define ARM64_STUR_H 0x78000000U
|
|
||||||
|
|
||||||
/* Load/store register (register offset) */
|
|
||||||
#define ARM64_LDR_X_REG 0xF8606800U
|
|
||||||
#define ARM64_LDR_W_REG 0xB8606800U
|
|
||||||
#define ARM64_LDR_B_REG 0x38606800U
|
|
||||||
#define ARM64_LDR_H_REG 0x78606800U
|
|
||||||
#define ARM64_STR_X_REG 0xF8206800U
|
|
||||||
#define ARM64_STR_W_REG 0xB8206800U
|
|
||||||
#define ARM64_STR_B_REG 0x38206800U
|
|
||||||
#define ARM64_STR_H_REG 0x78206800U
|
|
||||||
|
|
||||||
/* Load/store (pre/post-indexed) */
|
|
||||||
#define ARM64_STR_X_PRE 0xF8000000U /* STR X pre-indexed base */
|
|
||||||
#define ARM64_LDR_X_POST 0xF8400000U /* LDR X post-indexed base */
|
|
||||||
|
|
||||||
/* SIMD load/store (unsigned immediate) */
|
|
||||||
#define ARM64_LDR_SCALAR 0x3D400000U /* Base for scalar load (size built dynamically) */
|
|
||||||
#define ARM64_LDR_S_VEC 0xBD400000U
|
|
||||||
#define ARM64_LDR_D_VEC 0xFD400000U
|
|
||||||
#define ARM64_LDR_Q_VEC 0x3DC00000U
|
|
||||||
#define ARM64_STR_SCALAR 0x3D000000U /* Base for scalar store (size built dynamically) */
|
|
||||||
#define ARM64_STR_S_VEC 0xBD000000U
|
|
||||||
#define ARM64_STR_D_VEC 0xFD000000U
|
|
||||||
#define ARM64_STR_Q_VEC 0x3D800000U
|
|
||||||
|
|
||||||
/* SIMD load/store (unscaled immediate) */
|
|
||||||
#define ARM64_LDUR_S_SIMD 0xBC400000U
|
|
||||||
#define ARM64_LDUR_D_SIMD 0xFC400000U
|
|
||||||
#define ARM64_LDUR_Q_SIMD 0x3C400000U
|
|
||||||
#define ARM64_STUR_S_SIMD 0xBC000000U
|
|
||||||
#define ARM64_STUR_D_SIMD 0xFC000000U
|
|
||||||
#define ARM64_STUR_Q_SIMD 0x3C000000U
|
|
||||||
|
|
||||||
/* SIMD load/store (register offset) */
|
|
||||||
#define ARM64_LDR_S_REG 0xBC606800U
|
|
||||||
#define ARM64_LDR_D_REG 0xFC606800U
|
|
||||||
#define ARM64_LDR_Q_REG 0x3C606800U
|
|
||||||
#define ARM64_STR_S_REG 0xBC206800U
|
|
||||||
#define ARM64_STR_D_REG 0xFC206800U
|
|
||||||
#define ARM64_STR_Q_REG 0x3C206800U
|
|
||||||
|
|
||||||
/* Load/store pair */
|
|
||||||
#define ARM64_LDP_X 0xA9400000U
|
|
||||||
#define ARM64_LDP_X_PRE 0xA9C00000U
|
|
||||||
#define ARM64_LDP_X_POST 0xA8C00000U
|
|
||||||
#define ARM64_STP_X 0xA9000000U
|
|
||||||
#define ARM64_STP_X_PRE 0xA9800000U
|
|
||||||
#define ARM64_STP_X_POST 0xA8800000U
|
|
||||||
#define ARM64_LDP_D 0x6D400000U
|
|
||||||
#define ARM64_LDP_D_PRE 0x6DC00000U
|
|
||||||
#define ARM64_LDP_D_POST 0x6CC00000U
|
|
||||||
#define ARM64_STP_D 0x6D000000U
|
|
||||||
#define ARM64_STP_D_PRE 0x6D800000U
|
|
||||||
#define ARM64_STP_D_POST 0x6C800000U
|
|
||||||
|
|
||||||
/* Branch instructions */
|
|
||||||
#define ARM64_B 0x14000000U
|
|
||||||
#define ARM64_BL 0x94000000U
|
|
||||||
#define ARM64_BR 0xD61F0000U
|
|
||||||
#define ARM64_BLR 0xD63F0000U
|
|
||||||
#define ARM64_RET 0xD65F0000U
|
|
||||||
|
|
||||||
/* Conditional branch */
|
|
||||||
#define ARM64_B_COND 0x54000000U
|
|
||||||
|
|
||||||
/* Compare and branch */
|
|
||||||
#define ARM64_CBZ 0x34000000U
|
|
||||||
#define ARM64_CBNZ 0x35000000U
|
|
||||||
|
|
||||||
/* System instructions */
|
|
||||||
#define ARM64_NOP 0xD503201FU
|
|
||||||
#define ARM64_ISB 0xD50330DFU
|
|
||||||
#define ARM64_DSB 0xD503309FU
|
|
||||||
#define ARM64_DMB 0xD50330BFU
|
|
||||||
#define ARM64_MRS 0xD5380000U
|
|
||||||
#define ARM64_MSR 0xD5180000U
|
|
||||||
#define ARM64_MRS_FPCR 0xD53B4400U
|
|
||||||
#define ARM64_MRS_FPSR 0xD53B4420U
|
|
||||||
#define ARM64_MSR_FPCR 0xD51B4400U
|
|
||||||
#define ARM64_MSR_FPSR 0xD51B4420U
|
|
||||||
|
|
||||||
/* Shifts (register) */
|
|
||||||
#define ARM64_LSL_REG 0x1AC02000U
|
|
||||||
#define ARM64_LSR_REG 0x1AC02400U
|
|
||||||
#define ARM64_ASR_REG 0x1AC02800U
|
|
||||||
#define ARM64_ROR_REG 0x1AC02C00U
|
|
||||||
|
|
||||||
/* Shifts (immediate - UBFM/SBFM) */
|
|
||||||
#define ARM64_LSL_IMM 0xD3400000U
|
|
||||||
#define ARM64_LSR_IMM 0xD3400000U
|
|
||||||
#define ARM64_LSR_IMM_32 0x53000000U /* 32-bit LSR base */
|
|
||||||
#define ARM64_ASR_IMM 0x93400000U
|
|
||||||
|
|
||||||
/* Shifted register encoding for ORR/AND/EOR */
|
|
||||||
#define ARM64_SHIFT_LSL(imm) (((uint32_t)(imm) & 63) << 10)
|
|
||||||
#define ARM64_SHIFT_LSR(imm) (0x00200000U | (((uint32_t)(imm) & 63) << 10))
|
|
||||||
#define ARM64_SHIFT_ASR(imm) (0x00400000U | (((uint32_t)(imm) & 63) << 10))
|
|
||||||
#define ARM64_SHIFT_ROR(imm) (0x00600000U | (((uint32_t)(imm) & 63) << 10))
|
|
||||||
|
|
||||||
/* UBFM/SBFM immediate fields (for LSL/LSR/ASR immediate aliases) */
|
|
||||||
#define ARM64_IMM_R(r) (((uint32_t)(r) & 0x3F) << 16)
|
|
||||||
#define ARM64_IMM_S(s) (((uint32_t)(s) & 0x3F) << 10)
|
|
||||||
|
|
||||||
/* Extended register encoding */
|
|
||||||
#define ARM64_EXTEND_LSL(lsl) (((uint32_t)(lsl) & 7) << 10)
|
|
||||||
|
|
||||||
/* MOV (register) - ORR with zero register */
|
|
||||||
#define ARM64_MOV_REG 0x2A0003E0U
|
|
||||||
|
|
||||||
/* Address generation */
|
|
||||||
#define ARM64_ADRP 0x90000000U
|
|
||||||
#define ARM64_ADR 0x10000000U
|
|
||||||
|
|
||||||
/* Logical immediate */
|
|
||||||
#define ARM64_AND_IMM 0x12000000U
|
|
||||||
#define ARM64_ORR_IMM_BASE 0x32000000U
|
|
||||||
#define ARM64_EOR_IMM 0x52000000U
|
|
||||||
#define ARM64_ANDS_IMM 0x72000000U
|
|
||||||
#define ARM64_ORR_IMM 0x320003E0U /* ORR immediate alias with Rn = XZR/WZR */
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------ */
|
|
||||||
/* ARM64 instruction encoding helper macros */
|
|
||||||
/* ------------------------------------------------------------------ */
|
|
||||||
|
|
||||||
/* Register field encodings */
|
|
||||||
#define ARM64_RD(r) ((uint32_t)(r) & 0x1FU)
|
|
||||||
#define ARM64_RN(r) (((uint32_t)(r) & 0x1FU) << 5)
|
|
||||||
#define ARM64_RM(r) (((uint32_t)(r) & 0x1FU) << 16)
|
|
||||||
#define ARM64_RT(r) ((uint32_t)(r) & 0x1FU)
|
|
||||||
#define ARM64_RT2(r) (((uint32_t)(r) & 0x1FU) << 10)
|
|
||||||
|
|
||||||
/* Immediate field encodings */
|
|
||||||
#define ARM64_IMM12(v) (((uint32_t)(v) & 0xFFFU) << 10)
|
|
||||||
#define ARM64_IMM7(v) (((uint32_t)(v) & 0x7FU) << 15)
|
|
||||||
#define ARM64_IMM14(v) (((uint32_t)(v) & 0x3FFFU) << 5)
|
|
||||||
#define ARM64_IMM16(v) (((uint32_t)(v) & 0xFFFFU) << 5)
|
|
||||||
#define ARM64_IMM_HW(v, hw) (((uint32_t)(v) & 0xFFFFU) << 5 | (((hw) & 3) << 21))
|
|
||||||
|
|
||||||
/* Shift and size encodings */
|
|
||||||
#define ARM64_SIZE(s) (((uint32_t)(s) & 3) << 30)
|
|
||||||
#define ARM64_SF(s) (((uint32_t)(s) & 1) << 31)
|
|
||||||
#define ARM64_S(v) (((uint32_t)(v) & 1) << 29)
|
|
||||||
#define ARM64_N(v) (((uint32_t)(v) & 1) << 22)
|
|
||||||
#define ARM64_SH(v) (((uint32_t)(v) & 1) << 22)
|
|
||||||
|
|
||||||
/* Condition code encoding */
|
|
||||||
#define ARM64_COND(c) ((uint32_t)(c) & 0xFU)
|
|
||||||
|
|
||||||
/* Branch offset encoding */
|
|
||||||
#define ARM64_OFFSET26(v) (((uint32_t)(v) >> 2) & 0x3FFFFFFU)
|
|
||||||
#define ARM64_OFFSET19(v) (((uint32_t)(v) >> 2) & 0x7FFFFU)
|
|
||||||
#define ARM64_OFFSET14(v) (((uint32_t)(v) >> 2) & 0x3FFFU)
|
|
||||||
|
|
||||||
/* Special register field (for MRS/MSR) */
|
|
||||||
#undef ARM64_SYSREG
|
|
||||||
#define ARM64_SYSREG(op0, op1, crn, crm, op2) \
|
|
||||||
((((op0) & 3) << 19) | (((op1) & 7) << 16) | \
|
|
||||||
(((crn) & 15) << 12) | (((crm) & 15) << 8) | (((op2) & 7) << 5))
|
|
||||||
|
|
||||||
/* Barrier option encoding */
|
|
||||||
#define ARM64_ISB_OPTION(opt) (((uint32_t)(opt) & 0xFU) << 8)
|
|
||||||
#define ARM64_DSB_OPTION(opt) (((uint32_t)(opt) & 0xFU) << 8)
|
|
||||||
#define ARM64_DMB_OPTION(opt) (((uint32_t)(opt) & 0xFU) << 8)
|
|
||||||
|
|
||||||
/* Additional opcodes for code generator - VERIFIED */
|
|
||||||
/* Note: Many of these are specific instances, not general templates */
|
|
||||||
|
|
||||||
/* Floating-point move - VERIFIED */
|
|
||||||
#define ARM64_FMOV_D_S 0x1E604000U /* FMOV Dd,Dn (scalar) */
|
|
||||||
#define ARM64_FMOV_X_D 0x9E660000U /* FMOV Xd,Dn (general to FP) */
|
|
||||||
#define ARM64_FMOV_W_S 0x1E260000U /* FMOV Wd,Sn (general to FP) */
|
|
||||||
/* ARM64_FMOV_S_D removed: 0x4EA01C00 is SIMD vector, not scalar FMOV */
|
|
||||||
/* Use 0x1E204000 for FMOV Sd,Sn or 0x1E604000 variant for cross-size */
|
|
||||||
|
|
||||||
/* FMOV variants for code generator */
|
|
||||||
#define ARM64_FMOV_SCALAR 0x1E604000U /* FMOV Dd, Dn (scalar FP) */
|
|
||||||
#define ARM64_FMOV_XD 0x9E660000U /* FMOV Xd, Dn (FP to GP 64-bit) */
|
|
||||||
#define ARM64_FMOV_WS 0x1E260000U /* FMOV Wd, Sn (FP to GP 32-bit) */
|
|
||||||
|
|
||||||
/* MOV vector (ORR vector register alias) */
|
|
||||||
#define ARM64_MOV_V16B 0x4EA01C00U /* MOV Vd.16B, Vn.16B (ORR vector, Rm=Rn alias) */
|
|
||||||
|
|
||||||
/* Load/Store SIMD&FP - Base opcodes (register fields must be filled in) */
|
|
||||||
#define ARM64_STR_Q_PRE 0x3C800000U /* STR Q pre-index base */
|
|
||||||
#define ARM64_LDR_Q_POST 0x3CC00000U /* LDR Q post-index base */
|
|
||||||
|
|
||||||
/* LDPSW - Base opcode (register fields must be filled in) */
|
|
||||||
/* Use gen_ldst_pair() with appropriate mode for LDPSW */
|
|
||||||
/* Base encodings: 0x68C00000 (post), 0x69400000 (offset), 0x69C00000 (pre) */
|
|
||||||
|
|
||||||
/* ARM64_LDR_S_SIMD removed: 0x0D00801C is not a standard encoding */
|
|
||||||
/* Use ARM64_LDR_S (0xBD400000) for scalar S or ARM64_LDR_S_VEC for SIMD */
|
|
||||||
|
|
||||||
/* MOV between SIMD and general - Use UMOV/SMOV instead */
|
|
||||||
/* ARM64_MOV_V_D removed: 0x4E083C00 is UMOV/SMOV encoding */
|
|
||||||
/* Use appropriate UMOV/SMOV base: 0x0E002C00/0x0E003C00 (32-bit) */
|
|
||||||
/* or 0x4E002C00/0x4E003C00 (64-bit) */
|
|
||||||
|
|
||||||
/* Verified from previous section */
|
|
||||||
#define ARM64_FCMP 0x1E202008U /* FCMP with zero */
|
|
||||||
#define ARM64_SDIV 0x1AC00C00U /* SDIV (32-bit) */
|
|
||||||
|
|
||||||
/* EXTR (Extract) */
|
|
||||||
#define ARM64_EXTR 0x13800000U /* EXTR Wd, Wn, Wm, #imm (32-bit) */
|
|
||||||
#define ARM64_EXTR64 0x93C00000U /* EXTR Xd, Xn, Xm, #imm (64-bit) */
|
|
||||||
|
|
||||||
/* ARM64_MUL removed - use ARM64_MUL_REG with gen_dp_reg() */
|
|
||||||
|
|
||||||
/* ORR shifted - Base opcodes (register fields must be filled in) */
|
|
||||||
#define ARM64_ORR_REG_LSL 0x2A000000U /* ORR (shifted register) base */
|
|
||||||
/* ARM64_ORR_REG_LSL32 removed: use ARM64_ORR_REG_LSL with SF=1 */
|
|
||||||
/* ARM64_ORR_REG_MOV is duplicate of ARM64_MOV_REG */
|
|
||||||
|
|
||||||
/* LSR immediate - These are UBFM encodings, use gen_shift() instead */
|
|
||||||
/* Base UBFM encodings: 0x53000000 (W), 0xD3400000 (X) */
|
|
||||||
/* gen_shift() handles immr/imms encoding for LSR/LSL/ASR */
|
|
||||||
/* ARM64_LSR_W_8, ARM64_LSR_X_8, ARM64_LSR_X_16, ARM64_LSR_X_24 removed */
|
|
||||||
/* They are specific instances, not templates */
|
|
||||||
|
|
||||||
/* SUB shifted - Base opcode (use gen_sub_reg or asm handler) */
|
|
||||||
#define ARM64_SUB_REG_LSL 0xCB000000U /* SUB (shifted register) base */
|
|
||||||
|
|
||||||
/* Duplicates removed: ARM64_LDP_X, ARM64_B, ARM64_BL, ARM64_BR, ARM64_NOP */
|
|
||||||
/* These are already defined in their respective sections above */
|
|
||||||
542
asmtest.S
Normal file
542
asmtest.S
Normal file
@ -0,0 +1,542 @@
|
|||||||
|
|
||||||
|
/* some directive tests */
|
||||||
|
|
||||||
|
.byte 0xff
|
||||||
|
.byte 1, 2, 3
|
||||||
|
.short 1, 2, 3
|
||||||
|
.word 1, 2, 3
|
||||||
|
.long 1, 2, 3
|
||||||
|
.int 1, 2, 3
|
||||||
|
.align 8
|
||||||
|
.byte 1
|
||||||
|
.align 16, 0x90
|
||||||
|
.skip 3
|
||||||
|
.skip 15, 0x90
|
||||||
|
.string "hello\0world"
|
||||||
|
|
||||||
|
/* some label tests */
|
||||||
|
|
||||||
|
movl %eax, %ebx
|
||||||
|
L1:
|
||||||
|
movl %eax, %ebx
|
||||||
|
mov 0x10000, %eax
|
||||||
|
L2:
|
||||||
|
movl $L2 - L1, %ecx
|
||||||
|
var1:
|
||||||
|
nop ; nop ; nop ; nop
|
||||||
|
|
||||||
|
mov var1, %eax
|
||||||
|
|
||||||
|
/* instruction tests */
|
||||||
|
movl %eax, %ebx
|
||||||
|
mov 0x10000, %eax
|
||||||
|
mov 0x10000, %ax
|
||||||
|
mov 0x10000, %al
|
||||||
|
mov %al, 0x10000
|
||||||
|
|
||||||
|
mov $1, %edx
|
||||||
|
mov $1, %dx
|
||||||
|
mov $1, %dl
|
||||||
|
movb $2, 0x100(%ebx,%edx,2)
|
||||||
|
movw $2, 0x100(%ebx,%edx,2)
|
||||||
|
movl $2, 0x100(%ebx,%edx,2)
|
||||||
|
movl %eax, 0x100(%ebx,%edx,2)
|
||||||
|
movl 0x100(%ebx,%edx,2), %edx
|
||||||
|
movw %ax, 0x100(%ebx,%edx,2)
|
||||||
|
|
||||||
|
mov %cr3, %edx
|
||||||
|
mov %ecx, %cr3
|
||||||
|
movl %cr3, %eax
|
||||||
|
movl %tr3, %eax
|
||||||
|
movl %db3, %ebx
|
||||||
|
movl %dr6, %eax
|
||||||
|
movl %fs, %ecx
|
||||||
|
movl %ebx, %fs
|
||||||
|
|
||||||
|
movsbl 0x1000, %eax
|
||||||
|
movsbw 0x1000, %ax
|
||||||
|
movswl 0x1000, %eax
|
||||||
|
|
||||||
|
movzbl 0x1000, %eax
|
||||||
|
movzbw 0x1000, %ax
|
||||||
|
movzwl 0x1000, %eax
|
||||||
|
|
||||||
|
movzb 0x1000, %eax
|
||||||
|
movzb 0x1000, %ax
|
||||||
|
|
||||||
|
|
||||||
|
pushl %eax
|
||||||
|
pushw %ax
|
||||||
|
push %eax
|
||||||
|
push %cs
|
||||||
|
push %gs
|
||||||
|
push $1
|
||||||
|
push $100
|
||||||
|
|
||||||
|
popl %eax
|
||||||
|
popw %ax
|
||||||
|
pop %eax
|
||||||
|
pop %ds
|
||||||
|
pop %fs
|
||||||
|
|
||||||
|
xchg %eax, %ecx
|
||||||
|
xchg %edx, %eax
|
||||||
|
xchg %bx, 0x10000
|
||||||
|
xchg 0x10000, %ebx
|
||||||
|
xchg 0x10000, %dl
|
||||||
|
|
||||||
|
in $100, %al
|
||||||
|
in $100, %ax
|
||||||
|
in $100, %eax
|
||||||
|
in %dx, %al
|
||||||
|
in %dx, %ax
|
||||||
|
in %dx, %eax
|
||||||
|
inb %dx
|
||||||
|
inw %dx
|
||||||
|
inl %dx
|
||||||
|
|
||||||
|
out %al, $100
|
||||||
|
out %ax, $100
|
||||||
|
out %eax, $100
|
||||||
|
|
||||||
|
/* NOTE: gas is bugged here, so size must be added */
|
||||||
|
outb %al, %dx
|
||||||
|
outw %ax, %dx
|
||||||
|
outl %eax, %dx
|
||||||
|
|
||||||
|
leal 0x1000(%ebx), %ecx
|
||||||
|
lea 0x1000(%ebx), %ecx
|
||||||
|
|
||||||
|
les 0x2000, %eax
|
||||||
|
lds 0x2000, %ebx
|
||||||
|
lfs 0x2000, %ecx
|
||||||
|
lgs 0x2000, %edx
|
||||||
|
lss 0x2000, %edx
|
||||||
|
|
||||||
|
addl $0x123, %eax
|
||||||
|
add $0x123, %ebx
|
||||||
|
addl $0x123, 0x100
|
||||||
|
addl $0x123, 0x100(%ebx)
|
||||||
|
addl $0x123, 0x100(%ebx,%edx,2)
|
||||||
|
addl $0x123, 0x100(%esp)
|
||||||
|
addl $0x123, (%ebp)
|
||||||
|
addl $0x123, (%esp)
|
||||||
|
cmpl $0x123, (%esp)
|
||||||
|
|
||||||
|
add %eax, (%ebx)
|
||||||
|
add (%ebx), %eax
|
||||||
|
|
||||||
|
or %dx, (%ebx)
|
||||||
|
or (%ebx), %si
|
||||||
|
|
||||||
|
add %cl, (%ebx)
|
||||||
|
add (%ebx), %dl
|
||||||
|
|
||||||
|
inc %edx
|
||||||
|
incl 0x10000
|
||||||
|
incb 0x10000
|
||||||
|
dec %dx
|
||||||
|
|
||||||
|
test $1, %al
|
||||||
|
test $1, %cl
|
||||||
|
|
||||||
|
testl $1, 0x1000
|
||||||
|
testb $1, 0x1000
|
||||||
|
testw $1, 0x1000
|
||||||
|
test %eax, %ebx
|
||||||
|
test %eax, 0x1000
|
||||||
|
test 0x1000, %edx
|
||||||
|
|
||||||
|
not %edx
|
||||||
|
notw 0x10000
|
||||||
|
notl 0x10000
|
||||||
|
notb 0x10000
|
||||||
|
|
||||||
|
neg %edx
|
||||||
|
negw 0x10000
|
||||||
|
negl 0x10000
|
||||||
|
negb 0x10000
|
||||||
|
|
||||||
|
imul %ecx
|
||||||
|
mul %edx
|
||||||
|
mulb %cl
|
||||||
|
|
||||||
|
imul %eax, %ecx
|
||||||
|
imul 0x1000, %cx
|
||||||
|
imul $10, %eax, %ecx
|
||||||
|
imul $10, %ax, %cx
|
||||||
|
imul $10, %eax
|
||||||
|
imul $0x1100000, %eax
|
||||||
|
imul $1, %eax
|
||||||
|
|
||||||
|
idivw 0x1000
|
||||||
|
div %ecx
|
||||||
|
div %bl
|
||||||
|
div %ecx, %eax
|
||||||
|
|
||||||
|
|
||||||
|
shl %edx
|
||||||
|
shl $10, %edx
|
||||||
|
shl %cl, %edx
|
||||||
|
|
||||||
|
shld $1, %eax, %edx
|
||||||
|
shld %cl, %eax, %edx
|
||||||
|
shld %eax, %edx
|
||||||
|
|
||||||
|
shrd $1, %eax, %edx
|
||||||
|
shrd %cl, %eax, %edx
|
||||||
|
shrd %eax, %edx
|
||||||
|
|
||||||
|
L4:
|
||||||
|
call 0x1000
|
||||||
|
call L4
|
||||||
|
call *%eax
|
||||||
|
call *0x1000
|
||||||
|
call func1
|
||||||
|
|
||||||
|
lcall $0x100, $0x1000
|
||||||
|
|
||||||
|
jmp 0x1000
|
||||||
|
jmp *%eax
|
||||||
|
jmp *0x1000
|
||||||
|
|
||||||
|
ljmp $0x100, $0x1000
|
||||||
|
|
||||||
|
ret
|
||||||
|
|
||||||
|
ret $10
|
||||||
|
|
||||||
|
lret
|
||||||
|
|
||||||
|
lret $10
|
||||||
|
|
||||||
|
enter $1234, $10
|
||||||
|
|
||||||
|
L3:
|
||||||
|
jo 0x1000
|
||||||
|
jnp 0x1001
|
||||||
|
jne 0x1002
|
||||||
|
jg 0x1003
|
||||||
|
|
||||||
|
jo L3
|
||||||
|
jnp L3
|
||||||
|
jne L3
|
||||||
|
jg L3
|
||||||
|
|
||||||
|
loopne L3
|
||||||
|
loopnz L3
|
||||||
|
loope L3
|
||||||
|
loopz L3
|
||||||
|
loop L3
|
||||||
|
jecxz L3
|
||||||
|
|
||||||
|
|
||||||
|
seto %al
|
||||||
|
setnp 0x1000
|
||||||
|
setl 0xaaaa
|
||||||
|
setg %dl
|
||||||
|
|
||||||
|
fadd
|
||||||
|
fadd %st(1), %st
|
||||||
|
fadd %st(3)
|
||||||
|
|
||||||
|
faddp %st(5)
|
||||||
|
faddp
|
||||||
|
faddp %st(1), %st
|
||||||
|
|
||||||
|
fadds 0x1000
|
||||||
|
fiadds 0x1002
|
||||||
|
faddl 0x1004
|
||||||
|
fiaddl 0x1006
|
||||||
|
|
||||||
|
fmul
|
||||||
|
fmul %st(1), %st
|
||||||
|
fmul %st(3)
|
||||||
|
|
||||||
|
fmulp %st(5)
|
||||||
|
fmulp
|
||||||
|
fmulp %st(1), %st
|
||||||
|
|
||||||
|
fmuls 0x1000
|
||||||
|
fimuls 0x1002
|
||||||
|
fmull 0x1004
|
||||||
|
fimull 0x1006
|
||||||
|
|
||||||
|
fsub
|
||||||
|
fsub %st(1), %st
|
||||||
|
fsub %st(3)
|
||||||
|
|
||||||
|
fsubp %st(5)
|
||||||
|
fsubp
|
||||||
|
fsubp %st(1), %st
|
||||||
|
|
||||||
|
fsubs 0x1000
|
||||||
|
fisubs 0x1002
|
||||||
|
fsubl 0x1004
|
||||||
|
fisubl 0x1006
|
||||||
|
|
||||||
|
fsubr
|
||||||
|
fsubr %st(1), %st
|
||||||
|
fsubr %st(3)
|
||||||
|
|
||||||
|
fsubrp %st(5)
|
||||||
|
fsubrp
|
||||||
|
fsubrp %st(1), %st
|
||||||
|
|
||||||
|
fsubrs 0x1000
|
||||||
|
fisubrs 0x1002
|
||||||
|
fsubrl 0x1004
|
||||||
|
fisubrl 0x1006
|
||||||
|
|
||||||
|
fdiv
|
||||||
|
fdiv %st(1), %st
|
||||||
|
fdiv %st(3)
|
||||||
|
|
||||||
|
fdivp %st(5)
|
||||||
|
fdivp
|
||||||
|
fdivp %st(1), %st
|
||||||
|
|
||||||
|
fdivs 0x1000
|
||||||
|
fidivs 0x1002
|
||||||
|
fdivl 0x1004
|
||||||
|
fidivl 0x1006
|
||||||
|
|
||||||
|
fcom %st(3)
|
||||||
|
|
||||||
|
fcoms 0x1000
|
||||||
|
ficoms 0x1002
|
||||||
|
fcoml 0x1004
|
||||||
|
ficoml 0x1006
|
||||||
|
|
||||||
|
fcomp %st(5)
|
||||||
|
fcomp
|
||||||
|
fcompp
|
||||||
|
|
||||||
|
fcomps 0x1000
|
||||||
|
ficomps 0x1002
|
||||||
|
fcompl 0x1004
|
||||||
|
ficompl 0x1006
|
||||||
|
|
||||||
|
fld %st(5)
|
||||||
|
fldl 0x1000
|
||||||
|
flds 0x1002
|
||||||
|
fildl 0x1004
|
||||||
|
fst %st(4)
|
||||||
|
fstp %st(6)
|
||||||
|
fstpt 0x1006
|
||||||
|
fbstp 0x1008
|
||||||
|
|
||||||
|
fxch
|
||||||
|
fxch %st(4)
|
||||||
|
|
||||||
|
fucom %st(6)
|
||||||
|
fucomp %st(3)
|
||||||
|
fucompp
|
||||||
|
|
||||||
|
finit
|
||||||
|
fninit
|
||||||
|
fldcw 0x1000
|
||||||
|
fnstcw 0x1002
|
||||||
|
fstcw 0x1002
|
||||||
|
fnstsw 0x1004
|
||||||
|
fnstsw %eax
|
||||||
|
fstsw 0x1004
|
||||||
|
fstsw %eax
|
||||||
|
fnclex
|
||||||
|
fclex
|
||||||
|
fnstenv 0x1000
|
||||||
|
fstenv 0x1000
|
||||||
|
fldenv 0x1000
|
||||||
|
fnsave 0x1002
|
||||||
|
fsave 0x1000
|
||||||
|
frstor 0x1000
|
||||||
|
ffree %st(7)
|
||||||
|
ffreep %st(6)
|
||||||
|
|
||||||
|
ftst
|
||||||
|
fxam
|
||||||
|
fld1
|
||||||
|
fldl2t
|
||||||
|
fldl2e
|
||||||
|
fldpi
|
||||||
|
fldlg2
|
||||||
|
fldln2
|
||||||
|
fldz
|
||||||
|
|
||||||
|
f2xm1
|
||||||
|
fyl2x
|
||||||
|
fptan
|
||||||
|
fpatan
|
||||||
|
fxtract
|
||||||
|
fprem1
|
||||||
|
fdecstp
|
||||||
|
fincstp
|
||||||
|
fprem
|
||||||
|
fyl2xp1
|
||||||
|
fsqrt
|
||||||
|
fsincos
|
||||||
|
frndint
|
||||||
|
fscale
|
||||||
|
fsin
|
||||||
|
fcos
|
||||||
|
fchs
|
||||||
|
fabs
|
||||||
|
fnop
|
||||||
|
fwait
|
||||||
|
|
||||||
|
bswap %edx
|
||||||
|
xadd %ecx, %edx
|
||||||
|
xaddb %dl, 0x1000
|
||||||
|
xaddw %ax, 0x1000
|
||||||
|
xaddl %eax, 0x1000
|
||||||
|
cmpxchg %ecx, %edx
|
||||||
|
cmpxchgb %dl, 0x1000
|
||||||
|
cmpxchgw %ax, 0x1000
|
||||||
|
cmpxchgl %eax, 0x1000
|
||||||
|
invlpg 0x1000
|
||||||
|
cmpxchg8b 0x1002
|
||||||
|
|
||||||
|
fcmovb %st(5), %st
|
||||||
|
fcmove %st(5), %st
|
||||||
|
fcmovbe %st(5), %st
|
||||||
|
fcmovu %st(5), %st
|
||||||
|
fcmovnb %st(5), %st
|
||||||
|
fcmovne %st(5), %st
|
||||||
|
fcmovnbe %st(5), %st
|
||||||
|
fcmovnu %st(5), %st
|
||||||
|
fcomi %st(5), %st
|
||||||
|
fucomi %st(5), %st
|
||||||
|
fcomip %st(5), %st
|
||||||
|
fucomip %st(5), %st
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cmovo 0x1000, %eax
|
||||||
|
cmovs 0x1000, %eax
|
||||||
|
cmovns %edx, %edi
|
||||||
|
|
||||||
|
int $3
|
||||||
|
int $0x10
|
||||||
|
|
||||||
|
pusha
|
||||||
|
popa
|
||||||
|
clc
|
||||||
|
cld
|
||||||
|
cli
|
||||||
|
clts
|
||||||
|
cmc
|
||||||
|
lahf
|
||||||
|
sahf
|
||||||
|
pushfl
|
||||||
|
popfl
|
||||||
|
pushf
|
||||||
|
popf
|
||||||
|
stc
|
||||||
|
std
|
||||||
|
sti
|
||||||
|
aaa
|
||||||
|
aas
|
||||||
|
daa
|
||||||
|
das
|
||||||
|
aad
|
||||||
|
aam
|
||||||
|
cbw
|
||||||
|
cwd
|
||||||
|
cwde
|
||||||
|
cdq
|
||||||
|
cbtw
|
||||||
|
cwtd
|
||||||
|
cwtl
|
||||||
|
cltd
|
||||||
|
leave
|
||||||
|
int3
|
||||||
|
into
|
||||||
|
iret
|
||||||
|
rsm
|
||||||
|
hlt
|
||||||
|
wait
|
||||||
|
nop
|
||||||
|
|
||||||
|
/* XXX: handle prefixes */
|
||||||
|
#if 0
|
||||||
|
aword
|
||||||
|
addr16
|
||||||
|
#endif
|
||||||
|
lock
|
||||||
|
rep
|
||||||
|
repe
|
||||||
|
repz
|
||||||
|
repne
|
||||||
|
repnz
|
||||||
|
|
||||||
|
invd
|
||||||
|
wbinvd
|
||||||
|
cpuid
|
||||||
|
wrmsr
|
||||||
|
rdtsc
|
||||||
|
rdmsr
|
||||||
|
rdpmc
|
||||||
|
ud2
|
||||||
|
|
||||||
|
emms
|
||||||
|
movd %edx, %mm3
|
||||||
|
movd 0x1000, %mm2
|
||||||
|
movd %mm4, %ecx
|
||||||
|
movd %mm5, 0x1000
|
||||||
|
|
||||||
|
movq 0x1000, %mm2
|
||||||
|
movq %mm4, 0x1000
|
||||||
|
|
||||||
|
pand 0x1000, %mm3
|
||||||
|
pand %mm4, %mm5
|
||||||
|
|
||||||
|
psllw $1, %mm6
|
||||||
|
psllw 0x1000, %mm7
|
||||||
|
psllw %mm2, %mm7
|
||||||
|
|
||||||
|
xlat
|
||||||
|
cmpsb
|
||||||
|
scmpw
|
||||||
|
insl
|
||||||
|
outsw
|
||||||
|
lodsb
|
||||||
|
slodl
|
||||||
|
movsb
|
||||||
|
movsl
|
||||||
|
smovb
|
||||||
|
scasb
|
||||||
|
sscaw
|
||||||
|
stosw
|
||||||
|
sstol
|
||||||
|
|
||||||
|
bsf 0x1000, %ebx
|
||||||
|
bsr 0x1000, %ebx
|
||||||
|
bt %edx, 0x1000
|
||||||
|
btl $2, 0x1000
|
||||||
|
btc %edx, 0x1000
|
||||||
|
btcl $2, 0x1000
|
||||||
|
btr %edx, 0x1000
|
||||||
|
btrl $2, 0x1000
|
||||||
|
bts %edx, 0x1000
|
||||||
|
btsl $2, 0x1000
|
||||||
|
|
||||||
|
boundl %edx, 0x10000
|
||||||
|
boundw %bx, 0x1000
|
||||||
|
|
||||||
|
arpl %bx, 0x1000
|
||||||
|
lar 0x1000, %eax
|
||||||
|
lgdt 0x1000
|
||||||
|
lidt 0x1000
|
||||||
|
lldt 0x1000
|
||||||
|
lmsw 0x1000
|
||||||
|
lsl 0x1000, %ecx
|
||||||
|
ltr 0x1000
|
||||||
|
|
||||||
|
sgdt 0x1000
|
||||||
|
sidt 0x1000
|
||||||
|
sldt 0x1000
|
||||||
|
smsw 0x1000
|
||||||
|
str 0x1000
|
||||||
|
|
||||||
|
verr 0x1000
|
||||||
|
verw 0x1000
|
||||||
879
bcheck.c
Normal file
879
bcheck.c
Normal file
@ -0,0 +1,879 @@
|
|||||||
|
/*
|
||||||
|
* Tiny C Memory and bounds checker
|
||||||
|
*
|
||||||
|
* Copyright (c) 2002 Fabrice Bellard
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <string.h>
|
||||||
|
#ifndef __FreeBSD__
|
||||||
|
#include <malloc.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//#define BOUND_DEBUG
|
||||||
|
|
||||||
|
/* define so that bound array is static (faster, but use memory if
|
||||||
|
bound checking not used) */
|
||||||
|
//#define BOUND_STATIC
|
||||||
|
|
||||||
|
/* use malloc hooks. Currently the code cannot be reliable if no hooks */
|
||||||
|
#define CONFIG_TCC_MALLOC_HOOKS
|
||||||
|
|
||||||
|
#define HAVE_MEMALIGN
|
||||||
|
|
||||||
|
#ifdef __FreeBSD__
|
||||||
|
#warning Bound checking not fully supported on FreeBSD
|
||||||
|
#undef CONFIG_TCC_MALLOC_HOOKS
|
||||||
|
#undef HAVE_MEMALIGN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define BOUND_T1_BITS 13
|
||||||
|
#define BOUND_T2_BITS 11
|
||||||
|
#define BOUND_T3_BITS (32 - BOUND_T1_BITS - BOUND_T2_BITS)
|
||||||
|
|
||||||
|
#define BOUND_T1_SIZE (1 << BOUND_T1_BITS)
|
||||||
|
#define BOUND_T2_SIZE (1 << BOUND_T2_BITS)
|
||||||
|
#define BOUND_T3_SIZE (1 << BOUND_T3_BITS)
|
||||||
|
#define BOUND_E_BITS 4
|
||||||
|
|
||||||
|
#define BOUND_T23_BITS (BOUND_T2_BITS + BOUND_T3_BITS)
|
||||||
|
#define BOUND_T23_SIZE (1 << BOUND_T23_BITS)
|
||||||
|
|
||||||
|
|
||||||
|
/* this pointer is generated when bound check is incorrect */
|
||||||
|
#define INVALID_POINTER ((void *)(-2))
|
||||||
|
/* size of an empty region */
|
||||||
|
#define EMPTY_SIZE 0xffffffff
|
||||||
|
/* size of an invalid region */
|
||||||
|
#define INVALID_SIZE 0
|
||||||
|
|
||||||
|
typedef struct BoundEntry {
|
||||||
|
unsigned long start;
|
||||||
|
unsigned long size;
|
||||||
|
struct BoundEntry *next;
|
||||||
|
unsigned long is_invalid; /* true if pointers outside region are invalid */
|
||||||
|
} BoundEntry;
|
||||||
|
|
||||||
|
/* external interface */
|
||||||
|
void __bound_init(void);
|
||||||
|
void __bound_new_region(void *p, unsigned long size);
|
||||||
|
int __bound_delete_region(void *p);
|
||||||
|
|
||||||
|
/* currently, tcc cannot compile that because we use unsupported GNU C
|
||||||
|
extensions */
|
||||||
|
#if !defined(__TINYC__)
|
||||||
|
void *__bound_ptr_add(void *p, int offset) __attribute__((regparm(2)));
|
||||||
|
void *__bound_ptr_indir1(void *p, int offset) __attribute__((regparm(2)));
|
||||||
|
void *__bound_ptr_indir2(void *p, int offset) __attribute__((regparm(2)));
|
||||||
|
void *__bound_ptr_indir4(void *p, int offset) __attribute__((regparm(2)));
|
||||||
|
void *__bound_ptr_indir8(void *p, int offset) __attribute__((regparm(2)));
|
||||||
|
void *__bound_ptr_indir12(void *p, int offset) __attribute__((regparm(2)));
|
||||||
|
void *__bound_ptr_indir16(void *p, int offset) __attribute__((regparm(2)));
|
||||||
|
void __bound_local_new(void *p) __attribute__((regparm(1)));
|
||||||
|
void __bound_local_delete(void *p) __attribute__((regparm(1)));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void *__bound_malloc(size_t size, const void *caller);
|
||||||
|
void *__bound_memalign(size_t size, size_t align, const void *caller);
|
||||||
|
void __bound_free(void *ptr, const void *caller);
|
||||||
|
void *__bound_realloc(void *ptr, size_t size, const void *caller);
|
||||||
|
static void *libc_malloc(size_t size);
|
||||||
|
static void libc_free(void *ptr);
|
||||||
|
static void install_malloc_hooks(void);
|
||||||
|
static void restore_malloc_hooks(void);
|
||||||
|
|
||||||
|
#ifdef CONFIG_TCC_MALLOC_HOOKS
|
||||||
|
static void *saved_malloc_hook;
|
||||||
|
static void *saved_free_hook;
|
||||||
|
static void *saved_realloc_hook;
|
||||||
|
static void *saved_memalign_hook;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* linker definitions */
|
||||||
|
extern char _end;
|
||||||
|
|
||||||
|
/* TCC definitions */
|
||||||
|
extern char __bounds_start; /* start of static bounds table */
|
||||||
|
/* error message, just for TCC */
|
||||||
|
const char *__bound_error_msg;
|
||||||
|
|
||||||
|
/* runtime error output */
|
||||||
|
extern void rt_error(unsigned long pc, const char *fmt, ...);
|
||||||
|
|
||||||
|
#ifdef BOUND_STATIC
|
||||||
|
static BoundEntry *__bound_t1[BOUND_T1_SIZE]; /* page table */
|
||||||
|
#else
|
||||||
|
static BoundEntry **__bound_t1; /* page table */
|
||||||
|
#endif
|
||||||
|
static BoundEntry *__bound_empty_t2; /* empty page, for unused pages */
|
||||||
|
static BoundEntry *__bound_invalid_t2; /* invalid page, for invalid pointers */
|
||||||
|
|
||||||
|
static BoundEntry *__bound_find_region(BoundEntry *e1, void *p)
|
||||||
|
{
|
||||||
|
unsigned long addr, tmp;
|
||||||
|
BoundEntry *e;
|
||||||
|
|
||||||
|
e = e1;
|
||||||
|
while (e != NULL) {
|
||||||
|
addr = (unsigned long)p;
|
||||||
|
addr -= e->start;
|
||||||
|
if (addr <= e->size) {
|
||||||
|
/* put region at the head */
|
||||||
|
tmp = e1->start;
|
||||||
|
e1->start = e->start;
|
||||||
|
e->start = tmp;
|
||||||
|
tmp = e1->size;
|
||||||
|
e1->size = e->size;
|
||||||
|
e->size = tmp;
|
||||||
|
return e1;
|
||||||
|
}
|
||||||
|
e = e->next;
|
||||||
|
}
|
||||||
|
/* no entry found: return empty entry or invalid entry */
|
||||||
|
if (e1->is_invalid)
|
||||||
|
return __bound_invalid_t2;
|
||||||
|
else
|
||||||
|
return __bound_empty_t2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* print a bound error message */
|
||||||
|
static void bound_error(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
__bound_error_msg = fmt;
|
||||||
|
*(int *)0 = 0; /* force a runtime error */
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bound_alloc_error(void)
|
||||||
|
{
|
||||||
|
bound_error("not enough memory for bound checking code");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* currently, tcc cannot compile that because we use GNUC extensions */
|
||||||
|
#if !defined(__TINYC__)
|
||||||
|
|
||||||
|
/* return '(p + offset)' for pointer arithmetic (a pointer can reach
|
||||||
|
the end of a region in this case */
|
||||||
|
void *__bound_ptr_add(void *p, int offset)
|
||||||
|
{
|
||||||
|
unsigned long addr = (unsigned long)p;
|
||||||
|
BoundEntry *e;
|
||||||
|
#if defined(BOUND_DEBUG)
|
||||||
|
printf("add: 0x%x %d\n", (int)p, offset);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
e = __bound_t1[addr >> (BOUND_T2_BITS + BOUND_T3_BITS)];
|
||||||
|
e = (BoundEntry *)((char *)e +
|
||||||
|
((addr >> (BOUND_T3_BITS - BOUND_E_BITS)) &
|
||||||
|
((BOUND_T2_SIZE - 1) << BOUND_E_BITS)));
|
||||||
|
addr -= e->start;
|
||||||
|
if (addr > e->size) {
|
||||||
|
e = __bound_find_region(e, p);
|
||||||
|
addr = (unsigned long)p - e->start;
|
||||||
|
}
|
||||||
|
addr += offset;
|
||||||
|
if (addr > e->size)
|
||||||
|
return INVALID_POINTER; /* return an invalid pointer */
|
||||||
|
return p + offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* return '(p + offset)' for pointer indirection (the resulting must
|
||||||
|
be strictly inside the region */
|
||||||
|
#define BOUND_PTR_INDIR(dsize) \
|
||||||
|
void *__bound_ptr_indir ## dsize (void *p, int offset) \
|
||||||
|
{ \
|
||||||
|
unsigned long addr = (unsigned long)p; \
|
||||||
|
BoundEntry *e; \
|
||||||
|
\
|
||||||
|
e = __bound_t1[addr >> (BOUND_T2_BITS + BOUND_T3_BITS)]; \
|
||||||
|
e = (BoundEntry *)((char *)e + \
|
||||||
|
((addr >> (BOUND_T3_BITS - BOUND_E_BITS)) & \
|
||||||
|
((BOUND_T2_SIZE - 1) << BOUND_E_BITS))); \
|
||||||
|
addr -= e->start; \
|
||||||
|
if (addr > e->size) { \
|
||||||
|
e = __bound_find_region(e, p); \
|
||||||
|
addr = (unsigned long)p - e->start; \
|
||||||
|
} \
|
||||||
|
addr += offset + dsize; \
|
||||||
|
if (addr > e->size) \
|
||||||
|
return INVALID_POINTER; /* return an invalid pointer */ \
|
||||||
|
return p + offset; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __i386__
|
||||||
|
/* return the frame pointer of the caller */
|
||||||
|
#define GET_CALLER_FP(fp)\
|
||||||
|
{\
|
||||||
|
unsigned long *fp1;\
|
||||||
|
__asm__ __volatile__ ("movl %%ebp,%0" :"=g" (fp1));\
|
||||||
|
fp = fp1[0];\
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#error put code to extract the calling frame pointer
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* called when entering a function to add all the local regions */
|
||||||
|
void __bound_local_new(void *p1)
|
||||||
|
{
|
||||||
|
unsigned long addr, size, fp, *p = p1;
|
||||||
|
GET_CALLER_FP(fp);
|
||||||
|
for(;;) {
|
||||||
|
addr = p[0];
|
||||||
|
if (addr == 0)
|
||||||
|
break;
|
||||||
|
addr += fp;
|
||||||
|
size = p[1];
|
||||||
|
p += 2;
|
||||||
|
__bound_new_region((void *)addr, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* called when leaving a function to delete all the local regions */
|
||||||
|
void __bound_local_delete(void *p1)
|
||||||
|
{
|
||||||
|
unsigned long addr, fp, *p = p1;
|
||||||
|
GET_CALLER_FP(fp);
|
||||||
|
for(;;) {
|
||||||
|
addr = p[0];
|
||||||
|
if (addr == 0)
|
||||||
|
break;
|
||||||
|
addr += fp;
|
||||||
|
p += 2;
|
||||||
|
__bound_delete_region((void *)addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
void __bound_local_new(void *p)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
void __bound_local_delete(void *p)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void *__bound_ptr_add(void *p, int offset)
|
||||||
|
{
|
||||||
|
return p + offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BOUND_PTR_INDIR(dsize) \
|
||||||
|
void *__bound_ptr_indir ## dsize (void *p, int offset) \
|
||||||
|
{ \
|
||||||
|
return p + offset; \
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
BOUND_PTR_INDIR(1)
|
||||||
|
BOUND_PTR_INDIR(2)
|
||||||
|
BOUND_PTR_INDIR(4)
|
||||||
|
BOUND_PTR_INDIR(8)
|
||||||
|
BOUND_PTR_INDIR(12)
|
||||||
|
BOUND_PTR_INDIR(16)
|
||||||
|
|
||||||
|
static BoundEntry *__bound_new_page(void)
|
||||||
|
{
|
||||||
|
BoundEntry *page;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
page = libc_malloc(sizeof(BoundEntry) * BOUND_T2_SIZE);
|
||||||
|
if (!page)
|
||||||
|
bound_alloc_error();
|
||||||
|
for(i=0;i<BOUND_T2_SIZE;i++) {
|
||||||
|
/* put empty entries */
|
||||||
|
page[i].start = 0;
|
||||||
|
page[i].size = EMPTY_SIZE;
|
||||||
|
page[i].next = NULL;
|
||||||
|
page[i].is_invalid = 0;
|
||||||
|
}
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* currently we use malloc(). Should use bound_new_page() */
|
||||||
|
static BoundEntry *bound_new_entry(void)
|
||||||
|
{
|
||||||
|
BoundEntry *e;
|
||||||
|
e = libc_malloc(sizeof(BoundEntry));
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bound_free_entry(BoundEntry *e)
|
||||||
|
{
|
||||||
|
libc_free(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline BoundEntry *get_page(int index)
|
||||||
|
{
|
||||||
|
BoundEntry *page;
|
||||||
|
page = __bound_t1[index];
|
||||||
|
if (page == __bound_empty_t2 || page == __bound_invalid_t2) {
|
||||||
|
/* create a new page if necessary */
|
||||||
|
page = __bound_new_page();
|
||||||
|
__bound_t1[index] = page;
|
||||||
|
}
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* mark a region as being invalid (can only be used during init) */
|
||||||
|
static void mark_invalid(unsigned long addr, unsigned long size)
|
||||||
|
{
|
||||||
|
unsigned long start, end;
|
||||||
|
BoundEntry *page;
|
||||||
|
int t1_start, t1_end, i, j, t2_start, t2_end;
|
||||||
|
|
||||||
|
start = addr;
|
||||||
|
end = addr + size;
|
||||||
|
|
||||||
|
t2_start = (start + BOUND_T3_SIZE - 1) >> BOUND_T3_BITS;
|
||||||
|
if (end != 0)
|
||||||
|
t2_end = end >> BOUND_T3_BITS;
|
||||||
|
else
|
||||||
|
t2_end = 1 << (BOUND_T1_BITS + BOUND_T2_BITS);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
printf("mark_invalid: start = %x %x\n", t2_start, t2_end);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* first we handle full pages */
|
||||||
|
t1_start = (t2_start + BOUND_T2_SIZE - 1) >> BOUND_T2_BITS;
|
||||||
|
t1_end = t2_end >> BOUND_T2_BITS;
|
||||||
|
|
||||||
|
i = t2_start & (BOUND_T2_SIZE - 1);
|
||||||
|
j = t2_end & (BOUND_T2_SIZE - 1);
|
||||||
|
|
||||||
|
if (t1_start == t1_end) {
|
||||||
|
page = get_page(t2_start >> BOUND_T2_BITS);
|
||||||
|
for(; i < j; i++) {
|
||||||
|
page[i].size = INVALID_SIZE;
|
||||||
|
page[i].is_invalid = 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (i > 0) {
|
||||||
|
page = get_page(t2_start >> BOUND_T2_BITS);
|
||||||
|
for(; i < BOUND_T2_SIZE; i++) {
|
||||||
|
page[i].size = INVALID_SIZE;
|
||||||
|
page[i].is_invalid = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(i = t1_start; i < t1_end; i++) {
|
||||||
|
__bound_t1[i] = __bound_invalid_t2;
|
||||||
|
}
|
||||||
|
if (j != 0) {
|
||||||
|
page = get_page(t1_end);
|
||||||
|
for(i = 0; i < j; i++) {
|
||||||
|
page[i].size = INVALID_SIZE;
|
||||||
|
page[i].is_invalid = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __bound_init(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
BoundEntry *page;
|
||||||
|
unsigned long start, size;
|
||||||
|
int *p;
|
||||||
|
|
||||||
|
/* save malloc hooks and install bound check hooks */
|
||||||
|
install_malloc_hooks();
|
||||||
|
|
||||||
|
#ifndef BOUND_STATIC
|
||||||
|
__bound_t1 = libc_malloc(BOUND_T1_SIZE * sizeof(BoundEntry *));
|
||||||
|
if (!__bound_t1)
|
||||||
|
bound_alloc_error();
|
||||||
|
#endif
|
||||||
|
__bound_empty_t2 = __bound_new_page();
|
||||||
|
for(i=0;i<BOUND_T1_SIZE;i++) {
|
||||||
|
__bound_t1[i] = __bound_empty_t2;
|
||||||
|
}
|
||||||
|
|
||||||
|
page = __bound_new_page();
|
||||||
|
for(i=0;i<BOUND_T2_SIZE;i++) {
|
||||||
|
/* put invalid entries */
|
||||||
|
page[i].start = 0;
|
||||||
|
page[i].size = INVALID_SIZE;
|
||||||
|
page[i].next = NULL;
|
||||||
|
page[i].is_invalid = 1;
|
||||||
|
}
|
||||||
|
__bound_invalid_t2 = page;
|
||||||
|
|
||||||
|
/* invalid pointer zone */
|
||||||
|
start = (unsigned long)INVALID_POINTER & ~(BOUND_T23_SIZE - 1);
|
||||||
|
size = BOUND_T23_SIZE;
|
||||||
|
mark_invalid(start, size);
|
||||||
|
|
||||||
|
#if !defined(__TINYC__) && defined(CONFIG_TCC_MALLOC_HOOKS)
|
||||||
|
/* malloc zone is also marked invalid. can only use that with
|
||||||
|
hooks because all libs should use the same malloc. The solution
|
||||||
|
would be to build a new malloc for tcc. */
|
||||||
|
start = (unsigned long)&_end;
|
||||||
|
size = 128 * 0x100000;
|
||||||
|
mark_invalid(start, size);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* add all static bound check values */
|
||||||
|
p = (int *)&__bounds_start;
|
||||||
|
while (p[0] != 0) {
|
||||||
|
__bound_new_region((void *)p[0], p[1]);
|
||||||
|
p += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void add_region(BoundEntry *e,
|
||||||
|
unsigned long start, unsigned long size)
|
||||||
|
{
|
||||||
|
BoundEntry *e1;
|
||||||
|
if (e->start == 0) {
|
||||||
|
/* no region : add it */
|
||||||
|
e->start = start;
|
||||||
|
e->size = size;
|
||||||
|
} else {
|
||||||
|
/* already regions in the list: add it at the head */
|
||||||
|
e1 = bound_new_entry();
|
||||||
|
e1->start = e->start;
|
||||||
|
e1->size = e->size;
|
||||||
|
e1->next = e->next;
|
||||||
|
e->start = start;
|
||||||
|
e->size = size;
|
||||||
|
e->next = e1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* create a new region. It should not already exist in the region list */
|
||||||
|
void __bound_new_region(void *p, unsigned long size)
|
||||||
|
{
|
||||||
|
unsigned long start, end;
|
||||||
|
BoundEntry *page, *e, *e2;
|
||||||
|
int t1_start, t1_end, i, t2_start, t2_end;
|
||||||
|
|
||||||
|
start = (unsigned long)p;
|
||||||
|
end = start + size;
|
||||||
|
t1_start = start >> (BOUND_T2_BITS + BOUND_T3_BITS);
|
||||||
|
t1_end = end >> (BOUND_T2_BITS + BOUND_T3_BITS);
|
||||||
|
|
||||||
|
/* start */
|
||||||
|
page = get_page(t1_start);
|
||||||
|
t2_start = (start >> (BOUND_T3_BITS - BOUND_E_BITS)) &
|
||||||
|
((BOUND_T2_SIZE - 1) << BOUND_E_BITS);
|
||||||
|
t2_end = (end >> (BOUND_T3_BITS - BOUND_E_BITS)) &
|
||||||
|
((BOUND_T2_SIZE - 1) << BOUND_E_BITS);
|
||||||
|
#ifdef BOUND_DEBUG
|
||||||
|
printf("new %lx %lx %x %x %x %x\n",
|
||||||
|
start, end, t1_start, t1_end, t2_start, t2_end);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
e = (BoundEntry *)((char *)page + t2_start);
|
||||||
|
add_region(e, start, size);
|
||||||
|
|
||||||
|
if (t1_end == t1_start) {
|
||||||
|
/* same ending page */
|
||||||
|
e2 = (BoundEntry *)((char *)page + t2_end);
|
||||||
|
if (e2 > e) {
|
||||||
|
e++;
|
||||||
|
for(;e<e2;e++) {
|
||||||
|
e->start = start;
|
||||||
|
e->size = size;
|
||||||
|
}
|
||||||
|
add_region(e, start, size);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* mark until end of page */
|
||||||
|
e2 = page + BOUND_T2_SIZE;
|
||||||
|
e++;
|
||||||
|
for(;e<e2;e++) {
|
||||||
|
e->start = start;
|
||||||
|
e->size = size;
|
||||||
|
}
|
||||||
|
/* mark intermediate pages, if any */
|
||||||
|
for(i=t1_start+1;i<t1_end;i++) {
|
||||||
|
page = get_page(i);
|
||||||
|
e2 = page + BOUND_T2_SIZE;
|
||||||
|
for(e=page;e<e2;e++) {
|
||||||
|
e->start = start;
|
||||||
|
e->size = size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* last page */
|
||||||
|
page = get_page(t1_end);
|
||||||
|
e2 = (BoundEntry *)((char *)page + t2_end);
|
||||||
|
for(e=page;e<e2;e++) {
|
||||||
|
e->start = start;
|
||||||
|
e->size = size;
|
||||||
|
}
|
||||||
|
add_region(e, start, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* delete a region */
|
||||||
|
static inline void delete_region(BoundEntry *e,
|
||||||
|
void *p, unsigned long empty_size)
|
||||||
|
{
|
||||||
|
unsigned long addr;
|
||||||
|
BoundEntry *e1;
|
||||||
|
|
||||||
|
addr = (unsigned long)p;
|
||||||
|
addr -= e->start;
|
||||||
|
if (addr <= e->size) {
|
||||||
|
/* region found is first one */
|
||||||
|
e1 = e->next;
|
||||||
|
if (e1 == NULL) {
|
||||||
|
/* no more region: mark it empty */
|
||||||
|
e->start = 0;
|
||||||
|
e->size = empty_size;
|
||||||
|
} else {
|
||||||
|
/* copy next region in head */
|
||||||
|
e->start = e1->start;
|
||||||
|
e->size = e1->size;
|
||||||
|
e->next = e1->next;
|
||||||
|
bound_free_entry(e1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* find the matching region */
|
||||||
|
for(;;) {
|
||||||
|
e1 = e;
|
||||||
|
e = e->next;
|
||||||
|
/* region not found: do nothing */
|
||||||
|
if (e == NULL)
|
||||||
|
break;
|
||||||
|
addr = (unsigned long)p - e->start;
|
||||||
|
if (addr <= e->size) {
|
||||||
|
/* found: remove entry */
|
||||||
|
e1->next = e->next;
|
||||||
|
bound_free_entry(e);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* WARNING: 'p' must be the starting point of the region. */
|
||||||
|
/* return non zero if error */
|
||||||
|
int __bound_delete_region(void *p)
|
||||||
|
{
|
||||||
|
unsigned long start, end, addr, size, empty_size;
|
||||||
|
BoundEntry *page, *e, *e2;
|
||||||
|
int t1_start, t1_end, t2_start, t2_end, i;
|
||||||
|
|
||||||
|
start = (unsigned long)p;
|
||||||
|
t1_start = start >> (BOUND_T2_BITS + BOUND_T3_BITS);
|
||||||
|
t2_start = (start >> (BOUND_T3_BITS - BOUND_E_BITS)) &
|
||||||
|
((BOUND_T2_SIZE - 1) << BOUND_E_BITS);
|
||||||
|
|
||||||
|
/* find region size */
|
||||||
|
page = __bound_t1[t1_start];
|
||||||
|
e = (BoundEntry *)((char *)page + t2_start);
|
||||||
|
addr = start - e->start;
|
||||||
|
if (addr > e->size)
|
||||||
|
e = __bound_find_region(e, p);
|
||||||
|
/* test if invalid region */
|
||||||
|
if (e->size == EMPTY_SIZE || (unsigned long)p != e->start)
|
||||||
|
return -1;
|
||||||
|
/* compute the size we put in invalid regions */
|
||||||
|
if (e->is_invalid)
|
||||||
|
empty_size = INVALID_SIZE;
|
||||||
|
else
|
||||||
|
empty_size = EMPTY_SIZE;
|
||||||
|
size = e->size;
|
||||||
|
end = start + size;
|
||||||
|
|
||||||
|
/* now we can free each entry */
|
||||||
|
t1_end = end >> (BOUND_T2_BITS + BOUND_T3_BITS);
|
||||||
|
t2_end = (end >> (BOUND_T3_BITS - BOUND_E_BITS)) &
|
||||||
|
((BOUND_T2_SIZE - 1) << BOUND_E_BITS);
|
||||||
|
|
||||||
|
delete_region(e, p, empty_size);
|
||||||
|
if (t1_end == t1_start) {
|
||||||
|
/* same ending page */
|
||||||
|
e2 = (BoundEntry *)((char *)page + t2_end);
|
||||||
|
if (e2 > e) {
|
||||||
|
e++;
|
||||||
|
for(;e<e2;e++) {
|
||||||
|
e->start = 0;
|
||||||
|
e->size = empty_size;
|
||||||
|
}
|
||||||
|
delete_region(e, p, empty_size);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* mark until end of page */
|
||||||
|
e2 = page + BOUND_T2_SIZE;
|
||||||
|
e++;
|
||||||
|
for(;e<e2;e++) {
|
||||||
|
e->start = 0;
|
||||||
|
e->size = empty_size;
|
||||||
|
}
|
||||||
|
/* mark intermediate pages, if any */
|
||||||
|
/* XXX: should free them */
|
||||||
|
for(i=t1_start+1;i<t1_end;i++) {
|
||||||
|
page = get_page(i);
|
||||||
|
e2 = page + BOUND_T2_SIZE;
|
||||||
|
for(e=page;e<e2;e++) {
|
||||||
|
e->start = 0;
|
||||||
|
e->size = empty_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* last page */
|
||||||
|
page = get_page(t2_end);
|
||||||
|
e2 = (BoundEntry *)((char *)page + t2_end);
|
||||||
|
for(e=page;e<e2;e++) {
|
||||||
|
e->start = 0;
|
||||||
|
e->size = empty_size;
|
||||||
|
}
|
||||||
|
delete_region(e, p, empty_size);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* return the size of the region starting at p, or EMPTY_SIZE if non
|
||||||
|
existant region. */
|
||||||
|
static unsigned long get_region_size(void *p)
|
||||||
|
{
|
||||||
|
unsigned long addr = (unsigned long)p;
|
||||||
|
BoundEntry *e;
|
||||||
|
|
||||||
|
e = __bound_t1[addr >> (BOUND_T2_BITS + BOUND_T3_BITS)];
|
||||||
|
e = (BoundEntry *)((char *)e +
|
||||||
|
((addr >> (BOUND_T3_BITS - BOUND_E_BITS)) &
|
||||||
|
((BOUND_T2_SIZE - 1) << BOUND_E_BITS)));
|
||||||
|
addr -= e->start;
|
||||||
|
if (addr > e->size)
|
||||||
|
e = __bound_find_region(e, p);
|
||||||
|
if (e->start != (unsigned long)p)
|
||||||
|
return EMPTY_SIZE;
|
||||||
|
return e->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* patched memory functions */
|
||||||
|
|
||||||
|
static void install_malloc_hooks(void)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_TCC_MALLOC_HOOKS
|
||||||
|
saved_malloc_hook = __malloc_hook;
|
||||||
|
saved_free_hook = __free_hook;
|
||||||
|
saved_realloc_hook = __realloc_hook;
|
||||||
|
saved_memalign_hook = __memalign_hook;
|
||||||
|
__malloc_hook = __bound_malloc;
|
||||||
|
__free_hook = __bound_free;
|
||||||
|
__realloc_hook = __bound_realloc;
|
||||||
|
__memalign_hook = __bound_memalign;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void restore_malloc_hooks(void)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_TCC_MALLOC_HOOKS
|
||||||
|
__malloc_hook = saved_malloc_hook;
|
||||||
|
__free_hook = saved_free_hook;
|
||||||
|
__realloc_hook = saved_realloc_hook;
|
||||||
|
__memalign_hook = saved_memalign_hook;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *libc_malloc(size_t size)
|
||||||
|
{
|
||||||
|
void *ptr;
|
||||||
|
restore_malloc_hooks();
|
||||||
|
ptr = malloc(size);
|
||||||
|
install_malloc_hooks();
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void libc_free(void *ptr)
|
||||||
|
{
|
||||||
|
restore_malloc_hooks();
|
||||||
|
free(ptr);
|
||||||
|
install_malloc_hooks();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* XXX: we should use a malloc which ensure that it is unlikely that
|
||||||
|
two malloc'ed data have the same address if 'free' are made in
|
||||||
|
between. */
|
||||||
|
void *__bound_malloc(size_t size, const void *caller)
|
||||||
|
{
|
||||||
|
void *ptr;
|
||||||
|
|
||||||
|
/* we allocate one more byte to ensure the regions will be
|
||||||
|
separated by at least one byte. With the glibc malloc, it may
|
||||||
|
be in fact not necessary */
|
||||||
|
ptr = libc_malloc(size + 1);
|
||||||
|
|
||||||
|
if (!ptr)
|
||||||
|
return NULL;
|
||||||
|
__bound_new_region(ptr, size);
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *__bound_memalign(size_t size, size_t align, const void *caller)
|
||||||
|
{
|
||||||
|
void *ptr;
|
||||||
|
|
||||||
|
restore_malloc_hooks();
|
||||||
|
|
||||||
|
#ifndef HAVE_MEMALIGN
|
||||||
|
if (align > 4) {
|
||||||
|
/* XXX: handle it ? */
|
||||||
|
ptr = NULL;
|
||||||
|
} else {
|
||||||
|
/* we suppose that malloc aligns to at least four bytes */
|
||||||
|
ptr = malloc(size + 1);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
/* we allocate one more byte to ensure the regions will be
|
||||||
|
separated by at least one byte. With the glibc malloc, it may
|
||||||
|
be in fact not necessary */
|
||||||
|
ptr = memalign(size + 1, align);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
install_malloc_hooks();
|
||||||
|
|
||||||
|
if (!ptr)
|
||||||
|
return NULL;
|
||||||
|
__bound_new_region(ptr, size);
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __bound_free(void *ptr, const void *caller)
|
||||||
|
{
|
||||||
|
if (ptr == NULL)
|
||||||
|
return;
|
||||||
|
if (__bound_delete_region(ptr) != 0)
|
||||||
|
bound_error("freeing invalid region");
|
||||||
|
|
||||||
|
libc_free(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *__bound_realloc(void *ptr, size_t size, const void *caller)
|
||||||
|
{
|
||||||
|
void *ptr1;
|
||||||
|
int old_size;
|
||||||
|
|
||||||
|
if (size == 0) {
|
||||||
|
__bound_free(ptr, caller);
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
ptr1 = __bound_malloc(size, caller);
|
||||||
|
if (ptr == NULL || ptr1 == NULL)
|
||||||
|
return ptr1;
|
||||||
|
old_size = get_region_size(ptr);
|
||||||
|
if (old_size == EMPTY_SIZE)
|
||||||
|
bound_error("realloc'ing invalid pointer");
|
||||||
|
memcpy(ptr1, ptr, old_size);
|
||||||
|
__bound_free(ptr, caller);
|
||||||
|
return ptr1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef CONFIG_TCC_MALLOC_HOOKS
|
||||||
|
void *__bound_calloc(size_t nmemb, size_t size)
|
||||||
|
{
|
||||||
|
void *ptr;
|
||||||
|
size = size * nmemb;
|
||||||
|
ptr = __bound_malloc(size);
|
||||||
|
if (!ptr)
|
||||||
|
return NULL;
|
||||||
|
memset(ptr, 0, size);
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static void bound_dump(void)
|
||||||
|
{
|
||||||
|
BoundEntry *page, *e;
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
printf("region dump:\n");
|
||||||
|
for(i=0;i<BOUND_T1_SIZE;i++) {
|
||||||
|
page = __bound_t1[i];
|
||||||
|
for(j=0;j<BOUND_T2_SIZE;j++) {
|
||||||
|
e = page + j;
|
||||||
|
/* do not print invalid or empty entries */
|
||||||
|
if (e->size != EMPTY_SIZE && e->start != 0) {
|
||||||
|
printf("%08x:",
|
||||||
|
(i << (BOUND_T2_BITS + BOUND_T3_BITS)) +
|
||||||
|
(j << BOUND_T3_BITS));
|
||||||
|
do {
|
||||||
|
printf(" %08lx:%08lx", e->start, e->start + e->size);
|
||||||
|
e = e->next;
|
||||||
|
} while (e != NULL);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* some useful checked functions */
|
||||||
|
|
||||||
|
/* check that (p ... p + size - 1) lies inside 'p' region, if any */
|
||||||
|
static void __bound_check(const void *p, size_t size)
|
||||||
|
{
|
||||||
|
if (size == 0)
|
||||||
|
return;
|
||||||
|
p = __bound_ptr_add((void *)p, size);
|
||||||
|
if (p == INVALID_POINTER)
|
||||||
|
bound_error("invalid pointer");
|
||||||
|
}
|
||||||
|
|
||||||
|
void *__bound_memcpy(void *dst, const void *src, size_t size)
|
||||||
|
{
|
||||||
|
__bound_check(dst, size);
|
||||||
|
__bound_check(src, size);
|
||||||
|
/* check also region overlap */
|
||||||
|
if (src >= dst && src < dst + size)
|
||||||
|
bound_error("overlapping regions in memcpy()");
|
||||||
|
return memcpy(dst, src, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *__bound_memmove(void *dst, const void *src, size_t size)
|
||||||
|
{
|
||||||
|
__bound_check(dst, size);
|
||||||
|
__bound_check(src, size);
|
||||||
|
return memmove(dst, src, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *__bound_memset(void *dst, int c, size_t size)
|
||||||
|
{
|
||||||
|
__bound_check(dst, size);
|
||||||
|
return memset(dst, c, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* XXX: could be optimized */
|
||||||
|
int __bound_strlen(const char *s)
|
||||||
|
{
|
||||||
|
const char *p;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
len = 0;
|
||||||
|
for(;;) {
|
||||||
|
p = __bound_ptr_indir1((char *)s, len);
|
||||||
|
if (p == INVALID_POINTER)
|
||||||
|
bound_error("bad pointer in strlen()");
|
||||||
|
if (*p == '\0')
|
||||||
|
break;
|
||||||
|
len++;
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *__bound_strcpy(char *dst, const char *src)
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
len = __bound_strlen(src);
|
||||||
|
return __bound_memcpy(dst, src, len + 1);
|
||||||
|
}
|
||||||
|
|
||||||
@ -1,6 +1,5 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#define NB_ITS 1000000
|
#define NB_ITS 1000000
|
||||||
//#define NB_ITS 1
|
//#define NB_ITS 1
|
||||||
@ -75,6 +74,7 @@ int test5(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* error */
|
/* error */
|
||||||
|
/* XXX: currently: bug */
|
||||||
int test6(void)
|
int test6(void)
|
||||||
{
|
{
|
||||||
int i, sum = 0;
|
int i, sum = 0;
|
||||||
@ -169,68 +169,8 @@ int test13(void)
|
|||||||
return strlen(tab);
|
return strlen(tab);
|
||||||
}
|
}
|
||||||
|
|
||||||
int test14(void)
|
|
||||||
{
|
|
||||||
char *p = alloca(TAB_SIZE);
|
|
||||||
size_t ret;
|
|
||||||
memset(p, 'a', TAB_SIZE);
|
|
||||||
p[TAB_SIZE-1] = 0;
|
|
||||||
ret = strlen(p);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* error */
|
|
||||||
int test15(void)
|
|
||||||
{
|
|
||||||
char *p = alloca(TAB_SIZE-1);
|
|
||||||
size_t ret;
|
|
||||||
memset(p, 'a', TAB_SIZE);
|
|
||||||
p[TAB_SIZE-1] = 0;
|
|
||||||
ret = strlen(p);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ok */
|
|
||||||
int test16()
|
|
||||||
{
|
|
||||||
char *demo = "This is only a test.";
|
|
||||||
char *p, *q;
|
|
||||||
|
|
||||||
p = alloca(16);
|
|
||||||
strcpy(p,"12345678901234");
|
|
||||||
|
|
||||||
/* Test alloca embedded in a larger expression */
|
|
||||||
printf("alloca : %s : %s\n", p, strcpy(q=alloca(strlen(demo)+1),demo) );
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* error */
|
|
||||||
int test17()
|
|
||||||
{
|
|
||||||
char *demo = "This is only a test.";
|
|
||||||
char *p, *q;
|
|
||||||
|
|
||||||
p = alloca(16);
|
|
||||||
strcpy(p,"12345678901234");
|
|
||||||
|
|
||||||
/* Test alloca embedded in a larger expression */
|
|
||||||
printf("alloca : %s : %s\n", p, strcpy(q=alloca(strlen(demo)),demo) );
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int test18(void)
|
|
||||||
{
|
|
||||||
int i, sum = 0, n = TAB_SIZE;
|
|
||||||
int tab[n];
|
|
||||||
for(i=0;i<TAB_SIZE+1;i++) {
|
|
||||||
sum += tab[i];
|
|
||||||
}
|
|
||||||
return sum;
|
|
||||||
}
|
|
||||||
|
|
||||||
int (*table_test[])(void) = {
|
int (*table_test[])(void) = {
|
||||||
|
test1,
|
||||||
test1,
|
test1,
|
||||||
test2,
|
test2,
|
||||||
test3,
|
test3,
|
||||||
@ -244,46 +184,23 @@ int (*table_test[])(void) = {
|
|||||||
test11,
|
test11,
|
||||||
test12,
|
test12,
|
||||||
test13,
|
test13,
|
||||||
test14,
|
|
||||||
test15,
|
|
||||||
test16,
|
|
||||||
test17,
|
|
||||||
test18
|
|
||||||
};
|
};
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
char *cp;
|
|
||||||
int index;
|
int index;
|
||||||
int (*ftest)(void);
|
int (*ftest)(void);
|
||||||
int index_max = sizeof(table_test)/sizeof(table_test[0]);
|
|
||||||
|
|
||||||
/* check bounds checking main arg */
|
|
||||||
for (i = 0; i < argc; i++) {
|
|
||||||
cp = argv[i];
|
|
||||||
while (*cp) {
|
|
||||||
cp++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
printf(
|
printf("usage: boundtest n\n"
|
||||||
"test TCC bound checking system\n"
|
"test TCC bound checking system\n"
|
||||||
"usage: boundtest N\n"
|
);
|
||||||
" 1 <= N <= %d\n", index_max);
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
index = 0;
|
index = 0;
|
||||||
if (argc >= 2)
|
if (argc >= 2)
|
||||||
index = atoi(argv[1]) - 1;
|
index = atoi(argv[1]);
|
||||||
|
|
||||||
if ((index < 0) || (index >= index_max)) {
|
|
||||||
printf("N is outside of the valid range (%d)\n", index);
|
|
||||||
exit(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* well, we also use bounds on this ! */
|
/* well, we also use bounds on this ! */
|
||||||
ftest = table_test[index];
|
ftest = table_test[index];
|
||||||
ftest();
|
ftest();
|
||||||
125
c67-link.c
125
c67-link.c
@ -1,125 +0,0 @@
|
|||||||
#ifdef TARGET_DEFS_ONLY
|
|
||||||
|
|
||||||
#define EM_TCC_TARGET EM_C60
|
|
||||||
|
|
||||||
/* relocation type for 32 bit data relocation */
|
|
||||||
#define R_DATA_32 R_C60_32
|
|
||||||
#define R_DATA_PTR R_C60_32
|
|
||||||
#define R_JMP_SLOT R_C60_JMP_SLOT
|
|
||||||
#define R_GLOB_DAT R_C60_GLOB_DAT
|
|
||||||
#define R_COPY R_C60_COPY
|
|
||||||
#define R_RELATIVE R_C60_RELATIVE
|
|
||||||
|
|
||||||
#define R_NUM R_C60_NUM
|
|
||||||
|
|
||||||
#define ELF_START_ADDR 0x00000400
|
|
||||||
#define ELF_PAGE_SIZE 0x1000
|
|
||||||
|
|
||||||
#define PCRELATIVE_DLLPLT 0
|
|
||||||
#define RELOCATE_DLLPLT 0
|
|
||||||
|
|
||||||
#else /* !TARGET_DEFS_ONLY */
|
|
||||||
|
|
||||||
#include "tcc.h"
|
|
||||||
|
|
||||||
/* Returns 1 for a code relocation, 0 for a data relocation. For unknown
|
|
||||||
relocations, returns -1. */
|
|
||||||
ST_FUNC int code_reloc (int reloc_type)
|
|
||||||
{
|
|
||||||
switch (reloc_type) {
|
|
||||||
case R_C60_32:
|
|
||||||
case R_C60LO16:
|
|
||||||
case R_C60HI16:
|
|
||||||
case R_C60_GOT32:
|
|
||||||
case R_C60_GOTOFF:
|
|
||||||
case R_C60_GOTPC:
|
|
||||||
case R_C60_COPY:
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case R_C60_PLT32:
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Returns an enumerator to describe whether and when the relocation needs a
|
|
||||||
GOT and/or PLT entry to be created. See tcc.h for a description of the
|
|
||||||
different values. */
|
|
||||||
ST_FUNC int gotplt_entry_type (int reloc_type)
|
|
||||||
{
|
|
||||||
switch (reloc_type) {
|
|
||||||
case R_C60_32:
|
|
||||||
case R_C60LO16:
|
|
||||||
case R_C60HI16:
|
|
||||||
case R_C60_COPY:
|
|
||||||
return NO_GOTPLT_ENTRY;
|
|
||||||
|
|
||||||
case R_C60_GOTOFF:
|
|
||||||
case R_C60_GOTPC:
|
|
||||||
return BUILD_GOT_ONLY;
|
|
||||||
|
|
||||||
case R_C60_PLT32:
|
|
||||||
case R_C60_GOT32:
|
|
||||||
return ALWAYS_GOTPLT_ENTRY;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_attr *attr)
|
|
||||||
{
|
|
||||||
tcc_error_noabort("C67 got not implemented");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* relocate the PLT: compute addresses and offsets in the PLT now that final
|
|
||||||
address for PLT and GOT are known (see fill_program_header) */
|
|
||||||
ST_FUNC void relocate_plt(TCCState *s1)
|
|
||||||
{
|
|
||||||
uint8_t *p, *p_end;
|
|
||||||
|
|
||||||
if (!s1->plt)
|
|
||||||
return;
|
|
||||||
|
|
||||||
p = s1->plt->data;
|
|
||||||
p_end = p + s1->plt->data_offset;
|
|
||||||
|
|
||||||
if (p < p_end) {
|
|
||||||
/* XXX: TODO */
|
|
||||||
while (p < p_end) {
|
|
||||||
/* XXX: TODO */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val)
|
|
||||||
{
|
|
||||||
switch(type) {
|
|
||||||
case R_C60_32:
|
|
||||||
*(int *)ptr += val;
|
|
||||||
break;
|
|
||||||
case R_C60LO16:
|
|
||||||
{
|
|
||||||
uint32_t orig;
|
|
||||||
|
|
||||||
/* put the low 16 bits of the absolute address add to what is
|
|
||||||
already there */
|
|
||||||
orig = ((*(int *)(ptr )) >> 7) & 0xffff;
|
|
||||||
orig |= (((*(int *)(ptr+4)) >> 7) & 0xffff) << 16;
|
|
||||||
|
|
||||||
/* patch both at once - assumes always in pairs Low - High */
|
|
||||||
*(int *) ptr = (*(int *) ptr & (~(0xffff << 7)) ) |
|
|
||||||
(((val+orig) & 0xffff) << 7);
|
|
||||||
*(int *)(ptr+4) = (*(int *)(ptr+4) & (~(0xffff << 7)) ) |
|
|
||||||
((((val+orig)>>16) & 0xffff) << 7);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case R_C60HI16:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fprintf(stderr,"FIXME: handle reloc type %x at %x [%p] to %x\n",
|
|
||||||
type, (unsigned) addr, ptr, (unsigned) val);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* !TARGET_DEFS_ONLY */
|
|
||||||
446
coff.h
446
coff.h
@ -1,446 +0,0 @@
|
|||||||
/**************************************************************************/
|
|
||||||
/* COFF.H */
|
|
||||||
/* COFF data structures and related definitions used by the linker */
|
|
||||||
/**************************************************************************/
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
/* COFF FILE HEADER */
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
struct filehdr {
|
|
||||||
unsigned short f_magic; /* magic number */
|
|
||||||
unsigned short f_nscns; /* number of sections */
|
|
||||||
long f_timdat; /* time & date stamp */
|
|
||||||
long f_symptr; /* file pointer to symtab */
|
|
||||||
long f_nsyms; /* number of symtab entries */
|
|
||||||
unsigned short f_opthdr; /* sizeof(optional hdr) */
|
|
||||||
unsigned short f_flags; /* flags */
|
|
||||||
unsigned short f_TargetID; /* for C6x = 0x0099 */
|
|
||||||
};
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
/* File header flags */
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
#define F_RELFLG 0x01 /* relocation info stripped from file */
|
|
||||||
#define F_EXEC 0x02 /* file is executable (no unresolved refs) */
|
|
||||||
#define F_LNNO 0x04 /* line numbers stripped from file */
|
|
||||||
#define F_LSYMS 0x08 /* local symbols stripped from file */
|
|
||||||
#define F_GSP10 0x10 /* 34010 version */
|
|
||||||
#define F_GSP20 0x20 /* 34020 version */
|
|
||||||
#define F_SWABD 0x40 /* bytes swabbed (in names) */
|
|
||||||
#define F_AR16WR 0x80 /* byte ordering of an AR16WR (PDP-11) */
|
|
||||||
#define F_LITTLE 0x100 /* byte ordering of an AR32WR (vax) */
|
|
||||||
#define F_BIG 0x200 /* byte ordering of an AR32W (3B, maxi) */
|
|
||||||
#define F_PATCH 0x400 /* contains "patch" list in optional header */
|
|
||||||
#define F_NODF 0x400
|
|
||||||
|
|
||||||
#define F_VERSION (F_GSP10 | F_GSP20)
|
|
||||||
#define F_BYTE_ORDER (F_LITTLE | F_BIG)
|
|
||||||
#define FILHDR struct filehdr
|
|
||||||
|
|
||||||
/* #define FILHSZ sizeof(FILHDR) */
|
|
||||||
#define FILHSZ 22 /* above rounds to align on 4 bytes which causes problems */
|
|
||||||
|
|
||||||
#define COFF_C67_MAGIC 0x00c2
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
/* Macros to recognize magic numbers */
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
#define ISMAGIC(x) (((unsigned short)(x))==(unsigned short)magic)
|
|
||||||
#define ISARCHIVE(x) ((((unsigned short)(x))==(unsigned short)ARTYPE))
|
|
||||||
#define BADMAGIC(x) (((unsigned short)(x) & 0x8080) && !ISMAGIC(x))
|
|
||||||
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
/* OPTIONAL FILE HEADER */
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
typedef struct aouthdr {
|
|
||||||
short magic; /* see magic.h */
|
|
||||||
short vstamp; /* version stamp */
|
|
||||||
long tsize; /* text size in bytes, padded to FW bdry*/
|
|
||||||
long dsize; /* initialized data " " */
|
|
||||||
long bsize; /* uninitialized data " " */
|
|
||||||
long entrypt; /* entry pt. */
|
|
||||||
long text_start; /* base of text used for this file */
|
|
||||||
long data_start; /* base of data used for this file */
|
|
||||||
} AOUTHDR;
|
|
||||||
|
|
||||||
#define AOUTSZ sizeof(AOUTHDR)
|
|
||||||
|
|
||||||
/*----------------------------------------------------------------------*/
|
|
||||||
/* When a UNIX aout header is to be built in the optional header, */
|
|
||||||
/* the following magic numbers can appear in that header: */
|
|
||||||
/* */
|
|
||||||
/* AOUT1MAGIC : default : readonly sharable text segment */
|
|
||||||
/* AOUT2MAGIC: : writable text segment */
|
|
||||||
/* PAGEMAGIC : : configured for paging */
|
|
||||||
/*----------------------------------------------------------------------*/
|
|
||||||
#define AOUT1MAGIC 0410
|
|
||||||
#define AOUT2MAGIC 0407
|
|
||||||
#define PAGEMAGIC 0413
|
|
||||||
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
/* COMMON ARCHIVE FILE STRUCTURES */
|
|
||||||
/* */
|
|
||||||
/* ARCHIVE File Organization: */
|
|
||||||
/* _______________________________________________ */
|
|
||||||
/* |__________ARCHIVE_MAGIC_STRING_______________| */
|
|
||||||
/* |__________ARCHIVE_FILE_MEMBER_1______________| */
|
|
||||||
/* | | */
|
|
||||||
/* | Archive File Header "ar_hdr" | */
|
|
||||||
/* |.............................................| */
|
|
||||||
/* | Member Contents | */
|
|
||||||
/* | 1. External symbol directory | */
|
|
||||||
/* | 2. Text file | */
|
|
||||||
/* |_____________________________________________| */
|
|
||||||
/* |________ARCHIVE_FILE_MEMBER_2________________| */
|
|
||||||
/* | "ar_hdr" | */
|
|
||||||
/* |.............................................| */
|
|
||||||
/* | Member Contents (.o or text file) | */
|
|
||||||
/* |_____________________________________________| */
|
|
||||||
/* | . . . | */
|
|
||||||
/* | . . . | */
|
|
||||||
/* | . . . | */
|
|
||||||
/* |_____________________________________________| */
|
|
||||||
/* |________ARCHIVE_FILE_MEMBER_n________________| */
|
|
||||||
/* | "ar_hdr" | */
|
|
||||||
/* |.............................................| */
|
|
||||||
/* | Member Contents | */
|
|
||||||
/* |_____________________________________________| */
|
|
||||||
/* */
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#define COFF_ARMAG "!<arch>\n"
|
|
||||||
#define SARMAG 8
|
|
||||||
#define ARFMAG "`\n"
|
|
||||||
|
|
||||||
struct ar_hdr /* archive file member header - printable ascii */
|
|
||||||
{
|
|
||||||
char ar_name[16]; /* file member name - `/' terminated */
|
|
||||||
char ar_date[12]; /* file member date - decimal */
|
|
||||||
char ar_uid[6]; /* file member user id - decimal */
|
|
||||||
char ar_gid[6]; /* file member group id - decimal */
|
|
||||||
char ar_mode[8]; /* file member mode - octal */
|
|
||||||
char ar_size[10]; /* file member size - decimal */
|
|
||||||
char ar_fmag[2]; /* ARFMAG - string to end header */
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
/* SECTION HEADER */
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
struct scnhdr {
|
|
||||||
char s_name[8]; /* section name */
|
|
||||||
long s_paddr; /* physical address */
|
|
||||||
long s_vaddr; /* virtual address */
|
|
||||||
long s_size; /* section size */
|
|
||||||
long s_scnptr; /* file ptr to raw data for section */
|
|
||||||
long s_relptr; /* file ptr to relocation */
|
|
||||||
long s_lnnoptr; /* file ptr to line numbers */
|
|
||||||
unsigned int s_nreloc; /* number of relocation entries */
|
|
||||||
unsigned int s_nlnno; /* number of line number entries */
|
|
||||||
unsigned int s_flags; /* flags */
|
|
||||||
unsigned short s_reserved; /* reserved byte */
|
|
||||||
unsigned short s_page; /* memory page id */
|
|
||||||
};
|
|
||||||
|
|
||||||
#define SCNHDR struct scnhdr
|
|
||||||
#define SCNHSZ sizeof(SCNHDR)
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
/* Define constants for names of "special" sections */
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
/* #define _TEXT ".text" */
|
|
||||||
#define _DATA ".data"
|
|
||||||
#define _BSS ".bss"
|
|
||||||
#define _CINIT ".cinit"
|
|
||||||
#define _TV ".tv"
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
/* The low 4 bits of s_flags is used as a section "type" */
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
#define STYP_REG 0x00 /* "regular" : allocated, relocated, loaded */
|
|
||||||
#define STYP_DSECT 0x01 /* "dummy" : not allocated, relocated, not loaded */
|
|
||||||
#define STYP_NOLOAD 0x02 /* "noload" : allocated, relocated, not loaded */
|
|
||||||
#define STYP_GROUP 0x04 /* "grouped" : formed of input sections */
|
|
||||||
#define STYP_PAD 0x08 /* "padding" : not allocated, not relocated, loaded */
|
|
||||||
#define STYP_COPY 0x10 /* "copy" : used for C init tables -
|
|
||||||
not allocated, relocated,
|
|
||||||
loaded; reloc & lineno
|
|
||||||
entries processed normally */
|
|
||||||
#define STYP_TEXT 0x20 /* section contains text only */
|
|
||||||
#define STYP_DATA 0x40 /* section contains data only */
|
|
||||||
#define STYP_BSS 0x80 /* section contains bss only */
|
|
||||||
|
|
||||||
#define STYP_ALIGN 0x100 /* align flag passed by old version assemblers */
|
|
||||||
#define ALIGN_MASK 0x0F00 /* part of s_flags that is used for align vals */
|
|
||||||
#define ALIGNSIZE(x) (1 << ((x & ALIGN_MASK) >> 8))
|
|
||||||
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
/* RELOCATION ENTRIES */
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
struct reloc
|
|
||||||
{
|
|
||||||
long r_vaddr; /* (virtual) address of reference */
|
|
||||||
short r_symndx; /* index into symbol table */
|
|
||||||
unsigned short r_disp; /* additional bits for address calculation */
|
|
||||||
unsigned short r_type; /* relocation type */
|
|
||||||
};
|
|
||||||
|
|
||||||
#define RELOC struct reloc
|
|
||||||
#define RELSZ 10 /* sizeof(RELOC) */
|
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------*/
|
|
||||||
/* define all relocation types */
|
|
||||||
/*--------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#define R_ABS 0 /* absolute address - no relocation */
|
|
||||||
#define R_DIR16 01 /* UNUSED */
|
|
||||||
#define R_REL16 02 /* UNUSED */
|
|
||||||
#define R_DIR24 04 /* UNUSED */
|
|
||||||
#define R_REL24 05 /* 24 bits, direct */
|
|
||||||
#define R_DIR32 06 /* UNUSED */
|
|
||||||
#define R_RELBYTE 017 /* 8 bits, direct */
|
|
||||||
#define R_RELWORD 020 /* 16 bits, direct */
|
|
||||||
#define R_RELLONG 021 /* 32 bits, direct */
|
|
||||||
#define R_PCRBYTE 022 /* 8 bits, PC-relative */
|
|
||||||
#define R_PCRWORD 023 /* 16 bits, PC-relative */
|
|
||||||
#define R_PCRLONG 024 /* 32 bits, PC-relative */
|
|
||||||
#define R_OCRLONG 030 /* GSP: 32 bits, one's complement direct */
|
|
||||||
#define R_GSPPCR16 031 /* GSP: 16 bits, PC relative (in words) */
|
|
||||||
#define R_GSPOPR32 032 /* GSP: 32 bits, direct big-endian */
|
|
||||||
#define R_PARTLS16 040 /* Brahma: 16 bit offset of 24 bit address*/
|
|
||||||
#define R_PARTMS8 041 /* Brahma: 8 bit page of 24 bit address */
|
|
||||||
#define R_PARTLS7 050 /* DSP: 7 bit offset of 16 bit address */
|
|
||||||
#define R_PARTMS9 051 /* DSP: 9 bit page of 16 bit address */
|
|
||||||
#define R_REL13 052 /* DSP: 13 bits, direct */
|
|
||||||
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
/* LINE NUMBER ENTRIES */
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
struct lineno
|
|
||||||
{
|
|
||||||
union
|
|
||||||
{
|
|
||||||
long l_symndx ; /* sym. table index of function name
|
|
||||||
iff l_lnno == 0 */
|
|
||||||
long l_paddr ; /* (physical) address of line number */
|
|
||||||
} l_addr ;
|
|
||||||
unsigned short l_lnno ; /* line number */
|
|
||||||
};
|
|
||||||
|
|
||||||
#define LINENO struct lineno
|
|
||||||
#define LINESZ 6 /* sizeof(LINENO) */
|
|
||||||
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
/* STORAGE CLASSES */
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
#define C_EFCN -1 /* physical end of function */
|
|
||||||
#define C_NULL 0
|
|
||||||
#define C_AUTO 1 /* automatic variable */
|
|
||||||
#define C_EXT 2 /* external symbol */
|
|
||||||
#define C_STAT 3 /* static */
|
|
||||||
#define C_REG 4 /* register variable */
|
|
||||||
#define C_EXTDEF 5 /* external definition */
|
|
||||||
#define C_LABEL 6 /* label */
|
|
||||||
#define C_ULABEL 7 /* undefined label */
|
|
||||||
#define C_MOS 8 /* member of structure */
|
|
||||||
#define C_ARG 9 /* function argument */
|
|
||||||
#define C_STRTAG 10 /* structure tag */
|
|
||||||
#define C_MOU 11 /* member of union */
|
|
||||||
#define C_UNTAG 12 /* union tag */
|
|
||||||
#define C_TPDEF 13 /* type definition */
|
|
||||||
#define C_USTATIC 14 /* undefined static */
|
|
||||||
#define C_ENTAG 15 /* enumeration tag */
|
|
||||||
#define C_MOE 16 /* member of enumeration */
|
|
||||||
#define C_REGPARM 17 /* register parameter */
|
|
||||||
#define C_FIELD 18 /* bit field */
|
|
||||||
|
|
||||||
#define C_BLOCK 100 /* ".bb" or ".eb" */
|
|
||||||
#define C_FCN 101 /* ".bf" or ".ef" */
|
|
||||||
#define C_EOS 102 /* end of structure */
|
|
||||||
#define C_FILE 103 /* file name */
|
|
||||||
#define C_LINE 104 /* dummy sclass for line number entry */
|
|
||||||
#define C_ALIAS 105 /* duplicate tag */
|
|
||||||
#define C_HIDDEN 106 /* special storage class for external */
|
|
||||||
/* symbols in dmert public libraries */
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
/* SYMBOL TABLE ENTRIES */
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#define SYMNMLEN 8 /* Number of characters in a symbol name */
|
|
||||||
#define FILNMLEN 14 /* Number of characters in a file name */
|
|
||||||
#define DIMNUM 4 /* Number of array dimensions in auxiliary entry */
|
|
||||||
|
|
||||||
|
|
||||||
struct syment
|
|
||||||
{
|
|
||||||
union
|
|
||||||
{
|
|
||||||
char _n_name[SYMNMLEN]; /* old COFF version */
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
long _n_zeroes; /* new == 0 */
|
|
||||||
long _n_offset; /* offset into string table */
|
|
||||||
} _n_n;
|
|
||||||
char *_n_nptr[2]; /* allows for overlaying */
|
|
||||||
} _n;
|
|
||||||
long n_value; /* value of symbol */
|
|
||||||
short n_scnum; /* section number */
|
|
||||||
unsigned short n_type; /* type and derived type */
|
|
||||||
char n_sclass; /* storage class */
|
|
||||||
char n_numaux; /* number of aux. entries */
|
|
||||||
};
|
|
||||||
|
|
||||||
#define n_name _n._n_name
|
|
||||||
#define n_nptr _n._n_nptr[1]
|
|
||||||
#define n_zeroes _n._n_n._n_zeroes
|
|
||||||
#define n_offset _n._n_n._n_offset
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
/* Relocatable symbols have a section number of the */
|
|
||||||
/* section in which they are defined. Otherwise, section */
|
|
||||||
/* numbers have the following meanings: */
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
#define N_UNDEF 0 /* undefined symbol */
|
|
||||||
#define N_ABS -1 /* value of symbol is absolute */
|
|
||||||
#define N_DEBUG -2 /* special debugging symbol */
|
|
||||||
#define N_TV (unsigned short)-3 /* needs transfer vector (preload) */
|
|
||||||
#define P_TV (unsigned short)-4 /* needs transfer vector (postload) */
|
|
||||||
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
/* The fundamental type of a symbol packed into the low */
|
|
||||||
/* 4 bits of the word. */
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
#define _EF ".ef"
|
|
||||||
|
|
||||||
#define T_NULL 0 /* no type info */
|
|
||||||
#define T_ARG 1 /* function argument (only used by compiler) */
|
|
||||||
#define T_CHAR 2 /* character */
|
|
||||||
#define T_SHORT 3 /* short integer */
|
|
||||||
#define T_INT 4 /* integer */
|
|
||||||
#define T_LONG 5 /* long integer */
|
|
||||||
#define T_FLOAT 6 /* floating point */
|
|
||||||
#define T_DOUBLE 7 /* double word */
|
|
||||||
#define T_STRUCT 8 /* structure */
|
|
||||||
#define T_UNION 9 /* union */
|
|
||||||
#define T_ENUM 10 /* enumeration */
|
|
||||||
#define T_MOE 11 /* member of enumeration */
|
|
||||||
#define T_UCHAR 12 /* unsigned character */
|
|
||||||
#define T_USHORT 13 /* unsigned short */
|
|
||||||
#define T_UINT 14 /* unsigned integer */
|
|
||||||
#define T_ULONG 15 /* unsigned long */
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
/* derived types are: */
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
#define DT_NON 0 /* no derived type */
|
|
||||||
#define DT_PTR 1 /* pointer */
|
|
||||||
#define DT_FCN 2 /* function */
|
|
||||||
#define DT_ARY 3 /* array */
|
|
||||||
|
|
||||||
#define MKTYPE(basic, d1,d2,d3,d4,d5,d6) \
|
|
||||||
((basic) | ((d1) << 4) | ((d2) << 6) | ((d3) << 8) |\
|
|
||||||
((d4) << 10) | ((d5) << 12) | ((d6) << 14))
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
/* type packing constants and macros */
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
#define N_BTMASK_COFF 017
|
|
||||||
#define N_TMASK_COFF 060
|
|
||||||
#define N_TMASK1_COFF 0300
|
|
||||||
#define N_TMASK2_COFF 0360
|
|
||||||
#define N_BTSHFT_COFF 4
|
|
||||||
#define N_TSHIFT_COFF 2
|
|
||||||
|
|
||||||
#define BTYPE_COFF(x) ((x) & N_BTMASK_COFF)
|
|
||||||
#define ISINT(x) (((x) >= T_CHAR && (x) <= T_LONG) || \
|
|
||||||
((x) >= T_UCHAR && (x) <= T_ULONG) || (x) == T_ENUM)
|
|
||||||
#define ISFLT_COFF(x) ((x) == T_DOUBLE || (x) == T_FLOAT)
|
|
||||||
#define ISPTR_COFF(x) (((x) & N_TMASK_COFF) == (DT_PTR << N_BTSHFT_COFF))
|
|
||||||
#define ISFCN_COFF(x) (((x) & N_TMASK_COFF) == (DT_FCN << N_BTSHFT_COFF))
|
|
||||||
#define ISARY_COFF(x) (((x) & N_TMASK_COFF) == (DT_ARY << N_BTSHFT_COFF))
|
|
||||||
#define ISTAG_COFF(x) ((x)==C_STRTAG || (x)==C_UNTAG || (x)==C_ENTAG)
|
|
||||||
|
|
||||||
#define INCREF_COFF(x) ((((x)&~N_BTMASK_COFF)<<N_TSHIFT_COFF)|(DT_PTR<<N_BTSHFT_COFF)|(x&N_BTMASK_COFF))
|
|
||||||
#define DECREF_COFF(x) ((((x)>>N_TSHIFT_COFF)&~N_BTMASK_COFF)|((x)&N_BTMASK_COFF))
|
|
||||||
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
/* AUXILIARY SYMBOL ENTRY */
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
union auxent
|
|
||||||
{
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
long x_tagndx; /* str, un, or enum tag indx */
|
|
||||||
union
|
|
||||||
{
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
unsigned short x_lnno; /* declaration line number */
|
|
||||||
unsigned short x_size; /* str, union, array size */
|
|
||||||
} x_lnsz;
|
|
||||||
long x_fsize; /* size of function */
|
|
||||||
} x_misc;
|
|
||||||
union
|
|
||||||
{
|
|
||||||
struct /* if ISFCN, tag, or .bb */
|
|
||||||
{
|
|
||||||
long x_lnnoptr; /* ptr to fcn line # */
|
|
||||||
long x_endndx; /* entry ndx past block end */
|
|
||||||
} x_fcn;
|
|
||||||
struct /* if ISARY, up to 4 dimen. */
|
|
||||||
{
|
|
||||||
unsigned short x_dimen[DIMNUM];
|
|
||||||
} x_ary;
|
|
||||||
} x_fcnary;
|
|
||||||
unsigned short x_regcount; /* number of registers used by func */
|
|
||||||
} x_sym;
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
char x_fname[FILNMLEN];
|
|
||||||
} x_file;
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
long x_scnlen; /* section length */
|
|
||||||
unsigned short x_nreloc; /* number of relocation entries */
|
|
||||||
unsigned short x_nlinno; /* number of line numbers */
|
|
||||||
} x_scn;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define SYMENT struct syment
|
|
||||||
#define SYMESZ 18 /* sizeof(SYMENT) */
|
|
||||||
|
|
||||||
#define AUXENT union auxent
|
|
||||||
#define AUXESZ 18 /* sizeof(AUXENT) */
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
/* NAMES OF "SPECIAL" SYMBOLS */
|
|
||||||
/*------------------------------------------------------------------------*/
|
|
||||||
#define _STEXT ".text"
|
|
||||||
#define _ETEXT "etext"
|
|
||||||
#define _SDATA ".data"
|
|
||||||
#define _EDATA "edata"
|
|
||||||
#define _SBSS ".bss"
|
|
||||||
#define _END "end"
|
|
||||||
#define _CINITPTR "cinit"
|
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------*/
|
|
||||||
/* ENTRY POINT SYMBOLS */
|
|
||||||
/*--------------------------------------------------------------------------*/
|
|
||||||
#define _START "_start"
|
|
||||||
#define _MAIN "_main"
|
|
||||||
/* _CSTART "_c_int00" (defined in params.h) */
|
|
||||||
|
|
||||||
|
|
||||||
#define _TVORIG "_tvorig"
|
|
||||||
#define _TORIGIN "_torigin"
|
|
||||||
#define _DORIGIN "_dorigin"
|
|
||||||
|
|
||||||
#define _SORIGIN "_sorigin"
|
|
||||||
308
conftest.c
308
conftest.c
@ -1,308 +0,0 @@
|
|||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* with -D C2STR: convert tccdefs.h to C-strings */
|
|
||||||
|
|
||||||
#if C2STR
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
/* replace native host macros by compile-time versions */
|
|
||||||
const char *platform_macros[] = {
|
|
||||||
"__i386__", "TCC_TARGET_I386",
|
|
||||||
"__x86_64__", "TCC_TARGET_X86_64",
|
|
||||||
"_WIN32", "TCC_TARGET_PE",
|
|
||||||
"__arm__", "TCC_TARGET_ARM",
|
|
||||||
"__ARM_EABI__", "TCC_ARM_EABI",
|
|
||||||
"__aarch64__", "TCC_TARGET_ARM64",
|
|
||||||
"__riscv", "TCC_TARGET_RISCV64",
|
|
||||||
"__APPLE__", "TCC_TARGET_MACHO",
|
|
||||||
"__FreeBSD__", "TARGETOS_FreeBSD",
|
|
||||||
"__FreeBSD_kernel__", "TARGETOS_FreeBSD_kernel",
|
|
||||||
"__OpenBSD__", "TARGETOS_OpenBSD",
|
|
||||||
"__NetBSD__", "TARGETOS_NetBSD",
|
|
||||||
"__linux__", "TARGETOS_Linux",
|
|
||||||
"__ANDROID__", "TARGETOS_ANDROID",
|
|
||||||
|
|
||||||
"__SIZEOF_POINTER__", "PTR_SIZE",
|
|
||||||
"__SIZEOF_LONG__", "LONG_SIZE",
|
|
||||||
0
|
|
||||||
};
|
|
||||||
|
|
||||||
int isid(int c)
|
|
||||||
{
|
|
||||||
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
|
|
||||||
|| (c >= '0' && c <= '9') || c == '_';
|
|
||||||
}
|
|
||||||
|
|
||||||
int isspc(int c)
|
|
||||||
{
|
|
||||||
return (unsigned char)c <= ' ' && c != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
|
||||||
{
|
|
||||||
char l[1000], l2[1000], *p, *q, *p0;
|
|
||||||
FILE *fp, *op;
|
|
||||||
int c, e, f, s, cmt, cmt_n;
|
|
||||||
const char *r;
|
|
||||||
|
|
||||||
if (argc < 3)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
fp = fopen(argv[1], "rb");
|
|
||||||
op = fopen(argv[2], "wb");
|
|
||||||
if (!fp || !op) {
|
|
||||||
fprintf(stderr, "c2str: file error\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
cmt = cmt_n = 0;
|
|
||||||
for (;;) {
|
|
||||||
p = l;
|
|
||||||
append:
|
|
||||||
if (fgets(p, sizeof l - (p - l), fp)) {
|
|
||||||
p = strchr(p, 0);
|
|
||||||
while (p > l && isspc(p[-1]))
|
|
||||||
--p;
|
|
||||||
*p = 0;
|
|
||||||
} else if (p == l)
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* check for continuation */
|
|
||||||
if (p > l && p[-1] == '\\') {
|
|
||||||
p[-1] = ' ';
|
|
||||||
goto append;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* count & skip leading spaces */
|
|
||||||
p = l, q = l2, f = 0;
|
|
||||||
while (*p && isspc(*p))
|
|
||||||
++p, ++f;
|
|
||||||
|
|
||||||
/* handle comments */
|
|
||||||
if (p[0] == '/' && cmt == 0) {
|
|
||||||
if (p[1] == '*')
|
|
||||||
cmt = 2;
|
|
||||||
if (p[1] == '/')
|
|
||||||
cmt = 1;
|
|
||||||
}
|
|
||||||
if (cmt) {
|
|
||||||
fprintf(op, "%s", l);
|
|
||||||
if (++cmt_n == 1)
|
|
||||||
fprintf(op, " (converted, do not edit this file)");
|
|
||||||
fprintf(op, "\n");
|
|
||||||
if (cmt == 1)
|
|
||||||
cmt = 0;
|
|
||||||
if (cmt == 2) {
|
|
||||||
p = strchr(l, 0);
|
|
||||||
if (p >= l + 2 && p[-1] == '/' && p[-2] == '*')
|
|
||||||
cmt = 0;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (f < 4) {
|
|
||||||
do {
|
|
||||||
/* replace machine/os macros by compile-time counterparts */
|
|
||||||
for (e = f = 0; (r = platform_macros[f]); f += 2) {
|
|
||||||
c = strlen(r);
|
|
||||||
/* remove 'defined' */
|
|
||||||
//e = memcmp(p, "defined ", 8) ? 0 : 8;
|
|
||||||
if (0 == memcmp(p + e, r, c)) {
|
|
||||||
p += e + c;
|
|
||||||
q = strchr(strcpy(q, platform_macros[f + 1]), 0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
if (r)
|
|
||||||
continue;
|
|
||||||
} while (!!(*q++ = *p++));
|
|
||||||
/* output as is */
|
|
||||||
fprintf(op, "%s\n", l2);
|
|
||||||
continue;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
s = e = f = 0, p0 = p;
|
|
||||||
for (;;) {
|
|
||||||
c = *p++;
|
|
||||||
|
|
||||||
if (isspc(c)) {
|
|
||||||
s = 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == '/' && (p[0] == '/' || p[0] == '*'))
|
|
||||||
c = 0; /* trailing comment detected */
|
|
||||||
else if (s && q > l2
|
|
||||||
&& ((isid(q[-1]) && isid(c))
|
|
||||||
// keep space after macro name
|
|
||||||
|| (q >= l2 + 2
|
|
||||||
&& l2[0] == '#'
|
|
||||||
&& l2[1] == 'd'
|
|
||||||
&& f < 2 && !e
|
|
||||||
)))
|
|
||||||
*q++ = ' ', ++f;
|
|
||||||
s = 0;
|
|
||||||
|
|
||||||
if (c == '(')
|
|
||||||
++e;
|
|
||||||
if (c == ')')
|
|
||||||
--e;
|
|
||||||
if (c == '\\' || c == '\"')
|
|
||||||
*q++ = '\\';
|
|
||||||
*q++ = c;
|
|
||||||
if (c == 0)
|
|
||||||
break;
|
|
||||||
p0 = p;
|
|
||||||
}
|
|
||||||
/* output with quotes */
|
|
||||||
fprintf(op, " \"%s\\n\"%s\n", l2, p0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(fp);
|
|
||||||
fclose(op);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
/* get some information from the host compiler for configure */
|
|
||||||
|
|
||||||
#elif 1
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#if defined(_WIN32)
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <io.h>
|
|
||||||
int _CRT_glob = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Define architecture */
|
|
||||||
#if defined(__i386__) || defined _M_IX86
|
|
||||||
# define TRIPLET_ARCH "i386"
|
|
||||||
#elif defined(__x86_64__) || defined _M_AMD64
|
|
||||||
# define TRIPLET_ARCH "x86_64"
|
|
||||||
#elif defined(__arm__)
|
|
||||||
# define TRIPLET_ARCH "arm"
|
|
||||||
#elif defined(__aarch64__)
|
|
||||||
# define TRIPLET_ARCH "aarch64"
|
|
||||||
#elif defined(__riscv) && defined(__LP64__)
|
|
||||||
# define TRIPLET_ARCH "riscv64"
|
|
||||||
#else
|
|
||||||
# define TRIPLET_ARCH "unknown"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Define OS */
|
|
||||||
#if defined (__linux__)
|
|
||||||
# define TRIPLET_OS "linux"
|
|
||||||
#elif defined (__FreeBSD__) || defined (__FreeBSD_kernel__)
|
|
||||||
# define TRIPLET_OS "kfreebsd"
|
|
||||||
#elif defined(__NetBSD__)
|
|
||||||
# define TRIPLET_OS "netbsd"
|
|
||||||
#elif defined(__OpenBSD__)
|
|
||||||
# define TRIPLET_OS "openbsd"
|
|
||||||
#elif defined(_WIN32)
|
|
||||||
# define TRIPLET_OS "win32"
|
|
||||||
#elif defined(__APPLE__)
|
|
||||||
# define TRIPLET_OS "darwin"
|
|
||||||
#elif !defined (__GNU__)
|
|
||||||
# define TRIPLET_OS "unknown"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined __ANDROID__
|
|
||||||
# define ABI_PREFIX "android"
|
|
||||||
#else
|
|
||||||
# define ABI_PREFIX "gnu"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Define calling convention and ABI */
|
|
||||||
#if defined (__ARM_EABI__)
|
|
||||||
# if defined (__ARM_PCS_VFP)
|
|
||||||
# define TRIPLET_ABI ABI_PREFIX"eabihf"
|
|
||||||
# else
|
|
||||||
# define TRIPLET_ABI ABI_PREFIX"eabi"
|
|
||||||
# endif
|
|
||||||
#else
|
|
||||||
# define TRIPLET_ABI ABI_PREFIX
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined _WIN32
|
|
||||||
# define TRIPLET TRIPLET_ARCH "-" TRIPLET_OS
|
|
||||||
#elif defined __GNU__
|
|
||||||
# define TRIPLET TRIPLET_ARCH "-" TRIPLET_ABI
|
|
||||||
#else
|
|
||||||
# define TRIPLET TRIPLET_ARCH "-" TRIPLET_OS "-" TRIPLET_ABI
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
#if defined(_WIN32)
|
|
||||||
_setmode(_fileno(stdout), _O_BINARY); /* don't translate \n to \r\n */
|
|
||||||
#endif
|
|
||||||
switch(argc == 2 ? argv[1][0] : 0) {
|
|
||||||
case 'b'://igendian
|
|
||||||
{
|
|
||||||
volatile unsigned foo = 0x01234567;
|
|
||||||
puts(*(unsigned char*)&foo == 0x67 ? "no" : "yes");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#if defined(__clang__)
|
|
||||||
case 'm'://inor
|
|
||||||
printf("%d\n", __clang_minor__);
|
|
||||||
break;
|
|
||||||
case 'v'://ersion
|
|
||||||
printf("%d\n", __clang_major__);
|
|
||||||
break;
|
|
||||||
#elif defined(__TINYC__)
|
|
||||||
case 'v'://ersion
|
|
||||||
puts("0");
|
|
||||||
break;
|
|
||||||
case 'm'://inor
|
|
||||||
printf("%d\n", __TINYC__);
|
|
||||||
break;
|
|
||||||
#elif defined(_MSC_VER)
|
|
||||||
case 'v'://ersion
|
|
||||||
puts("0");
|
|
||||||
break;
|
|
||||||
case 'm'://inor
|
|
||||||
printf("%d\n", _MSC_VER);
|
|
||||||
break;
|
|
||||||
#elif defined(__GNUC__) && defined(__GNUC_MINOR__)
|
|
||||||
/* GNU comes last as other compilers may add 'GNU' compatibility */
|
|
||||||
case 'm'://inor
|
|
||||||
printf("%d\n", __GNUC_MINOR__);
|
|
||||||
break;
|
|
||||||
case 'v'://ersion
|
|
||||||
printf("%d\n", __GNUC__);
|
|
||||||
break;
|
|
||||||
#else
|
|
||||||
case 'm'://inor
|
|
||||||
case 'v'://ersion
|
|
||||||
puts("0");
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
case 't'://riplet
|
|
||||||
puts(TRIPLET);
|
|
||||||
break;
|
|
||||||
case 'c'://ompiler
|
|
||||||
#if defined(__clang__)
|
|
||||||
puts("clang");
|
|
||||||
#elif defined(__TINYC__)
|
|
||||||
puts("tcc");
|
|
||||||
#elif defined(_MSC_VER)
|
|
||||||
puts("msvc");
|
|
||||||
#elif defined(__GNUC__)
|
|
||||||
puts("gcc");
|
|
||||||
#else
|
|
||||||
puts("unknown");
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------- */
|
|
||||||
#endif
|
|
||||||
@ -1,7 +1,7 @@
|
|||||||
#!/usr/local/bin/tcc -run
|
#! /usr/local/bin/tcc -run
|
||||||
#include <tcclib.h>
|
#include <tcclib.h>
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
printf("Hello World\n");
|
printf("Hello World\n");
|
||||||
return 0;
|
return 0;
|
||||||
@ -1,5 +1,4 @@
|
|||||||
#include <stdlib.h>
|
#include "tcclib.h"
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#define N 20
|
#define N 20
|
||||||
|
|
||||||
@ -24,7 +23,7 @@ int find(int n, int i1, int a, int b, int op)
|
|||||||
return 1;
|
return 1;
|
||||||
tab[i1] = n;
|
tab[i1] = n;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(i=0;i<nb_num;i++) {
|
for(i=0;i<nb_num;i++) {
|
||||||
for(j=i+1;j<nb_num;j++) {
|
for(j=i+1;j<nb_num;j++) {
|
||||||
a = tab[i];
|
a = tab[i];
|
||||||
@ -53,7 +52,7 @@ int find(int n, int i1, int a, int b, int op)
|
|||||||
if (find(c, i, b, a, '/'))
|
if (find(c, i, b, a, '/'))
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
stack_ptr--;
|
stack_ptr--;
|
||||||
tab[i] = a;
|
tab[i] = a;
|
||||||
tab[j] = b;
|
tab[j] = b;
|
||||||
@ -67,7 +66,7 @@ int find(int n, int i1, int a, int b, int op)
|
|||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int i, res, p;
|
int i, res, p;
|
||||||
|
|
||||||
if (argc < 3) {
|
if (argc < 3) {
|
||||||
printf("usage: %s: result numbers...\n"
|
printf("usage: %s: result numbers...\n"
|
||||||
"Try to find result from numbers with the 4 basic operations.\n", argv[0]);
|
"Try to find result from numbers with the 4 basic operations.\n", argv[0]);
|
||||||
@ -86,7 +85,7 @@ int main(int argc, char **argv)
|
|||||||
res = find(0, 0, 0, 0, ' ');
|
res = find(0, 0, 0, 0, ' ');
|
||||||
if (res) {
|
if (res) {
|
||||||
for(i=0;i<=stack_ptr;i++) {
|
for(i=0;i<=stack_ptr;i++) {
|
||||||
printf("%d %c %d = %d\n",
|
printf("%d %c %d = %d\n",
|
||||||
stack_res[3*i], stack_op[i],
|
stack_res[3*i], stack_op[i],
|
||||||
stack_res[3*i+1], stack_res[3*i+2]);
|
stack_res[3*i+1], stack_res[3*i+2]);
|
||||||
}
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
#include <tcclib.h>
|
#include <tcclib.h>
|
||||||
|
|
||||||
int fib(int n)
|
int fib(n)
|
||||||
{
|
{
|
||||||
if (n <= 2)
|
if (n <= 2)
|
||||||
return 1;
|
return 1;
|
||||||
@ -8,7 +8,7 @@ int fib(int n)
|
|||||||
return fib(n-1) + fib(n-2);
|
return fib(n-1) + fib(n-2);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int n;
|
int n;
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
@ -16,8 +16,8 @@ int main(int argc, char **argv)
|
|||||||
"Compute nth Fibonacci number\n");
|
"Compute nth Fibonacci number\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
n = atoi(argv[1]);
|
n = atoi(argv[1]);
|
||||||
printf("fib(%d) = %d\n", n, fib(n));
|
printf("fib(%d) = %d\n", n, fib(n, 2));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1,10 +1,9 @@
|
|||||||
#!/usr/local/bin/tcc -run -L/usr/X11R6/lib -lX11
|
#!./tcc -run -L/usr/X11R6/lib -lX11
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
/* Yes, TCC can use X11 too ! */
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
|
|
||||||
/* Yes, TCC can use X11 too ! */
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
Display *display;
|
Display *display;
|
||||||
@ -17,8 +16,8 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
printf("X11 display opened.\n");
|
printf("X11 display opened.\n");
|
||||||
screen = XScreenOfDisplay(display, 0);
|
screen = XScreenOfDisplay(display, 0);
|
||||||
printf("width = %d\nheight = %d\ndepth = %d\n",
|
printf("width = %d\nheight = %d\ndepth = %d\n",
|
||||||
screen->width,
|
screen->width,
|
||||||
screen->height,
|
screen->height,
|
||||||
screen->root_depth);
|
screen->root_depth);
|
||||||
XCloseDisplay(display);
|
XCloseDisplay(display);
|
||||||
@ -1,7 +1,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
printf("Hello World\n");
|
printf("Hello World\n");
|
||||||
return 0;
|
return 0;
|
||||||
@ -27,7 +27,7 @@
|
|||||||
#define DBL_MAX_10_EXP 308
|
#define DBL_MAX_10_EXP 308
|
||||||
|
|
||||||
/* horrible intel long double */
|
/* horrible intel long double */
|
||||||
#if defined __i386__ || defined __x86_64__
|
#ifdef __i386__
|
||||||
|
|
||||||
#define LDBL_MANT_DIG 64
|
#define LDBL_MANT_DIG 64
|
||||||
#define LDBL_DIG 18
|
#define LDBL_DIG 18
|
||||||
@ -38,37 +38,19 @@
|
|||||||
#define LDBL_MAX_EXP 16384
|
#define LDBL_MAX_EXP 16384
|
||||||
#define LDBL_MAX 1.18973149535723176502e+4932L
|
#define LDBL_MAX 1.18973149535723176502e+4932L
|
||||||
#define LDBL_MAX_10_EXP 4932
|
#define LDBL_MAX_10_EXP 4932
|
||||||
#define DECIMAL_DIG 21
|
|
||||||
|
|
||||||
#elif defined __aarch64__ || defined __riscv
|
|
||||||
/*
|
|
||||||
* Use values from:
|
|
||||||
* gcc -dM -E -xc /dev/null | grep LDBL | sed -e "s/__//g"
|
|
||||||
*/
|
|
||||||
#define LDBL_MANT_DIG 113
|
|
||||||
#define LDBL_DIG 33
|
|
||||||
#define LDBL_EPSILON 1.92592994438723585305597794258492732e-34L
|
|
||||||
#define LDBL_MIN_EXP (-16381)
|
|
||||||
#define LDBL_MIN 3.36210314311209350626267781732175260e-4932L
|
|
||||||
#define LDBL_MIN_10_EXP (-4931)
|
|
||||||
#define LDBL_MAX_EXP 16384
|
|
||||||
#define LDBL_MAX 1.18973149535723176508575932662800702e+4932L
|
|
||||||
#define LDBL_MAX_10_EXP 4932
|
|
||||||
#define DECIMAL_DIG 36
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
/* same as IEEE double */
|
/* same as IEEE double */
|
||||||
#define LDBL_MANT_DIG 53
|
#define LDBL_MANT_DIG 53
|
||||||
#define LDBL_DIG 15
|
#define LDBL_DIG 15
|
||||||
#define LDBL_EPSILON 2.2204460492503131e-16L
|
#define LDBL_EPSILON 2.2204460492503131e-16
|
||||||
#define LDBL_MIN_EXP (-1021)
|
#define LDBL_MIN_EXP (-1021)
|
||||||
#define LDBL_MIN 2.2250738585072014e-308L
|
#define LDBL_MIN 2.2250738585072014e-308
|
||||||
#define LDBL_MIN_10_EXP (-307)
|
#define LDBL_MIN_10_EXP (-307)
|
||||||
#define LDBL_MAX_EXP 1024
|
#define LDBL_MAX_EXP 1024
|
||||||
#define LDBL_MAX 1.7976931348623157e+308L
|
#define LDBL_MAX 1.7976931348623157e+308
|
||||||
#define LDBL_MAX_10_EXP 308
|
#define LDBL_MAX_10_EXP 308
|
||||||
#define DECIMAL_DIG 17
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
33
gcctestsuite.sh
Executable file
33
gcctestsuite.sh
Executable file
@ -0,0 +1,33 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
TESTSUITE_PATH=$HOME/gcc/gcc-3.2/gcc/testsuite/gcc.c-torture
|
||||||
|
TCC="./tcc -B. -I. -DNO_TRAMPOLINES"
|
||||||
|
rm -f tcc.sum tcc.log
|
||||||
|
nb_failed="0"
|
||||||
|
|
||||||
|
for src in $TESTSUITE_PATH/compile/*.c ; do
|
||||||
|
echo $TCC -o /tmp/test.o -c $src
|
||||||
|
$TCC -o /tmp/test.o -c $src >> tcc.log 2>&1
|
||||||
|
if [ "$?" == "0" ] ; then
|
||||||
|
result="PASS"
|
||||||
|
else
|
||||||
|
result="FAIL"
|
||||||
|
nb_failed=$[ $nb_failed + 1 ]
|
||||||
|
fi
|
||||||
|
echo "$result: $src" >> tcc.sum
|
||||||
|
done
|
||||||
|
|
||||||
|
for src in $TESTSUITE_PATH/execute/*.c ; do
|
||||||
|
echo $TCC $src
|
||||||
|
$TCC $src >> tcc.log 2>&1
|
||||||
|
if [ "$?" == "0" ] ; then
|
||||||
|
result="PASS"
|
||||||
|
else
|
||||||
|
result="FAIL"
|
||||||
|
nb_failed=$[ $nb_failed + 1 ]
|
||||||
|
fi
|
||||||
|
echo "$result: $src" >> tcc.sum
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "$nb_failed test(s) failed." >> tcc.sum
|
||||||
|
echo "$nb_failed test(s) failed."
|
||||||
1460
i386-asm.c
1460
i386-asm.c
File diff suppressed because it is too large
Load Diff
372
i386-asm.h
372
i386-asm.h
@ -1,12 +1,12 @@
|
|||||||
DEF_ASM_OP0(clc, 0xf8) /* must be first OP0 */
|
DEF_ASM_OP0(pusha, 0x60) /* must be first OP0 */
|
||||||
|
DEF_ASM_OP0(popa, 0x61)
|
||||||
|
DEF_ASM_OP0(clc, 0xf8)
|
||||||
DEF_ASM_OP0(cld, 0xfc)
|
DEF_ASM_OP0(cld, 0xfc)
|
||||||
DEF_ASM_OP0(cli, 0xfa)
|
DEF_ASM_OP0(cli, 0xfa)
|
||||||
DEF_ASM_OP0(clts, 0x0f06)
|
DEF_ASM_OP0(clts, 0x0f06)
|
||||||
DEF_ASM_OP0(cmc, 0xf5)
|
DEF_ASM_OP0(cmc, 0xf5)
|
||||||
DEF_ASM_OP0(lahf, 0x9f)
|
DEF_ASM_OP0(lahf, 0x9f)
|
||||||
DEF_ASM_OP0(sahf, 0x9e)
|
DEF_ASM_OP0(sahf, 0x9e)
|
||||||
DEF_ASM_OP0(pusha, 0x60)
|
|
||||||
DEF_ASM_OP0(popa, 0x61)
|
|
||||||
DEF_ASM_OP0(pushfl, 0x9c)
|
DEF_ASM_OP0(pushfl, 0x9c)
|
||||||
DEF_ASM_OP0(popfl, 0x9d)
|
DEF_ASM_OP0(popfl, 0x9d)
|
||||||
DEF_ASM_OP0(pushf, 0x9c)
|
DEF_ASM_OP0(pushf, 0x9c)
|
||||||
@ -33,60 +33,50 @@
|
|||||||
DEF_ASM_OP0(iret, 0xcf)
|
DEF_ASM_OP0(iret, 0xcf)
|
||||||
DEF_ASM_OP0(rsm, 0x0faa)
|
DEF_ASM_OP0(rsm, 0x0faa)
|
||||||
DEF_ASM_OP0(hlt, 0xf4)
|
DEF_ASM_OP0(hlt, 0xf4)
|
||||||
|
DEF_ASM_OP0(wait, 0x9b)
|
||||||
DEF_ASM_OP0(nop, 0x90)
|
DEF_ASM_OP0(nop, 0x90)
|
||||||
DEF_ASM_OP0(pause, 0xf390)
|
|
||||||
DEF_ASM_OP0(xlat, 0xd7)
|
DEF_ASM_OP0(xlat, 0xd7)
|
||||||
|
|
||||||
/* Control-Flow Enforcement */
|
/* strings */
|
||||||
DEF_ASM_OP0L(endbr32, 0xf30f1e, 7, OPC_MODRM)
|
ALT(DEF_ASM_OP0L(cmpsb, 0xa6, 0, OPC_BWL))
|
||||||
|
ALT(DEF_ASM_OP0L(scmpb, 0xa6, 0, OPC_BWL))
|
||||||
/* strings */
|
|
||||||
ALT(DEF_ASM_OP0L(cmpsb, 0xa6, 0, OPC_BWLX))
|
|
||||||
ALT(DEF_ASM_OP0L(scmpb, 0xa6, 0, OPC_BWLX))
|
|
||||||
|
|
||||||
ALT(DEF_ASM_OP0L(insb, 0x6c, 0, OPC_BWL))
|
ALT(DEF_ASM_OP0L(insb, 0x6c, 0, OPC_BWL))
|
||||||
ALT(DEF_ASM_OP0L(outsb, 0x6e, 0, OPC_BWL))
|
ALT(DEF_ASM_OP0L(outsb, 0x6e, 0, OPC_BWL))
|
||||||
|
|
||||||
ALT(DEF_ASM_OP0L(lodsb, 0xac, 0, OPC_BWLX))
|
ALT(DEF_ASM_OP0L(lodsb, 0xac, 0, OPC_BWL))
|
||||||
ALT(DEF_ASM_OP0L(slodb, 0xac, 0, OPC_BWLX))
|
ALT(DEF_ASM_OP0L(slodb, 0xac, 0, OPC_BWL))
|
||||||
|
|
||||||
ALT(DEF_ASM_OP0L(movsb, 0xa4, 0, OPC_BWLX))
|
ALT(DEF_ASM_OP0L(movsb, 0xa4, 0, OPC_BWL))
|
||||||
ALT(DEF_ASM_OP0L(smovb, 0xa4, 0, OPC_BWLX))
|
ALT(DEF_ASM_OP0L(smovb, 0xa4, 0, OPC_BWL))
|
||||||
|
|
||||||
ALT(DEF_ASM_OP0L(scasb, 0xae, 0, OPC_BWLX))
|
ALT(DEF_ASM_OP0L(scasb, 0xae, 0, OPC_BWL))
|
||||||
ALT(DEF_ASM_OP0L(sscab, 0xae, 0, OPC_BWLX))
|
ALT(DEF_ASM_OP0L(sscab, 0xae, 0, OPC_BWL))
|
||||||
|
|
||||||
ALT(DEF_ASM_OP0L(stosb, 0xaa, 0, OPC_BWLX))
|
ALT(DEF_ASM_OP0L(stosb, 0xaa, 0, OPC_BWL))
|
||||||
ALT(DEF_ASM_OP0L(sstob, 0xaa, 0, OPC_BWLX))
|
ALT(DEF_ASM_OP0L(sstob, 0xaa, 0, OPC_BWL))
|
||||||
|
|
||||||
/* bits */
|
/* bits */
|
||||||
|
|
||||||
ALT(DEF_ASM_OP2(bsfw, 0x0fbc, 0, OPC_MODRM | OPC_WLX, OPT_REGW | OPT_EA, OPT_REGW))
|
ALT(DEF_ASM_OP2(bsfw, 0x0fbc, 0, OPC_MODRM | OPC_WL, OPT_REGW | OPT_EA, OPT_REGW))
|
||||||
ALT(DEF_ASM_OP2(bsrw, 0x0fbd, 0, OPC_MODRM | OPC_WLX, OPT_REGW | OPT_EA, OPT_REGW))
|
ALT(DEF_ASM_OP2(bsrw, 0x0fbd, 0, OPC_MODRM | OPC_WL, OPT_REGW | OPT_EA, OPT_REGW))
|
||||||
|
|
||||||
ALT(DEF_ASM_OP2(btw, 0x0fa3, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_REGW | OPT_EA))
|
ALT(DEF_ASM_OP2(btw, 0x0fa3, 0, OPC_MODRM | OPC_WL, OPT_REGW, OPT_REGW | OPT_EA))
|
||||||
ALT(DEF_ASM_OP2(btw, 0x0fba, 4, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW | OPT_EA))
|
ALT(DEF_ASM_OP2(btw, 0x0fba, 4, OPC_MODRM | OPC_WL, OPT_IM8, OPT_REGW | OPT_EA))
|
||||||
|
|
||||||
ALT(DEF_ASM_OP2(btsw, 0x0fab, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_REGW | OPT_EA))
|
ALT(DEF_ASM_OP2(btsw, 0x0fab, 0, OPC_MODRM | OPC_WL, OPT_REGW, OPT_REGW | OPT_EA))
|
||||||
ALT(DEF_ASM_OP2(btsw, 0x0fba, 5, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW | OPT_EA))
|
ALT(DEF_ASM_OP2(btsw, 0x0fba, 5, OPC_MODRM | OPC_WL, OPT_IM8, OPT_REGW | OPT_EA))
|
||||||
|
|
||||||
ALT(DEF_ASM_OP2(btrw, 0x0fb3, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_REGW | OPT_EA))
|
ALT(DEF_ASM_OP2(btrw, 0x0fb3, 0, OPC_MODRM | OPC_WL, OPT_REGW, OPT_REGW | OPT_EA))
|
||||||
ALT(DEF_ASM_OP2(btrw, 0x0fba, 6, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW | OPT_EA))
|
ALT(DEF_ASM_OP2(btrw, 0x0fba, 6, OPC_MODRM | OPC_WL, OPT_IM8, OPT_REGW | OPT_EA))
|
||||||
|
|
||||||
ALT(DEF_ASM_OP2(btcw, 0x0fbb, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_REGW | OPT_EA))
|
ALT(DEF_ASM_OP2(btcw, 0x0fbb, 0, OPC_MODRM | OPC_WL, OPT_REGW, OPT_REGW | OPT_EA))
|
||||||
ALT(DEF_ASM_OP2(btcw, 0x0fba, 7, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW | OPT_EA))
|
ALT(DEF_ASM_OP2(btcw, 0x0fba, 7, OPC_MODRM | OPC_WL, OPT_IM8, OPT_REGW | OPT_EA))
|
||||||
|
|
||||||
ALT(DEF_ASM_OP2(popcntw, 0xf30fb8, 0, OPC_MODRM | OPC_WLX, OPT_REGW | OPT_EA, OPT_REGW))
|
|
||||||
|
|
||||||
ALT(DEF_ASM_OP2(tzcntw, 0xf30fbc, 0, OPC_MODRM | OPC_WLX, OPT_REGW | OPT_EA, OPT_REGW))
|
|
||||||
ALT(DEF_ASM_OP2(lzcntw, 0xf30fbd, 0, OPC_MODRM | OPC_WLX, OPT_REGW | OPT_EA, OPT_REGW))
|
|
||||||
|
|
||||||
/* prefixes */
|
/* prefixes */
|
||||||
DEF_ASM_OP0(wait, 0x9b)
|
|
||||||
DEF_ASM_OP0(fwait, 0x9b)
|
|
||||||
DEF_ASM_OP0(aword, 0x67)
|
DEF_ASM_OP0(aword, 0x67)
|
||||||
DEF_ASM_OP0(addr16, 0x67)
|
DEF_ASM_OP0(addr16, 0x67)
|
||||||
ALT(DEF_ASM_OP0(word, 0x66))
|
DEF_ASM_OP0(word, 0x66)
|
||||||
DEF_ASM_OP0(data16, 0x66)
|
DEF_ASM_OP0(data16, 0x66)
|
||||||
DEF_ASM_OP0(lock, 0xf0)
|
DEF_ASM_OP0(lock, 0xf0)
|
||||||
DEF_ASM_OP0(rep, 0xf3)
|
DEF_ASM_OP0(rep, 0xf3)
|
||||||
@ -105,43 +95,43 @@ ALT(DEF_ASM_OP2(lzcntw, 0xf30fbd, 0, OPC_MODRM | OPC_WLX, OPT_REGW | OPT_EA, OPT
|
|||||||
DEF_ASM_OP0(ud2, 0x0f0b)
|
DEF_ASM_OP0(ud2, 0x0f0b)
|
||||||
|
|
||||||
/* NOTE: we took the same order as gas opcode definition order */
|
/* NOTE: we took the same order as gas opcode definition order */
|
||||||
ALT(DEF_ASM_OP2(movb, 0xa0, 0, OPC_BWLX, OPT_ADDR, OPT_EAX))
|
ALT(DEF_ASM_OP2(movb, 0xa0, 0, OPC_BWL, OPT_ADDR, OPT_EAX))
|
||||||
ALT(DEF_ASM_OP2(movb, 0xa2, 0, OPC_BWLX, OPT_EAX, OPT_ADDR))
|
ALT(DEF_ASM_OP2(movb, 0xa2, 0, OPC_BWL, OPT_EAX, OPT_ADDR))
|
||||||
ALT(DEF_ASM_OP2(movb, 0x88, 0, OPC_MODRM | OPC_BWLX, OPT_REG, OPT_EA | OPT_REG))
|
ALT(DEF_ASM_OP2(movb, 0x88, 0, OPC_MODRM | OPC_BWL, OPT_REG, OPT_EA | OPT_REG))
|
||||||
ALT(DEF_ASM_OP2(movb, 0x8a, 0, OPC_MODRM | OPC_BWLX, OPT_EA | OPT_REG, OPT_REG))
|
ALT(DEF_ASM_OP2(movb, 0x8a, 0, OPC_MODRM | OPC_BWL, OPT_EA | OPT_REG, OPT_REG))
|
||||||
ALT(DEF_ASM_OP2(movb, 0xb0, 0, OPC_REG | OPC_BWLX, OPT_IM, OPT_REG))
|
ALT(DEF_ASM_OP2(movb, 0xb0, 0, OPC_REG | OPC_BWL, OPT_IM, OPT_REG))
|
||||||
ALT(DEF_ASM_OP2(movb, 0xc6, 0, OPC_MODRM | OPC_BWLX, OPT_IM, OPT_REG | OPT_EA))
|
ALT(DEF_ASM_OP2(movb, 0xc6, 0, OPC_MODRM | OPC_BWL, OPT_IM, OPT_REG | OPT_EA))
|
||||||
|
|
||||||
ALT(DEF_ASM_OP2(movw, 0x8c, 0, OPC_MODRM | OPC_WLX, OPT_SEG, OPT_EA | OPT_REG))
|
ALT(DEF_ASM_OP2(movw, 0x8c, 0, OPC_MODRM | OPC_WL, OPT_SEG, OPT_EA | OPT_REG))
|
||||||
ALT(DEF_ASM_OP2(movw, 0x8e, 0, OPC_MODRM | OPC_WLX, OPT_EA | OPT_REG, OPT_SEG))
|
ALT(DEF_ASM_OP2(movw, 0x8e, 0, OPC_MODRM | OPC_WL, OPT_EA | OPT_REG, OPT_SEG))
|
||||||
|
|
||||||
ALT(DEF_ASM_OP2(movw, 0x0f20, 0, OPC_MODRM | OPC_WLX, OPT_CR, OPT_REG32))
|
ALT(DEF_ASM_OP2(movw, 0x0f20, 0, OPC_MODRM | OPC_WL, OPT_CR, OPT_REG32))
|
||||||
ALT(DEF_ASM_OP2(movw, 0x0f21, 0, OPC_MODRM | OPC_WLX, OPT_DB, OPT_REG32))
|
ALT(DEF_ASM_OP2(movw, 0x0f21, 0, OPC_MODRM | OPC_WL, OPT_DB, OPT_REG32))
|
||||||
ALT(DEF_ASM_OP2(movw, 0x0f24, 0, OPC_MODRM | OPC_WLX, OPT_TR, OPT_REG32))
|
ALT(DEF_ASM_OP2(movw, 0x0f24, 0, OPC_MODRM | OPC_WL, OPT_TR, OPT_REG32))
|
||||||
ALT(DEF_ASM_OP2(movw, 0x0f22, 0, OPC_MODRM | OPC_WLX, OPT_REG32, OPT_CR))
|
ALT(DEF_ASM_OP2(movw, 0x0f22, 0, OPC_MODRM | OPC_WL, OPT_REG32, OPT_CR))
|
||||||
ALT(DEF_ASM_OP2(movw, 0x0f23, 0, OPC_MODRM | OPC_WLX, OPT_REG32, OPT_DB))
|
ALT(DEF_ASM_OP2(movw, 0x0f23, 0, OPC_MODRM | OPC_WL, OPT_REG32, OPT_DB))
|
||||||
ALT(DEF_ASM_OP2(movw, 0x0f26, 0, OPC_MODRM | OPC_WLX, OPT_REG32, OPT_TR))
|
ALT(DEF_ASM_OP2(movw, 0x0f26, 0, OPC_MODRM | OPC_WL, OPT_REG32, OPT_TR))
|
||||||
|
|
||||||
ALT(DEF_ASM_OP2(movsbl, 0x0fbe, 0, OPC_MODRM, OPT_REG8 | OPT_EA, OPT_REG32))
|
ALT(DEF_ASM_OP2(movsbl, 0x0fbe, 0, OPC_MODRM, OPT_REG8 | OPT_EA, OPT_REG32))
|
||||||
ALT(DEF_ASM_OP2(movsbw, 0x660fbe, 0, OPC_MODRM, OPT_REG8 | OPT_EA, OPT_REG16))
|
ALT(DEF_ASM_OP2(movsbw, 0x0fbe, 0, OPC_MODRM | OPC_D16, OPT_REG8 | OPT_EA, OPT_REG16))
|
||||||
ALT(DEF_ASM_OP2(movswl, 0x0fbf, 0, OPC_MODRM, OPT_REG16 | OPT_EA, OPT_REG32))
|
ALT(DEF_ASM_OP2(movswl, 0x0fbf, 0, OPC_MODRM, OPT_REG16 | OPT_EA, OPT_REG32))
|
||||||
ALT(DEF_ASM_OP2(movzbw, 0x0fb6, 0, OPC_MODRM | OPC_WLX, OPT_REG8 | OPT_EA, OPT_REGW))
|
ALT(DEF_ASM_OP2(movzbw, 0x0fb6, 0, OPC_MODRM | OPC_WL, OPT_REG8 | OPT_EA, OPT_REGW))
|
||||||
ALT(DEF_ASM_OP2(movzwl, 0x0fb7, 0, OPC_MODRM, OPT_REG16 | OPT_EA, OPT_REG32))
|
ALT(DEF_ASM_OP2(movzwl, 0x0fb7, 0, OPC_MODRM, OPT_REG16 | OPT_EA, OPT_REG32))
|
||||||
|
|
||||||
ALT(DEF_ASM_OP1(pushw, 0x50, 0, OPC_REG | OPC_WLX, OPT_REGW))
|
ALT(DEF_ASM_OP1(pushw, 0x50, 0, OPC_REG | OPC_WL, OPT_REGW))
|
||||||
ALT(DEF_ASM_OP1(pushw, 0xff, 6, OPC_MODRM | OPC_WLX, OPT_REGW | OPT_EA))
|
ALT(DEF_ASM_OP1(pushw, 0xff, 6, OPC_MODRM | OPC_WL, OPT_REGW | OPT_EA))
|
||||||
ALT(DEF_ASM_OP1(pushw, 0x6a, 0, OPC_WLX, OPT_IM8S))
|
ALT(DEF_ASM_OP1(push, 0x6a, 0, 0, OPT_IM8S))
|
||||||
ALT(DEF_ASM_OP1(pushw, 0x68, 0, OPC_WLX, OPT_IM32))
|
ALT(DEF_ASM_OP1(push, 0x68, 0, 0, OPT_IM32))
|
||||||
ALT(DEF_ASM_OP1(pushw, 0x06, 0, OPC_WLX, OPT_SEG))
|
ALT(DEF_ASM_OP1(push, 0x06, 0, 0, OPT_SEG))
|
||||||
|
|
||||||
ALT(DEF_ASM_OP1(popw, 0x58, 0, OPC_REG | OPC_WLX, OPT_REGW))
|
ALT(DEF_ASM_OP1(popw, 0x58, 0, OPC_REG | OPC_WL, OPT_REGW))
|
||||||
ALT(DEF_ASM_OP1(popw, 0x8f, 0, OPC_MODRM | OPC_WLX, OPT_REGW | OPT_EA))
|
ALT(DEF_ASM_OP1(popw, 0x8f, 0, OPC_MODRM | OPC_WL, OPT_REGW | OPT_EA))
|
||||||
ALT(DEF_ASM_OP1(popw, 0x07, 0, OPC_WLX, OPT_SEG))
|
ALT(DEF_ASM_OP1(pop, 0x07, 0, 0, OPT_SEG))
|
||||||
|
|
||||||
ALT(DEF_ASM_OP2(xchgw, 0x90, 0, OPC_REG | OPC_WLX, OPT_REGW, OPT_EAX))
|
ALT(DEF_ASM_OP2(xchgw, 0x90, 0, OPC_REG | OPC_WL, OPT_REG, OPT_EAX))
|
||||||
ALT(DEF_ASM_OP2(xchgw, 0x90, 0, OPC_REG | OPC_WLX, OPT_EAX, OPT_REGW))
|
ALT(DEF_ASM_OP2(xchgw, 0x90, 0, OPC_REG | OPC_WL, OPT_EAX, OPT_REG))
|
||||||
ALT(DEF_ASM_OP2(xchgb, 0x86, 0, OPC_MODRM | OPC_BWLX, OPT_REG, OPT_EA | OPT_REG))
|
ALT(DEF_ASM_OP2(xchgb, 0x86, 0, OPC_MODRM | OPC_BWL, OPT_REG, OPT_EA | OPT_REG))
|
||||||
ALT(DEF_ASM_OP2(xchgb, 0x86, 0, OPC_MODRM | OPC_BWLX, OPT_EA | OPT_REG, OPT_REG))
|
ALT(DEF_ASM_OP2(xchgb, 0x86, 0, OPC_MODRM | OPC_BWL, OPT_EA | OPT_REG, OPT_REG))
|
||||||
|
|
||||||
ALT(DEF_ASM_OP2(inb, 0xe4, 0, OPC_BWL, OPT_IM8, OPT_EAX))
|
ALT(DEF_ASM_OP2(inb, 0xe4, 0, OPC_BWL, OPT_IM8, OPT_EAX))
|
||||||
ALT(DEF_ASM_OP1(inb, 0xe4, 0, OPC_BWL, OPT_IM8))
|
ALT(DEF_ASM_OP1(inb, 0xe4, 0, OPC_BWL, OPT_IM8))
|
||||||
@ -153,7 +143,7 @@ ALT(DEF_ASM_OP1(outb, 0xe6, 0, OPC_BWL, OPT_IM8))
|
|||||||
ALT(DEF_ASM_OP2(outb, 0xee, 0, OPC_BWL, OPT_EAX, OPT_DX))
|
ALT(DEF_ASM_OP2(outb, 0xee, 0, OPC_BWL, OPT_EAX, OPT_DX))
|
||||||
ALT(DEF_ASM_OP1(outb, 0xee, 0, OPC_BWL, OPT_DX))
|
ALT(DEF_ASM_OP1(outb, 0xee, 0, OPC_BWL, OPT_DX))
|
||||||
|
|
||||||
ALT(DEF_ASM_OP2(leaw, 0x8d, 0, OPC_MODRM | OPC_WLX, OPT_EA, OPT_REG))
|
ALT(DEF_ASM_OP2(leaw, 0x8d, 0, OPC_MODRM | OPC_WL, OPT_EA, OPT_REG))
|
||||||
|
|
||||||
ALT(DEF_ASM_OP2(les, 0xc4, 0, OPC_MODRM, OPT_EA, OPT_REG32))
|
ALT(DEF_ASM_OP2(les, 0xc4, 0, OPC_MODRM, OPT_EA, OPT_REG32))
|
||||||
ALT(DEF_ASM_OP2(lds, 0xc5, 0, OPC_MODRM, OPT_EA, OPT_REG32))
|
ALT(DEF_ASM_OP2(lds, 0xc5, 0, OPC_MODRM, OPT_EA, OPT_REG32))
|
||||||
@ -162,80 +152,77 @@ ALT(DEF_ASM_OP2(lfs, 0x0fb4, 0, OPC_MODRM, OPT_EA, OPT_REG32))
|
|||||||
ALT(DEF_ASM_OP2(lgs, 0x0fb5, 0, OPC_MODRM, OPT_EA, OPT_REG32))
|
ALT(DEF_ASM_OP2(lgs, 0x0fb5, 0, OPC_MODRM, OPT_EA, OPT_REG32))
|
||||||
|
|
||||||
/* arith */
|
/* arith */
|
||||||
ALT(DEF_ASM_OP2(addb, 0x00, 0, OPC_ARITH | OPC_MODRM | OPC_BWLX, OPT_REG, OPT_EA | OPT_REG)) /* XXX: use D bit ? */
|
ALT(DEF_ASM_OP2(addb, 0x00, 0, OPC_ARITH | OPC_MODRM | OPC_BWL, OPT_REG, OPT_EA | OPT_REG)) /* XXX: use D bit ? */
|
||||||
ALT(DEF_ASM_OP2(addb, 0x02, 0, OPC_ARITH | OPC_MODRM | OPC_BWLX, OPT_EA | OPT_REG, OPT_REG))
|
ALT(DEF_ASM_OP2(addb, 0x02, 0, OPC_ARITH | OPC_MODRM | OPC_BWL, OPT_EA | OPT_REG, OPT_REG))
|
||||||
ALT(DEF_ASM_OP2(addb, 0x04, 0, OPC_ARITH | OPC_BWLX, OPT_IM, OPT_EAX))
|
ALT(DEF_ASM_OP2(addb, 0x04, 0, OPC_ARITH | OPC_BWL, OPT_IM, OPT_EAX))
|
||||||
ALT(DEF_ASM_OP2(addw, 0x83, 0, OPC_ARITH | OPC_MODRM | OPC_WLX, OPT_IM8S, OPT_EA | OPT_REGW))
|
ALT(DEF_ASM_OP2(addb, 0x80, 0, OPC_ARITH | OPC_MODRM | OPC_BWL, OPT_IM, OPT_EA | OPT_REG))
|
||||||
ALT(DEF_ASM_OP2(addb, 0x80, 0, OPC_ARITH | OPC_MODRM | OPC_BWLX, OPT_IM, OPT_EA | OPT_REG))
|
ALT(DEF_ASM_OP2(addw, 0x83, 0, OPC_ARITH | OPC_MODRM | OPC_WL, OPT_IM8S, OPT_EA | OPT_REG))
|
||||||
|
|
||||||
ALT(DEF_ASM_OP2(testb, 0x84, 0, OPC_MODRM | OPC_BWLX, OPT_REG, OPT_EA | OPT_REG))
|
ALT(DEF_ASM_OP2(testb, 0x84, 0, OPC_MODRM | OPC_BWL, OPT_EA | OPT_REG, OPT_REG))
|
||||||
ALT(DEF_ASM_OP2(testb, 0x84, 0, OPC_MODRM | OPC_BWLX, OPT_EA | OPT_REG, OPT_REG))
|
ALT(DEF_ASM_OP2(testb, 0x84, 0, OPC_MODRM | OPC_BWL, OPT_REG, OPT_EA | OPT_REG))
|
||||||
ALT(DEF_ASM_OP2(testb, 0xa8, 0, OPC_BWLX, OPT_IM, OPT_EAX))
|
ALT(DEF_ASM_OP2(testb, 0xa8, 0, OPC_BWL, OPT_IM, OPT_EAX))
|
||||||
ALT(DEF_ASM_OP2(testb, 0xf6, 0, OPC_MODRM | OPC_BWLX, OPT_IM, OPT_EA | OPT_REG))
|
ALT(DEF_ASM_OP2(testb, 0xf6, 0, OPC_MODRM | OPC_BWL, OPT_IM, OPT_EA | OPT_REG))
|
||||||
|
|
||||||
ALT(DEF_ASM_OP1(incw, 0x40, 0, OPC_REG | OPC_WLX, OPT_REGW))
|
ALT(DEF_ASM_OP1(incw, 0x40, 0, OPC_REG | OPC_WL, OPT_REGW))
|
||||||
ALT(DEF_ASM_OP1(incb, 0xfe, 0, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA))
|
ALT(DEF_ASM_OP1(incb, 0xfe, 0, OPC_MODRM | OPC_BWL, OPT_REG | OPT_EA))
|
||||||
ALT(DEF_ASM_OP1(decw, 0x48, 0, OPC_REG | OPC_WLX, OPT_REGW))
|
ALT(DEF_ASM_OP1(decw, 0x48, 0, OPC_REG | OPC_WL, OPT_REGW))
|
||||||
ALT(DEF_ASM_OP1(decb, 0xfe, 1, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA))
|
ALT(DEF_ASM_OP1(decb, 0xfe, 1, OPC_MODRM | OPC_BWL, OPT_REG | OPT_EA))
|
||||||
|
|
||||||
ALT(DEF_ASM_OP1(notb, 0xf6, 2, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA))
|
ALT(DEF_ASM_OP1(notb, 0xf6, 2, OPC_MODRM | OPC_BWL, OPT_REG | OPT_EA))
|
||||||
ALT(DEF_ASM_OP1(negb, 0xf6, 3, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA))
|
ALT(DEF_ASM_OP1(negb, 0xf6, 3, OPC_MODRM | OPC_BWL, OPT_REG | OPT_EA))
|
||||||
|
|
||||||
ALT(DEF_ASM_OP1(mulb, 0xf6, 4, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA))
|
ALT(DEF_ASM_OP1(mulb, 0xf6, 4, OPC_MODRM | OPC_BWL, OPT_REG | OPT_EA))
|
||||||
ALT(DEF_ASM_OP1(imulb, 0xf6, 5, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA))
|
ALT(DEF_ASM_OP1(imulb, 0xf6, 5, OPC_MODRM | OPC_BWL, OPT_REG | OPT_EA))
|
||||||
|
|
||||||
ALT(DEF_ASM_OP2(imulw, 0x0faf, 0, OPC_MODRM | OPC_WLX, OPT_REG | OPT_EA, OPT_REG))
|
ALT(DEF_ASM_OP2(imulw, 0x0faf, 0, OPC_MODRM | OPC_WL, OPT_REG | OPT_EA, OPT_REG))
|
||||||
ALT(DEF_ASM_OP3(imulw, 0x6b, 0, OPC_MODRM | OPC_WLX, OPT_IM8S, OPT_REGW | OPT_EA, OPT_REGW))
|
ALT(DEF_ASM_OP3(imulw, 0x6b, 0, OPC_MODRM | OPC_WL, OPT_IM8S, OPT_REGW | OPT_EA, OPT_REGW))
|
||||||
ALT(DEF_ASM_OP2(imulw, 0x6b, 0, OPC_MODRM | OPC_WLX, OPT_IM8S, OPT_REGW))
|
ALT(DEF_ASM_OP2(imulw, 0x6b, 0, OPC_MODRM | OPC_WL, OPT_IM8S, OPT_REGW))
|
||||||
ALT(DEF_ASM_OP3(imulw, 0x69, 0, OPC_MODRM | OPC_WLX, OPT_IMW, OPT_REGW | OPT_EA, OPT_REGW))
|
ALT(DEF_ASM_OP3(imulw, 0x69, 0, OPC_MODRM | OPC_WL, OPT_IMW, OPT_REGW | OPT_EA, OPT_REGW))
|
||||||
ALT(DEF_ASM_OP2(imulw, 0x69, 0, OPC_MODRM | OPC_WLX, OPT_IMW, OPT_REGW))
|
ALT(DEF_ASM_OP2(imulw, 0x69, 0, OPC_MODRM | OPC_WL, OPT_IMW, OPT_REGW))
|
||||||
|
|
||||||
ALT(DEF_ASM_OP1(divb, 0xf6, 6, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA))
|
ALT(DEF_ASM_OP1(divb, 0xf6, 6, OPC_MODRM | OPC_BWL, OPT_REG | OPT_EA))
|
||||||
ALT(DEF_ASM_OP2(divb, 0xf6, 6, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA, OPT_EAX))
|
ALT(DEF_ASM_OP2(divb, 0xf6, 6, OPC_MODRM | OPC_BWL, OPT_REG | OPT_EA, OPT_EAX))
|
||||||
ALT(DEF_ASM_OP1(idivb, 0xf6, 7, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA))
|
ALT(DEF_ASM_OP1(idivb, 0xf6, 7, OPC_MODRM | OPC_BWL, OPT_REG | OPT_EA))
|
||||||
ALT(DEF_ASM_OP2(idivb, 0xf6, 7, OPC_MODRM | OPC_BWLX, OPT_REG | OPT_EA, OPT_EAX))
|
ALT(DEF_ASM_OP2(idivb, 0xf6, 7, OPC_MODRM | OPC_BWL, OPT_REG | OPT_EA, OPT_EAX))
|
||||||
|
|
||||||
/* shifts */
|
/* shifts */
|
||||||
ALT(DEF_ASM_OP2(rolb, 0xc0, 0, OPC_MODRM | OPC_BWLX | OPC_SHIFT, OPT_IM8, OPT_EA | OPT_REG))
|
ALT(DEF_ASM_OP2(rolb, 0xc0, 0, OPC_MODRM | OPC_BWL | OPC_SHIFT, OPT_IM8, OPT_EA | OPT_REG))
|
||||||
ALT(DEF_ASM_OP2(rolb, 0xd2, 0, OPC_MODRM | OPC_BWLX | OPC_SHIFT, OPT_CL, OPT_EA | OPT_REG))
|
ALT(DEF_ASM_OP2(rolb, 0xd2, 0, OPC_MODRM | OPC_BWL | OPC_SHIFT, OPT_CL, OPT_EA | OPT_REG))
|
||||||
ALT(DEF_ASM_OP1(rolb, 0xd0, 0, OPC_MODRM | OPC_BWLX | OPC_SHIFT, OPT_EA | OPT_REG))
|
ALT(DEF_ASM_OP1(rolb, 0xd0, 0, OPC_MODRM | OPC_BWL | OPC_SHIFT, OPT_EA | OPT_REG))
|
||||||
|
|
||||||
ALT(DEF_ASM_OP3(shldw, 0x0fa4, 0, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW, OPT_EA | OPT_REGW))
|
ALT(DEF_ASM_OP3(shldw, 0x0fa4, 0, OPC_MODRM | OPC_WL, OPT_IM8, OPT_REGW, OPT_EA | OPT_REGW))
|
||||||
ALT(DEF_ASM_OP3(shldw, 0x0fa5, 0, OPC_MODRM | OPC_WLX, OPT_CL, OPT_REGW, OPT_EA | OPT_REGW))
|
ALT(DEF_ASM_OP3(shldw, 0x0fa5, 0, OPC_MODRM | OPC_WL, OPT_CL, OPT_REGW, OPT_EA | OPT_REGW))
|
||||||
ALT(DEF_ASM_OP2(shldw, 0x0fa5, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_EA | OPT_REGW))
|
ALT(DEF_ASM_OP2(shldw, 0x0fa5, 0, OPC_MODRM | OPC_WL, OPT_REGW, OPT_EA | OPT_REGW))
|
||||||
ALT(DEF_ASM_OP3(shrdw, 0x0fac, 0, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW, OPT_EA | OPT_REGW))
|
ALT(DEF_ASM_OP3(shrdw, 0x0fac, 0, OPC_MODRM | OPC_WL, OPT_IM8, OPT_REGW, OPT_EA | OPT_REGW))
|
||||||
ALT(DEF_ASM_OP3(shrdw, 0x0fad, 0, OPC_MODRM | OPC_WLX, OPT_CL, OPT_REGW, OPT_EA | OPT_REGW))
|
ALT(DEF_ASM_OP3(shrdw, 0x0fad, 0, OPC_MODRM | OPC_WL, OPT_CL, OPT_REGW, OPT_EA | OPT_REGW))
|
||||||
ALT(DEF_ASM_OP2(shrdw, 0x0fad, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_EA | OPT_REGW))
|
ALT(DEF_ASM_OP2(shrdw, 0x0fad, 0, OPC_MODRM | OPC_WL, OPT_REGW, OPT_EA | OPT_REGW))
|
||||||
|
|
||||||
ALT(DEF_ASM_OP1(call, 0xff, 2, OPC_MODRM, OPT_INDIR))
|
ALT(DEF_ASM_OP1(call, 0xff, 2, OPC_MODRM, OPT_INDIR))
|
||||||
ALT(DEF_ASM_OP1(call, 0xe8, 0, 0, OPT_DISP))
|
ALT(DEF_ASM_OP1(call, 0xe8, 0, OPC_JMP, OPT_ADDR))
|
||||||
ALT(DEF_ASM_OP1(jmp, 0xff, 4, OPC_MODRM, OPT_INDIR))
|
ALT(DEF_ASM_OP1(jmp, 0xff, 4, OPC_MODRM, OPT_INDIR))
|
||||||
ALT(DEF_ASM_OP1(jmp, 0xeb, 0, 0, OPT_DISP8))
|
ALT(DEF_ASM_OP1(jmp, 0xeb, 0, OPC_SHORTJMP | OPC_JMP, OPT_ADDR))
|
||||||
|
|
||||||
ALT(DEF_ASM_OP2(lcall, 0x9a, 0, 0, OPT_IM16, OPT_IM32))
|
ALT(DEF_ASM_OP2(lcall, 0x9a, 0, 0, OPT_IM16, OPT_IM32))
|
||||||
ALT(DEF_ASM_OP1(lcall, 0xff, 3, OPC_MODRM, OPT_EA))
|
ALT(DEF_ASM_OP1(lcall, 0xff, 3, 0, OPT_EA))
|
||||||
ALT(DEF_ASM_OP2(ljmp, 0xea, 0, 0, OPT_IM16, OPT_IM32))
|
ALT(DEF_ASM_OP2(ljmp, 0xea, 0, 0, OPT_IM16, OPT_IM32))
|
||||||
ALT(DEF_ASM_OP1(ljmp, 0xff, 5, OPC_MODRM, OPT_EA))
|
ALT(DEF_ASM_OP1(ljmp, 0xff, 5, 0, OPT_EA))
|
||||||
|
|
||||||
ALT(DEF_ASM_OP1(int, 0xcd, 0, 0, OPT_IM8))
|
ALT(DEF_ASM_OP1(int, 0xcd, 0, 0, OPT_IM8))
|
||||||
ALT(DEF_ASM_OP1(seto, 0x0f90, 0, OPC_MODRM | OPC_TEST, OPT_REG8 | OPT_EA))
|
ALT(DEF_ASM_OP1(seto, 0x0f90, 0, OPC_MODRM | OPC_TEST, OPT_REG8 | OPT_EA))
|
||||||
ALT(DEF_ASM_OP1(setob, 0x0f90, 0, OPC_MODRM | OPC_TEST, OPT_REG8 | OPT_EA))
|
|
||||||
DEF_ASM_OP2(enter, 0xc8, 0, 0, OPT_IM16, OPT_IM8)
|
DEF_ASM_OP2(enter, 0xc8, 0, 0, OPT_IM16, OPT_IM8)
|
||||||
DEF_ASM_OP0(leave, 0xc9)
|
DEF_ASM_OP0(leave, 0xc9)
|
||||||
DEF_ASM_OP0(ret, 0xc3)
|
DEF_ASM_OP0(ret, 0xc3)
|
||||||
DEF_ASM_OP0(retl,0xc3)
|
|
||||||
ALT(DEF_ASM_OP1(retl,0xc2, 0, 0, OPT_IM16))
|
|
||||||
ALT(DEF_ASM_OP1(ret, 0xc2, 0, 0, OPT_IM16))
|
ALT(DEF_ASM_OP1(ret, 0xc2, 0, 0, OPT_IM16))
|
||||||
DEF_ASM_OP0(lret, 0xcb)
|
DEF_ASM_OP0(lret, 0xcb)
|
||||||
ALT(DEF_ASM_OP1(lret, 0xca, 0, 0, OPT_IM16))
|
ALT(DEF_ASM_OP1(lret, 0xca, 0, 0, OPT_IM16))
|
||||||
|
|
||||||
ALT(DEF_ASM_OP1(jo, 0x70, 0, OPC_TEST, OPT_DISP8))
|
ALT(DEF_ASM_OP1(jo, 0x70, 0, OPC_SHORTJMP | OPC_JMP | OPC_TEST, OPT_ADDR))
|
||||||
DEF_ASM_OP1(loopne, 0xe0, 0, 0, OPT_DISP8)
|
DEF_ASM_OP1(loopne, 0xe0, 0, OPC_SHORTJMP, OPT_ADDR)
|
||||||
DEF_ASM_OP1(loopnz, 0xe0, 0, 0, OPT_DISP8)
|
DEF_ASM_OP1(loopnz, 0xe0, 0, OPC_SHORTJMP, OPT_ADDR)
|
||||||
DEF_ASM_OP1(loope, 0xe1, 0, 0, OPT_DISP8)
|
DEF_ASM_OP1(loope, 0xe1, 0, OPC_SHORTJMP, OPT_ADDR)
|
||||||
DEF_ASM_OP1(loopz, 0xe1, 0, 0, OPT_DISP8)
|
DEF_ASM_OP1(loopz, 0xe1, 0, OPC_SHORTJMP, OPT_ADDR)
|
||||||
DEF_ASM_OP1(loop, 0xe2, 0, 0, OPT_DISP8)
|
DEF_ASM_OP1(loop, 0xe2, 0, OPC_SHORTJMP, OPT_ADDR)
|
||||||
DEF_ASM_OP1(jecxz, 0xe3, 0, 0, OPT_DISP8)
|
DEF_ASM_OP1(jecxz, 0xe3, 0, OPC_SHORTJMP, OPT_ADDR)
|
||||||
|
|
||||||
/* float */
|
/* float */
|
||||||
/* specific fcomp handling */
|
/* specific fcomp handling */
|
||||||
@ -243,8 +230,6 @@ ALT(DEF_ASM_OP0L(fcomp, 0xd8d9, 0, 0))
|
|||||||
|
|
||||||
ALT(DEF_ASM_OP1(fadd, 0xd8c0, 0, OPC_FARITH | OPC_REG, OPT_ST))
|
ALT(DEF_ASM_OP1(fadd, 0xd8c0, 0, OPC_FARITH | OPC_REG, OPT_ST))
|
||||||
ALT(DEF_ASM_OP2(fadd, 0xd8c0, 0, OPC_FARITH | OPC_REG, OPT_ST, OPT_ST0))
|
ALT(DEF_ASM_OP2(fadd, 0xd8c0, 0, OPC_FARITH | OPC_REG, OPT_ST, OPT_ST0))
|
||||||
ALT(DEF_ASM_OP2(fadd, 0xdcc0, 0, OPC_FARITH | OPC_REG, OPT_ST0, OPT_ST))
|
|
||||||
ALT(DEF_ASM_OP2(fmul, 0xdcc8, 0, OPC_FARITH | OPC_REG, OPT_ST0, OPT_ST))
|
|
||||||
ALT(DEF_ASM_OP0L(fadd, 0xdec1, 0, OPC_FARITH))
|
ALT(DEF_ASM_OP0L(fadd, 0xdec1, 0, OPC_FARITH))
|
||||||
ALT(DEF_ASM_OP1(faddp, 0xdec0, 0, OPC_FARITH | OPC_REG, OPT_ST))
|
ALT(DEF_ASM_OP1(faddp, 0xdec0, 0, OPC_FARITH | OPC_REG, OPT_ST))
|
||||||
ALT(DEF_ASM_OP2(faddp, 0xdec0, 0, OPC_FARITH | OPC_REG, OPT_ST, OPT_ST0))
|
ALT(DEF_ASM_OP2(faddp, 0xdec0, 0, OPC_FARITH | OPC_REG, OPT_ST, OPT_ST0))
|
||||||
@ -287,6 +272,7 @@ ALT(DEF_ASM_OP1(fiadds, 0xde, 0, OPC_FARITH | OPC_MODRM, OPT_EA))
|
|||||||
DEF_ASM_OP0(fninit, 0xdbe3)
|
DEF_ASM_OP0(fninit, 0xdbe3)
|
||||||
DEF_ASM_OP0(fnclex, 0xdbe2)
|
DEF_ASM_OP0(fnclex, 0xdbe2)
|
||||||
DEF_ASM_OP0(fnop, 0xd9d0)
|
DEF_ASM_OP0(fnop, 0xd9d0)
|
||||||
|
DEF_ASM_OP0(fwait, 0x9b)
|
||||||
|
|
||||||
/* fp load */
|
/* fp load */
|
||||||
DEF_ASM_OP1(fld, 0xd9c0, 0, OPC_REG, OPT_ST)
|
DEF_ASM_OP1(fld, 0xd9c0, 0, OPC_REG, OPT_ST)
|
||||||
@ -344,17 +330,15 @@ ALT(DEF_ASM_OP1(fstsw, 0xdd, 7, OPC_MODRM | OPC_FWAIT, OPT_EA ))
|
|||||||
DEF_ASM_OP1(frstor, 0xdd, 4, OPC_MODRM, OPT_EA )
|
DEF_ASM_OP1(frstor, 0xdd, 4, OPC_MODRM, OPT_EA )
|
||||||
DEF_ASM_OP1(ffree, 0xddc0, 4, OPC_REG, OPT_ST )
|
DEF_ASM_OP1(ffree, 0xddc0, 4, OPC_REG, OPT_ST )
|
||||||
DEF_ASM_OP1(ffreep, 0xdfc0, 4, OPC_REG, OPT_ST )
|
DEF_ASM_OP1(ffreep, 0xdfc0, 4, OPC_REG, OPT_ST )
|
||||||
DEF_ASM_OP1(fxsave, 0x0fae, 0, OPC_MODRM, OPT_EA )
|
|
||||||
DEF_ASM_OP1(fxrstor, 0x0fae, 1, OPC_MODRM, OPT_EA )
|
|
||||||
|
|
||||||
/* segments */
|
/* segments */
|
||||||
DEF_ASM_OP2(arpl, 0x63, 0, OPC_MODRM, OPT_REG16, OPT_REG16 | OPT_EA)
|
DEF_ASM_OP2(arpl, 0x63, 0, OPC_MODRM, OPT_REG16, OPT_REG16 | OPT_EA)
|
||||||
ALT(DEF_ASM_OP2(larw, 0x0f02, 0, OPC_MODRM | OPC_WLX, OPT_REG | OPT_EA, OPT_REG))
|
DEF_ASM_OP2(lar, 0x0f02, 0, OPC_MODRM, OPT_REG32 | OPT_EA, OPT_REG32)
|
||||||
DEF_ASM_OP1(lgdt, 0x0f01, 2, OPC_MODRM, OPT_EA)
|
DEF_ASM_OP1(lgdt, 0x0f01, 2, OPC_MODRM, OPT_EA)
|
||||||
DEF_ASM_OP1(lidt, 0x0f01, 3, OPC_MODRM, OPT_EA)
|
DEF_ASM_OP1(lidt, 0x0f01, 3, OPC_MODRM, OPT_EA)
|
||||||
DEF_ASM_OP1(lldt, 0x0f00, 2, OPC_MODRM, OPT_EA | OPT_REG)
|
DEF_ASM_OP1(lldt, 0x0f00, 2, OPC_MODRM, OPT_EA | OPT_REG)
|
||||||
DEF_ASM_OP1(lmsw, 0x0f01, 6, OPC_MODRM, OPT_EA | OPT_REG)
|
DEF_ASM_OP1(lmsw, 0x0f01, 6, OPC_MODRM, OPT_EA | OPT_REG)
|
||||||
ALT(DEF_ASM_OP2(lslw, 0x0f03, 0, OPC_MODRM | OPC_WLX, OPT_EA | OPT_REG, OPT_REG))
|
ALT(DEF_ASM_OP2(lslw, 0x0f03, 0, OPC_MODRM | OPC_WL, OPT_EA | OPT_REG, OPT_REG))
|
||||||
DEF_ASM_OP1(ltr, 0x0f00, 3, OPC_MODRM, OPT_EA | OPT_REG)
|
DEF_ASM_OP1(ltr, 0x0f00, 3, OPC_MODRM, OPT_EA | OPT_REG)
|
||||||
DEF_ASM_OP1(sgdt, 0x0f01, 0, OPC_MODRM, OPT_EA)
|
DEF_ASM_OP1(sgdt, 0x0f01, 0, OPC_MODRM, OPT_EA)
|
||||||
DEF_ASM_OP1(sidt, 0x0f01, 1, OPC_MODRM, OPT_EA)
|
DEF_ASM_OP1(sidt, 0x0f01, 1, OPC_MODRM, OPT_EA)
|
||||||
@ -366,18 +350,19 @@ ALT(DEF_ASM_OP2(lslw, 0x0f03, 0, OPC_MODRM | OPC_WLX, OPT_EA | OPT_REG, OPT_REG)
|
|||||||
|
|
||||||
/* 486 */
|
/* 486 */
|
||||||
DEF_ASM_OP1(bswap, 0x0fc8, 0, OPC_REG, OPT_REG32 )
|
DEF_ASM_OP1(bswap, 0x0fc8, 0, OPC_REG, OPT_REG32 )
|
||||||
ALT(DEF_ASM_OP2(xaddb, 0x0fc0, 0, OPC_MODRM | OPC_BWLX, OPT_REG, OPT_REG | OPT_EA ))
|
ALT(DEF_ASM_OP2(xaddb, 0x0fc0, 0, OPC_MODRM | OPC_BWL, OPT_REG, OPT_REG | OPT_EA ))
|
||||||
ALT(DEF_ASM_OP2(cmpxchgb, 0x0fb0, 0, OPC_MODRM | OPC_BWLX, OPT_REG, OPT_REG | OPT_EA ))
|
ALT(DEF_ASM_OP2(cmpxchgb, 0x0fb0, 0, OPC_MODRM | OPC_BWL, OPT_REG, OPT_REG | OPT_EA ))
|
||||||
DEF_ASM_OP1(invlpg, 0x0f01, 7, OPC_MODRM, OPT_EA )
|
DEF_ASM_OP1(invlpg, 0x0f01, 7, OPC_MODRM, OPT_EA )
|
||||||
|
|
||||||
DEF_ASM_OP2(boundl, 0x62, 0, OPC_MODRM, OPT_REG32, OPT_EA)
|
DEF_ASM_OP2(boundl, 0x62, 0, OPC_MODRM, OPT_REG32, OPT_EA)
|
||||||
DEF_ASM_OP2(boundw, 0x6662, 0, OPC_MODRM, OPT_REG16, OPT_EA)
|
DEF_ASM_OP2(boundw, 0x62, 0, OPC_MODRM | OPC_D16, OPT_REG16, OPT_EA)
|
||||||
|
|
||||||
/* pentium */
|
/* pentium */
|
||||||
DEF_ASM_OP1(cmpxchg8b, 0x0fc7, 1, OPC_MODRM, OPT_EA )
|
DEF_ASM_OP1(cmpxchg8b, 0x0fc7, 1, OPC_MODRM, OPT_EA )
|
||||||
|
|
||||||
/* pentium pro */
|
/* pentium pro */
|
||||||
ALT(DEF_ASM_OP2(cmovo, 0x0f40, 0, OPC_MODRM | OPC_TEST | OPC_WLX, OPT_REGW | OPT_EA, OPT_REGW))
|
ALT(DEF_ASM_OP2(cmovo, 0x0f40, 0, OPC_MODRM | OPC_TEST, OPT_REG32 | OPT_EA, OPT_REG32))
|
||||||
|
|
||||||
DEF_ASM_OP2(fcmovb, 0xdac0, 0, OPC_REG, OPT_ST, OPT_ST0 )
|
DEF_ASM_OP2(fcmovb, 0xdac0, 0, OPC_REG, OPT_ST, OPT_ST0 )
|
||||||
DEF_ASM_OP2(fcmove, 0xdac8, 0, OPC_REG, OPT_ST, OPT_ST0 )
|
DEF_ASM_OP2(fcmove, 0xdac8, 0, OPC_REG, OPT_ST, OPT_ST0 )
|
||||||
DEF_ASM_OP2(fcmovbe, 0xdad0, 0, OPC_REG, OPT_ST, OPT_ST0 )
|
DEF_ASM_OP2(fcmovbe, 0xdad0, 0, OPC_REG, OPT_ST, OPT_ST0 )
|
||||||
@ -394,93 +379,62 @@ ALT(DEF_ASM_OP2(cmovo, 0x0f40, 0, OPC_MODRM | OPC_TEST | OPC_WLX, OPT_REGW | OPT
|
|||||||
|
|
||||||
/* mmx */
|
/* mmx */
|
||||||
DEF_ASM_OP0(emms, 0x0f77) /* must be last OP0 */
|
DEF_ASM_OP0(emms, 0x0f77) /* must be last OP0 */
|
||||||
DEF_ASM_OP2(movd, 0x0f6e, 0, OPC_MODRM, OPT_EA | OPT_REG32, OPT_MMXSSE )
|
DEF_ASM_OP2(movd, 0x0f6e, 0, OPC_MODRM, OPT_EA | OPT_REG32, OPT_MMX )
|
||||||
|
ALT(DEF_ASM_OP2(movd, 0x0f7e, 0, OPC_MODRM, OPT_MMX, OPT_EA | OPT_REG32 ))
|
||||||
DEF_ASM_OP2(movq, 0x0f6f, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
DEF_ASM_OP2(movq, 0x0f6f, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||||
ALT(DEF_ASM_OP2(movd, 0x0f7e, 0, OPC_MODRM, OPT_MMXSSE, OPT_EA | OPT_REG32 ))
|
|
||||||
ALT(DEF_ASM_OP2(movq, 0x0f7f, 0, OPC_MODRM, OPT_MMX, OPT_EA | OPT_MMX ))
|
ALT(DEF_ASM_OP2(movq, 0x0f7f, 0, OPC_MODRM, OPT_MMX, OPT_EA | OPT_MMX ))
|
||||||
ALT(DEF_ASM_OP2(movq, 0x660fd6, 0, OPC_MODRM, OPT_SSE, OPT_EA | OPT_SSE ))
|
DEF_ASM_OP2(packssdw, 0x0f6b, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||||
ALT(DEF_ASM_OP2(movq, 0xf30f7e, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE ))
|
DEF_ASM_OP2(packsswb, 0x0f63, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||||
|
DEF_ASM_OP2(packuswb, 0x0f67, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||||
DEF_ASM_OP2(packssdw, 0x0f6b, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
DEF_ASM_OP2(paddb, 0x0ffc, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||||
DEF_ASM_OP2(packsswb, 0x0f63, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
DEF_ASM_OP2(paddw, 0x0ffd, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||||
DEF_ASM_OP2(packuswb, 0x0f67, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
DEF_ASM_OP2(paddd, 0x0ffe, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||||
DEF_ASM_OP2(paddb, 0x0ffc, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
DEF_ASM_OP2(paddsb, 0x0fec, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||||
DEF_ASM_OP2(paddw, 0x0ffd, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
DEF_ASM_OP2(paddsw, 0x0fed, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||||
DEF_ASM_OP2(paddd, 0x0ffe, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
DEF_ASM_OP2(paddusb, 0x0fdc, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||||
DEF_ASM_OP2(paddsb, 0x0fec, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
DEF_ASM_OP2(paddusw, 0x0fdd, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||||
DEF_ASM_OP2(paddsw, 0x0fed, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
DEF_ASM_OP2(pand, 0x0fdb, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||||
DEF_ASM_OP2(paddusb, 0x0fdc, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
DEF_ASM_OP2(pandn, 0x0fdf, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||||
DEF_ASM_OP2(paddusw, 0x0fdd, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
DEF_ASM_OP2(pcmpeqb, 0x0f74, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||||
DEF_ASM_OP2(pand, 0x0fdb, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
DEF_ASM_OP2(pcmpeqw, 0x0f75, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||||
DEF_ASM_OP2(pandn, 0x0fdf, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
DEF_ASM_OP2(pcmpeqd, 0x0f76, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||||
DEF_ASM_OP2(pcmpeqb, 0x0f74, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
DEF_ASM_OP2(pcmpgtb, 0x0f64, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||||
DEF_ASM_OP2(pcmpeqw, 0x0f75, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
DEF_ASM_OP2(pcmpgtw, 0x0f65, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||||
DEF_ASM_OP2(pcmpeqd, 0x0f76, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
DEF_ASM_OP2(pcmpgtd, 0x0f66, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||||
DEF_ASM_OP2(pcmpgtb, 0x0f64, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
DEF_ASM_OP2(pmaddwd, 0x0ff5, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||||
DEF_ASM_OP2(pcmpgtw, 0x0f65, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
DEF_ASM_OP2(pmulhw, 0x0fe5, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||||
DEF_ASM_OP2(pcmpgtd, 0x0f66, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
DEF_ASM_OP2(pmullw, 0x0fd5, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||||
DEF_ASM_OP2(pmaddwd, 0x0ff5, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
DEF_ASM_OP2(por, 0x0feb, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||||
DEF_ASM_OP2(pmulhw, 0x0fe5, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
DEF_ASM_OP2(psllw, 0x0ff1, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||||
DEF_ASM_OP2(pmullw, 0x0fd5, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
ALT(DEF_ASM_OP2(psllw, 0x0f71, 6, OPC_MODRM, OPT_IM8, OPT_MMX ))
|
||||||
DEF_ASM_OP2(por, 0x0feb, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
DEF_ASM_OP2(pslld, 0x0ff2, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||||
DEF_ASM_OP2(psllw, 0x0ff1, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
ALT(DEF_ASM_OP2(pslld, 0x0f72, 6, OPC_MODRM, OPT_IM8, OPT_MMX ))
|
||||||
ALT(DEF_ASM_OP2(psllw, 0x0f71, 6, OPC_MODRM, OPT_IM8, OPT_MMXSSE ))
|
DEF_ASM_OP2(psllq, 0x0ff3, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||||
DEF_ASM_OP2(pslld, 0x0ff2, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
ALT(DEF_ASM_OP2(psllq, 0x0f73, 6, OPC_MODRM, OPT_IM8, OPT_MMX ))
|
||||||
ALT(DEF_ASM_OP2(pslld, 0x0f72, 6, OPC_MODRM, OPT_IM8, OPT_MMXSSE ))
|
DEF_ASM_OP2(psraw, 0x0fe1, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||||
DEF_ASM_OP2(psllq, 0x0ff3, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
ALT(DEF_ASM_OP2(psraw, 0x0f71, 4, OPC_MODRM, OPT_IM8, OPT_MMX ))
|
||||||
ALT(DEF_ASM_OP2(psllq, 0x0f73, 6, OPC_MODRM, OPT_IM8, OPT_MMXSSE ))
|
DEF_ASM_OP2(psrad, 0x0fe2, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||||
DEF_ASM_OP2(psraw, 0x0fe1, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
ALT(DEF_ASM_OP2(psrad, 0x0f72, 4, OPC_MODRM, OPT_IM8, OPT_MMX ))
|
||||||
ALT(DEF_ASM_OP2(psraw, 0x0f71, 4, OPC_MODRM, OPT_IM8, OPT_MMXSSE ))
|
DEF_ASM_OP2(psrlw, 0x0fd1, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||||
DEF_ASM_OP2(psrad, 0x0fe2, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
ALT(DEF_ASM_OP2(psrlw, 0x0f71, 2, OPC_MODRM, OPT_IM8, OPT_MMX ))
|
||||||
ALT(DEF_ASM_OP2(psrad, 0x0f72, 4, OPC_MODRM, OPT_IM8, OPT_MMXSSE ))
|
DEF_ASM_OP2(psrld, 0x0fd2, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||||
DEF_ASM_OP2(psrlw, 0x0fd1, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
ALT(DEF_ASM_OP2(psrld, 0x0f72, 2, OPC_MODRM, OPT_IM8, OPT_MMX ))
|
||||||
ALT(DEF_ASM_OP2(psrlw, 0x0f71, 2, OPC_MODRM, OPT_IM8, OPT_MMXSSE ))
|
DEF_ASM_OP2(psrlq, 0x0fd3, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||||
DEF_ASM_OP2(psrld, 0x0fd2, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
ALT(DEF_ASM_OP2(psrlq, 0x0f73, 2, OPC_MODRM, OPT_IM8, OPT_MMX ))
|
||||||
ALT(DEF_ASM_OP2(psrld, 0x0f72, 2, OPC_MODRM, OPT_IM8, OPT_MMXSSE ))
|
DEF_ASM_OP2(psubb, 0x0ff8, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||||
DEF_ASM_OP2(psrlq, 0x0fd3, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
DEF_ASM_OP2(psubw, 0x0ff9, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||||
ALT(DEF_ASM_OP2(psrlq, 0x0f73, 2, OPC_MODRM, OPT_IM8, OPT_MMXSSE ))
|
DEF_ASM_OP2(psubd, 0x0ffa, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||||
DEF_ASM_OP2(psubb, 0x0ff8, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
DEF_ASM_OP2(psubsb, 0x0fe8, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||||
DEF_ASM_OP2(psubw, 0x0ff9, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
DEF_ASM_OP2(psubsw, 0x0fe9, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||||
DEF_ASM_OP2(psubd, 0x0ffa, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
DEF_ASM_OP2(psubusb, 0x0fd8, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||||
DEF_ASM_OP2(psubsb, 0x0fe8, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
DEF_ASM_OP2(psubusw, 0x0fd9, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||||
DEF_ASM_OP2(psubsw, 0x0fe9, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
DEF_ASM_OP2(punpckhbw, 0x0f68, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||||
DEF_ASM_OP2(psubusb, 0x0fd8, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
DEF_ASM_OP2(punpckhwd, 0x0f69, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||||
DEF_ASM_OP2(psubusw, 0x0fd9, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
DEF_ASM_OP2(punpckhdq, 0x0f6a, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||||
DEF_ASM_OP2(punpckhbw, 0x0f68, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
DEF_ASM_OP2(punpcklbw, 0x0f60, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||||
DEF_ASM_OP2(punpckhwd, 0x0f69, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
DEF_ASM_OP2(punpcklwd, 0x0f61, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||||
DEF_ASM_OP2(punpckhdq, 0x0f6a, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
DEF_ASM_OP2(punpckldq, 0x0f62, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||||
DEF_ASM_OP2(punpcklbw, 0x0f60, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
DEF_ASM_OP2(pxor, 0x0fef, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_MMX )
|
||||||
DEF_ASM_OP2(punpcklwd, 0x0f61, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
|
||||||
DEF_ASM_OP2(punpckldq, 0x0f62, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
|
||||||
DEF_ASM_OP2(pxor, 0x0fef, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
|
||||||
|
|
||||||
/* sse */
|
|
||||||
DEF_ASM_OP1(ldmxcsr, 0x0fae, 2, OPC_MODRM, OPT_EA)
|
|
||||||
DEF_ASM_OP1(stmxcsr, 0x0fae, 3, OPC_MODRM, OPT_EA)
|
|
||||||
DEF_ASM_OP2(movups, 0x0f10, 0, OPC_MODRM, OPT_EA | OPT_REG32, OPT_SSE )
|
|
||||||
ALT(DEF_ASM_OP2(movups, 0x0f11, 0, OPC_MODRM, OPT_SSE, OPT_EA | OPT_REG32 ))
|
|
||||||
DEF_ASM_OP2(movaps, 0x0f28, 0, OPC_MODRM, OPT_EA | OPT_REG32, OPT_SSE )
|
|
||||||
ALT(DEF_ASM_OP2(movaps, 0x0f29, 0, OPC_MODRM, OPT_SSE, OPT_EA | OPT_REG32 ))
|
|
||||||
DEF_ASM_OP2(movhps, 0x0f16, 0, OPC_MODRM, OPT_EA | OPT_REG32, OPT_SSE )
|
|
||||||
ALT(DEF_ASM_OP2(movhps, 0x0f17, 0, OPC_MODRM, OPT_SSE, OPT_EA | OPT_REG32 ))
|
|
||||||
DEF_ASM_OP2(addps, 0x0f58, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )
|
|
||||||
DEF_ASM_OP2(cvtpi2ps, 0x0f2a, 0, OPC_MODRM, OPT_EA | OPT_MMX, OPT_SSE )
|
|
||||||
DEF_ASM_OP2(cvtps2pi, 0x0f2d, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_MMX )
|
|
||||||
DEF_ASM_OP2(cvttps2pi, 0x0f2c, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_MMX )
|
|
||||||
DEF_ASM_OP2(divps, 0x0f5e, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )
|
|
||||||
DEF_ASM_OP2(maxps, 0x0f5f, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )
|
|
||||||
DEF_ASM_OP2(minps, 0x0f5d, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )
|
|
||||||
DEF_ASM_OP2(mulps, 0x0f59, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )
|
|
||||||
DEF_ASM_OP2(pavgb, 0x0fe0, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )
|
|
||||||
DEF_ASM_OP2(pavgw, 0x0fe3, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )
|
|
||||||
DEF_ASM_OP2(pmaxsw, 0x0fee, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
|
||||||
DEF_ASM_OP2(pmaxub, 0x0fde, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
|
||||||
DEF_ASM_OP2(pminsw, 0x0fea, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
|
||||||
DEF_ASM_OP2(pminub, 0x0fda, 0, OPC_MODRM, OPT_EA | OPT_MMXSSE, OPT_MMXSSE )
|
|
||||||
DEF_ASM_OP2(rcpss, 0x0f53, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )
|
|
||||||
DEF_ASM_OP2(rsqrtps, 0x0f52, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )
|
|
||||||
DEF_ASM_OP2(sqrtps, 0x0f51, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )
|
|
||||||
DEF_ASM_OP2(subps, 0x0f5c, 0, OPC_MODRM, OPT_EA | OPT_SSE, OPT_SSE )
|
|
||||||
|
|
||||||
#undef ALT
|
#undef ALT
|
||||||
#undef DEF_ASM_OP0
|
#undef DEF_ASM_OP0
|
||||||
|
|||||||
1044
i386-gen.c
1044
i386-gen.c
File diff suppressed because it is too large
Load Diff
360
i386-link.c
360
i386-link.c
@ -1,360 +0,0 @@
|
|||||||
#ifdef TARGET_DEFS_ONLY
|
|
||||||
|
|
||||||
#define EM_TCC_TARGET EM_386
|
|
||||||
|
|
||||||
/* relocation type for 32 bit data relocation */
|
|
||||||
#define R_DATA_32 R_386_32
|
|
||||||
#define R_DATA_PTR R_386_32
|
|
||||||
#define R_JMP_SLOT R_386_JMP_SLOT
|
|
||||||
#define R_GLOB_DAT R_386_GLOB_DAT
|
|
||||||
#define R_COPY R_386_COPY
|
|
||||||
#define R_RELATIVE R_386_RELATIVE
|
|
||||||
|
|
||||||
#define R_NUM R_386_NUM
|
|
||||||
|
|
||||||
#define ELF_START_ADDR 0x08048000
|
|
||||||
#define ELF_PAGE_SIZE 0x1000
|
|
||||||
|
|
||||||
#if defined CONFIG_TCC_PIC
|
|
||||||
#define PCRELATIVE_DLLPLT 1
|
|
||||||
#else
|
|
||||||
#define PCRELATIVE_DLLPLT 0
|
|
||||||
#endif
|
|
||||||
#define RELOCATE_DLLPLT 1
|
|
||||||
|
|
||||||
#else /* !TARGET_DEFS_ONLY */
|
|
||||||
|
|
||||||
#include "tcc.h"
|
|
||||||
|
|
||||||
#ifdef NEED_RELOC_TYPE
|
|
||||||
/* Returns 1 for a code relocation, 0 for a data relocation. For unknown
|
|
||||||
relocations, returns -1. */
|
|
||||||
ST_FUNC int code_reloc (int reloc_type)
|
|
||||||
{
|
|
||||||
switch (reloc_type) {
|
|
||||||
case R_386_RELATIVE:
|
|
||||||
case R_386_16:
|
|
||||||
case R_386_32:
|
|
||||||
case R_386_GOTPC:
|
|
||||||
case R_386_GOTOFF:
|
|
||||||
case R_386_GOT32:
|
|
||||||
case R_386_GOT32X:
|
|
||||||
case R_386_GLOB_DAT:
|
|
||||||
case R_386_COPY:
|
|
||||||
case R_386_TLS_GD:
|
|
||||||
case R_386_TLS_LDM:
|
|
||||||
case R_386_TLS_LDO_32:
|
|
||||||
case R_386_TLS_LE:
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case R_386_PC16:
|
|
||||||
case R_386_PC32:
|
|
||||||
case R_386_PLT32:
|
|
||||||
case R_386_JMP_SLOT:
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Returns an enumerator to describe whether and when the relocation needs a
|
|
||||||
GOT and/or PLT entry to be created. See tcc.h for a description of the
|
|
||||||
different values. */
|
|
||||||
ST_FUNC int gotplt_entry_type (int reloc_type)
|
|
||||||
{
|
|
||||||
switch (reloc_type) {
|
|
||||||
case R_386_RELATIVE:
|
|
||||||
case R_386_16:
|
|
||||||
case R_386_GLOB_DAT:
|
|
||||||
case R_386_JMP_SLOT:
|
|
||||||
case R_386_COPY:
|
|
||||||
return NO_GOTPLT_ENTRY;
|
|
||||||
|
|
||||||
case R_386_32:
|
|
||||||
/* This relocations shouldn't normally need GOT or PLT
|
|
||||||
slots if it weren't for simplicity in the code generator.
|
|
||||||
See our caller for comments. */
|
|
||||||
return AUTO_GOTPLT_ENTRY;
|
|
||||||
|
|
||||||
case R_386_PC16:
|
|
||||||
case R_386_PC32:
|
|
||||||
return AUTO_GOTPLT_ENTRY;
|
|
||||||
|
|
||||||
case R_386_GOTPC:
|
|
||||||
case R_386_GOTOFF:
|
|
||||||
return BUILD_GOT_ONLY;
|
|
||||||
|
|
||||||
case R_386_GOT32:
|
|
||||||
case R_386_GOT32X:
|
|
||||||
case R_386_PLT32:
|
|
||||||
case R_386_TLS_GD:
|
|
||||||
case R_386_TLS_LDM:
|
|
||||||
case R_386_TLS_LDO_32:
|
|
||||||
case R_386_TLS_LE:
|
|
||||||
return ALWAYS_GOTPLT_ENTRY;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef NEED_BUILD_GOT
|
|
||||||
ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_attr *attr)
|
|
||||||
{
|
|
||||||
Section *plt = s1->plt;
|
|
||||||
uint8_t *p;
|
|
||||||
int modrm;
|
|
||||||
unsigned plt_offset, relofs;
|
|
||||||
|
|
||||||
/* on i386 if we build a DLL, we add a %ebx offset */
|
|
||||||
if (s1->output_type & TCC_OUTPUT_DYN)
|
|
||||||
modrm = 0xa3;
|
|
||||||
else
|
|
||||||
modrm = 0x25;
|
|
||||||
|
|
||||||
/* empty PLT: create PLT0 entry that pushes the library identifier
|
|
||||||
(GOT + PTR_SIZE) and jumps to ld.so resolution routine
|
|
||||||
(GOT + 2 * PTR_SIZE) */
|
|
||||||
if (plt->data_offset == 0) {
|
|
||||||
p = section_ptr_add(plt, 16);
|
|
||||||
p[0] = 0xff; /* pushl got + PTR_SIZE */
|
|
||||||
p[1] = modrm + 0x10;
|
|
||||||
write32le(p + 2, PTR_SIZE);
|
|
||||||
p[6] = 0xff; /* jmp *(got + PTR_SIZE * 2) */
|
|
||||||
p[7] = modrm;
|
|
||||||
write32le(p + 8, PTR_SIZE * 2);
|
|
||||||
}
|
|
||||||
plt_offset = plt->data_offset;
|
|
||||||
|
|
||||||
/* The PLT slot refers to the relocation entry it needs via offset.
|
|
||||||
The reloc entry is created below, so its offset is the current
|
|
||||||
data_offset */
|
|
||||||
relofs = s1->plt->reloc ? s1->plt->reloc->data_offset : 0;
|
|
||||||
|
|
||||||
/* Jump to GOT entry where ld.so initially put the address of ip + 4 */
|
|
||||||
p = section_ptr_add(plt, 16);
|
|
||||||
p[0] = 0xff; /* jmp *(got + x) */
|
|
||||||
p[1] = modrm;
|
|
||||||
write32le(p + 2, got_offset);
|
|
||||||
p[6] = 0x68; /* push $xxx */
|
|
||||||
write32le(p + 7, relofs - sizeof (ElfW_Rel));
|
|
||||||
p[11] = 0xe9; /* jmp plt_start */
|
|
||||||
write32le(p + 12, -(plt->data_offset));
|
|
||||||
return plt_offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* relocate the PLT: compute addresses and offsets in the PLT now that final
|
|
||||||
address for PLT and GOT are known (see fill_program_header) */
|
|
||||||
ST_FUNC void relocate_plt(TCCState *s1)
|
|
||||||
{
|
|
||||||
uint8_t *p, *p_end;
|
|
||||||
|
|
||||||
if (!s1->plt)
|
|
||||||
return;
|
|
||||||
|
|
||||||
p = s1->plt->data;
|
|
||||||
p_end = p + s1->plt->data_offset;
|
|
||||||
|
|
||||||
if (!(s1->output_type & TCC_OUTPUT_DYN) && p < p_end) {
|
|
||||||
add32le(p + 2, s1->got->sh_addr);
|
|
||||||
add32le(p + 8, s1->got->sh_addr);
|
|
||||||
p += 16;
|
|
||||||
while (p < p_end) {
|
|
||||||
add32le(p + 2, s1->got->sh_addr);
|
|
||||||
p += 16;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s1->plt->reloc) {
|
|
||||||
ElfW_Rel *rel;
|
|
||||||
int x = s1->plt->sh_addr + 16 + 6;
|
|
||||||
p = s1->got->data;
|
|
||||||
for_each_elem(s1->plt->reloc, 0, rel, ElfW_Rel) {
|
|
||||||
write32le(p + rel->r_offset, x);
|
|
||||||
x += 16;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val)
|
|
||||||
{
|
|
||||||
int sym_index, esym_index;
|
|
||||||
|
|
||||||
sym_index = ELFW(R_SYM)(rel->r_info);
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case R_386_32:
|
|
||||||
if (s1->output_type & TCC_OUTPUT_DYN) {
|
|
||||||
esym_index = get_sym_attr(s1, sym_index, 0)->dyn_index;
|
|
||||||
qrel->r_offset = rel->r_offset;
|
|
||||||
if (esym_index) {
|
|
||||||
qrel->r_info = ELFW(R_INFO)(esym_index, R_386_32);
|
|
||||||
qrel++;
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
qrel->r_info = ELFW(R_INFO)(0, R_386_RELATIVE);
|
|
||||||
qrel++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
add32le(ptr, val);
|
|
||||||
return;
|
|
||||||
case R_386_PC32:
|
|
||||||
if (s1->output_type == TCC_OUTPUT_DLL) {
|
|
||||||
/* DLL relocation */
|
|
||||||
esym_index = get_sym_attr(s1, sym_index, 0)->dyn_index;
|
|
||||||
if (esym_index) {
|
|
||||||
qrel->r_offset = rel->r_offset;
|
|
||||||
qrel->r_info = ELFW(R_INFO)(esym_index, R_386_PC32);
|
|
||||||
qrel++;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
add32le(ptr, val - addr);
|
|
||||||
return;
|
|
||||||
case R_386_PLT32:
|
|
||||||
add32le(ptr, val - addr);
|
|
||||||
return;
|
|
||||||
case R_386_GLOB_DAT:
|
|
||||||
case R_386_JMP_SLOT:
|
|
||||||
write32le(ptr, val);
|
|
||||||
return;
|
|
||||||
case R_386_GOTPC:
|
|
||||||
add32le(ptr, s1->got->sh_addr - addr);
|
|
||||||
return;
|
|
||||||
case R_386_GOTOFF:
|
|
||||||
add32le(ptr, val - s1->got->sh_addr);
|
|
||||||
return;
|
|
||||||
case R_386_GOT32:
|
|
||||||
case R_386_GOT32X:
|
|
||||||
/* we load the got offset */
|
|
||||||
add32le(ptr, get_sym_attr(s1, sym_index, 0)->got_offset);
|
|
||||||
return;
|
|
||||||
case R_386_16:
|
|
||||||
if (s1->output_format != TCC_OUTPUT_FORMAT_BINARY) {
|
|
||||||
output_file:
|
|
||||||
tcc_error_noabort("can only produce 16-bit binary files");
|
|
||||||
}
|
|
||||||
write16le(ptr, read16le(ptr) + val);
|
|
||||||
return;
|
|
||||||
case R_386_PC16:
|
|
||||||
if (s1->output_format != TCC_OUTPUT_FORMAT_BINARY)
|
|
||||||
goto output_file;
|
|
||||||
write16le(ptr, read16le(ptr) + val - addr);
|
|
||||||
return;
|
|
||||||
case R_386_RELATIVE:
|
|
||||||
#ifdef TCC_TARGET_PE
|
|
||||||
add32le(ptr, val - s1->pe_imagebase);
|
|
||||||
#endif
|
|
||||||
/* do nothing */
|
|
||||||
return;
|
|
||||||
case R_386_COPY:
|
|
||||||
/* This relocation must copy initialized data from the library
|
|
||||||
to the program .bss segment. Currently made like for ARM
|
|
||||||
(to remove noise of default case). Is this true?
|
|
||||||
*/
|
|
||||||
return;
|
|
||||||
case R_386_TLS_GD:
|
|
||||||
{
|
|
||||||
static const unsigned char expect[] = {
|
|
||||||
/* lea 0(,%ebx,1),%eax */
|
|
||||||
0x8d, 0x04, 0x1d, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
/* call __tls_get_addr@PLT */
|
|
||||||
0xe8, 0xfc, 0xff, 0xff, 0xff };
|
|
||||||
static const unsigned char replace[] = {
|
|
||||||
/* mov %gs:0,%eax */
|
|
||||||
0x65, 0xa1, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
/* sub 0,%eax */
|
|
||||||
0x81, 0xe8, 0x00, 0x00, 0x00, 0x00 };
|
|
||||||
|
|
||||||
if (memcmp (ptr-3, expect, sizeof(expect)) == 0) {
|
|
||||||
ElfW(Sym) *sym;
|
|
||||||
Section *sec;
|
|
||||||
int32_t x;
|
|
||||||
|
|
||||||
memcpy(ptr-3, replace, sizeof(replace));
|
|
||||||
rel[1].r_info = ELFW(R_INFO)(0, R_386_NONE);
|
|
||||||
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
|
|
||||||
sec = s1->sections[sym->st_shndx];
|
|
||||||
x = sym->st_value - sec->sh_addr - sec->data_offset;
|
|
||||||
add32le(ptr + 5, -x);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
tcc_error_noabort("unexpected R_386_TLS_GD pattern");
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
case R_386_TLS_LDM:
|
|
||||||
{
|
|
||||||
static const unsigned char expect[] = {
|
|
||||||
/* lea 0(%ebx),%eax */
|
|
||||||
0x8d, 0x83, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
/* call __tls_get_addr@PLT */
|
|
||||||
0xe8, 0xfc, 0xff, 0xff, 0xff };
|
|
||||||
static const unsigned char replace[] = {
|
|
||||||
/* mov %gs:0,%eax */
|
|
||||||
0x65, 0xa1, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
/* nop */
|
|
||||||
0x90,
|
|
||||||
/* lea 0(%esi,%eiz,1),%esi */
|
|
||||||
0x8d, 0x74, 0x26, 0x00 };
|
|
||||||
|
|
||||||
if (memcmp (ptr-2, expect, sizeof(expect)) == 0) {
|
|
||||||
memcpy(ptr-2, replace, sizeof(replace));
|
|
||||||
rel[1].r_info = ELFW(R_INFO)(0, R_386_NONE);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
tcc_error_noabort("unexpected R_386_TLS_LDM pattern");
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
case R_386_TLS_LDO_32:
|
|
||||||
{
|
|
||||||
ElfW(Sym) *sym;
|
|
||||||
Section *sec;
|
|
||||||
int32_t x;
|
|
||||||
|
|
||||||
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
|
|
||||||
sec = s1->sections[sym->st_shndx];
|
|
||||||
x = val - sec->sh_addr - sec->data_offset;
|
|
||||||
add32le(ptr, x);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
case R_386_TLS_LE:
|
|
||||||
{
|
|
||||||
ElfW(Sym) *sym;
|
|
||||||
Section *sec;
|
|
||||||
int32_t x;
|
|
||||||
addr_t tls_start = 0, tls_end = 0, tls_align = 1;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
|
|
||||||
sec = s1->sections[sym->st_shndx];
|
|
||||||
|
|
||||||
for (i = 1; i < s1->nb_sections; i++) {
|
|
||||||
Section *s = s1->sections[i];
|
|
||||||
if (s->sh_flags & SHF_TLS && s->sh_size) {
|
|
||||||
if (!tls_start || s->sh_addr < tls_start)
|
|
||||||
tls_start = s->sh_addr;
|
|
||||||
if (s->sh_addr + s->sh_size > tls_end)
|
|
||||||
tls_end = s->sh_addr + s->sh_size;
|
|
||||||
if (s->sh_addralign > tls_align)
|
|
||||||
tls_align = s->sh_addralign;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (tls_end > tls_start) {
|
|
||||||
addr_t tls_size = tls_end - tls_start;
|
|
||||||
addr_t aligned_size = (tls_size + tls_align - 1) & ~(tls_align - 1);
|
|
||||||
x = val - (tls_start + aligned_size);
|
|
||||||
} else {
|
|
||||||
x = val - sec->sh_addr - sec->data_offset;
|
|
||||||
}
|
|
||||||
add32le(ptr, x);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
case R_386_NONE:
|
|
||||||
return;
|
|
||||||
default:
|
|
||||||
fprintf(stderr,"FIXME: handle reloc type %d at %x [%p] to %x\n",
|
|
||||||
type, (unsigned)addr, ptr, (unsigned)val);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* !TARGET_DEFS_ONLY */
|
|
||||||
332
i386-tok.h
332
i386-tok.h
@ -1,332 +0,0 @@
|
|||||||
/* ------------------------------------------------------------------ */
|
|
||||||
/* WARNING: relative order of tokens is important. */
|
|
||||||
|
|
||||||
#define DEF_BWL(x) \
|
|
||||||
DEF(TOK_ASM_ ## x ## b, #x "b") \
|
|
||||||
DEF(TOK_ASM_ ## x ## w, #x "w") \
|
|
||||||
DEF(TOK_ASM_ ## x ## l, #x "l") \
|
|
||||||
DEF(TOK_ASM_ ## x, #x)
|
|
||||||
#define DEF_WL(x) \
|
|
||||||
DEF(TOK_ASM_ ## x ## w, #x "w") \
|
|
||||||
DEF(TOK_ASM_ ## x ## l, #x "l") \
|
|
||||||
DEF(TOK_ASM_ ## x, #x)
|
|
||||||
#ifdef TCC_TARGET_X86_64
|
|
||||||
# define DEF_BWLQ(x) \
|
|
||||||
DEF(TOK_ASM_ ## x ## b, #x "b") \
|
|
||||||
DEF(TOK_ASM_ ## x ## w, #x "w") \
|
|
||||||
DEF(TOK_ASM_ ## x ## l, #x "l") \
|
|
||||||
DEF(TOK_ASM_ ## x ## q, #x "q") \
|
|
||||||
DEF(TOK_ASM_ ## x, #x)
|
|
||||||
# define DEF_WLQ(x) \
|
|
||||||
DEF(TOK_ASM_ ## x ## w, #x "w") \
|
|
||||||
DEF(TOK_ASM_ ## x ## l, #x "l") \
|
|
||||||
DEF(TOK_ASM_ ## x ## q, #x "q") \
|
|
||||||
DEF(TOK_ASM_ ## x, #x)
|
|
||||||
# define DEF_BWLX DEF_BWLQ
|
|
||||||
# define DEF_WLX DEF_WLQ
|
|
||||||
/* number of sizes + 1 */
|
|
||||||
# define NBWLX 5
|
|
||||||
#else
|
|
||||||
# define DEF_BWLX DEF_BWL
|
|
||||||
# define DEF_WLX DEF_WL
|
|
||||||
/* number of sizes + 1 */
|
|
||||||
# define NBWLX 4
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define DEF_FP1(x) \
|
|
||||||
DEF(TOK_ASM_ ## f ## x ## s, "f" #x "s") \
|
|
||||||
DEF(TOK_ASM_ ## fi ## x ## l, "fi" #x "l") \
|
|
||||||
DEF(TOK_ASM_ ## f ## x ## l, "f" #x "l") \
|
|
||||||
DEF(TOK_ASM_ ## fi ## x ## s, "fi" #x "s")
|
|
||||||
|
|
||||||
#define DEF_FP(x) \
|
|
||||||
DEF(TOK_ASM_ ## f ## x, "f" #x ) \
|
|
||||||
DEF(TOK_ASM_ ## f ## x ## p, "f" #x "p") \
|
|
||||||
DEF_FP1(x)
|
|
||||||
|
|
||||||
#define DEF_ASMTEST(x,suffix) \
|
|
||||||
DEF_ASM(x ## o ## suffix) \
|
|
||||||
DEF_ASM(x ## no ## suffix) \
|
|
||||||
DEF_ASM(x ## b ## suffix) \
|
|
||||||
DEF_ASM(x ## c ## suffix) \
|
|
||||||
DEF_ASM(x ## nae ## suffix) \
|
|
||||||
DEF_ASM(x ## nb ## suffix) \
|
|
||||||
DEF_ASM(x ## nc ## suffix) \
|
|
||||||
DEF_ASM(x ## ae ## suffix) \
|
|
||||||
DEF_ASM(x ## e ## suffix) \
|
|
||||||
DEF_ASM(x ## z ## suffix) \
|
|
||||||
DEF_ASM(x ## ne ## suffix) \
|
|
||||||
DEF_ASM(x ## nz ## suffix) \
|
|
||||||
DEF_ASM(x ## be ## suffix) \
|
|
||||||
DEF_ASM(x ## na ## suffix) \
|
|
||||||
DEF_ASM(x ## nbe ## suffix) \
|
|
||||||
DEF_ASM(x ## a ## suffix) \
|
|
||||||
DEF_ASM(x ## s ## suffix) \
|
|
||||||
DEF_ASM(x ## ns ## suffix) \
|
|
||||||
DEF_ASM(x ## p ## suffix) \
|
|
||||||
DEF_ASM(x ## pe ## suffix) \
|
|
||||||
DEF_ASM(x ## np ## suffix) \
|
|
||||||
DEF_ASM(x ## po ## suffix) \
|
|
||||||
DEF_ASM(x ## l ## suffix) \
|
|
||||||
DEF_ASM(x ## nge ## suffix) \
|
|
||||||
DEF_ASM(x ## nl ## suffix) \
|
|
||||||
DEF_ASM(x ## ge ## suffix) \
|
|
||||||
DEF_ASM(x ## le ## suffix) \
|
|
||||||
DEF_ASM(x ## ng ## suffix) \
|
|
||||||
DEF_ASM(x ## nle ## suffix) \
|
|
||||||
DEF_ASM(x ## g ## suffix)
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------ */
|
|
||||||
/* register */
|
|
||||||
DEF_ASM(al)
|
|
||||||
DEF_ASM(cl)
|
|
||||||
DEF_ASM(dl)
|
|
||||||
DEF_ASM(bl)
|
|
||||||
DEF_ASM(ah)
|
|
||||||
DEF_ASM(ch)
|
|
||||||
DEF_ASM(dh)
|
|
||||||
DEF_ASM(bh)
|
|
||||||
DEF_ASM(ax)
|
|
||||||
DEF_ASM(cx)
|
|
||||||
DEF_ASM(dx)
|
|
||||||
DEF_ASM(bx)
|
|
||||||
DEF_ASM(sp)
|
|
||||||
DEF_ASM(bp)
|
|
||||||
DEF_ASM(si)
|
|
||||||
DEF_ASM(di)
|
|
||||||
DEF_ASM(eax)
|
|
||||||
DEF_ASM(ecx)
|
|
||||||
DEF_ASM(edx)
|
|
||||||
DEF_ASM(ebx)
|
|
||||||
DEF_ASM(esp)
|
|
||||||
DEF_ASM(ebp)
|
|
||||||
DEF_ASM(esi)
|
|
||||||
DEF_ASM(edi)
|
|
||||||
#ifdef TCC_TARGET_X86_64
|
|
||||||
DEF_ASM(rax)
|
|
||||||
DEF_ASM(rcx)
|
|
||||||
DEF_ASM(rdx)
|
|
||||||
DEF_ASM(rbx)
|
|
||||||
DEF_ASM(rsp)
|
|
||||||
DEF_ASM(rbp)
|
|
||||||
DEF_ASM(rsi)
|
|
||||||
DEF_ASM(rdi)
|
|
||||||
#endif
|
|
||||||
DEF_ASM(mm0)
|
|
||||||
DEF_ASM(mm1)
|
|
||||||
DEF_ASM(mm2)
|
|
||||||
DEF_ASM(mm3)
|
|
||||||
DEF_ASM(mm4)
|
|
||||||
DEF_ASM(mm5)
|
|
||||||
DEF_ASM(mm6)
|
|
||||||
DEF_ASM(mm7)
|
|
||||||
DEF_ASM(xmm0)
|
|
||||||
DEF_ASM(xmm1)
|
|
||||||
DEF_ASM(xmm2)
|
|
||||||
DEF_ASM(xmm3)
|
|
||||||
DEF_ASM(xmm4)
|
|
||||||
DEF_ASM(xmm5)
|
|
||||||
DEF_ASM(xmm6)
|
|
||||||
DEF_ASM(xmm7)
|
|
||||||
DEF_ASM(cr0)
|
|
||||||
DEF_ASM(cr1)
|
|
||||||
DEF_ASM(cr2)
|
|
||||||
DEF_ASM(cr3)
|
|
||||||
DEF_ASM(cr4)
|
|
||||||
DEF_ASM(cr5)
|
|
||||||
DEF_ASM(cr6)
|
|
||||||
DEF_ASM(cr7)
|
|
||||||
DEF_ASM(tr0)
|
|
||||||
DEF_ASM(tr1)
|
|
||||||
DEF_ASM(tr2)
|
|
||||||
DEF_ASM(tr3)
|
|
||||||
DEF_ASM(tr4)
|
|
||||||
DEF_ASM(tr5)
|
|
||||||
DEF_ASM(tr6)
|
|
||||||
DEF_ASM(tr7)
|
|
||||||
DEF_ASM(db0)
|
|
||||||
DEF_ASM(db1)
|
|
||||||
DEF_ASM(db2)
|
|
||||||
DEF_ASM(db3)
|
|
||||||
DEF_ASM(db4)
|
|
||||||
DEF_ASM(db5)
|
|
||||||
DEF_ASM(db6)
|
|
||||||
DEF_ASM(db7)
|
|
||||||
DEF_ASM(dr0)
|
|
||||||
DEF_ASM(dr1)
|
|
||||||
DEF_ASM(dr2)
|
|
||||||
DEF_ASM(dr3)
|
|
||||||
DEF_ASM(dr4)
|
|
||||||
DEF_ASM(dr5)
|
|
||||||
DEF_ASM(dr6)
|
|
||||||
DEF_ASM(dr7)
|
|
||||||
DEF_ASM(es)
|
|
||||||
DEF_ASM(cs)
|
|
||||||
DEF_ASM(ss)
|
|
||||||
DEF_ASM(ds)
|
|
||||||
DEF_ASM(fs)
|
|
||||||
DEF_ASM(gs)
|
|
||||||
DEF_ASM(st)
|
|
||||||
DEF_ASM(rip)
|
|
||||||
|
|
||||||
#ifdef TCC_TARGET_X86_64
|
|
||||||
/* The four low parts of sp/bp/si/di that exist only on
|
|
||||||
x86-64 (encoding aliased to ah,ch,dh,dh when not using REX). */
|
|
||||||
DEF_ASM(spl)
|
|
||||||
DEF_ASM(bpl)
|
|
||||||
DEF_ASM(sil)
|
|
||||||
DEF_ASM(dil)
|
|
||||||
#endif
|
|
||||||
/* generic two operands */
|
|
||||||
DEF_BWLX(mov)
|
|
||||||
|
|
||||||
DEF_BWLX(add)
|
|
||||||
DEF_BWLX(or)
|
|
||||||
DEF_BWLX(adc)
|
|
||||||
DEF_BWLX(sbb)
|
|
||||||
DEF_BWLX(and)
|
|
||||||
DEF_BWLX(sub)
|
|
||||||
DEF_BWLX(xor)
|
|
||||||
DEF_BWLX(cmp)
|
|
||||||
|
|
||||||
/* unary ops */
|
|
||||||
DEF_BWLX(inc)
|
|
||||||
DEF_BWLX(dec)
|
|
||||||
DEF_BWLX(not)
|
|
||||||
DEF_BWLX(neg)
|
|
||||||
DEF_BWLX(mul)
|
|
||||||
DEF_BWLX(imul)
|
|
||||||
DEF_BWLX(div)
|
|
||||||
DEF_BWLX(idiv)
|
|
||||||
|
|
||||||
DEF_BWLX(xchg)
|
|
||||||
DEF_BWLX(test)
|
|
||||||
|
|
||||||
/* shifts */
|
|
||||||
DEF_BWLX(rol)
|
|
||||||
DEF_BWLX(ror)
|
|
||||||
DEF_BWLX(rcl)
|
|
||||||
DEF_BWLX(rcr)
|
|
||||||
DEF_BWLX(shl)
|
|
||||||
DEF_BWLX(shr)
|
|
||||||
DEF_BWLX(sar)
|
|
||||||
|
|
||||||
DEF_WLX(shld)
|
|
||||||
DEF_WLX(shrd)
|
|
||||||
|
|
||||||
DEF_ASM(pushw)
|
|
||||||
DEF_ASM(pushl)
|
|
||||||
#ifdef TCC_TARGET_X86_64
|
|
||||||
DEF_ASM(pushq)
|
|
||||||
#endif
|
|
||||||
DEF_ASM(push)
|
|
||||||
|
|
||||||
DEF_ASM(popw)
|
|
||||||
DEF_ASM(popl)
|
|
||||||
#ifdef TCC_TARGET_X86_64
|
|
||||||
DEF_ASM(popq)
|
|
||||||
#endif
|
|
||||||
DEF_ASM(pop)
|
|
||||||
|
|
||||||
DEF_BWL(in)
|
|
||||||
DEF_BWL(out)
|
|
||||||
|
|
||||||
DEF_WLX(movzb)
|
|
||||||
DEF_ASM(movzwl)
|
|
||||||
DEF_ASM(movsbw)
|
|
||||||
DEF_ASM(movsbl)
|
|
||||||
DEF_ASM(movswl)
|
|
||||||
#ifdef TCC_TARGET_X86_64
|
|
||||||
DEF_ASM(movsbq)
|
|
||||||
DEF_ASM(movswq)
|
|
||||||
DEF_ASM(movzwq)
|
|
||||||
DEF_ASM(movslq)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
DEF_WLX(lea)
|
|
||||||
|
|
||||||
DEF_ASM(les)
|
|
||||||
DEF_ASM(lds)
|
|
||||||
DEF_ASM(lss)
|
|
||||||
DEF_ASM(lfs)
|
|
||||||
DEF_ASM(lgs)
|
|
||||||
|
|
||||||
DEF_ASM(call)
|
|
||||||
DEF_ASM(jmp)
|
|
||||||
DEF_ASM(lcall)
|
|
||||||
DEF_ASM(ljmp)
|
|
||||||
|
|
||||||
DEF_ASMTEST(j,)
|
|
||||||
|
|
||||||
DEF_ASMTEST(set,)
|
|
||||||
DEF_ASMTEST(set,b)
|
|
||||||
DEF_ASMTEST(cmov,)
|
|
||||||
|
|
||||||
DEF_WLX(bsf)
|
|
||||||
DEF_WLX(bsr)
|
|
||||||
DEF_WLX(bt)
|
|
||||||
DEF_WLX(bts)
|
|
||||||
DEF_WLX(btr)
|
|
||||||
DEF_WLX(btc)
|
|
||||||
DEF_WLX(popcnt)
|
|
||||||
DEF_WLX(tzcnt)
|
|
||||||
DEF_WLX(lzcnt)
|
|
||||||
|
|
||||||
DEF_WLX(lar)
|
|
||||||
DEF_WLX(lsl)
|
|
||||||
|
|
||||||
/* generic FP ops */
|
|
||||||
DEF_FP(add)
|
|
||||||
DEF_FP(mul)
|
|
||||||
|
|
||||||
DEF_ASM(fcom)
|
|
||||||
DEF_ASM(fcom_1) /* non existent op, just to have a regular table */
|
|
||||||
DEF_FP1(com)
|
|
||||||
|
|
||||||
DEF_FP(comp)
|
|
||||||
DEF_FP(sub)
|
|
||||||
DEF_FP(subr)
|
|
||||||
DEF_FP(div)
|
|
||||||
DEF_FP(divr)
|
|
||||||
|
|
||||||
DEF_BWLX(xadd)
|
|
||||||
DEF_BWLX(cmpxchg)
|
|
||||||
|
|
||||||
/* string ops */
|
|
||||||
DEF_BWLX(cmps)
|
|
||||||
DEF_BWLX(scmp)
|
|
||||||
DEF_BWL(ins)
|
|
||||||
DEF_BWL(outs)
|
|
||||||
DEF_BWLX(lods)
|
|
||||||
DEF_BWLX(slod)
|
|
||||||
DEF_BWLX(movs)
|
|
||||||
DEF_BWLX(smov)
|
|
||||||
DEF_BWLX(scas)
|
|
||||||
DEF_BWLX(ssca)
|
|
||||||
DEF_BWLX(stos)
|
|
||||||
DEF_BWLX(ssto)
|
|
||||||
|
|
||||||
/* generic asm ops */
|
|
||||||
#define ALT(x)
|
|
||||||
#define DEF_ASM_OP0(name, opcode) DEF_ASM(name)
|
|
||||||
#define DEF_ASM_OP0L(name, opcode, group, instr_type)
|
|
||||||
#define DEF_ASM_OP1(name, opcode, group, instr_type, op0)
|
|
||||||
#define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1)
|
|
||||||
#define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2)
|
|
||||||
#ifdef TCC_TARGET_X86_64
|
|
||||||
# include "x86_64-asm.h"
|
|
||||||
#else
|
|
||||||
# include "i386-asm.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define ALT(x)
|
|
||||||
#define DEF_ASM_OP0(name, opcode)
|
|
||||||
#define DEF_ASM_OP0L(name, opcode, group, instr_type) DEF_ASM(name)
|
|
||||||
#define DEF_ASM_OP1(name, opcode, group, instr_type, op0) DEF_ASM(name)
|
|
||||||
#define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1) DEF_ASM(name)
|
|
||||||
#define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2) DEF_ASM(name)
|
|
||||||
#ifdef TCC_TARGET_X86_64
|
|
||||||
# include "x86_64-asm.h"
|
|
||||||
#else
|
|
||||||
# include "i386-asm.h"
|
|
||||||
#endif
|
|
||||||
52
il-gen.c
52
il-gen.c
@ -3,23 +3,21 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 2002 Fabrice Bellard
|
* Copyright (c) 2002 Fabrice Bellard
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* it under the terms of the GNU General Public License as published by
|
||||||
* License as published by the Free Software Foundation; either
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
* version 2 of the License, or (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This library is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* Lesser General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU General Public License
|
||||||
* License along with this library; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#error this code has bit-rotted since 2003
|
|
||||||
|
|
||||||
/* number of available registers */
|
/* number of available registers */
|
||||||
#define NB_REGS 3
|
#define NB_REGS 3
|
||||||
|
|
||||||
@ -43,7 +41,7 @@ enum {
|
|||||||
REG_ST2,
|
REG_ST2,
|
||||||
};
|
};
|
||||||
|
|
||||||
const int reg_classes[NB_REGS] = {
|
int reg_classes[NB_REGS] = {
|
||||||
/* ST0 */ RC_ST | RC_ST0,
|
/* ST0 */ RC_ST | RC_ST0,
|
||||||
/* ST1 */ RC_ST | RC_ST1,
|
/* ST1 */ RC_ST | RC_ST1,
|
||||||
/* ST2 */ RC_ST,
|
/* ST2 */ RC_ST,
|
||||||
@ -55,11 +53,11 @@ const int reg_classes[NB_REGS] = {
|
|||||||
#define REG_FRET REG_ST0 /* float return register */
|
#define REG_FRET REG_ST0 /* float return register */
|
||||||
|
|
||||||
/* defined if function parameters must be evaluated in reverse order */
|
/* defined if function parameters must be evaluated in reverse order */
|
||||||
/* #define INVERT_FUNC_PARAMS */
|
//#define INVERT_FUNC_PARAMS
|
||||||
|
|
||||||
/* defined if structures are passed as pointers. Otherwise structures
|
/* defined if structures are passed as pointers. Otherwise structures
|
||||||
are directly pushed on stack. */
|
are directly pushed on stack. */
|
||||||
/* #define FUNC_STRUCT_PARAM_AS_PTR */
|
//#define FUNC_STRUCT_PARAM_AS_PTR
|
||||||
|
|
||||||
/* pointer size, in bytes */
|
/* pointer size, in bytes */
|
||||||
#define PTR_SIZE 4
|
#define PTR_SIZE 4
|
||||||
@ -195,7 +193,7 @@ static void il_type_to_str(char *buf, int buf_size,
|
|||||||
pstrcat(buf, buf_size, tstr);
|
pstrcat(buf, buf_size, tstr);
|
||||||
break;
|
break;
|
||||||
case VT_STRUCT:
|
case VT_STRUCT:
|
||||||
tcc_error("structures not handled yet");
|
error("structures not handled yet");
|
||||||
break;
|
break;
|
||||||
case VT_FUNC:
|
case VT_FUNC:
|
||||||
s = sym_find((unsigned)t >> VT_STRUCT_SHIFT);
|
s = sym_find((unsigned)t >> VT_STRUCT_SHIFT);
|
||||||
@ -389,7 +387,7 @@ void gfunc_start(GFuncContext *c, int func_call)
|
|||||||
void gfunc_param(GFuncContext *c)
|
void gfunc_param(GFuncContext *c)
|
||||||
{
|
{
|
||||||
if ((vtop->t & VT_BTYPE) == VT_STRUCT) {
|
if ((vtop->t & VT_BTYPE) == VT_STRUCT) {
|
||||||
tcc_error("structures passed as value not handled yet");
|
error("structures passed as value not handled yet");
|
||||||
} else {
|
} else {
|
||||||
/* simply push on stack */
|
/* simply push on stack */
|
||||||
gv(RC_ST0);
|
gv(RC_ST0);
|
||||||
@ -443,7 +441,6 @@ void gfunc_prolog(int t)
|
|||||||
/* if the function returns a structure, then add an
|
/* if the function returns a structure, then add an
|
||||||
implicit pointer parameter */
|
implicit pointer parameter */
|
||||||
func_vt = sym->t;
|
func_vt = sym->t;
|
||||||
func_var = (sym->c == FUNC_ELLIPSIS);
|
|
||||||
if ((func_vt & VT_BTYPE) == VT_STRUCT) {
|
if ((func_vt & VT_BTYPE) == VT_STRUCT) {
|
||||||
func_vc = addr;
|
func_vc = addr;
|
||||||
addr++;
|
addr++;
|
||||||
@ -452,7 +449,7 @@ void gfunc_prolog(int t)
|
|||||||
while ((sym = sym->next) != NULL) {
|
while ((sym = sym->next) != NULL) {
|
||||||
u = sym->t;
|
u = sym->t;
|
||||||
sym_push(sym->v & ~SYM_FIELD, u,
|
sym_push(sym->v & ~SYM_FIELD, u,
|
||||||
VT_LOCAL | lvalue_type(sym->type.t), addr);
|
VT_LOCAL | VT_LVAL, addr);
|
||||||
addr++;
|
addr++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -531,6 +528,19 @@ int gtst(int inv, int t)
|
|||||||
t = gjmp(t);
|
t = gjmp(t);
|
||||||
gsym(vtop->c.i);
|
gsym(vtop->c.i);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (is_float(vtop->t)) {
|
||||||
|
vpushi(0);
|
||||||
|
gen_op(TOK_NE);
|
||||||
|
}
|
||||||
|
if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_FORWARD)) == VT_CONST) {
|
||||||
|
/* constant jmp optimization */
|
||||||
|
if ((vtop->c.i != 0) != inv)
|
||||||
|
t = gjmp(t);
|
||||||
|
} else {
|
||||||
|
v = gv(RC_INT);
|
||||||
|
t = out_opj(IL_OP_BRTRUE - inv, t);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
vtop--;
|
vtop--;
|
||||||
return t;
|
return t;
|
||||||
@ -602,7 +612,7 @@ void gen_opi(int op)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* generate a floating point operation 'v = t1 op t2' instruction. The
|
/* generate a floating point operation 'v = t1 op t2' instruction. The
|
||||||
two operands are guaranteed to have the same floating point type */
|
two operands are guaranted to have the same floating point type */
|
||||||
void gen_opf(int op)
|
void gen_opf(int op)
|
||||||
{
|
{
|
||||||
/* same as integer */
|
/* same as integer */
|
||||||
|
|||||||
@ -1,16 +0,0 @@
|
|||||||
#ifndef _STDALIGN_H
|
|
||||||
#define _STDALIGN_H
|
|
||||||
|
|
||||||
#if __STDC_VERSION__ < 201112L && (defined(__GNUC__) || defined(__TINYC__))
|
|
||||||
# define _Alignas(t) __attribute__((__aligned__(t)))
|
|
||||||
# define _Alignof(t) __alignof__(t)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define alignas _Alignas
|
|
||||||
#define alignof _Alignof
|
|
||||||
|
|
||||||
#define __alignas_is_defined 1
|
|
||||||
#define __alignof_is_defined 1
|
|
||||||
|
|
||||||
#endif /* _STDALIGN_H */
|
|
||||||
|
|
||||||
@ -1,14 +0,0 @@
|
|||||||
#ifndef _STDARG_H
|
|
||||||
#define _STDARG_H
|
|
||||||
|
|
||||||
typedef __builtin_va_list va_list;
|
|
||||||
#define va_start __builtin_va_start
|
|
||||||
#define va_arg __builtin_va_arg
|
|
||||||
#define va_copy __builtin_va_copy
|
|
||||||
#define va_end __builtin_va_end
|
|
||||||
|
|
||||||
/* fix a buggy dependency on GCC in libio.h */
|
|
||||||
typedef va_list __gnuc_va_list;
|
|
||||||
#define _VA_LIST_DEFINED
|
|
||||||
|
|
||||||
#endif /* _STDARG_H */
|
|
||||||
@ -1,171 +0,0 @@
|
|||||||
/* This file is derived from clang's stdatomic.h */
|
|
||||||
|
|
||||||
/*===---- stdatomic.h - Standard header for atomic types and operations -----===
|
|
||||||
*
|
|
||||||
* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
||||||
* See https://llvm.org/LICENSE.txt for license information.
|
|
||||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
||||||
*
|
|
||||||
*===-----------------------------------------------------------------------===
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _STDATOMIC_H
|
|
||||||
#define _STDATOMIC_H
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
#define __ATOMIC_RELAXED 0
|
|
||||||
#define __ATOMIC_CONSUME 1
|
|
||||||
#define __ATOMIC_ACQUIRE 2
|
|
||||||
#define __ATOMIC_RELEASE 3
|
|
||||||
#define __ATOMIC_ACQ_REL 4
|
|
||||||
#define __ATOMIC_SEQ_CST 5
|
|
||||||
|
|
||||||
/* Memory ordering */
|
|
||||||
typedef enum {
|
|
||||||
memory_order_relaxed = __ATOMIC_RELAXED,
|
|
||||||
memory_order_consume = __ATOMIC_CONSUME,
|
|
||||||
memory_order_acquire = __ATOMIC_ACQUIRE,
|
|
||||||
memory_order_release = __ATOMIC_RELEASE,
|
|
||||||
memory_order_acq_rel = __ATOMIC_ACQ_REL,
|
|
||||||
memory_order_seq_cst = __ATOMIC_SEQ_CST,
|
|
||||||
} memory_order;
|
|
||||||
|
|
||||||
/* Atomic typedefs */
|
|
||||||
typedef _Atomic(_Bool) atomic_bool;
|
|
||||||
typedef _Atomic(char) atomic_char;
|
|
||||||
typedef _Atomic(signed char) atomic_schar;
|
|
||||||
typedef _Atomic(unsigned char) atomic_uchar;
|
|
||||||
typedef _Atomic(short) atomic_short;
|
|
||||||
typedef _Atomic(unsigned short) atomic_ushort;
|
|
||||||
typedef _Atomic(int) atomic_int;
|
|
||||||
typedef _Atomic(unsigned int) atomic_uint;
|
|
||||||
typedef _Atomic(long) atomic_long;
|
|
||||||
typedef _Atomic(unsigned long) atomic_ulong;
|
|
||||||
typedef _Atomic(long long) atomic_llong;
|
|
||||||
typedef _Atomic(unsigned long long) atomic_ullong;
|
|
||||||
typedef _Atomic(uint_least16_t) atomic_char16_t;
|
|
||||||
typedef _Atomic(uint_least32_t) atomic_char32_t;
|
|
||||||
typedef _Atomic(wchar_t) atomic_wchar_t;
|
|
||||||
typedef _Atomic(int_least8_t) atomic_int_least8_t;
|
|
||||||
typedef _Atomic(uint_least8_t) atomic_uint_least8_t;
|
|
||||||
typedef _Atomic(int_least16_t) atomic_int_least16_t;
|
|
||||||
typedef _Atomic(uint_least16_t) atomic_uint_least16_t;
|
|
||||||
typedef _Atomic(int_least32_t) atomic_int_least32_t;
|
|
||||||
typedef _Atomic(uint_least32_t) atomic_uint_least32_t;
|
|
||||||
typedef _Atomic(int_least64_t) atomic_int_least64_t;
|
|
||||||
typedef _Atomic(uint_least64_t) atomic_uint_least64_t;
|
|
||||||
typedef _Atomic(int_fast8_t) atomic_int_fast8_t;
|
|
||||||
typedef _Atomic(uint_fast8_t) atomic_uint_fast8_t;
|
|
||||||
typedef _Atomic(int_fast16_t) atomic_int_fast16_t;
|
|
||||||
typedef _Atomic(uint_fast16_t) atomic_uint_fast16_t;
|
|
||||||
typedef _Atomic(int_fast32_t) atomic_int_fast32_t;
|
|
||||||
typedef _Atomic(uint_fast32_t) atomic_uint_fast32_t;
|
|
||||||
typedef _Atomic(int_fast64_t) atomic_int_fast64_t;
|
|
||||||
typedef _Atomic(uint_fast64_t) atomic_uint_fast64_t;
|
|
||||||
typedef _Atomic(intptr_t) atomic_intptr_t;
|
|
||||||
typedef _Atomic(uintptr_t) atomic_uintptr_t;
|
|
||||||
typedef _Atomic(size_t) atomic_size_t;
|
|
||||||
typedef _Atomic(ptrdiff_t) atomic_ptrdiff_t;
|
|
||||||
typedef _Atomic(intmax_t) atomic_intmax_t;
|
|
||||||
typedef _Atomic(uintmax_t) atomic_uintmax_t;
|
|
||||||
|
|
||||||
/* Atomic flag */
|
|
||||||
typedef struct {
|
|
||||||
atomic_bool value;
|
|
||||||
} atomic_flag;
|
|
||||||
|
|
||||||
#define ATOMIC_FLAG_INIT {0}
|
|
||||||
#define ATOMIC_VAR_INIT(value) (value)
|
|
||||||
|
|
||||||
/* Generic routines */
|
|
||||||
#define atomic_init(object, desired) \
|
|
||||||
atomic_store_explicit(object, desired, __ATOMIC_RELAXED)
|
|
||||||
|
|
||||||
#define __atomic_store_n(ptr, val, order) \
|
|
||||||
(*(ptr) = (val), __atomic_store((ptr), &(typeof(*(ptr))){val}, (order)))
|
|
||||||
#define atomic_store_explicit(object, desired, order) \
|
|
||||||
({ __typeof__ (object) ptr = (object); \
|
|
||||||
__typeof__ (*ptr) tmp = (desired); \
|
|
||||||
__atomic_store (ptr, &tmp, (order)); \
|
|
||||||
})
|
|
||||||
#define atomic_store(object, desired) \
|
|
||||||
atomic_store_explicit (object, desired, __ATOMIC_SEQ_CST)
|
|
||||||
|
|
||||||
#define __atomic_load_n(ptr, order) \
|
|
||||||
({ typeof(*(ptr)) __val; \
|
|
||||||
__atomic_load((ptr), &__val, (order)); \
|
|
||||||
__val; })
|
|
||||||
#define atomic_load_explicit(object, order) \
|
|
||||||
({ __typeof__ (object) ptr = (object); \
|
|
||||||
__typeof__ ((void)0,*ptr) tmp; \
|
|
||||||
__atomic_load (ptr, &tmp, (order)); \
|
|
||||||
tmp; \
|
|
||||||
})
|
|
||||||
#define atomic_load(object) atomic_load_explicit (object, __ATOMIC_SEQ_CST)
|
|
||||||
|
|
||||||
#define atomic_exchange_explicit(object, desired, order) \
|
|
||||||
({ __typeof__ (object) ptr = (object); \
|
|
||||||
__typeof__ (*ptr) val = (desired); \
|
|
||||||
__typeof__ (*ptr) tmp; \
|
|
||||||
__atomic_exchange (ptr, &val, &tmp, (order)); \
|
|
||||||
tmp; \
|
|
||||||
})
|
|
||||||
#define atomic_exchange(object, desired) \
|
|
||||||
atomic_exchange_explicit (object, desired, __ATOMIC_SEQ_CST)
|
|
||||||
#define __atomic_compare_exchange_n(ptr, expected, desired, weak, success, failure) \
|
|
||||||
({ typeof(*(ptr)) __desired = (desired); \
|
|
||||||
__atomic_compare_exchange((ptr), (expected), &__desired, \
|
|
||||||
(weak), (success), (failure)); })
|
|
||||||
#define atomic_compare_exchange_strong_explicit(object, expected, desired, success, failure) \
|
|
||||||
({ __typeof__ (object) ptr = (object); \
|
|
||||||
__typeof__ (*ptr) tmp = desired; \
|
|
||||||
__atomic_compare_exchange(ptr, expected, &tmp, 0, success, failure); \
|
|
||||||
})
|
|
||||||
#define atomic_compare_exchange_strong(object, expected, desired) \
|
|
||||||
atomic_compare_exchange_strong_explicit (object, expected, desired, \
|
|
||||||
__ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
|
|
||||||
#define atomic_compare_exchange_weak_explicit(object, expected, desired, success, failure) \
|
|
||||||
({ __typeof__ (object) ptr = (object); \
|
|
||||||
__typeof__ (*ptr) tmp = desired; \
|
|
||||||
__atomic_compare_exchange(ptr, expected, &tmp, 1, success, failure); \
|
|
||||||
})
|
|
||||||
#define atomic_compare_exchange_weak(object, expected, desired) \
|
|
||||||
atomic_compare_exchange_weak_explicit (object, expected, desired, \
|
|
||||||
__ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
|
|
||||||
|
|
||||||
#define atomic_fetch_add(object, operand) \
|
|
||||||
__atomic_fetch_add(object, operand, __ATOMIC_SEQ_CST)
|
|
||||||
#define atomic_fetch_add_explicit __atomic_fetch_add
|
|
||||||
|
|
||||||
#define atomic_fetch_sub(object, operand) \
|
|
||||||
__atomic_fetch_sub(object, operand, __ATOMIC_SEQ_CST)
|
|
||||||
#define atomic_fetch_sub_explicit __atomic_fetch_sub
|
|
||||||
|
|
||||||
#define atomic_fetch_or(object, operand) \
|
|
||||||
__atomic_fetch_or(object, operand, __ATOMIC_SEQ_CST)
|
|
||||||
#define atomic_fetch_or_explicit __atomic_fetch_or
|
|
||||||
|
|
||||||
#define atomic_fetch_xor(object, operand) \
|
|
||||||
__atomic_fetch_xor(object, operand, __ATOMIC_SEQ_CST)
|
|
||||||
#define atomic_fetch_xor_explicit __atomic_fetch_xor
|
|
||||||
|
|
||||||
#define atomic_fetch_and(object, operand) \
|
|
||||||
__atomic_fetch_and(object, operand, __ATOMIC_SEQ_CST)
|
|
||||||
#define atomic_fetch_and_explicit __atomic_fetch_and
|
|
||||||
|
|
||||||
extern void atomic_thread_fence (memory_order);
|
|
||||||
#define __atomic_thread_fence(order) atomic_thread_fence (order)
|
|
||||||
extern void atomic_signal_fence (memory_order);
|
|
||||||
#define __atomic_signal_fence(order) atomic_signal_fence(order)
|
|
||||||
#define atomic_signal_fence(order) __atomic_signal_fence (order)
|
|
||||||
extern bool __atomic_is_lock_free(size_t size, void *ptr);
|
|
||||||
#define atomic_is_lock_free(OBJ) __atomic_is_lock_free (sizeof (*(OBJ)), (OBJ))
|
|
||||||
|
|
||||||
extern bool atomic_flag_test_and_set(void *object);
|
|
||||||
extern bool atomic_flag_test_and_set_explicit(void *object, memory_order order);
|
|
||||||
extern void atomic_flag_clear(void *object);
|
|
||||||
extern void atomic_flag_clear_explicit(void *object, memory_order order);
|
|
||||||
#endif /* _STDATOMIC_H */
|
|
||||||
@ -1,39 +0,0 @@
|
|||||||
#ifndef _STDDEF_H
|
|
||||||
#define _STDDEF_H
|
|
||||||
|
|
||||||
typedef __SIZE_TYPE__ size_t;
|
|
||||||
typedef __PTRDIFF_TYPE__ ssize_t;
|
|
||||||
typedef __WCHAR_TYPE__ wchar_t;
|
|
||||||
typedef __PTRDIFF_TYPE__ ptrdiff_t;
|
|
||||||
typedef __PTRDIFF_TYPE__ intptr_t;
|
|
||||||
typedef __SIZE_TYPE__ uintptr_t;
|
|
||||||
|
|
||||||
#if __STDC_VERSION__ >= 201112L
|
|
||||||
typedef union { long long __ll; long double __ld; } max_align_t;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef NULL
|
|
||||||
#define NULL ((void*)0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#undef offsetof
|
|
||||||
#define offsetof(type, field) __builtin_offsetof(type, field)
|
|
||||||
|
|
||||||
void *alloca(size_t size);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Older glibc require a wint_t from <stddef.h> (when requested
|
|
||||||
by __need_wint_t, as otherwise stddef.h isn't allowed to
|
|
||||||
define this type). Note that this must be outside the normal
|
|
||||||
_STDDEF_H guard, so that it works even when we've included the file
|
|
||||||
already (without requiring wint_t). Some other libs define _WINT_T
|
|
||||||
if they've already provided that type, so we can use that as guard.
|
|
||||||
TCC defines __WINT_TYPE__ for us. */
|
|
||||||
#if defined (__need_wint_t)
|
|
||||||
#ifndef _WINT_T
|
|
||||||
#define _WINT_T
|
|
||||||
typedef __WINT_TYPE__ wint_t;
|
|
||||||
#endif
|
|
||||||
#undef __need_wint_t
|
|
||||||
#endif
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
#ifndef _STDNORETURN_H
|
|
||||||
#define _STDNORETURN_H
|
|
||||||
|
|
||||||
/* ISOC11 noreturn */
|
|
||||||
#define noreturn _Noreturn
|
|
||||||
|
|
||||||
#endif /* _STDNORETURN_H */
|
|
||||||
@ -1,338 +0,0 @@
|
|||||||
/* tccdefs.h
|
|
||||||
|
|
||||||
Nothing is defined before this file except target machine, target os
|
|
||||||
and the few things related to option settings in tccpp.c:tcc_predefs().
|
|
||||||
|
|
||||||
This file is either included at runtime as is, or converted and
|
|
||||||
included as C-strings at compile-time (depending on CONFIG_TCC_PREDEFS).
|
|
||||||
|
|
||||||
Note that line indent matters:
|
|
||||||
|
|
||||||
- in lines starting at column 1, platform macros are replaced by
|
|
||||||
corresponding TCC target compile-time macros. See conftest.c for
|
|
||||||
the list of platform macros supported in lines starting at column 1.
|
|
||||||
|
|
||||||
- only lines indented >= 4 are actually included into the executable,
|
|
||||||
check tccdefs_.h.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if __SIZEOF_POINTER__ == 4
|
|
||||||
/* 32bit systems. */
|
|
||||||
#if defined __OpenBSD__
|
|
||||||
#define __SIZE_TYPE__ unsigned long
|
|
||||||
#define __PTRDIFF_TYPE__ long
|
|
||||||
#else
|
|
||||||
#define __SIZE_TYPE__ unsigned int
|
|
||||||
#define __PTRDIFF_TYPE__ int
|
|
||||||
#endif
|
|
||||||
#define __ILP32__ 1
|
|
||||||
#define __INT64_TYPE__ long long
|
|
||||||
#elif __SIZEOF_LONG__ == 4
|
|
||||||
/* 64bit Windows. */
|
|
||||||
#define __SIZE_TYPE__ unsigned long long
|
|
||||||
#define __PTRDIFF_TYPE__ long long
|
|
||||||
#define __LLP64__ 1
|
|
||||||
#define __INT64_TYPE__ long long
|
|
||||||
#else
|
|
||||||
/* Other 64bit systems. */
|
|
||||||
#define __SIZE_TYPE__ unsigned long
|
|
||||||
#define __PTRDIFF_TYPE__ long
|
|
||||||
#define __LP64__ 1
|
|
||||||
# if defined __linux__
|
|
||||||
#define __INT64_TYPE__ long
|
|
||||||
# else /* APPLE, BSD */
|
|
||||||
#define __INT64_TYPE__ long long
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
#define __SIZEOF_INT__ 4
|
|
||||||
#define __INT_MAX__ 0x7fffffff
|
|
||||||
#if __SIZEOF_LONG__ == 4
|
|
||||||
#define __LONG_MAX__ 0x7fffffffL
|
|
||||||
#else
|
|
||||||
#define __LONG_MAX__ 0x7fffffffffffffffL
|
|
||||||
#endif
|
|
||||||
#define __SIZEOF_LONG_LONG__ 8
|
|
||||||
#define __LONG_LONG_MAX__ 0x7fffffffffffffffLL
|
|
||||||
#define __CHAR_BIT__ 8
|
|
||||||
#define __ORDER_LITTLE_ENDIAN__ 1234
|
|
||||||
#define __ORDER_BIG_ENDIAN__ 4321
|
|
||||||
#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
|
|
||||||
#if defined _WIN32
|
|
||||||
#define __WCHAR_TYPE__ unsigned short
|
|
||||||
#define __WINT_TYPE__ unsigned short
|
|
||||||
#elif defined __linux__
|
|
||||||
#define __WCHAR_TYPE__ int
|
|
||||||
#define __WINT_TYPE__ unsigned int
|
|
||||||
#else
|
|
||||||
#define __WCHAR_TYPE__ int
|
|
||||||
#define __WINT_TYPE__ int
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if __STDC_VERSION__ >= 201112L
|
|
||||||
# define __STDC_NO_ATOMICS__ 1
|
|
||||||
# define __STDC_NO_COMPLEX__ 1
|
|
||||||
# define __STDC_NO_THREADS__ 1
|
|
||||||
#if !defined _WIN32
|
|
||||||
# define __STDC_UTF_16__ 1
|
|
||||||
# define __STDC_UTF_32__ 1
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined _WIN32
|
|
||||||
#define __declspec(x) __attribute__((x))
|
|
||||||
#define __cdecl
|
|
||||||
|
|
||||||
#elif defined __FreeBSD__
|
|
||||||
#define __GNUC__ 9
|
|
||||||
#define __GNUC_MINOR__ 3
|
|
||||||
#define __GNUC_PATCHLEVEL__ 0
|
|
||||||
#define __GNUC_STDC_INLINE__ 1
|
|
||||||
#define __NO_TLS 1
|
|
||||||
#define __RUNETYPE_INTERNAL 1
|
|
||||||
# if __SIZEOF_POINTER__ == 8
|
|
||||||
#define __SIZEOF_SIZE_T__ 8
|
|
||||||
#define __SIZEOF_PTRDIFF_T__ 8
|
|
||||||
#else
|
|
||||||
#define __SIZEOF_SIZE_T__ 4
|
|
||||||
#define __SIZEOF_PTRDIFF_T__ 4
|
|
||||||
# endif
|
|
||||||
|
|
||||||
#elif defined __FreeBSD_kernel__
|
|
||||||
|
|
||||||
#elif defined __NetBSD__
|
|
||||||
#define __GNUC__ 4
|
|
||||||
#define __GNUC_MINOR__ 1
|
|
||||||
#define __GNUC_PATCHLEVEL__ 0
|
|
||||||
#define _Pragma(x)
|
|
||||||
#define __ELF__ 1
|
|
||||||
#if defined __aarch64__
|
|
||||||
#define _LOCORE /* avoids usage of __asm */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#elif defined __OpenBSD__
|
|
||||||
#define __GNUC__ 4
|
|
||||||
#define _ANSI_LIBRARY 1
|
|
||||||
|
|
||||||
#elif defined __APPLE__
|
|
||||||
/* emulate APPLE-GCC to make libc's headerfiles compile: */
|
|
||||||
#define __GNUC__ 4 /* darwin emits warning on GCC<4 */
|
|
||||||
#define __APPLE_CC__ 1 /* for <TargetConditionals.h> */
|
|
||||||
#define __LITTLE_ENDIAN__ 1
|
|
||||||
#define _DONT_USE_CTYPE_INLINE_ 1
|
|
||||||
/* avoids usage of GCC/clang specific builtins in libc-headerfiles: */
|
|
||||||
#define __FINITE_MATH_ONLY__ 1
|
|
||||||
#define _FORTIFY_SOURCE 0
|
|
||||||
//#define __has_builtin(x) 0
|
|
||||||
#define _Float16 short unsigned int /* fake type just for size & alignment (macOS Sequoia) */
|
|
||||||
|
|
||||||
#elif defined __ANDROID__
|
|
||||||
#define BIONIC_IOCTL_NO_SIGNEDNESS_OVERLOAD
|
|
||||||
|
|
||||||
#else
|
|
||||||
/* Linux */
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Some derived integer types needed to get stdint.h to compile correctly on some platforms */
|
|
||||||
#ifndef __NetBSD__
|
|
||||||
#define __UINTPTR_TYPE__ unsigned __PTRDIFF_TYPE__
|
|
||||||
#define __INTPTR_TYPE__ __PTRDIFF_TYPE__
|
|
||||||
#endif
|
|
||||||
#define __INT32_TYPE__ int
|
|
||||||
|
|
||||||
#if !defined _WIN32
|
|
||||||
/* glibc defines. We do not support __USER_NAME_PREFIX__ */
|
|
||||||
#define __REDIRECT(name, proto, alias) name proto __asm__ (#alias)
|
|
||||||
#define __REDIRECT_NTH(name, proto, alias) name proto __asm__ (#alias) __THROW
|
|
||||||
#define __REDIRECT_NTHNL(name, proto, alias) name proto __asm__ (#alias) __THROWNL
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* not implemented */
|
|
||||||
#define __PRETTY_FUNCTION__ __FUNCTION__
|
|
||||||
#define __has_builtin(x) 0
|
|
||||||
#define __has_feature(x) 0
|
|
||||||
#define __has_attribute(x) 0
|
|
||||||
/* C23 Keywords */
|
|
||||||
#define _Nonnull
|
|
||||||
#define _Nullable
|
|
||||||
#define _Nullable_result
|
|
||||||
#define _Null_unspecified
|
|
||||||
|
|
||||||
/* skip __builtin... with -E */
|
|
||||||
#ifndef __TCC_PP__
|
|
||||||
|
|
||||||
#define __builtin_offsetof(type, field) ((__SIZE_TYPE__)&((type*)0)->field)
|
|
||||||
#define __builtin_extract_return_addr(x) x
|
|
||||||
#if !defined __linux__ && !defined _WIN32
|
|
||||||
/* used by math.h */
|
|
||||||
#define __builtin_huge_val() 1e500
|
|
||||||
#define __builtin_huge_valf() 1e50f
|
|
||||||
#define __builtin_huge_vall() 1e5000L
|
|
||||||
# if defined __APPLE__
|
|
||||||
#define __builtin_nanf(ignored_string) (0.0F/0.0F)
|
|
||||||
/* used by floats.h to implement FLT_ROUNDS C99 macro. 1 == to nearest */
|
|
||||||
#define __builtin_flt_rounds() 1
|
|
||||||
/* used by _fd_def.h */
|
|
||||||
#define __builtin_bzero(p, ignored_size) bzero(p, sizeof(*(p)))
|
|
||||||
# else
|
|
||||||
#define __builtin_nanf(ignored_string) (0.0F/0.0F)
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* GCC's __uint128_t appears in some Linux/OSX header files.
|
|
||||||
Just make it some type with same size and alignment. */
|
|
||||||
struct __uint128__ { char x[16]; } __attribute((__aligned__(16)));
|
|
||||||
#define __int128_t struct __uint128__
|
|
||||||
#define __uint128_t struct __uint128__
|
|
||||||
|
|
||||||
/* __builtin_va_list */
|
|
||||||
#if defined __x86_64__
|
|
||||||
#if !defined _WIN32
|
|
||||||
/* GCC compatible definition of va_list. */
|
|
||||||
/* This should be in sync with the declaration in our lib/va_list.c */
|
|
||||||
typedef struct {
|
|
||||||
unsigned gp_offset, fp_offset;
|
|
||||||
union {
|
|
||||||
unsigned overflow_offset;
|
|
||||||
char *overflow_arg_area;
|
|
||||||
};
|
|
||||||
char *reg_save_area;
|
|
||||||
} __builtin_va_list[1];
|
|
||||||
|
|
||||||
void *__va_arg(__builtin_va_list ap, int arg_type, int size, int align);
|
|
||||||
#define __builtin_va_start(ap, last) \
|
|
||||||
(*(ap) = *(__builtin_va_list)((char*)__builtin_frame_address(0) - 24))
|
|
||||||
#define __builtin_va_arg(ap, t) \
|
|
||||||
(*(t *)(__va_arg(ap, __builtin_va_arg_types(t), sizeof(t), __alignof__(t))))
|
|
||||||
#define __builtin_va_copy(dest, src) (*(dest) = *(src))
|
|
||||||
|
|
||||||
#else /* _WIN64 */
|
|
||||||
typedef char *__builtin_va_list;
|
|
||||||
#define __builtin_va_arg(ap, t) ((sizeof(t) > 8 || (sizeof(t) & (sizeof(t) - 1))) \
|
|
||||||
? **(t **)((ap += 8) - 8) : *(t *)((ap += 8) - 8))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#elif defined __arm__
|
|
||||||
typedef char *__builtin_va_list;
|
|
||||||
#define _tcc_alignof(type) ((int)&((struct {char c;type x;} *)0)->x)
|
|
||||||
#define _tcc_align(addr,type) (((unsigned)addr + _tcc_alignof(type) - 1) \
|
|
||||||
& ~(_tcc_alignof(type) - 1))
|
|
||||||
#define __builtin_va_start(ap,last) (ap = ((char *)&(last)) + ((sizeof(last)+3)&~3))
|
|
||||||
#define __builtin_va_arg(ap,type) (ap = (void *) ((_tcc_align(ap,type)+sizeof(type)+3) \
|
|
||||||
&~3), *(type *)(ap - ((sizeof(type)+3)&~3)))
|
|
||||||
|
|
||||||
#elif defined __aarch64__
|
|
||||||
#if defined _WIN32
|
|
||||||
typedef char *__builtin_va_list;
|
|
||||||
#elif defined __APPLE__
|
|
||||||
typedef struct {
|
|
||||||
void *__stack;
|
|
||||||
} __builtin_va_list;
|
|
||||||
|
|
||||||
#else
|
|
||||||
typedef struct {
|
|
||||||
void *__stack, *__gr_top, *__vr_top;
|
|
||||||
int __gr_offs, __vr_offs;
|
|
||||||
} __builtin_va_list;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
#elif defined __riscv
|
|
||||||
typedef char *__builtin_va_list;
|
|
||||||
#define __va_reg_size (__riscv_xlen >> 3)
|
|
||||||
#define _tcc_align(addr,type) (((unsigned long)addr + __alignof__(type) - 1) \
|
|
||||||
& -(__alignof__(type)))
|
|
||||||
#define __builtin_va_arg(ap,type) (*(sizeof(type) > (2*__va_reg_size) ? *(type **)((ap += __va_reg_size) - __va_reg_size) : (ap = (va_list)(_tcc_align(ap,type) + (sizeof(type)+__va_reg_size - 1)& -__va_reg_size), (type *)(ap - ((sizeof(type)+ __va_reg_size - 1)& -__va_reg_size)))))
|
|
||||||
|
|
||||||
#else /* __i386__ */
|
|
||||||
typedef char *__builtin_va_list;
|
|
||||||
#define __builtin_va_start(ap,last) (ap = ((char *)&(last)) + ((sizeof(last)+3)&~3))
|
|
||||||
#define __builtin_va_arg(ap,t) (*(t*)((ap+=(sizeof(t)+3)&~3)-((sizeof(t)+3)&~3)))
|
|
||||||
|
|
||||||
#endif
|
|
||||||
#define __builtin_va_end(ap) (void)(ap)
|
|
||||||
#ifndef __builtin_va_copy
|
|
||||||
# define __builtin_va_copy(dest, src) (dest) = (src)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* TCC BBUILTIN AND BOUNDS ALIASES */
|
|
||||||
#ifdef __leading_underscore
|
|
||||||
# define __RENAME(X) __asm__("_"X)
|
|
||||||
#else
|
|
||||||
# define __RENAME(X) __asm__(X)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __TCC_BCHECK__
|
|
||||||
# define __BUILTINBC(ret,name,params) ret __builtin_##name params __RENAME("__bound_"#name);
|
|
||||||
# define __BOUND(ret,name,params) ret name params __RENAME("__bound_"#name);
|
|
||||||
#else
|
|
||||||
# define __BUILTINBC(ret,name,params) ret __builtin_##name params __RENAME(#name);
|
|
||||||
# define __BOUND(ret,name,params)
|
|
||||||
#endif
|
|
||||||
#ifdef _WIN32
|
|
||||||
#define __BOTH __BOUND
|
|
||||||
#define __BUILTIN(ret,name,params)
|
|
||||||
#else
|
|
||||||
#define __BOTH(ret,name,params) __BUILTINBC(ret,name,params)__BOUND(ret,name,params)
|
|
||||||
#define __BUILTIN(ret,name,params) ret __builtin_##name params __RENAME(#name);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
__BOTH(void*, memcpy, (void *, const void*, __SIZE_TYPE__))
|
|
||||||
__BOTH(void*, memmove, (void *, const void*, __SIZE_TYPE__))
|
|
||||||
__BOTH(void*, memset, (void *, int, __SIZE_TYPE__))
|
|
||||||
__BOTH(int, memcmp, (const void *, const void*, __SIZE_TYPE__))
|
|
||||||
__BOTH(__SIZE_TYPE__, strlen, (const char *))
|
|
||||||
__BOTH(char*, strcpy, (char *, const char *))
|
|
||||||
__BOTH(char*, strncpy, (char *, const char*, __SIZE_TYPE__))
|
|
||||||
__BOTH(int, strcmp, (const char*, const char*))
|
|
||||||
__BOTH(int, strncmp, (const char*, const char*, __SIZE_TYPE__))
|
|
||||||
__BOTH(char*, strcat, (char*, const char*))
|
|
||||||
__BOTH(char*, strncat, (char*, const char*, __SIZE_TYPE__))
|
|
||||||
__BOTH(char*, strchr, (const char*, int))
|
|
||||||
__BOTH(char*, strrchr, (const char*, int))
|
|
||||||
__BOTH(char*, strdup, (const char*))
|
|
||||||
#if defined __ARM_EABI__
|
|
||||||
__BOUND(void*,__aeabi_memcpy,(void*,const void*,__SIZE_TYPE__))
|
|
||||||
__BOUND(void*,__aeabi_memmove,(void*,const void*,__SIZE_TYPE__))
|
|
||||||
__BOUND(void*,__aeabi_memmove4,(void*,const void*,__SIZE_TYPE__))
|
|
||||||
__BOUND(void*,__aeabi_memmove8,(void*,const void*,__SIZE_TYPE__))
|
|
||||||
__BOUND(void*,__aeabi_memset,(void*,int,__SIZE_TYPE__))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined __linux__ || defined __APPLE__ // HAVE MALLOC_REDIR
|
|
||||||
#define __MAYBE_REDIR __BUILTIN
|
|
||||||
#else
|
|
||||||
#define __MAYBE_REDIR __BOTH
|
|
||||||
#endif
|
|
||||||
__MAYBE_REDIR(void*, malloc, (__SIZE_TYPE__))
|
|
||||||
__MAYBE_REDIR(void*, realloc, (void *, __SIZE_TYPE__))
|
|
||||||
__MAYBE_REDIR(void*, calloc, (__SIZE_TYPE__, __SIZE_TYPE__))
|
|
||||||
__MAYBE_REDIR(void*, memalign, (__SIZE_TYPE__, __SIZE_TYPE__))
|
|
||||||
__MAYBE_REDIR(void, free, (void*))
|
|
||||||
__BOTH(void*, alloca, (__SIZE_TYPE__))
|
|
||||||
void *alloca(__SIZE_TYPE__);
|
|
||||||
__BUILTIN(void, abort, (void))
|
|
||||||
__BOUND(void, longjmp, ())
|
|
||||||
#if !defined _WIN32
|
|
||||||
__BOUND(void*, mmap, ())
|
|
||||||
__BOUND(int, munmap, ())
|
|
||||||
#endif
|
|
||||||
#undef __BUILTINBC
|
|
||||||
#undef __BUILTIN
|
|
||||||
#undef __BOUND
|
|
||||||
#undef __BOTH
|
|
||||||
#undef __MAYBE_REDIR
|
|
||||||
#undef __RENAME
|
|
||||||
|
|
||||||
#define __BUILTIN_EXTERN(name,u) \
|
|
||||||
int __builtin_##name(u int); \
|
|
||||||
int __builtin_##name##l(u long); \
|
|
||||||
int __builtin_##name##ll(u long long);
|
|
||||||
__BUILTIN_EXTERN(ffs,)
|
|
||||||
__BUILTIN_EXTERN(clz, unsigned)
|
|
||||||
__BUILTIN_EXTERN(ctz, unsigned)
|
|
||||||
__BUILTIN_EXTERN(clrsb,)
|
|
||||||
__BUILTIN_EXTERN(popcount, unsigned)
|
|
||||||
__BUILTIN_EXTERN(parity, unsigned)
|
|
||||||
#undef __BUILTIN_EXTERN
|
|
||||||
|
|
||||||
#endif /* ndef __TCC_PP__ */
|
|
||||||
@ -1,89 +0,0 @@
|
|||||||
/*
|
|
||||||
* ISO C Standard: 7.22 Type-generic math <tgmath.h>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _TGMATH_H
|
|
||||||
#define _TGMATH_H
|
|
||||||
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
#ifndef __cplusplus
|
|
||||||
#define __tgmath_real(x, F) \
|
|
||||||
_Generic ((x), float: F##f, long double: F##l, default: F)(x)
|
|
||||||
#define __tgmath_real_2_1(x, y, F) \
|
|
||||||
_Generic ((x), float: F##f, long double: F##l, default: F)(x, y)
|
|
||||||
#define __tgmath_real_2(x, y, F) \
|
|
||||||
_Generic ((x)+(y), float: F##f, long double: F##l, default: F)(x, y)
|
|
||||||
#define __tgmath_real_3_2(x, y, z, F) \
|
|
||||||
_Generic ((x)+(y), float: F##f, long double: F##l, default: F)(x, y, z)
|
|
||||||
#define __tgmath_real_3(x, y, z, F) \
|
|
||||||
_Generic ((x)+(y)+(z), float: F##f, long double: F##l, default: F)(x, y, z)
|
|
||||||
|
|
||||||
/* Functions defined in both <math.h> and <complex.h> (7.22p4) */
|
|
||||||
#define acos(z) __tgmath_real(z, acos)
|
|
||||||
#define asin(z) __tgmath_real(z, asin)
|
|
||||||
#define atan(z) __tgmath_real(z, atan)
|
|
||||||
#define acosh(z) __tgmath_real(z, acosh)
|
|
||||||
#define asinh(z) __tgmath_real(z, asinh)
|
|
||||||
#define atanh(z) __tgmath_real(z, atanh)
|
|
||||||
#define cos(z) __tgmath_real(z, cos)
|
|
||||||
#define sin(z) __tgmath_real(z, sin)
|
|
||||||
#define tan(z) __tgmath_real(z, tan)
|
|
||||||
#define cosh(z) __tgmath_real(z, cosh)
|
|
||||||
#define sinh(z) __tgmath_real(z, sinh)
|
|
||||||
#define tanh(z) __tgmath_real(z, tanh)
|
|
||||||
#define exp(z) __tgmath_real(z, exp)
|
|
||||||
#define log(z) __tgmath_real(z, log)
|
|
||||||
#define pow(z1,z2) __tgmath_real_2(z1, z2, pow)
|
|
||||||
#define sqrt(z) __tgmath_real(z, sqrt)
|
|
||||||
#define fabs(z) __tgmath_real(z, fabs)
|
|
||||||
|
|
||||||
/* Functions defined in <math.h> only (7.22p5) */
|
|
||||||
#define atan2(x,y) __tgmath_real_2(x, y, atan2)
|
|
||||||
#define cbrt(x) __tgmath_real(x, cbrt)
|
|
||||||
#define ceil(x) __tgmath_real(x, ceil)
|
|
||||||
#define copysign(x,y) __tgmath_real_2(x, y, copysign)
|
|
||||||
#define erf(x) __tgmath_real(x, erf)
|
|
||||||
#define erfc(x) __tgmath_real(x, erfc)
|
|
||||||
#define exp2(x) __tgmath_real(x, exp2)
|
|
||||||
#define expm1(x) __tgmath_real(x, expm1)
|
|
||||||
#define fdim(x,y) __tgmath_real_2(x, y, fdim)
|
|
||||||
#define floor(x) __tgmath_real(x, floor)
|
|
||||||
#define fma(x,y,z) __tgmath_real_3(x, y, z, fma)
|
|
||||||
#define fmax(x,y) __tgmath_real_2(x, y, fmax)
|
|
||||||
#define fmin(x,y) __tgmath_real_2(x, y, fmin)
|
|
||||||
#define fmod(x,y) __tgmath_real_2(x, y, fmod)
|
|
||||||
#define frexp(x,y) __tgmath_real_2_1(x, y, frexp)
|
|
||||||
#define hypot(x,y) __tgmath_real_2(x, y, hypot)
|
|
||||||
#define ilogb(x) __tgmath_real(x, ilogb)
|
|
||||||
#define ldexp(x,y) __tgmath_real_2_1(x, y, ldexp)
|
|
||||||
#define lgamma(x) __tgmath_real(x, lgamma)
|
|
||||||
#define llrint(x) __tgmath_real(x, llrint)
|
|
||||||
#define llround(x) __tgmath_real(x, llround)
|
|
||||||
#define log10(x) __tgmath_real(x, log10)
|
|
||||||
#define log1p(x) __tgmath_real(x, log1p)
|
|
||||||
#define log2(x) __tgmath_real(x, log2)
|
|
||||||
#define logb(x) __tgmath_real(x, logb)
|
|
||||||
#define lrint(x) __tgmath_real(x, lrint)
|
|
||||||
#define lround(x) __tgmath_real(x, lround)
|
|
||||||
#define nearbyint(x) __tgmath_real(x, nearbyint)
|
|
||||||
#define nextafter(x,y) __tgmath_real_2(x, y, nextafter)
|
|
||||||
#define nexttoward(x,y) __tgmath_real_2(x, y, nexttoward)
|
|
||||||
#define remainder(x,y) __tgmath_real_2(x, y, remainder)
|
|
||||||
#define remquo(x,y,z) __tgmath_real_3_2(x, y, z, remquo)
|
|
||||||
#define rint(x) __tgmath_real(x, rint)
|
|
||||||
#define round(x) __tgmath_real(x, round)
|
|
||||||
#define scalbln(x,y) __tgmath_real_2_1(x, y, scalbln)
|
|
||||||
#define scalbn(x,y) __tgmath_real_2_1(x, y, scalbn)
|
|
||||||
#define tgamma(x) __tgmath_real(x, tgamma)
|
|
||||||
#define trunc(x) __tgmath_real(x, trunc)
|
|
||||||
|
|
||||||
/* Functions defined in <complex.h> only (7.22p6)
|
|
||||||
#define carg(z) __tgmath_cplx_only(z, carg)
|
|
||||||
#define cimag(z) __tgmath_cplx_only(z, cimag)
|
|
||||||
#define conj(z) __tgmath_cplx_only(z, conj)
|
|
||||||
#define cproj(z) __tgmath_cplx_only(z, cproj)
|
|
||||||
#define creal(z) __tgmath_cplx_only(z, creal)
|
|
||||||
*/
|
|
||||||
#endif /* __cplusplus */
|
|
||||||
#endif /* _TGMATH_H */
|
|
||||||
@ -1,12 +0,0 @@
|
|||||||
/**
|
|
||||||
* This file has no copyright assigned and is placed in the Public Domain.
|
|
||||||
* This file is part of the w64 mingw-runtime package.
|
|
||||||
* No warranty is given; refer to the file DISCLAIMER within this package.
|
|
||||||
*/
|
|
||||||
#ifndef _VARARGS_H
|
|
||||||
#define _VARARGS_H
|
|
||||||
|
|
||||||
#error "TinyCC no longer implements <varargs.h>."
|
|
||||||
#error "Revise your code to use <stdarg.h>."
|
|
||||||
|
|
||||||
#endif
|
|
||||||
106
lib/Makefile
106
lib/Makefile
@ -1,106 +0,0 @@
|
|||||||
#
|
|
||||||
# Tiny C Compiler Makefile for libtcc1.a
|
|
||||||
#
|
|
||||||
|
|
||||||
TOP = ..
|
|
||||||
include $(TOP)/Makefile
|
|
||||||
VPATH = $(TOPSRC)/lib $(TOPSRC)/win32/lib
|
|
||||||
T = $(or $(CROSS_TARGET),$(NATIVE_TARGET),unknown)
|
|
||||||
X = $(if $(CROSS_TARGET),$(CROSS_TARGET)-)
|
|
||||||
XCFG = $(or $(findstring -win,$T),-unx)
|
|
||||||
S = $(if $(findstring yes,$(SILENT)),@$(info * $@))
|
|
||||||
|
|
||||||
TCC = $(TOP)/$(X)tcc$(EXESUF)
|
|
||||||
XTCC ?= $(TOP)/$(X)tcc$(EXESUF)
|
|
||||||
XCC = $(XTCC)
|
|
||||||
XAR = $(XTCC) -ar
|
|
||||||
XFLAGS-unx = -B$(TOPSRC)
|
|
||||||
XFLAGS-win = -B$(TOPSRC)/win32 -I$(TOPSRC)/include
|
|
||||||
XFLAGS = $(XFLAGS$(XCFG))
|
|
||||||
BFLAGS = -bt
|
|
||||||
|
|
||||||
# in order to use gcc, type: make <target>-libtcc1-usegcc=yes
|
|
||||||
arm-libtcc1-usegcc ?= no
|
|
||||||
|
|
||||||
# This makes bounds checking 40%..60% faster.
|
|
||||||
#x86_64-libtcc1-usegcc=yes
|
|
||||||
#i386-libtcc1-usegcc=yes
|
|
||||||
|
|
||||||
ifeq "$($(T)-libtcc1-usegcc)" "yes"
|
|
||||||
XCC = $(CC)
|
|
||||||
XAR = $(AR)
|
|
||||||
XFLAGS = $(CFLAGS) -fPIC -fno-omit-frame-pointer -Wno-unused-function -Wno-unused-variable
|
|
||||||
BFLAGS = $(if $(CONFIG_dwarf),-gdwarf,-gstabs)
|
|
||||||
endif
|
|
||||||
|
|
||||||
XFLAGS += -I$(TOP)
|
|
||||||
|
|
||||||
I386_O = libtcc1.o $(COMMON_O)
|
|
||||||
X86_64_O = libtcc1.o $(COMMON_O)
|
|
||||||
ARM_O = libtcc1.o armeabi.o armflush.o $(COMMON_O)
|
|
||||||
ARM64_O = lib-arm64.o $(COMMON_O)
|
|
||||||
RISCV64_O = lib-arm64.o $(COMMON_O)
|
|
||||||
COMMON_O = stdatomic.o atomic.o builtin.o alloca.o alloca-bt.o
|
|
||||||
WIN_O = crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o winex.o
|
|
||||||
LIN_O = dsohandle.o
|
|
||||||
OSX_O =
|
|
||||||
|
|
||||||
# backtrace/bcheck/run only for native compiler
|
|
||||||
Nat = $(if $X,no,)
|
|
||||||
Cbt = $(Nat)$(subst yes,,$(CONFIG_backtrace))
|
|
||||||
Cbc = $(Cbt)$(subst yes,,$(CONFIG_bcheck))
|
|
||||||
|
|
||||||
$(Nat)COMMON_O += runmain.o tcov.o
|
|
||||||
$(Cbt)COMMON_O += bt-exe.o bt-log.o
|
|
||||||
$(Cbt)WIN_O += bt-dll.o
|
|
||||||
$(Cbc)COMMON_O += bcheck.o
|
|
||||||
|
|
||||||
# not in libtcc1.a
|
|
||||||
EXTRA_O = runmain.o bt-exe.o bt-dll.o bt-log.o bcheck.o
|
|
||||||
|
|
||||||
OBJ-i386 = $(I386_O) pic86.o $(LIN_O)
|
|
||||||
OBJ-x86_64 = $(X86_64_O) va_list.o $(LIN_O)
|
|
||||||
OBJ-x86_64-osx = $(X86_64_O) va_list.o $(OSX_O)
|
|
||||||
OBJ-i386-win32 = $(I386_O) chkstk.o $(WIN_O)
|
|
||||||
OBJ-x86_64-win32 = $(X86_64_O) chkstk.o $(WIN_O)
|
|
||||||
OBJ-arm64 = $(ARM64_O) armflush.o $(LIN_O)
|
|
||||||
OBJ-arm64-osx = $(ARM64_O) $(OSX_O)
|
|
||||||
OBJ-arm64-win32 = $(ARM64_O) chkstk.o $(WIN_O)
|
|
||||||
OBJ-arm = $(ARM_O) $(LIN_O)
|
|
||||||
OBJ-arm-fpa = $(OBJ-arm)
|
|
||||||
OBJ-arm-fpa-ld = $(OBJ-arm)
|
|
||||||
OBJ-arm-vfp = $(OBJ-arm)
|
|
||||||
OBJ-arm-eabi = $(OBJ-arm)
|
|
||||||
OBJ-arm-eabihf = $(OBJ-arm)
|
|
||||||
OBJ-arm-wince = $(ARM_O) $(WIN_O)
|
|
||||||
OBJ-riscv64 = $(RISCV64_O) lib-riscv.o $(LIN_O)
|
|
||||||
|
|
||||||
OBJ-extra = $(filter $(EXTRA_O),$(OBJ-$T))
|
|
||||||
OBJ-libtcc1 = $(addprefix $(X),$(filter-out $(OBJ-extra),$(OBJ-$T)))
|
|
||||||
|
|
||||||
ALL = $(addprefix $(TOP)/,$(X)libtcc1.a $(OBJ-extra))
|
|
||||||
|
|
||||||
all: $(ALL)
|
|
||||||
|
|
||||||
$(TOP)/$(X)libtcc1.a : $(OBJ-libtcc1) $(TCC)
|
|
||||||
$S$(XAR) rcs $@ $(OBJ-libtcc1)
|
|
||||||
|
|
||||||
$(X)%.o : %.c $(TCC)
|
|
||||||
$S$(XCC) -c $< -o $@ $(XFLAGS)
|
|
||||||
|
|
||||||
$(X)%.o : %.S $(TCC)
|
|
||||||
$S$(XCC) -c $< -o $@ $(XFLAGS)
|
|
||||||
|
|
||||||
$(TOP)/%.o : %.c $(TCC)
|
|
||||||
$S$(XCC) -c $< -o $@ $(XFLAGS)
|
|
||||||
|
|
||||||
$(TOP)/bcheck.o : XFLAGS += $(BFLAGS)
|
|
||||||
|
|
||||||
$(X)crt1w.o : crt1.c
|
|
||||||
$(X)wincrt1w.o : wincrt1.c
|
|
||||||
|
|
||||||
# don't try to make it
|
|
||||||
$(TCC) : ;
|
|
||||||
|
|
||||||
clean :
|
|
||||||
rm -f *.o $(addprefix $(TOP)/,*libtcc1.a $(EXTRA_O))
|
|
||||||
200
lib/alloca-bt.S
200
lib/alloca-bt.S
@ -1,200 +0,0 @@
|
|||||||
/* ---------------------------------------------- */
|
|
||||||
/* alloca-bt.S */
|
|
||||||
|
|
||||||
#ifdef __leading_underscore
|
|
||||||
# define _(s) _##s
|
|
||||||
#else
|
|
||||||
# define _(s) s
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* ---------------------------------------------- */
|
|
||||||
#if defined __i386__
|
|
||||||
|
|
||||||
.globl _(__bound_alloca)
|
|
||||||
_(__bound_alloca):
|
|
||||||
pop %edx
|
|
||||||
pop %eax
|
|
||||||
mov %eax, %ecx
|
|
||||||
test %eax,%eax
|
|
||||||
jz p6
|
|
||||||
add $3 + 1,%eax
|
|
||||||
and $-4,%eax
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
p4:
|
|
||||||
cmp $4096,%eax
|
|
||||||
jb p5
|
|
||||||
test %eax,-4096(%esp)
|
|
||||||
sub $4096,%esp
|
|
||||||
sub $4096,%eax
|
|
||||||
jmp p4
|
|
||||||
|
|
||||||
p5:
|
|
||||||
#endif
|
|
||||||
|
|
||||||
sub %eax,%esp
|
|
||||||
mov %esp,%eax
|
|
||||||
|
|
||||||
push %edx
|
|
||||||
push %eax
|
|
||||||
push %ecx
|
|
||||||
push %eax
|
|
||||||
call _(__bound_new_region)
|
|
||||||
add $8, %esp
|
|
||||||
pop %eax
|
|
||||||
pop %edx
|
|
||||||
|
|
||||||
p6:
|
|
||||||
push %edx
|
|
||||||
push %edx
|
|
||||||
ret
|
|
||||||
|
|
||||||
/* ---------------------------------------------- */
|
|
||||||
#elif defined __x86_64__
|
|
||||||
|
|
||||||
.globl _(__bound_alloca)
|
|
||||||
_(__bound_alloca):
|
|
||||||
#ifdef _WIN32
|
|
||||||
inc %rcx # add one extra to separate regions
|
|
||||||
jmp _(alloca)
|
|
||||||
.globl _(__bound_alloca_nr)
|
|
||||||
_(__bound_alloca_nr):
|
|
||||||
dec %rcx
|
|
||||||
push %rax
|
|
||||||
mov %rcx,%rdx
|
|
||||||
mov %rax,%rcx
|
|
||||||
sub $32,%rsp
|
|
||||||
call _(__bound_new_region)
|
|
||||||
add $32,%rsp
|
|
||||||
pop %rax
|
|
||||||
ret
|
|
||||||
#else
|
|
||||||
pop %rdx
|
|
||||||
mov %rdi,%rax
|
|
||||||
and %eax,%eax
|
|
||||||
jz p3
|
|
||||||
mov %rax,%rsi # size, a second parm to the __bound_new_region
|
|
||||||
add $15 + 1,%rax # add one extra to separate regions
|
|
||||||
and $-16,%rax
|
|
||||||
|
|
||||||
sub %rax,%rsp
|
|
||||||
mov %rsp,%rdi # pointer, a first parm to the __bound_new_region
|
|
||||||
mov %rsp,%rax
|
|
||||||
|
|
||||||
push %rdx
|
|
||||||
push %rax
|
|
||||||
call _(__bound_new_region)
|
|
||||||
pop %rax
|
|
||||||
pop %rdx
|
|
||||||
|
|
||||||
p3:
|
|
||||||
push %rdx
|
|
||||||
ret
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* ---------------------------------------------- */
|
|
||||||
#elif defined __arm__
|
|
||||||
|
|
||||||
.globl _(__bound_alloca)
|
|
||||||
_(__bound_alloca):
|
|
||||||
mov r1, r0
|
|
||||||
add r0, r0, #1
|
|
||||||
rsb sp, r0, sp
|
|
||||||
bic sp, sp, #7
|
|
||||||
mov r0, sp
|
|
||||||
push { lr }
|
|
||||||
bl _(__bound_new_region)
|
|
||||||
pop { lr }
|
|
||||||
mov r0, sp
|
|
||||||
mov pc, lr
|
|
||||||
|
|
||||||
/* ---------------------------------------------- */
|
|
||||||
#elif defined __aarch64__ || defined __arm64__
|
|
||||||
|
|
||||||
.globl _(__bound_alloca)
|
|
||||||
_(__bound_alloca):
|
|
||||||
#ifdef __TINYC__
|
|
||||||
.int 0xaa0003e1
|
|
||||||
.int 0x91004000
|
|
||||||
.int 0x927cec00
|
|
||||||
#ifdef _WIN32
|
|
||||||
.int 0xb4000160
|
|
||||||
.int 0xd2820002
|
|
||||||
.int 0xeb02001f
|
|
||||||
.int 0x540000c3
|
|
||||||
.int 0xcb2263e3
|
|
||||||
.int 0xf940007f
|
|
||||||
.int 0xcb2263ff
|
|
||||||
.int 0xcb020000
|
|
||||||
.int 0x17fffffa
|
|
||||||
.int 0xb4000040
|
|
||||||
#endif
|
|
||||||
.int 0xcb2063ff
|
|
||||||
.int 0x910003e0
|
|
||||||
.int 0xa9bf7bfd
|
|
||||||
.reloc ., R_AARCH64_CALL26, _(__bound_new_region)
|
|
||||||
.int 0x94000000
|
|
||||||
.int 0xa8c17bfd
|
|
||||||
.int 0x910003e0
|
|
||||||
.int 0xd65f03c0
|
|
||||||
#else
|
|
||||||
mov x1, x0
|
|
||||||
add x0, x0, #16 // Round up to 16-byte boundary
|
|
||||||
and x0, x0, #-16 // Ensure 16-byte alignment
|
|
||||||
#ifdef _WIN32
|
|
||||||
cbz x0, p100 // If size is 0, skip to return
|
|
||||||
// Windows requires page-wise allocation with stack probing
|
|
||||||
mov x2, #4096 // Page size = 4096 bytes
|
|
||||||
|
|
||||||
p101:
|
|
||||||
cmp x0, x2 // Compare remaining size with page size
|
|
||||||
b.lo p102 // If less than page, jump to remainder
|
|
||||||
|
|
||||||
// Probe first, then allocate
|
|
||||||
sub x3, sp, x2 // Calculate guard page address (sp - 4096)
|
|
||||||
ldr xzr, [x3] // Touch guard page FIRST
|
|
||||||
sub sp, sp, x2 // THEN allocate the page
|
|
||||||
|
|
||||||
sub x0, x0, x2 // Decrement remaining size
|
|
||||||
b p101 // Continue loop
|
|
||||||
|
|
||||||
p102:
|
|
||||||
// Allocate remaining bytes (less than one page)
|
|
||||||
cbz x0, p100 // If no remaining bytes, skip
|
|
||||||
sub sp, sp, x0 // Allocate remaining space
|
|
||||||
#else
|
|
||||||
// Non-Windows: simple one-time allocation
|
|
||||||
sub sp, sp, x0 // Allocate space on stack
|
|
||||||
#endif
|
|
||||||
|
|
||||||
p100:
|
|
||||||
mov x0, sp // Return allocated address
|
|
||||||
stp x29, x30, [sp, #-16]!
|
|
||||||
bl _(__bound_new_region)
|
|
||||||
ldp x29, x30, [sp], #16
|
|
||||||
mov x0, sp // Return allocated address
|
|
||||||
ret // Return to caller
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* ---------------------------------------------- */
|
|
||||||
#elif defined __riscv
|
|
||||||
|
|
||||||
.globl _(__bound_alloca)
|
|
||||||
_(__bound_alloca):
|
|
||||||
mv a1, a0
|
|
||||||
sub sp, sp, a0
|
|
||||||
addi sp, sp, -16
|
|
||||||
andi sp, sp, -16
|
|
||||||
add a0, sp, zero
|
|
||||||
addi sp,sp,-16
|
|
||||||
sd s0,0(sp)
|
|
||||||
sd ra,8(sp)
|
|
||||||
jal _(__bound_new_region)
|
|
||||||
ld s0,0(sp)
|
|
||||||
ld ra,8(sp)
|
|
||||||
addi sp,sp,16
|
|
||||||
add a0, sp, zero
|
|
||||||
ret
|
|
||||||
|
|
||||||
/* ---------------------------------------------- */
|
|
||||||
#endif
|
|
||||||
148
lib/alloca.S
148
lib/alloca.S
@ -1,148 +0,0 @@
|
|||||||
/* ---------------------------------------------- */
|
|
||||||
/* alloca.S */
|
|
||||||
|
|
||||||
#ifdef __leading_underscore
|
|
||||||
# define _(s) _##s
|
|
||||||
#else
|
|
||||||
# define _(s) s
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* ---------------------------------------------- */
|
|
||||||
#if defined __i386__
|
|
||||||
|
|
||||||
.globl _(alloca), _(__alloca)
|
|
||||||
_(alloca):
|
|
||||||
_(__alloca):
|
|
||||||
pop %edx
|
|
||||||
pop %eax
|
|
||||||
add $3,%eax
|
|
||||||
and $-4,%eax
|
|
||||||
jz p3
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
p1:
|
|
||||||
cmp $4096,%eax
|
|
||||||
jb p2
|
|
||||||
test %eax,-4096(%esp)
|
|
||||||
sub $4096,%esp
|
|
||||||
sub $4096,%eax
|
|
||||||
jmp p1
|
|
||||||
p2:
|
|
||||||
#endif
|
|
||||||
sub %eax,%esp
|
|
||||||
mov %esp,%eax
|
|
||||||
p3:
|
|
||||||
push %edx
|
|
||||||
push %edx
|
|
||||||
ret
|
|
||||||
|
|
||||||
/* ---------------------------------------------- */
|
|
||||||
#elif defined __x86_64__
|
|
||||||
|
|
||||||
.globl _(alloca)
|
|
||||||
_(alloca):
|
|
||||||
pop %rdx
|
|
||||||
#ifdef _WIN32
|
|
||||||
mov %rcx,%rax
|
|
||||||
#else
|
|
||||||
mov %rdi,%rax
|
|
||||||
#endif
|
|
||||||
add $15,%rax
|
|
||||||
and $-16,%rax
|
|
||||||
jz p3
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
p1:
|
|
||||||
cmp $4096,%rax
|
|
||||||
jb p2
|
|
||||||
test %rax,-4096(%rsp)
|
|
||||||
sub $4096,%rsp
|
|
||||||
sub $4096,%rax
|
|
||||||
jmp p1
|
|
||||||
p2:
|
|
||||||
#endif
|
|
||||||
sub %rax,%rsp
|
|
||||||
mov %rsp,%rax
|
|
||||||
p3:
|
|
||||||
push %rdx
|
|
||||||
ret
|
|
||||||
|
|
||||||
/* ---------------------------------------------- */
|
|
||||||
#elif defined __arm__
|
|
||||||
|
|
||||||
.globl _(alloca)
|
|
||||||
_(alloca):
|
|
||||||
rsb sp, r0, sp
|
|
||||||
bic sp, sp, #7
|
|
||||||
mov r0, sp
|
|
||||||
mov pc, lr
|
|
||||||
|
|
||||||
/* ---------------------------------------------- */
|
|
||||||
#elif defined __aarch64__ || defined __arm64__
|
|
||||||
|
|
||||||
.globl _(alloca)
|
|
||||||
_(alloca):
|
|
||||||
#ifdef __TINYC__
|
|
||||||
.int 0x91003c00
|
|
||||||
.int 0x927cec00
|
|
||||||
#ifdef _WIN32
|
|
||||||
.int 0xb4000160
|
|
||||||
.int 0xd2820001
|
|
||||||
.int 0xeb01001f
|
|
||||||
.int 0x540000c3
|
|
||||||
.int 0xcb2163e2
|
|
||||||
.int 0xf940005f
|
|
||||||
.int 0xcb2163ff
|
|
||||||
.int 0xcb010000
|
|
||||||
.int 0x17fffffa
|
|
||||||
.int 0xb4000040
|
|
||||||
#endif
|
|
||||||
.int 0xcb2063ff
|
|
||||||
.int 0x910003e0
|
|
||||||
.int 0xd65f03c0
|
|
||||||
#else
|
|
||||||
add x0, x0, #15 // Round up to 16-byte boundary
|
|
||||||
and x0, x0, #-16 // Ensure 16-byte alignment
|
|
||||||
#ifdef _WIN32
|
|
||||||
cbz x0, p100 // If size is 0, skip to return
|
|
||||||
// Windows requires page-wise allocation with stack probing
|
|
||||||
mov x1, #4096 // Page size = 4096 bytes
|
|
||||||
|
|
||||||
p101:
|
|
||||||
cmp x0, x1 // Compare remaining size with page size
|
|
||||||
b.lo p102 // If less than page, jump to remainder
|
|
||||||
|
|
||||||
// Probe first, then allocate
|
|
||||||
sub x2, sp, x1 // Calculate guard page address (sp - 4096)
|
|
||||||
ldr xzr, [x2] // Touch guard page FIRST
|
|
||||||
sub sp, sp, x1 // THEN allocate the page
|
|
||||||
|
|
||||||
sub x0, x0, x1 // Decrement remaining size
|
|
||||||
b p101 // Continue loop
|
|
||||||
|
|
||||||
p102:
|
|
||||||
// Allocate remaining bytes (less than one page)
|
|
||||||
cbz x0, p100 // If no remaining bytes, skip
|
|
||||||
sub sp, sp, x0 // Allocate remaining space
|
|
||||||
#else
|
|
||||||
// Non-Windows: simple one-time allocation
|
|
||||||
sub sp, sp, x0 // Allocate space on stack
|
|
||||||
#endif
|
|
||||||
|
|
||||||
p100:
|
|
||||||
mov x0, sp // Return allocated address
|
|
||||||
ret // Return to caller
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* ---------------------------------------------- */
|
|
||||||
#elif defined __riscv
|
|
||||||
|
|
||||||
.globl _(alloca)
|
|
||||||
_(alloca):
|
|
||||||
sub sp, sp, a0
|
|
||||||
addi sp, sp, -15
|
|
||||||
andi sp, sp, -16
|
|
||||||
add a0, sp, zero
|
|
||||||
ret
|
|
||||||
|
|
||||||
#endif
|
|
||||||
642
lib/armeabi.c
642
lib/armeabi.c
@ -1,642 +0,0 @@
|
|||||||
/* TCC ARM runtime EABI
|
|
||||||
Copyright (C) 2013 Thomas Preud'homme
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
||||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.*/
|
|
||||||
|
|
||||||
#ifdef __TINYC__
|
|
||||||
#define INT_MIN (-2147483647 - 1)
|
|
||||||
#define INT_MAX 2147483647
|
|
||||||
#define UINT_MAX 0xffffffff
|
|
||||||
#define LONG_MIN (-2147483647L - 1)
|
|
||||||
#define LONG_MAX 2147483647L
|
|
||||||
#define ULONG_MAX 0xffffffffUL
|
|
||||||
#define LLONG_MAX 9223372036854775807LL
|
|
||||||
#define LLONG_MIN (-9223372036854775807LL - 1)
|
|
||||||
#define ULLONG_MAX 0xffffffffffffffffULL
|
|
||||||
#else
|
|
||||||
#include <limits.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* We rely on the little endianness and EABI calling convention for this to
|
|
||||||
work */
|
|
||||||
|
|
||||||
typedef struct double_unsigned_struct {
|
|
||||||
unsigned low;
|
|
||||||
unsigned high;
|
|
||||||
} double_unsigned_struct;
|
|
||||||
|
|
||||||
typedef struct unsigned_int_struct {
|
|
||||||
unsigned low;
|
|
||||||
int high;
|
|
||||||
} unsigned_int_struct;
|
|
||||||
|
|
||||||
#define REGS_RETURN(name, type) \
|
|
||||||
static void name ## _return(type ret) {}
|
|
||||||
|
|
||||||
|
|
||||||
/* Float helper functions */
|
|
||||||
|
|
||||||
#define FLOAT_EXP_BITS 8
|
|
||||||
#define FLOAT_FRAC_BITS 23
|
|
||||||
|
|
||||||
#define DOUBLE_EXP_BITS 11
|
|
||||||
#define DOUBLE_FRAC_BITS 52
|
|
||||||
|
|
||||||
#define ONE_EXP(type) ((1 << (type ## _EXP_BITS - 1)) - 1)
|
|
||||||
|
|
||||||
REGS_RETURN(unsigned_int_struct, unsigned_int_struct)
|
|
||||||
REGS_RETURN(double_unsigned_struct, double_unsigned_struct)
|
|
||||||
|
|
||||||
/* float -> integer: (sign) 1.fraction x 2^(exponent - exp_for_one) */
|
|
||||||
|
|
||||||
|
|
||||||
/* float to [unsigned] long long conversion */
|
|
||||||
#define DEFINE__AEABI_F2XLZ(name, with_sign) \
|
|
||||||
void __aeabi_ ## name(unsigned val) \
|
|
||||||
{ \
|
|
||||||
int exp, high_shift, sign; \
|
|
||||||
double_unsigned_struct ret; \
|
|
||||||
\
|
|
||||||
/* compute sign */ \
|
|
||||||
sign = val >> 31; \
|
|
||||||
\
|
|
||||||
/* compute real exponent */ \
|
|
||||||
exp = val >> FLOAT_FRAC_BITS; \
|
|
||||||
exp &= (1 << FLOAT_EXP_BITS) - 1; \
|
|
||||||
exp -= ONE_EXP(FLOAT); \
|
|
||||||
\
|
|
||||||
/* undefined behavior if truncated value cannot be represented */ \
|
|
||||||
if (with_sign) { \
|
|
||||||
if (exp > 62) /* |val| too big, double cannot represent LLONG_MAX */ \
|
|
||||||
return; \
|
|
||||||
} else { \
|
|
||||||
if ((sign && exp >= 0) || exp > 63) /* if val < 0 || val too big */ \
|
|
||||||
return; \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
val &= (1 << FLOAT_FRAC_BITS) - 1; \
|
|
||||||
if (exp >= 32) { \
|
|
||||||
ret.high = 1 << (exp - 32); \
|
|
||||||
if (exp - 32 >= FLOAT_FRAC_BITS) { \
|
|
||||||
ret.high |= val << (exp - 32 - FLOAT_FRAC_BITS); \
|
|
||||||
ret.low = 0; \
|
|
||||||
} else { \
|
|
||||||
high_shift = FLOAT_FRAC_BITS - (exp - 32); \
|
|
||||||
ret.high |= val >> high_shift; \
|
|
||||||
ret.low = val << (32 - high_shift); \
|
|
||||||
} \
|
|
||||||
} else { \
|
|
||||||
ret.high = 0; \
|
|
||||||
ret.low = 1 << exp; \
|
|
||||||
if (exp > FLOAT_FRAC_BITS) \
|
|
||||||
ret.low |= val << (exp - FLOAT_FRAC_BITS); \
|
|
||||||
else \
|
|
||||||
ret.low |= val >> (FLOAT_FRAC_BITS - exp); \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
/* encode negative integer using 2's complement */ \
|
|
||||||
if (with_sign && sign) { \
|
|
||||||
ret.low = ~ret.low; \
|
|
||||||
ret.high = ~ret.high; \
|
|
||||||
if (ret.low == UINT_MAX) { \
|
|
||||||
ret.low = 0; \
|
|
||||||
ret.high++; \
|
|
||||||
} else \
|
|
||||||
ret.low++; \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
double_unsigned_struct_return(ret); \
|
|
||||||
}
|
|
||||||
|
|
||||||
/* float to unsigned long long conversion */
|
|
||||||
DEFINE__AEABI_F2XLZ(f2ulz, 0)
|
|
||||||
|
|
||||||
/* float to long long conversion */
|
|
||||||
DEFINE__AEABI_F2XLZ(f2lz, 1)
|
|
||||||
|
|
||||||
/* double to [unsigned] long long conversion */
|
|
||||||
#define DEFINE__AEABI_D2XLZ(name, with_sign) \
|
|
||||||
void __aeabi_ ## name(double_unsigned_struct val) \
|
|
||||||
{ \
|
|
||||||
int exp, high_shift, sign; \
|
|
||||||
double_unsigned_struct ret; \
|
|
||||||
\
|
|
||||||
if ((val.high & ~0x80000000) == 0 && val.low == 0) { \
|
|
||||||
ret.low = ret.high = 0; \
|
|
||||||
goto _ret_; \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
/* compute sign */ \
|
|
||||||
sign = val.high >> 31; \
|
|
||||||
\
|
|
||||||
/* compute real exponent */ \
|
|
||||||
exp = (val.high >> (DOUBLE_FRAC_BITS - 32)); \
|
|
||||||
exp &= (1 << DOUBLE_EXP_BITS) - 1; \
|
|
||||||
exp -= ONE_EXP(DOUBLE); \
|
|
||||||
\
|
|
||||||
/* undefined behavior if truncated value cannot be represented */ \
|
|
||||||
if (with_sign) { \
|
|
||||||
if (exp > 62) /* |val| too big, double cannot represent LLONG_MAX */ \
|
|
||||||
return; \
|
|
||||||
} else { \
|
|
||||||
if ((sign && exp >= 0) || exp > 63) /* if val < 0 || val too big */ \
|
|
||||||
return; \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
val.high &= (1 << (DOUBLE_FRAC_BITS - 32)) - 1; \
|
|
||||||
if (exp >= 32) { \
|
|
||||||
ret.high = 1 << (exp - 32); \
|
|
||||||
if (exp >= DOUBLE_FRAC_BITS) { \
|
|
||||||
high_shift = exp - DOUBLE_FRAC_BITS; \
|
|
||||||
ret.high |= val.high << high_shift; \
|
|
||||||
ret.high |= val.low >> (32 - high_shift); \
|
|
||||||
ret.low = val.low << high_shift; \
|
|
||||||
} else { \
|
|
||||||
high_shift = DOUBLE_FRAC_BITS - exp; \
|
|
||||||
ret.high |= val.high >> high_shift; \
|
|
||||||
ret.low = val.high << (32 - high_shift); \
|
|
||||||
ret.low |= val.low >> high_shift; \
|
|
||||||
} \
|
|
||||||
} else { \
|
|
||||||
ret.high = 0; \
|
|
||||||
ret.low = 1 << exp; \
|
|
||||||
if (exp > DOUBLE_FRAC_BITS - 32) { \
|
|
||||||
high_shift = exp - (DOUBLE_FRAC_BITS - 32); \
|
|
||||||
ret.low |= val.high << high_shift; \
|
|
||||||
ret.low |= val.low >> (32 - high_shift); \
|
|
||||||
} else \
|
|
||||||
ret.low |= val.high >> (DOUBLE_FRAC_BITS - 32 - exp); \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
/* encode negative integer using 2's complement */ \
|
|
||||||
if (with_sign && sign) { \
|
|
||||||
ret.low = ~ret.low; \
|
|
||||||
ret.high = ~ret.high; \
|
|
||||||
if (ret.low == UINT_MAX) { \
|
|
||||||
ret.low = 0; \
|
|
||||||
ret.high++; \
|
|
||||||
} else \
|
|
||||||
ret.low++; \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
_ret_: \
|
|
||||||
double_unsigned_struct_return(ret); \
|
|
||||||
}
|
|
||||||
|
|
||||||
/* double to unsigned long long conversion */
|
|
||||||
DEFINE__AEABI_D2XLZ(d2ulz, 0)
|
|
||||||
|
|
||||||
/* double to long long conversion */
|
|
||||||
DEFINE__AEABI_D2XLZ(d2lz, 1)
|
|
||||||
|
|
||||||
/* long long to float conversion */
|
|
||||||
#define DEFINE__AEABI_XL2F(name, with_sign) \
|
|
||||||
unsigned __aeabi_ ## name(unsigned long long v) \
|
|
||||||
{ \
|
|
||||||
int s /* shift */, flb /* first lost bit */, sign = 0; \
|
|
||||||
unsigned p = 0 /* power */, ret; \
|
|
||||||
double_unsigned_struct val; \
|
|
||||||
\
|
|
||||||
/* fraction in negative float is encoded in 1's complement */ \
|
|
||||||
if (with_sign && (v & (1ULL << 63))) { \
|
|
||||||
sign = 1; \
|
|
||||||
v = ~v + 1; \
|
|
||||||
} \
|
|
||||||
val.low = v; \
|
|
||||||
val.high = v >> 32; \
|
|
||||||
/* fill fraction bits */ \
|
|
||||||
for (s = 31, p = 1 << 31; p && !(val.high & p); s--, p >>= 1); \
|
|
||||||
if (p) { \
|
|
||||||
ret = val.high & (p - 1); \
|
|
||||||
if (s < FLOAT_FRAC_BITS) { \
|
|
||||||
ret <<= FLOAT_FRAC_BITS - s; \
|
|
||||||
ret |= val.low >> (32 - (FLOAT_FRAC_BITS - s)); \
|
|
||||||
flb = (val.low >> (32 - (FLOAT_FRAC_BITS - s - 1))) & 1; \
|
|
||||||
} else { \
|
|
||||||
flb = (ret >> (s - FLOAT_FRAC_BITS - 1)) & 1; \
|
|
||||||
ret >>= s - FLOAT_FRAC_BITS; \
|
|
||||||
} \
|
|
||||||
s += 32; \
|
|
||||||
} else { \
|
|
||||||
for (s = 31, p = 1 << 31; p && !(val.low & p); s--, p >>= 1); \
|
|
||||||
if (p) { \
|
|
||||||
ret = val.low & (p - 1); \
|
|
||||||
if (s <= FLOAT_FRAC_BITS) { \
|
|
||||||
ret <<= FLOAT_FRAC_BITS - s; \
|
|
||||||
flb = 0; \
|
|
||||||
} else { \
|
|
||||||
flb = (ret >> (s - FLOAT_FRAC_BITS - 1)) & 1; \
|
|
||||||
ret >>= s - FLOAT_FRAC_BITS; \
|
|
||||||
} \
|
|
||||||
} else \
|
|
||||||
return 0; \
|
|
||||||
} \
|
|
||||||
if (flb) \
|
|
||||||
ret++; \
|
|
||||||
\
|
|
||||||
/* fill exponent bits */ \
|
|
||||||
ret |= (s + ONE_EXP(FLOAT)) << FLOAT_FRAC_BITS; \
|
|
||||||
\
|
|
||||||
/* fill sign bit */ \
|
|
||||||
ret |= sign << 31; \
|
|
||||||
\
|
|
||||||
return ret; \
|
|
||||||
}
|
|
||||||
|
|
||||||
/* unsigned long long to float conversion */
|
|
||||||
DEFINE__AEABI_XL2F(ul2f, 0)
|
|
||||||
|
|
||||||
/* long long to float conversion */
|
|
||||||
DEFINE__AEABI_XL2F(l2f, 1)
|
|
||||||
|
|
||||||
/* long long to double conversion */
|
|
||||||
#define __AEABI_XL2D(name, with_sign) \
|
|
||||||
void __aeabi_ ## name(unsigned long long v) \
|
|
||||||
{ \
|
|
||||||
int s /* shift */, high_shift, sign = 0; \
|
|
||||||
unsigned tmp, p = 0; \
|
|
||||||
double_unsigned_struct val, ret; \
|
|
||||||
\
|
|
||||||
/* fraction in negative float is encoded in 1's complement */ \
|
|
||||||
if (with_sign && (v & (1ULL << 63))) { \
|
|
||||||
sign = 1; \
|
|
||||||
v = ~v + 1; \
|
|
||||||
} \
|
|
||||||
val.low = v; \
|
|
||||||
val.high = v >> 32; \
|
|
||||||
\
|
|
||||||
/* fill fraction bits */ \
|
|
||||||
for (s = 31, p = 1 << 31; p && !(val.high & p); s--, p >>= 1); \
|
|
||||||
if (p) { \
|
|
||||||
tmp = val.high & (p - 1); \
|
|
||||||
if (s < DOUBLE_FRAC_BITS - 32) { \
|
|
||||||
high_shift = DOUBLE_FRAC_BITS - 32 - s; \
|
|
||||||
ret.high = tmp << high_shift; \
|
|
||||||
ret.high |= val.low >> (32 - high_shift); \
|
|
||||||
ret.low = val.low << high_shift; \
|
|
||||||
} else { \
|
|
||||||
high_shift = s - (DOUBLE_FRAC_BITS - 32); \
|
|
||||||
ret.high = tmp >> high_shift; \
|
|
||||||
ret.low = tmp << (32 - high_shift); \
|
|
||||||
ret.low |= val.low >> high_shift; \
|
|
||||||
if ((val.low >> (high_shift - 1)) & 1) { \
|
|
||||||
if (ret.low == UINT_MAX) { \
|
|
||||||
ret.high++; \
|
|
||||||
ret.low = 0; \
|
|
||||||
} else \
|
|
||||||
ret.low++; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
s += 32; \
|
|
||||||
} else { \
|
|
||||||
for (s = 31, p = 1 << 31; p && !(val.low & p); s--, p >>= 1); \
|
|
||||||
if (p) { \
|
|
||||||
tmp = val.low & (p - 1); \
|
|
||||||
if (s <= DOUBLE_FRAC_BITS - 32) { \
|
|
||||||
high_shift = DOUBLE_FRAC_BITS - 32 - s; \
|
|
||||||
ret.high = tmp << high_shift; \
|
|
||||||
ret.low = 0; \
|
|
||||||
} else { \
|
|
||||||
high_shift = s - (DOUBLE_FRAC_BITS - 32); \
|
|
||||||
ret.high = tmp >> high_shift; \
|
|
||||||
ret.low = tmp << (32 - high_shift); \
|
|
||||||
} \
|
|
||||||
} else { \
|
|
||||||
ret.high = ret.low = 0; \
|
|
||||||
goto _ret_; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
/* fill exponent bits */ \
|
|
||||||
ret.high |= (s + ONE_EXP(DOUBLE)) << (DOUBLE_FRAC_BITS - 32); \
|
|
||||||
\
|
|
||||||
/* fill sign bit */ \
|
|
||||||
ret.high |= sign << 31; \
|
|
||||||
\
|
|
||||||
_ret_: \
|
|
||||||
double_unsigned_struct_return(ret); \
|
|
||||||
}
|
|
||||||
|
|
||||||
/* unsigned long long to double conversion */
|
|
||||||
__AEABI_XL2D(ul2d, 0)
|
|
||||||
|
|
||||||
/* long long to double conversion */
|
|
||||||
__AEABI_XL2D(l2d, 1)
|
|
||||||
|
|
||||||
#if 1
|
|
||||||
/* Long long helper functions */
|
|
||||||
|
|
||||||
/* TODO: add error in case of den == 0 (see §4.3.1 and §4.3.2) */
|
|
||||||
|
|
||||||
#define define_aeabi_xdivmod_signed_type(basetype, type) \
|
|
||||||
typedef struct type { \
|
|
||||||
basetype quot; \
|
|
||||||
unsigned basetype rem; \
|
|
||||||
} type
|
|
||||||
|
|
||||||
#define define_aeabi_xdivmod_unsigned_type(basetype, type) \
|
|
||||||
typedef struct type { \
|
|
||||||
basetype quot; \
|
|
||||||
basetype rem; \
|
|
||||||
} type
|
|
||||||
|
|
||||||
#define AEABI_UXDIVMOD(name,type, rettype, typemacro) \
|
|
||||||
static inline rettype aeabi_ ## name (type num, type den) \
|
|
||||||
{ \
|
|
||||||
rettype ret; \
|
|
||||||
type quot = 0; \
|
|
||||||
\
|
|
||||||
/* Increase quotient while it is less than numerator */ \
|
|
||||||
while (num >= den) { \
|
|
||||||
type q = 1; \
|
|
||||||
\
|
|
||||||
/* Find closest power of two */ \
|
|
||||||
while ((q << 1) * den <= num && q * den <= typemacro ## _MAX / 2) \
|
|
||||||
q <<= 1; \
|
|
||||||
\
|
|
||||||
/* Compute difference between current quotient and numerator */ \
|
|
||||||
num -= q * den; \
|
|
||||||
quot += q; \
|
|
||||||
} \
|
|
||||||
ret.quot = quot; \
|
|
||||||
ret.rem = num; \
|
|
||||||
return ret; \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define __AEABI_XDIVMOD(name, type, uiname, rettype, urettype, typemacro) \
|
|
||||||
void __aeabi_ ## name(type numerator, type denominator) \
|
|
||||||
{ \
|
|
||||||
unsigned type num, den; \
|
|
||||||
urettype uxdiv_ret; \
|
|
||||||
rettype ret; \
|
|
||||||
\
|
|
||||||
if (numerator >= 0) \
|
|
||||||
num = numerator; \
|
|
||||||
else \
|
|
||||||
num = 0 - numerator; \
|
|
||||||
if (denominator >= 0) \
|
|
||||||
den = denominator; \
|
|
||||||
else \
|
|
||||||
den = 0 - denominator; \
|
|
||||||
uxdiv_ret = aeabi_ ## uiname(num, den); \
|
|
||||||
/* signs differ */ \
|
|
||||||
if ((numerator & typemacro ## _MIN) != (denominator & typemacro ## _MIN)) \
|
|
||||||
ret.quot = 0 - uxdiv_ret.quot; \
|
|
||||||
else \
|
|
||||||
ret.quot = uxdiv_ret.quot; \
|
|
||||||
if (numerator < 0) \
|
|
||||||
ret.rem = 0 - uxdiv_ret.rem; \
|
|
||||||
else \
|
|
||||||
ret.rem = uxdiv_ret.rem; \
|
|
||||||
\
|
|
||||||
rettype ## _return(ret); \
|
|
||||||
}
|
|
||||||
|
|
||||||
define_aeabi_xdivmod_signed_type(long long, lldiv_t);
|
|
||||||
define_aeabi_xdivmod_unsigned_type(unsigned long long, ulldiv_t);
|
|
||||||
define_aeabi_xdivmod_signed_type(int, idiv_t);
|
|
||||||
define_aeabi_xdivmod_unsigned_type(unsigned, uidiv_t);
|
|
||||||
|
|
||||||
REGS_RETURN(lldiv_t, lldiv_t)
|
|
||||||
REGS_RETURN(ulldiv_t, ulldiv_t)
|
|
||||||
REGS_RETURN(idiv_t, idiv_t)
|
|
||||||
REGS_RETURN(uidiv_t, uidiv_t)
|
|
||||||
|
|
||||||
AEABI_UXDIVMOD(uldivmod, unsigned long long, ulldiv_t, ULLONG)
|
|
||||||
|
|
||||||
__AEABI_XDIVMOD(ldivmod, long long, uldivmod, lldiv_t, ulldiv_t, LLONG)
|
|
||||||
|
|
||||||
void __aeabi_uldivmod(unsigned long long num, unsigned long long den)
|
|
||||||
{
|
|
||||||
ulldiv_t_return(aeabi_uldivmod(num, den));
|
|
||||||
}
|
|
||||||
|
|
||||||
void __aeabi_llsl(double_unsigned_struct val, int shift)
|
|
||||||
{
|
|
||||||
double_unsigned_struct ret;
|
|
||||||
|
|
||||||
if (shift >= 32) {
|
|
||||||
val.high = val.low;
|
|
||||||
val.low = 0;
|
|
||||||
shift -= 32;
|
|
||||||
}
|
|
||||||
if (shift > 0) {
|
|
||||||
ret.low = val.low << shift;
|
|
||||||
ret.high = (val.high << shift) | (val.low >> (32 - shift));
|
|
||||||
double_unsigned_struct_return(ret);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
double_unsigned_struct_return(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define aeabi_lsr(val, shift, fill, type) \
|
|
||||||
type ## _struct ret; \
|
|
||||||
\
|
|
||||||
if (shift >= 32) { \
|
|
||||||
val.low = val.high; \
|
|
||||||
val.high = fill; \
|
|
||||||
shift -= 32; \
|
|
||||||
} \
|
|
||||||
if (shift > 0) { \
|
|
||||||
ret.high = val.high >> shift; \
|
|
||||||
ret.low = (val.high << (32 - shift)) | (val.low >> shift); \
|
|
||||||
type ## _struct_return(ret); \
|
|
||||||
return; \
|
|
||||||
} \
|
|
||||||
type ## _struct_return(val);
|
|
||||||
|
|
||||||
void __aeabi_llsr(double_unsigned_struct val, int shift)
|
|
||||||
{
|
|
||||||
aeabi_lsr(val, shift, 0, double_unsigned);
|
|
||||||
}
|
|
||||||
|
|
||||||
void __aeabi_lasr(unsigned_int_struct val, int shift)
|
|
||||||
{
|
|
||||||
aeabi_lsr(val, shift, val.high >> 31, unsigned_int);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Integer division functions */
|
|
||||||
|
|
||||||
#if 0 /* very slow */
|
|
||||||
AEABI_UXDIVMOD(uidivmod, unsigned, uidiv_t, UINT)
|
|
||||||
|
|
||||||
int __aeabi_idiv(int numerator, int denominator)
|
|
||||||
{
|
|
||||||
unsigned num, den;
|
|
||||||
uidiv_t ret;
|
|
||||||
|
|
||||||
if (numerator >= 0)
|
|
||||||
num = numerator;
|
|
||||||
else
|
|
||||||
num = 0 - numerator;
|
|
||||||
if (denominator >= 0)
|
|
||||||
den = denominator;
|
|
||||||
else
|
|
||||||
den = 0 - denominator;
|
|
||||||
ret = aeabi_uidivmod(num, den);
|
|
||||||
if ((numerator & INT_MIN) != (denominator & INT_MIN)) /* signs differ */
|
|
||||||
ret.quot *= -1;
|
|
||||||
return ret.quot;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned __aeabi_uidiv(unsigned num, unsigned den)
|
|
||||||
{
|
|
||||||
return aeabi_uidivmod(num, den).quot;
|
|
||||||
}
|
|
||||||
|
|
||||||
__AEABI_XDIVMOD(idivmod, int, uidivmod, idiv_t, uidiv_t, INT)
|
|
||||||
|
|
||||||
void __aeabi_uidivmod(unsigned num, unsigned den)
|
|
||||||
{
|
|
||||||
uidiv_t_return(aeabi_uidivmod(num, den));
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
# define UIDIVMOD_ASM 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Some targets do not have all eabi calls (OpenBSD) */
|
|
||||||
typedef __SIZE_TYPE__ size_t;
|
|
||||||
extern void *memcpy(void *dest, const void *src, size_t n);
|
|
||||||
extern void *memmove(void *dest, const void *src, size_t n);
|
|
||||||
extern void *memset(void *s, int c, size_t n);
|
|
||||||
|
|
||||||
void *
|
|
||||||
__aeabi_memcpy (void *dest, const void *src, size_t n)
|
|
||||||
{
|
|
||||||
return memcpy (dest, src, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
void *
|
|
||||||
__aeabi_memmove (void *dest, const void *src, size_t n)
|
|
||||||
{
|
|
||||||
return memmove (dest, src, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
void *
|
|
||||||
__aeabi_memmove4 (void *dest, const void *src, size_t n)
|
|
||||||
{
|
|
||||||
return memmove (dest, src, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
void *
|
|
||||||
__aeabi_memmove8 (void *dest, const void *src, size_t n)
|
|
||||||
{
|
|
||||||
return memmove (dest, src, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
void *
|
|
||||||
__aeabi_memset (void *s, size_t n, int c)
|
|
||||||
{
|
|
||||||
return memset (s, c, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ***************************************************************** */
|
|
||||||
#if UIDIVMOD_ASM
|
|
||||||
#include <config.h>
|
|
||||||
__asm__(
|
|
||||||
"\n .global __aeabi_idiv, __aeabi_idivmod"
|
|
||||||
"\n .global __aeabi_uidiv, __aeabi_uidivmod"
|
|
||||||
#if __ARM_FEATURE_IDIV
|
|
||||||
"\n__aeabi_idiv:"
|
|
||||||
"\n__aeabi_idivmod:"
|
|
||||||
"\n mov r2, r0"
|
|
||||||
"\n sdiv r0, r0, r1"
|
|
||||||
"\n mls r1, r1, r0, r2"
|
|
||||||
"\n bx lr"
|
|
||||||
|
|
||||||
"\n__aeabi_uidiv:"
|
|
||||||
"\n__aeabi_uidivmod:"
|
|
||||||
"\n mov r2, r0"
|
|
||||||
"\n udiv r0, r0, r1"
|
|
||||||
"\n mls r1, r1, r0, r2"
|
|
||||||
"\n bx lr"
|
|
||||||
#else
|
|
||||||
/* Runtime ABI for the ARM Cortex-M0
|
|
||||||
* idivmod.S: signed 32 bit division (quotient and remainder)
|
|
||||||
*
|
|
||||||
* Copyright (c) 2012 Jörg Mische <bobbl@gmx.de>
|
|
||||||
*
|
|
||||||
* Permission to use, copy, modify, and/or distribute this software for any
|
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
|
||||||
* copyright notice and this permission notice appear in all copies.
|
|
||||||
*/
|
|
||||||
"\n__aeabi_idiv:"
|
|
||||||
"\n__aeabi_idivmod:"
|
|
||||||
"\n cmp r0, #0"
|
|
||||||
"\n bge .Lnumerator_pos"
|
|
||||||
"\n rsb r0, r0, #0" // num = -num
|
|
||||||
"\n cmp r1, #0"
|
|
||||||
"\n bge .Lboth_neg"
|
|
||||||
"\n rsb r1, r1, #0" // den = -den
|
|
||||||
"\n push {lr}"
|
|
||||||
"\n bl __aeabi_uidivmod"
|
|
||||||
"\n rsb r1, r1, #0" // rem = -rem
|
|
||||||
"\n pop {pc}"
|
|
||||||
"\n.Lboth_neg:"
|
|
||||||
"\n push {lr}"
|
|
||||||
"\n bl __aeabi_uidivmod"
|
|
||||||
"\n rsb r0, r0, #0" // quot = -quot
|
|
||||||
"\n rsb r1, r1, #0" // rem = -rem
|
|
||||||
"\n pop {pc}"
|
|
||||||
"\n.Ldenom_neg:"
|
|
||||||
"\n rsb r1, r1, #0" // den = -den
|
|
||||||
"\n push {lr}"
|
|
||||||
"\n bl __aeabi_uidivmod"
|
|
||||||
"\n rsb r0, r0, #0" // quot = -quot
|
|
||||||
"\n pop {pc}"
|
|
||||||
"\n.Lnumerator_pos:"
|
|
||||||
"\n cmp r1, #0"
|
|
||||||
"\n blt .Ldenom_neg"
|
|
||||||
|
|
||||||
// Divide r0 by r1 and return the quotient in r0 and the remainder in r1
|
|
||||||
"\n__aeabi_uidiv:"
|
|
||||||
"\n__aeabi_uidivmod:"
|
|
||||||
// Shift left the denominator until it is greater than the numerator
|
|
||||||
"\n mov r2, #1" // counter
|
|
||||||
"\n mov r3, #0" // result
|
|
||||||
"\n cmp r0, r1"
|
|
||||||
"\n bls .Lsub_loop"
|
|
||||||
"\n adds r1, #0" // dont shift if denominator would overflow
|
|
||||||
"\n bmi .Lsub_loop"
|
|
||||||
"\n beq .Luidiv0"
|
|
||||||
"\n.Ldenom_shift_loop:"
|
|
||||||
"\n lsl r2, #1"
|
|
||||||
"\n lsls r1, #1"
|
|
||||||
"\n bmi .Lsub_loop"
|
|
||||||
"\n cmp r0, r1"
|
|
||||||
"\n bhi .Ldenom_shift_loop"
|
|
||||||
"\n.Lsub_loop:"
|
|
||||||
"\n cmp r0, r1" // if (num >= den)...
|
|
||||||
"\n subcs r0, r1" // numerator -= denom
|
|
||||||
"\n orrcs r3, r2" // result(r3) |= bitmask(r2)
|
|
||||||
"\n lsr r1, #1" // denom(r1) >>= 1
|
|
||||||
"\n lsrs r2, #1" // bitmask(r2) >>= 1
|
|
||||||
"\n bne .Lsub_loop"
|
|
||||||
"\n mov r1, r0" // remainder(r1) = numerator(r0)
|
|
||||||
"\n mov r0, r3" // quotient(r0) = result(r3)
|
|
||||||
"\n bx lr"
|
|
||||||
"\n.Luidiv0:" // XXX: division by zero
|
|
||||||
"\n mov r0, #0"
|
|
||||||
"\n bx lr"
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
#endif /* UIDIVMOD_ASM */
|
|
||||||
/* ***************************************************************** */
|
|
||||||
#endif
|
|
||||||
@ -1,64 +0,0 @@
|
|||||||
/* armflush.c - flush the instruction cache
|
|
||||||
|
|
||||||
__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 */
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------- */
|
|
||||||
#if defined __arm__
|
|
||||||
|
|
||||||
#ifdef __TINYC__
|
|
||||||
|
|
||||||
/* syscall wrapper */
|
|
||||||
unsigned _tccsyscall(unsigned syscall_nr, ...);
|
|
||||||
|
|
||||||
/* arm-tcc supports only fake asm currently */
|
|
||||||
__asm__(
|
|
||||||
".global _tccsyscall\n"
|
|
||||||
"_tccsyscall:\n"
|
|
||||||
"push {r7, lr}\n\t"
|
|
||||||
"mov r7, r0\n\t"
|
|
||||||
"mov r0, r1\n\t"
|
|
||||||
"mov r1, r2\n\t"
|
|
||||||
"mov r2, r3\n\t"
|
|
||||||
"svc #0\n\t"
|
|
||||||
"pop {r7, pc}"
|
|
||||||
);
|
|
||||||
|
|
||||||
/* from unistd.h: */
|
|
||||||
#if defined(__thumb__) || defined(__ARM_EABI__)
|
|
||||||
# define __NR_SYSCALL_BASE 0x0
|
|
||||||
#else
|
|
||||||
# define __NR_SYSCALL_BASE 0x900000
|
|
||||||
#endif
|
|
||||||
#define __ARM_NR_BASE (__NR_SYSCALL_BASE+0x0f0000)
|
|
||||||
#define __ARM_NR_cacheflush (__ARM_NR_BASE+2)
|
|
||||||
|
|
||||||
#define syscall _tccsyscall
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#define _GNU_SOURCE
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/syscall.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Flushing for tccrun */
|
|
||||||
void __clear_cache(void *beginning, void *end)
|
|
||||||
{
|
|
||||||
/* __ARM_NR_cacheflush is kernel private and should not be used in user space.
|
|
||||||
* However, there is no ARM asm parser in tcc so we use it for now */
|
|
||||||
syscall(__ARM_NR_cacheflush, beginning, end, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------- */
|
|
||||||
#elif defined __aarch64__
|
|
||||||
void __clear_cache(void *beg, void *end)
|
|
||||||
{
|
|
||||||
__arm64_clear_cache(beg, end);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------- */
|
|
||||||
#endif
|
|
||||||
2669
lib/atomic.S
2669
lib/atomic.S
File diff suppressed because it is too large
Load Diff
2261
lib/bcheck.c
2261
lib/bcheck.c
File diff suppressed because it is too large
Load Diff
95
lib/bt-dll.c
95
lib/bt-dll.c
@ -1,95 +0,0 @@
|
|||||||
/* ------------------------------------------------------------- */
|
|
||||||
/* stubs for calling bcheck functions from a dll. */
|
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#define REDIR_ALL \
|
|
||||||
REDIR(__bt_init) \
|
|
||||||
REDIR(__bt_exit) \
|
|
||||||
REDIR(tcc_backtrace) \
|
|
||||||
\
|
|
||||||
REDIR(__bound_ptr_add) \
|
|
||||||
REDIR(__bound_ptr_indir1) \
|
|
||||||
REDIR(__bound_ptr_indir2) \
|
|
||||||
REDIR(__bound_ptr_indir4) \
|
|
||||||
REDIR(__bound_ptr_indir8) \
|
|
||||||
REDIR(__bound_ptr_indir12) \
|
|
||||||
REDIR(__bound_ptr_indir16) \
|
|
||||||
REDIR(__bound_local_new) \
|
|
||||||
REDIR(__bound_local_delete) \
|
|
||||||
REDIR(__bound_new_region) \
|
|
||||||
\
|
|
||||||
REDIR(__bound_free) \
|
|
||||||
REDIR(__bound_malloc) \
|
|
||||||
REDIR(__bound_realloc) \
|
|
||||||
REDIR(__bound_memcpy) \
|
|
||||||
REDIR(__bound_memcmp) \
|
|
||||||
REDIR(__bound_memmove) \
|
|
||||||
REDIR(__bound_memset) \
|
|
||||||
REDIR(__bound_strlen) \
|
|
||||||
REDIR(__bound_strcpy) \
|
|
||||||
REDIR(__bound_strncpy) \
|
|
||||||
REDIR(__bound_strcmp) \
|
|
||||||
REDIR(__bound_strncmp) \
|
|
||||||
REDIR(__bound_strcat) \
|
|
||||||
REDIR(__bound_strchr) \
|
|
||||||
REDIR(__bound_strdup) \
|
|
||||||
REDIR(__bound_strncat) \
|
|
||||||
REDIR(__bound_strrchr) \
|
|
||||||
REDIR(__bound_setjmp) \
|
|
||||||
REDIR(__bound_longjmp)
|
|
||||||
|
|
||||||
#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__
|
|
||||||
# define REDIR(s) \
|
|
||||||
__asm__(".global "_(s)";"_(s)":"); \
|
|
||||||
__asm__(".int 0x58000090"); /* ldr x16, [pc, #16] */ \
|
|
||||||
__asm__(".int 0xf9400210"); /* ldr x16, [x16] */ \
|
|
||||||
__asm__(".int 0xd61f0200"); /* br x16 */ \
|
|
||||||
__asm__(".int 0xd503201f"); /* nop for alignment */ \
|
|
||||||
__asm__(".quad all_ptrs + (. - all_jmps - 16) / 24 * 8"); \
|
|
||||||
__asm__(".type "_(s)",function\n.size "_(s)",.-"_(s));
|
|
||||||
|
|
||||||
__asm__(".text\n.align 8\nall_jmps:");
|
|
||||||
REDIR_ALL
|
|
||||||
#else
|
|
||||||
# define REDIR(s) \
|
|
||||||
__asm__(".global "_(s)";"_(s)":"); goto *all_ptrs.s;
|
|
||||||
static void all_jmps() { REDIR_ALL }
|
|
||||||
#endif
|
|
||||||
#undef REDIR
|
|
||||||
|
|
||||||
void __bt_init_dll(int bcheck)
|
|
||||||
{
|
|
||||||
const char *s = all_names;
|
|
||||||
void **p = (void**)&all_ptrs;
|
|
||||||
do {
|
|
||||||
*p = (void*)GetProcAddress(GetModuleHandle(NULL), (char*)s);
|
|
||||||
if (NULL == *p) {
|
|
||||||
char buf[100];
|
|
||||||
sprintf(buf,
|
|
||||||
"Error: function '%s()' not found in executable. "
|
|
||||||
"(Need -bt or -b for linking the exe.)", s);
|
|
||||||
if (GetStdHandle(STD_ERROR_HANDLE))
|
|
||||||
fprintf(stderr, "TCC/BCHECK: %s\n", buf), fflush(stderr);
|
|
||||||
else
|
|
||||||
MessageBox(NULL, buf, "TCC/BCHECK", MB_ICONERROR);
|
|
||||||
ExitProcess(1);
|
|
||||||
}
|
|
||||||
s = strchr(s,'\0') + 1, ++p;
|
|
||||||
} while (*s && (bcheck || p < &all_ptrs.__bound_ptr_add));
|
|
||||||
}
|
|
||||||
87
lib/bt-exe.c
87
lib/bt-exe.c
@ -1,87 +0,0 @@
|
|||||||
/* ------------------------------------------------------------- */
|
|
||||||
/* for linking rt_printline and the signal/exception handler
|
|
||||||
from tccrun.c into executables. */
|
|
||||||
|
|
||||||
#define CONFIG_TCC_BACKTRACE_ONLY
|
|
||||||
#define ONE_SOURCE 1
|
|
||||||
#define pstrcpy tcc_pstrcpy
|
|
||||||
#include "../tccrun.c"
|
|
||||||
|
|
||||||
#ifndef _WIN32
|
|
||||||
# define __declspec(n)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef _WIN64
|
|
||||||
static void bt_init_pe_prog_base(rt_context *p)
|
|
||||||
{
|
|
||||||
MEMORY_BASIC_INFORMATION mbi;
|
|
||||||
addr_t imagebase;
|
|
||||||
|
|
||||||
if (!p->prog_base)
|
|
||||||
return;
|
|
||||||
if (!VirtualQuery(p, &mbi, sizeof(mbi)) || !mbi.AllocationBase)
|
|
||||||
return;
|
|
||||||
imagebase = (addr_t)mbi.AllocationBase - p->prog_base;
|
|
||||||
p->prog_base = (addr_t)mbi.AllocationBase - (imagebase & 0xffffffffu);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
__declspec(dllexport)
|
|
||||||
void __bt_init(rt_context *p, int is_exe)
|
|
||||||
{
|
|
||||||
__attribute__((weak)) int main();
|
|
||||||
__attribute__((weak)) void __bound_init(void*, int);
|
|
||||||
|
|
||||||
//fprintf(stderr, "__bt_init %d %p %p %p\n", is_exe, p, p->stab_sym, p->bounds_start), fflush(stderr);
|
|
||||||
|
|
||||||
/* call __bound_init here due to redirection of sigaction */
|
|
||||||
/* needed to add global symbols */
|
|
||||||
if (p->bounds_start)
|
|
||||||
__bound_init(p->bounds_start, -1);
|
|
||||||
|
|
||||||
#ifdef _WIN64
|
|
||||||
bt_init_pe_prog_base(p);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* add to chain */
|
|
||||||
rt_wait_sem();
|
|
||||||
p->next = g_rc, g_rc = p;
|
|
||||||
rt_post_sem();
|
|
||||||
if (is_exe) {
|
|
||||||
/* we are the executable (not a dll) */
|
|
||||||
p->top_func = main;
|
|
||||||
set_exception_handler();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
__declspec(dllexport)
|
|
||||||
void __bt_exit(rt_context *p)
|
|
||||||
{
|
|
||||||
struct rt_context *rc, **pp;
|
|
||||||
__attribute__((weak)) void __bound_exit_dll(void*);
|
|
||||||
|
|
||||||
//fprintf(stderr, "__bt_exit %d %p\n", !!p->top_func, p);
|
|
||||||
|
|
||||||
if (p->bounds_start)
|
|
||||||
__bound_exit_dll(p->bounds_start);
|
|
||||||
|
|
||||||
/* remove from chain */
|
|
||||||
rt_wait_sem();
|
|
||||||
for (pp = &g_rc; rc = *pp, rc; pp = &rc->next)
|
|
||||||
if (rc == p) {
|
|
||||||
*pp = rc->next;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
rt_post_sem();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* copy a string and truncate it. */
|
|
||||||
ST_FUNC char *pstrcpy(char *buf, size_t buf_size, const char *s)
|
|
||||||
{
|
|
||||||
int l = strlen(s);
|
|
||||||
if (l >= buf_size)
|
|
||||||
l = buf_size - 1;
|
|
||||||
memcpy(buf, s, l);
|
|
||||||
buf[l] = 0;
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
56
lib/bt-log.c
56
lib/bt-log.c
@ -1,56 +0,0 @@
|
|||||||
/* ------------------------------------------------------------- */
|
|
||||||
/* function to get a stack backtrace on demand with a message */
|
|
||||||
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#undef __attribute__
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
# define DLL_EXPORT __declspec(dllexport)
|
|
||||||
#else
|
|
||||||
# define DLL_EXPORT
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Needed when using ...libtcc1-usegcc=yes in lib/Makefile */
|
|
||||||
#if (defined(__GNUC__) && (__GNUC__ >= 6)) || defined(__clang__)
|
|
||||||
#pragma GCC diagnostic push
|
|
||||||
#pragma GCC diagnostic ignored "-Wframe-address"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct rt_frame {
|
|
||||||
void *ip, *fp, *sp;
|
|
||||||
} rt_frame;
|
|
||||||
|
|
||||||
__attribute__((weak))
|
|
||||||
int _tcc_backtrace(rt_frame *f, const char *fmt, va_list ap);
|
|
||||||
|
|
||||||
DLL_EXPORT int tcc_backtrace(const char *fmt, ...)
|
|
||||||
{
|
|
||||||
va_list ap;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (_tcc_backtrace) {
|
|
||||||
rt_frame f;
|
|
||||||
f.fp = __builtin_frame_address(1);
|
|
||||||
f.ip = __builtin_return_address(0);
|
|
||||||
va_start(ap, fmt);
|
|
||||||
ret = _tcc_backtrace(&f, fmt, ap);
|
|
||||||
va_end(ap);
|
|
||||||
} else {
|
|
||||||
const char *p, *nl = "\n";
|
|
||||||
if (fmt[0] == '^' && (p = strchr(fmt + 1, fmt[0])))
|
|
||||||
fmt = p + 1;
|
|
||||||
if (fmt[0] == '\001')
|
|
||||||
++fmt, nl = "";
|
|
||||||
va_start(ap, fmt);
|
|
||||||
ret = vfprintf(stderr, fmt, ap);
|
|
||||||
va_end(ap);
|
|
||||||
fprintf(stderr, "%s", nl), fflush(stderr);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if (defined(__GNUC__) && (__GNUC__ >= 6)) || defined(__clang__)
|
|
||||||
#pragma GCC diagnostic pop
|
|
||||||
#endif
|
|
||||||
164
lib/builtin.c
164
lib/builtin.c
@ -1,164 +0,0 @@
|
|||||||
/* uses alias to allow building with gcc/clang */
|
|
||||||
#ifdef __TINYC__
|
|
||||||
#define BUILTIN(x) __builtin_##x
|
|
||||||
#define BUILTINN(x) "__builtin_" # x
|
|
||||||
#else
|
|
||||||
#define BUILTIN(x) __tcc_builtin_##x
|
|
||||||
#define BUILTINN(x) "__tcc_builtin_" # x
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* ---------------------------------------------- */
|
|
||||||
/* This file implements:
|
|
||||||
* __builtin_ffs
|
|
||||||
* __builtin_clz
|
|
||||||
* __builtin_ctz
|
|
||||||
* __builtin_clrsb
|
|
||||||
* __builtin_popcount
|
|
||||||
* __builtin_parity
|
|
||||||
* for int, long and long long
|
|
||||||
*/
|
|
||||||
|
|
||||||
static const unsigned char table_1_32[] = {
|
|
||||||
0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
|
|
||||||
31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
|
|
||||||
};
|
|
||||||
static const unsigned char table_2_32[32] = {
|
|
||||||
31, 22, 30, 21, 18, 10, 29, 2, 20, 17, 15, 13, 9, 6, 28, 1,
|
|
||||||
23, 19, 11, 3, 16, 14, 7, 24, 12, 4, 8, 25, 5, 26, 27, 0
|
|
||||||
};
|
|
||||||
static const unsigned char table_1_64[] = {
|
|
||||||
0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28,
|
|
||||||
62, 5, 39, 46, 44, 42, 22, 9, 24, 35, 59, 56, 49, 18, 29, 11,
|
|
||||||
63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10,
|
|
||||||
51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12
|
|
||||||
};
|
|
||||||
static const unsigned char table_2_64[] = {
|
|
||||||
63, 16, 62, 7, 15, 36, 61, 3, 6, 14, 22, 26, 35, 47, 60, 2,
|
|
||||||
9, 5, 28, 11, 13, 21, 42, 19, 25, 31, 34, 40, 46, 52, 59, 1,
|
|
||||||
17, 8, 37, 4, 23, 27, 48, 10, 29, 12, 43, 20, 32, 41, 53, 18,
|
|
||||||
38, 24, 49, 30, 44, 33, 54, 39, 50, 45, 55, 51, 56, 57, 58, 0
|
|
||||||
};
|
|
||||||
|
|
||||||
#define FFSI(x) \
|
|
||||||
return table_1_32[((x & -x) * 0x077cb531u) >> 27] + (x != 0);
|
|
||||||
#define FFSL(x) \
|
|
||||||
return table_1_64[((x & -x) * 0x022fdd63cc95386dull) >> 58] + (x != 0);
|
|
||||||
#define CTZI(x) \
|
|
||||||
return table_1_32[((x & -x) * 0x077cb531u) >> 27];
|
|
||||||
#define CTZL(x) \
|
|
||||||
return table_1_64[((x & -x) * 0x022fdd63cc95386dull) >> 58];
|
|
||||||
#define CLZI(x) \
|
|
||||||
x |= x >> 1; \
|
|
||||||
x |= x >> 2; \
|
|
||||||
x |= x >> 4; \
|
|
||||||
x |= x >> 8; \
|
|
||||||
x |= x >> 16; \
|
|
||||||
return table_2_32[(x * 0x07c4acddu) >> 27];
|
|
||||||
#define CLZL(x) \
|
|
||||||
x |= x >> 1; \
|
|
||||||
x |= x >> 2; \
|
|
||||||
x |= x >> 4; \
|
|
||||||
x |= x >> 8; \
|
|
||||||
x |= x >> 16; \
|
|
||||||
x |= x >> 32; \
|
|
||||||
return table_2_64[x * 0x03f79d71b4cb0a89ull >> 58];
|
|
||||||
#define POPCOUNTI(x, m) \
|
|
||||||
x = x - ((x >> 1) & 0x55555555); \
|
|
||||||
x = (x & 0x33333333) + ((x >> 2) & 0x33333333); \
|
|
||||||
x = (x + (x >> 4)) & 0xf0f0f0f; \
|
|
||||||
return ((x * 0x01010101) >> 24) & m;
|
|
||||||
#define POPCOUNTL(x, m) \
|
|
||||||
x = x - ((x >> 1) & 0x5555555555555555ull); \
|
|
||||||
x = (x & 0x3333333333333333ull) + ((x >> 2) & 0x3333333333333333ull); \
|
|
||||||
x = (x + (x >> 4)) & 0xf0f0f0f0f0f0f0full; \
|
|
||||||
return ((x * 0x0101010101010101ull) >> 56) & m;
|
|
||||||
|
|
||||||
/* Returns one plus the index of the least significant 1-bit of x,
|
|
||||||
or if x is zero, returns zero. */
|
|
||||||
int BUILTIN(ffs) (int x) { FFSI(x) }
|
|
||||||
int BUILTIN(ffsll) (long long x) { FFSL(x) }
|
|
||||||
#if __SIZEOF_LONG__ == 4
|
|
||||||
int BUILTIN(ffsl) (long x) __attribute__((alias(BUILTINN(ffs))));
|
|
||||||
#else
|
|
||||||
int BUILTIN(ffsl) (long x) __attribute__((alias(BUILTINN(ffsll))));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Returns the number of leading 0-bits in x, starting at the most significant
|
|
||||||
bit position. If x is 0, the result is undefined. */
|
|
||||||
int BUILTIN(clz) (unsigned int x) { CLZI(x) }
|
|
||||||
int BUILTIN(clzll) (unsigned long long x) { CLZL(x) }
|
|
||||||
#if __SIZEOF_LONG__ == 4
|
|
||||||
int BUILTIN(clzl) (unsigned long x) __attribute__((alias(BUILTINN(clz))));
|
|
||||||
#else
|
|
||||||
int BUILTIN(clzl) (unsigned long x) __attribute__((alias(BUILTINN(clzll))));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Returns the number of trailing 0-bits in x, starting at the least
|
|
||||||
significant bit position. If x is 0, the result is undefined. */
|
|
||||||
int BUILTIN(ctz) (unsigned int x) { CTZI(x) }
|
|
||||||
int BUILTIN(ctzll) (unsigned long long x) { CTZL(x) }
|
|
||||||
#if __SIZEOF_LONG__ == 4
|
|
||||||
int BUILTIN(ctzl) (unsigned long x) __attribute__((alias(BUILTINN(ctz))));
|
|
||||||
#else
|
|
||||||
int BUILTIN(ctzl) (unsigned long x) __attribute__((alias(BUILTINN(ctzll))));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Returns the number of leading redundant sign bits in x, i.e. the number
|
|
||||||
of bits following the most significant bit that are identical to it.
|
|
||||||
There are no special cases for 0 or other values. */
|
|
||||||
int BUILTIN(clrsb) (int x) { if (x < 0) x = ~x; x <<= 1; CLZI(x) }
|
|
||||||
int BUILTIN(clrsbll) (long long x) { if (x < 0) x = ~x; x <<= 1; CLZL(x) }
|
|
||||||
#if __SIZEOF_LONG__ == 4
|
|
||||||
int BUILTIN(clrsbl) (long x) __attribute__((alias(BUILTINN(clrsb))));
|
|
||||||
#else
|
|
||||||
int BUILTIN(clrsbl) (long x) __attribute__((alias(BUILTINN(clrsbll))));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Returns the number of 1-bits in x.*/
|
|
||||||
int BUILTIN(popcount) (unsigned int x) { POPCOUNTI(x, 0x3f) }
|
|
||||||
int BUILTIN(popcountll) (unsigned long long x) { POPCOUNTL(x, 0x7f) }
|
|
||||||
#if __SIZEOF_LONG__ == 4
|
|
||||||
int BUILTIN(popcountl) (unsigned long x) __attribute__((alias(BUILTINN(popcount))));
|
|
||||||
#else
|
|
||||||
int BUILTIN(popcountl ) (unsigned long x) __attribute__((alias(BUILTINN(popcountll))));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Returns the parity of x, i.e. the number of 1-bits in x modulo 2. */
|
|
||||||
int BUILTIN(parity) (unsigned int x) { POPCOUNTI(x, 0x01) }
|
|
||||||
int BUILTIN(parityll) (unsigned long long x) { POPCOUNTL(x, 0x01) }
|
|
||||||
#if __SIZEOF_LONG__ == 4
|
|
||||||
int BUILTIN(parityl) (unsigned long x) __attribute__((alias(BUILTINN(parity))));
|
|
||||||
#else
|
|
||||||
int BUILTIN(parityl) (unsigned long x) __attribute__((alias(BUILTINN(parityll))));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef __TINYC__
|
|
||||||
#if defined(__GNUC__) && (__GNUC__ >= 6)
|
|
||||||
/* gcc overrides alias from __builtin_ffs... to ffs.. so use assembly code */
|
|
||||||
__asm__(".globl __builtin_ffs");
|
|
||||||
__asm__(".set __builtin_ffs,__tcc_builtin_ffs");
|
|
||||||
__asm__(".globl __builtin_ffsl");
|
|
||||||
__asm__(".set __builtin_ffsl,__tcc_builtin_ffsl");
|
|
||||||
__asm__(".globl __builtin_ffsll");
|
|
||||||
__asm__(".set __builtin_ffsll,__tcc_builtin_ffsll");
|
|
||||||
#else
|
|
||||||
int __builtin_ffs(int x) __attribute__((alias("__tcc_builtin_ffs")));
|
|
||||||
int __builtin_ffsl(long x) __attribute__((alias("__tcc_builtin_ffsl")));
|
|
||||||
int __builtin_ffsll(long long x) __attribute__((alias("__tcc_builtin_ffsll")));
|
|
||||||
#endif
|
|
||||||
int __builtin_clz(unsigned int x) __attribute__((alias("__tcc_builtin_clz")));
|
|
||||||
int __builtin_clzl(unsigned long x) __attribute__((alias("__tcc_builtin_clzl")));
|
|
||||||
int __builtin_clzll(unsigned long long x) __attribute__((alias("__tcc_builtin_clzll")));
|
|
||||||
int __builtin_ctz(unsigned int x) __attribute__((alias("__tcc_builtin_ctz")));
|
|
||||||
int __builtin_ctzl(unsigned long x) __attribute__((alias("__tcc_builtin_ctzl")));
|
|
||||||
int __builtin_ctzll(unsigned long long x) __attribute__((alias("__tcc_builtin_ctzll")));
|
|
||||||
int __builtin_clrsb(int x) __attribute__((alias("__tcc_builtin_clrsb")));
|
|
||||||
int __builtin_clrsbl(long x) __attribute__((alias("__tcc_builtin_clrsbl")));
|
|
||||||
int __builtin_clrsbll(long long x) __attribute__((alias("__tcc_builtin_clrsbll")));
|
|
||||||
int __builtin_popcount(unsigned int x) __attribute__((alias("__tcc_builtin_popcount")));
|
|
||||||
int __builtin_popcountl(unsigned long x) __attribute__((alias("__tcc_builtin_popcountl")));
|
|
||||||
int __builtin_popcountll(unsigned long long x) __attribute__((alias("__tcc_builtin_popcountll")));
|
|
||||||
int __builtin_parity(unsigned int x) __attribute__((alias("__tcc_builtin_parity")));
|
|
||||||
int __builtin_parityl(unsigned long x) __attribute__((alias("__tcc_builtin_parityl")));
|
|
||||||
int __builtin_parityll(unsigned long long x) __attribute__((alias("__tcc_builtin_parityll")));
|
|
||||||
#endif
|
|
||||||
@ -1 +0,0 @@
|
|||||||
void * __dso_handle __attribute((visibility("hidden"))) = &__dso_handle;
|
|
||||||
678
lib/lib-arm64.c
678
lib/lib-arm64.c
@ -1,678 +0,0 @@
|
|||||||
/*
|
|
||||||
* TCC runtime library for arm64.
|
|
||||||
*
|
|
||||||
* Copyright (c) 2015 Edmund Grimley Evans
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef __TINYC__
|
|
||||||
typedef signed char int8_t;
|
|
||||||
typedef unsigned char uint8_t;
|
|
||||||
typedef short int16_t;
|
|
||||||
typedef unsigned short uint16_t;
|
|
||||||
typedef int int32_t;
|
|
||||||
typedef unsigned uint32_t;
|
|
||||||
typedef long long int64_t;
|
|
||||||
typedef unsigned long long uint64_t;
|
|
||||||
#else
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <string.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef union {
|
|
||||||
struct { uint64_t x0, x1; };
|
|
||||||
long double f;
|
|
||||||
} u128_t;
|
|
||||||
|
|
||||||
typedef union {
|
|
||||||
uint64_t x;
|
|
||||||
double f;
|
|
||||||
} u64_t;
|
|
||||||
|
|
||||||
typedef union {
|
|
||||||
uint32_t x;
|
|
||||||
float f;
|
|
||||||
} u32_t;
|
|
||||||
|
|
||||||
static long double f3_zero(int sgn)
|
|
||||||
{
|
|
||||||
u128_t x = { 0, (uint64_t)sgn << 63 };
|
|
||||||
return x.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
static long double f3_infinity(int sgn)
|
|
||||||
{
|
|
||||||
u128_t x = { 0, (uint64_t)sgn << 63 | 0x7fff000000000000 };
|
|
||||||
return x.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
static long double f3_NaN(void)
|
|
||||||
{
|
|
||||||
#if 0
|
|
||||||
// ARM's default NaN usually has just the top fraction bit set:
|
|
||||||
u128_t x = { 0, 0x7fff800000000000 };
|
|
||||||
#else
|
|
||||||
// GCC's library sets all fraction bits:
|
|
||||||
u128_t x = { -1, 0x7fffffffffffffff };
|
|
||||||
#endif
|
|
||||||
return x.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int fp3_convert_NaN(long double *f, int sgn, u128_t *mnt)
|
|
||||||
{
|
|
||||||
u128_t x = { mnt->x0,
|
|
||||||
mnt->x1 | 0x7fff800000000000 | (uint64_t)sgn << 63 };
|
|
||||||
*f = x.f;
|
|
||||||
return 1;
|
|
||||||
#define fp3_convert_NaN(a,b,c) fp3_convert_NaN(a,b,&c)
|
|
||||||
}
|
|
||||||
|
|
||||||
static int fp3_detect_NaNs(long double *f,
|
|
||||||
int a_sgn, int a_exp, u128_t *a,
|
|
||||||
int b_sgn, int b_exp, u128_t *b)
|
|
||||||
#define a (*a)
|
|
||||||
#define b (*b)
|
|
||||||
{
|
|
||||||
#if 0
|
|
||||||
// Detect signalling NaNs:
|
|
||||||
if (a_exp == 32767 && (a.x0 | a.x1 << 16) && !(a.x1 >> 47 & 1))
|
|
||||||
return fp3_convert_NaN(f, a_sgn, a);
|
|
||||||
if (b_exp == 32767 && (b.x0 | b.x1 << 16) && !(b.x1 >> 47 & 1))
|
|
||||||
return fp3_convert_NaN(f, b_sgn, b);
|
|
||||||
#endif
|
|
||||||
// Detect quiet NaNs:
|
|
||||||
if (a_exp == 32767 && (a.x0 | a.x1 << 16))
|
|
||||||
return fp3_convert_NaN(f, a_sgn, a);
|
|
||||||
if (b_exp == 32767 && (b.x0 | b.x1 << 16))
|
|
||||||
return fp3_convert_NaN(f, b_sgn, b);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
#undef a
|
|
||||||
#undef b
|
|
||||||
#define fp3_detect_NaNs(a,b,c,d,e,f,g) fp3_detect_NaNs(a,b,c,&d,e,f,&g)
|
|
||||||
}
|
|
||||||
|
|
||||||
static void f3_unpack(int *sgn, int32_t *exp, u128_t *mnt, long double f)
|
|
||||||
{
|
|
||||||
u128_t x;
|
|
||||||
|
|
||||||
x.f = f;
|
|
||||||
*sgn = x.x1 >> 63;
|
|
||||||
*exp = x.x1 >> 48 & 32767;
|
|
||||||
x.x1 = x.x1 << 16 >> 16;
|
|
||||||
if (*exp)
|
|
||||||
x.x1 |= (uint64_t)1 << 48;
|
|
||||||
else
|
|
||||||
*exp = 1;
|
|
||||||
mnt->f = x.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void f3_normalise(int32_t *exp, u128_t *mnt)
|
|
||||||
{
|
|
||||||
int sh;
|
|
||||||
if (!(mnt->x0 | mnt->x1))
|
|
||||||
return;
|
|
||||||
if (!mnt->x1) {
|
|
||||||
mnt->x1 = mnt->x0;
|
|
||||||
mnt->x0 = 0;
|
|
||||||
*exp -= 64;
|
|
||||||
}
|
|
||||||
for (sh = 32; sh; sh >>= 1) {
|
|
||||||
if (!(mnt->x1 >> (64 - sh))) {
|
|
||||||
mnt->x1 = mnt->x1 << sh | mnt->x0 >> (64 - sh);
|
|
||||||
mnt->x0 = mnt->x0 << sh;
|
|
||||||
*exp -= sh;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void f3_sticky_shift(int32_t sh, u128_t *x)
|
|
||||||
{
|
|
||||||
if (sh >= 128) {
|
|
||||||
x->x0 = !!(x->x0 | x->x1);
|
|
||||||
x->x1 = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (sh >= 64) {
|
|
||||||
x->x0 = x->x1 | !!x->x0;
|
|
||||||
x->x1 = 0;
|
|
||||||
sh -= 64;
|
|
||||||
}
|
|
||||||
if (sh > 0) {
|
|
||||||
x->x0 = x->x0 >> sh | x->x1 << (64 - sh) | !!(x->x0 << (64 - sh));
|
|
||||||
x->x1 = x->x1 >> sh;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static long double f3_round(int sgn, int32_t exp, u128_t *x)
|
|
||||||
{
|
|
||||||
long double f;
|
|
||||||
int error;
|
|
||||||
|
|
||||||
if (exp > 0) {
|
|
||||||
f3_sticky_shift(13, x);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
f3_sticky_shift(14 - exp, x);
|
|
||||||
exp = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
error = x->x0 & 3;
|
|
||||||
x->x0 = x->x0 >> 2 | x->x1 << 62;
|
|
||||||
x->x1 = x->x1 >> 2;
|
|
||||||
|
|
||||||
if (error == 3 || ((error == 2) & (x->x0 & 1))) {
|
|
||||||
if (!++x->x0) {
|
|
||||||
++x->x1;
|
|
||||||
if (x->x1 == (uint64_t)1 << 48)
|
|
||||||
exp = 1;
|
|
||||||
else if (x->x1 == (uint64_t)1 << 49) {
|
|
||||||
++exp;
|
|
||||||
x->x0 = x->x0 >> 1 | x->x1 << 63;
|
|
||||||
x->x1 = x->x1 >> 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (exp >= 32767)
|
|
||||||
return f3_infinity(sgn);
|
|
||||||
|
|
||||||
x->x1 = x->x1 << 16 >> 16 | (uint64_t)exp << 48 | (uint64_t)sgn << 63;
|
|
||||||
return x->f;
|
|
||||||
}
|
|
||||||
|
|
||||||
static long double f3_add(long double fa, long double fb, int neg)
|
|
||||||
{
|
|
||||||
u128_t a, b, x;
|
|
||||||
int32_t a_exp, b_exp, x_exp;
|
|
||||||
int a_sgn, b_sgn, x_sgn;
|
|
||||||
long double fx;
|
|
||||||
|
|
||||||
f3_unpack(&a_sgn, &a_exp, &a, fa);
|
|
||||||
f3_unpack(&b_sgn, &b_exp, &b, fb);
|
|
||||||
|
|
||||||
if (fp3_detect_NaNs(&fx, a_sgn, a_exp, a, b_sgn, b_exp, b))
|
|
||||||
return fx;
|
|
||||||
|
|
||||||
b_sgn ^= neg;
|
|
||||||
|
|
||||||
// Handle infinities and zeroes:
|
|
||||||
if (a_exp == 32767 && b_exp == 32767 && a_sgn != b_sgn)
|
|
||||||
return f3_NaN();
|
|
||||||
if (a_exp == 32767)
|
|
||||||
return f3_infinity(a_sgn);
|
|
||||||
if (b_exp == 32767)
|
|
||||||
return f3_infinity(b_sgn);
|
|
||||||
if (!(a.x0 | a.x1 | b.x0 | b.x1))
|
|
||||||
return f3_zero(a_sgn & b_sgn);
|
|
||||||
|
|
||||||
a.x1 = a.x1 << 3 | a.x0 >> 61;
|
|
||||||
a.x0 = a.x0 << 3;
|
|
||||||
b.x1 = b.x1 << 3 | b.x0 >> 61;
|
|
||||||
b.x0 = b.x0 << 3;
|
|
||||||
|
|
||||||
if (a_exp <= b_exp) {
|
|
||||||
f3_sticky_shift(b_exp - a_exp, &a);
|
|
||||||
a_exp = b_exp;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
f3_sticky_shift(a_exp - b_exp, &b);
|
|
||||||
b_exp = a_exp;
|
|
||||||
}
|
|
||||||
|
|
||||||
x_sgn = a_sgn;
|
|
||||||
x_exp = a_exp;
|
|
||||||
if (a_sgn == b_sgn) {
|
|
||||||
x.x0 = a.x0 + b.x0;
|
|
||||||
x.x1 = a.x1 + b.x1 + (x.x0 < a.x0);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
x.x0 = a.x0 - b.x0;
|
|
||||||
x.x1 = a.x1 - b.x1 - (x.x0 > a.x0);
|
|
||||||
if (x.x1 >> 63) {
|
|
||||||
x_sgn ^= 1;
|
|
||||||
x.x0 = -x.x0;
|
|
||||||
x.x1 = -x.x1 - !!x.x0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(x.x0 | x.x1))
|
|
||||||
return f3_zero(0);
|
|
||||||
|
|
||||||
f3_normalise(&x_exp, &x);
|
|
||||||
|
|
||||||
return f3_round(x_sgn, x_exp + 12, &x);
|
|
||||||
}
|
|
||||||
|
|
||||||
long double __addtf3(long double a, long double b)
|
|
||||||
{
|
|
||||||
return f3_add(a, b, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
long double __subtf3(long double a, long double b)
|
|
||||||
{
|
|
||||||
return f3_add(a, b, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
long double __multf3(long double fa, long double fb)
|
|
||||||
{
|
|
||||||
u128_t a, b, x;
|
|
||||||
int32_t a_exp, b_exp, x_exp;
|
|
||||||
int a_sgn, b_sgn, x_sgn;
|
|
||||||
long double fx;
|
|
||||||
|
|
||||||
f3_unpack(&a_sgn, &a_exp, &a, fa);
|
|
||||||
f3_unpack(&b_sgn, &b_exp, &b, fb);
|
|
||||||
|
|
||||||
if (fp3_detect_NaNs(&fx, a_sgn, a_exp, a, b_sgn, b_exp, b))
|
|
||||||
return fx;
|
|
||||||
|
|
||||||
// Handle infinities and zeroes:
|
|
||||||
if ((a_exp == 32767 && !(b.x0 | b.x1)) ||
|
|
||||||
(b_exp == 32767 && !(a.x0 | a.x1)))
|
|
||||||
return f3_NaN();
|
|
||||||
if (a_exp == 32767 || b_exp == 32767)
|
|
||||||
return f3_infinity(a_sgn ^ b_sgn);
|
|
||||||
if (!(a.x0 | a.x1) || !(b.x0 | b.x1))
|
|
||||||
return f3_zero(a_sgn ^ b_sgn);
|
|
||||||
|
|
||||||
f3_normalise(&a_exp, &a);
|
|
||||||
f3_normalise(&b_exp, &b);
|
|
||||||
|
|
||||||
x_sgn = a_sgn ^ b_sgn;
|
|
||||||
x_exp = a_exp + b_exp - 16352;
|
|
||||||
|
|
||||||
{
|
|
||||||
// Convert to base (1 << 30), discarding bottom 6 bits, which are zero,
|
|
||||||
// so there are (32, 30, 30, 30) bits in (a3, a2, a1, a0):
|
|
||||||
uint64_t a0 = a.x0 << 28 >> 34;
|
|
||||||
uint64_t b0 = b.x0 << 28 >> 34;
|
|
||||||
uint64_t a1 = a.x0 >> 36 | a.x1 << 62 >> 34;
|
|
||||||
uint64_t b1 = b.x0 >> 36 | b.x1 << 62 >> 34;
|
|
||||||
uint64_t a2 = a.x1 << 32 >> 34;
|
|
||||||
uint64_t b2 = b.x1 << 32 >> 34;
|
|
||||||
uint64_t a3 = a.x1 >> 32;
|
|
||||||
uint64_t b3 = b.x1 >> 32;
|
|
||||||
// Use 16 small multiplications and additions that do not overflow:
|
|
||||||
uint64_t x0 = a0 * b0;
|
|
||||||
uint64_t x1 = (x0 >> 30) + a0 * b1 + a1 * b0;
|
|
||||||
uint64_t x2 = (x1 >> 30) + a0 * b2 + a1 * b1 + a2 * b0;
|
|
||||||
uint64_t x3 = (x2 >> 30) + a0 * b3 + a1 * b2 + a2 * b1 + a3 * b0;
|
|
||||||
uint64_t x4 = (x3 >> 30) + a1 * b3 + a2 * b2 + a3 * b1;
|
|
||||||
uint64_t x5 = (x4 >> 30) + a2 * b3 + a3 * b2;
|
|
||||||
uint64_t x6 = (x5 >> 30) + a3 * b3;
|
|
||||||
// We now have (64, 30, 30, ...) bits in (x6, x5, x4, ...).
|
|
||||||
// Take the top 128 bits, setting bottom bit if any lower bits were set:
|
|
||||||
uint64_t y0 = (x5 << 34 | x4 << 34 >> 30 | x3 << 34 >> 60 |
|
|
||||||
!!(x3 << 38 | (x2 | x1 | x0) << 34));
|
|
||||||
uint64_t y1 = x6;
|
|
||||||
// Top bit may be zero. Renormalise:
|
|
||||||
if (!(y1 >> 63)) {
|
|
||||||
y1 = y1 << 1 | y0 >> 63;
|
|
||||||
y0 = y0 << 1;
|
|
||||||
--x_exp;
|
|
||||||
}
|
|
||||||
x.x0 = y0;
|
|
||||||
x.x1 = y1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return f3_round(x_sgn, x_exp, &x);
|
|
||||||
}
|
|
||||||
|
|
||||||
long double __divtf3(long double fa, long double fb)
|
|
||||||
{
|
|
||||||
u128_t a, b, x;
|
|
||||||
int32_t a_exp, b_exp, x_exp;
|
|
||||||
int a_sgn, b_sgn, x_sgn, i;
|
|
||||||
long double fx;
|
|
||||||
|
|
||||||
f3_unpack(&a_sgn, &a_exp, &a, fa);
|
|
||||||
f3_unpack(&b_sgn, &b_exp, &b, fb);
|
|
||||||
|
|
||||||
if (fp3_detect_NaNs(&fx, a_sgn, a_exp, a, b_sgn, b_exp, b))
|
|
||||||
return fx;
|
|
||||||
|
|
||||||
// Handle infinities and zeroes:
|
|
||||||
if ((a_exp == 32767 && b_exp == 32767) ||
|
|
||||||
(!(a.x0 | a.x1) && !(b.x0 | b.x1)))
|
|
||||||
return f3_NaN();
|
|
||||||
if (a_exp == 32767 || !(b.x0 | b.x1))
|
|
||||||
return f3_infinity(a_sgn ^ b_sgn);
|
|
||||||
if (!(a.x0 | a.x1) || b_exp == 32767)
|
|
||||||
return f3_zero(a_sgn ^ b_sgn);
|
|
||||||
|
|
||||||
f3_normalise(&a_exp, &a);
|
|
||||||
f3_normalise(&b_exp, &b);
|
|
||||||
|
|
||||||
x_sgn = a_sgn ^ b_sgn;
|
|
||||||
x_exp = a_exp - b_exp + 16395;
|
|
||||||
|
|
||||||
a.x0 = a.x0 >> 1 | a.x1 << 63;
|
|
||||||
a.x1 = a.x1 >> 1;
|
|
||||||
b.x0 = b.x0 >> 1 | b.x1 << 63;
|
|
||||||
b.x1 = b.x1 >> 1;
|
|
||||||
x.x0 = 0;
|
|
||||||
x.x1 = 0;
|
|
||||||
for (i = 0; i < 116; i++) {
|
|
||||||
x.x1 = x.x1 << 1 | x.x0 >> 63;
|
|
||||||
x.x0 = x.x0 << 1;
|
|
||||||
if (a.x1 > b.x1 || (a.x1 == b.x1 && a.x0 >= b.x0)) {
|
|
||||||
a.x1 = a.x1 - b.x1 - (a.x0 < b.x0);
|
|
||||||
a.x0 = a.x0 - b.x0;
|
|
||||||
x.x0 |= 1;
|
|
||||||
}
|
|
||||||
a.x1 = a.x1 << 1 | a.x0 >> 63;
|
|
||||||
a.x0 = a.x0 << 1;
|
|
||||||
}
|
|
||||||
x.x0 |= !!(a.x0 | a.x1);
|
|
||||||
|
|
||||||
f3_normalise(&x_exp, &x);
|
|
||||||
|
|
||||||
return f3_round(x_sgn, x_exp, &x);
|
|
||||||
}
|
|
||||||
|
|
||||||
long double __negtf2(long double f)
|
|
||||||
{
|
|
||||||
((u128_t*)&f)->x1 ^= 1UL << 63;
|
|
||||||
return f;
|
|
||||||
}
|
|
||||||
|
|
||||||
long double __extendsftf2(float f)
|
|
||||||
{
|
|
||||||
u128_t x;
|
|
||||||
u32_t u;
|
|
||||||
uint32_t a;
|
|
||||||
uint64_t aa;
|
|
||||||
|
|
||||||
u.f = f, a = u.x;
|
|
||||||
aa = a;
|
|
||||||
|
|
||||||
x.x0 = 0;
|
|
||||||
if (!(a << 1))
|
|
||||||
x.x1 = aa << 32;
|
|
||||||
else if (a << 1 >> 24 == 255)
|
|
||||||
x.x1 = (0x7fff000000000000 | aa >> 31 << 63 | aa << 41 >> 16 |
|
|
||||||
(uint64_t)!!(a << 9) << 47);
|
|
||||||
else if (a << 1 >> 24 == 0) {
|
|
||||||
uint64_t adj = 0;
|
|
||||||
while (!(a << 1 >> 1 >> (23 - adj)))
|
|
||||||
adj++;
|
|
||||||
x.x1 = aa >> 31 << 63 | (16256 - adj + 1) << 48 | aa << adj << 41 >> 16;
|
|
||||||
} else
|
|
||||||
x.x1 = (aa >> 31 << 63 | ((aa >> 23 & 255) + 16256) << 48 |
|
|
||||||
aa << 41 >> 16);
|
|
||||||
return x.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
long double __extenddftf2(double f)
|
|
||||||
{
|
|
||||||
u128_t x;
|
|
||||||
u64_t u;
|
|
||||||
uint64_t a;
|
|
||||||
|
|
||||||
u.f = f, a = u.x;
|
|
||||||
|
|
||||||
x.x0 = a << 60;
|
|
||||||
if (!(a << 1))
|
|
||||||
x.x1 = a;
|
|
||||||
else if (a << 1 >> 53 == 2047)
|
|
||||||
x.x1 = (0x7fff000000000000 | a >> 63 << 63 | a << 12 >> 16 |
|
|
||||||
(uint64_t)!!(a << 12) << 47);
|
|
||||||
else if (a << 1 >> 53 == 0) {
|
|
||||||
uint64_t adj = 0;
|
|
||||||
while (!(a << 1 >> 1 >> (52 - adj)))
|
|
||||||
adj++;
|
|
||||||
x.x0 <<= adj;
|
|
||||||
x.x1 = a >> 63 << 63 | (15360 - adj + 1) << 48 | a << adj << 12 >> 16;
|
|
||||||
} else
|
|
||||||
x.x1 = a >> 63 << 63 | ((a >> 52 & 2047) + 15360) << 48 | a << 12 >> 16;
|
|
||||||
return x.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
float __trunctfsf2(long double f)
|
|
||||||
{
|
|
||||||
u128_t mnt;
|
|
||||||
int32_t exp;
|
|
||||||
int sgn;
|
|
||||||
u32_t x;
|
|
||||||
#define x x.x
|
|
||||||
|
|
||||||
f3_unpack(&sgn, &exp, &mnt, f);
|
|
||||||
if (exp == 32767 && (mnt.x0 | mnt.x1 << 16))
|
|
||||||
x = 0x7fc00000 | (uint32_t)sgn << 31 | (mnt.x1 >> 25 & 0x007fffff);
|
|
||||||
else if (exp > 16510)
|
|
||||||
x = 0x7f800000 | (uint32_t)sgn << 31;
|
|
||||||
else if (exp < 16233)
|
|
||||||
x = (uint32_t)sgn << 31;
|
|
||||||
else {
|
|
||||||
exp -= 16257;
|
|
||||||
x = mnt.x1 >> 23 | !!(mnt.x0 | mnt.x1 << 41);
|
|
||||||
if (exp < 0) {
|
|
||||||
x = x >> -exp | !!(x << (32 + exp));
|
|
||||||
exp = 0;
|
|
||||||
}
|
|
||||||
if ((x & 3) == 3 || (x & 7) == 6)
|
|
||||||
x += 4;
|
|
||||||
x = ((x >> 2) + (exp << 23)) | (uint32_t)sgn << 31;
|
|
||||||
}
|
|
||||||
#undef x
|
|
||||||
return x.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
double __trunctfdf2(long double f)
|
|
||||||
{
|
|
||||||
u128_t mnt;
|
|
||||||
int32_t exp;
|
|
||||||
int sgn;
|
|
||||||
u64_t x;
|
|
||||||
#define x x.x
|
|
||||||
|
|
||||||
f3_unpack(&sgn, &exp, &mnt, f);
|
|
||||||
if (exp == 32767 && (mnt.x0 | mnt.x1 << 16))
|
|
||||||
x = (0x7ff8000000000000 | (uint64_t)sgn << 63 |
|
|
||||||
mnt.x1 << 16 >> 12 | mnt.x0 >> 60);
|
|
||||||
else if (exp > 17406)
|
|
||||||
x = 0x7ff0000000000000 | (uint64_t)sgn << 63;
|
|
||||||
else if (exp < 15308)
|
|
||||||
x = (uint64_t)sgn << 63;
|
|
||||||
else {
|
|
||||||
exp -= 15361;
|
|
||||||
x = mnt.x1 << 6 | mnt.x0 >> 58 | !!(mnt.x0 << 6);
|
|
||||||
if (exp < 0) {
|
|
||||||
x = x >> -exp | !!(x << (64 + exp));
|
|
||||||
exp = 0;
|
|
||||||
}
|
|
||||||
if ((x & 3) == 3 || (x & 7) == 6)
|
|
||||||
x += 4;
|
|
||||||
x = ((x >> 2) + ((uint64_t)exp << 52)) | (uint64_t)sgn << 63;
|
|
||||||
}
|
|
||||||
#undef x
|
|
||||||
return x.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t __fixtfsi(long double fa)
|
|
||||||
{
|
|
||||||
u128_t a;
|
|
||||||
int32_t a_exp;
|
|
||||||
int a_sgn;
|
|
||||||
int32_t x;
|
|
||||||
f3_unpack(&a_sgn, &a_exp, &a, fa);
|
|
||||||
if (a_exp < 16369)
|
|
||||||
return 0;
|
|
||||||
if (a_exp > 16413)
|
|
||||||
return a_sgn ? -0x80000000 : 0x7fffffff;
|
|
||||||
x = a.x1 >> (16431 - a_exp);
|
|
||||||
return a_sgn ? -x : x;
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t __fixtfdi(long double fa)
|
|
||||||
{
|
|
||||||
u128_t a;
|
|
||||||
int32_t a_exp;
|
|
||||||
int a_sgn;
|
|
||||||
int64_t x;
|
|
||||||
f3_unpack(&a_sgn, &a_exp, &a, fa);
|
|
||||||
if (a_exp < 16383)
|
|
||||||
return 0;
|
|
||||||
if (a_exp > 16445)
|
|
||||||
return a_sgn ? -0x8000000000000000 : 0x7fffffffffffffff;
|
|
||||||
x = (a.x1 << 15 | a.x0 >> 49) >> (16446 - a_exp);
|
|
||||||
return a_sgn ? -x : x;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t __fixunstfsi(long double fa)
|
|
||||||
{
|
|
||||||
u128_t a;
|
|
||||||
int32_t a_exp;
|
|
||||||
int a_sgn;
|
|
||||||
f3_unpack(&a_sgn, &a_exp, &a, fa);
|
|
||||||
if (a_sgn || a_exp < 16369)
|
|
||||||
return 0;
|
|
||||||
if (a_exp > 16414)
|
|
||||||
return -1;
|
|
||||||
return a.x1 >> (16431 - a_exp);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t __fixunstfdi(long double fa)
|
|
||||||
{
|
|
||||||
u128_t a;
|
|
||||||
int32_t a_exp;
|
|
||||||
int a_sgn;
|
|
||||||
f3_unpack(&a_sgn, &a_exp, &a, fa);
|
|
||||||
if (a_sgn || a_exp < 16383)
|
|
||||||
return 0;
|
|
||||||
if (a_exp > 16446)
|
|
||||||
return -1;
|
|
||||||
return (a.x1 << 15 | a.x0 >> 49) >> (16446 - a_exp);
|
|
||||||
}
|
|
||||||
|
|
||||||
long double __floatsitf(int32_t a)
|
|
||||||
{
|
|
||||||
int sgn = 0;
|
|
||||||
int exp = 16414;
|
|
||||||
uint32_t mnt = a;
|
|
||||||
u128_t x = { 0, 0 };
|
|
||||||
int i;
|
|
||||||
if (a) {
|
|
||||||
if (a < 0) {
|
|
||||||
sgn = 1;
|
|
||||||
mnt = -mnt;
|
|
||||||
}
|
|
||||||
for (i = 16; i; i >>= 1)
|
|
||||||
if (!(mnt >> (32 - i))) {
|
|
||||||
mnt <<= i;
|
|
||||||
exp -= i;
|
|
||||||
}
|
|
||||||
x.x1 = ((uint64_t)sgn << 63 | (uint64_t)exp << 48 |
|
|
||||||
(uint64_t)(mnt << 1) << 16);
|
|
||||||
}
|
|
||||||
return x.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
long double __floatditf(int64_t a)
|
|
||||||
{
|
|
||||||
int sgn = 0;
|
|
||||||
int exp = 16446;
|
|
||||||
uint64_t mnt = a;
|
|
||||||
u128_t x = { 0, 0 };
|
|
||||||
int i;
|
|
||||||
if (a) {
|
|
||||||
if (a < 0) {
|
|
||||||
sgn = 1;
|
|
||||||
mnt = -mnt;
|
|
||||||
}
|
|
||||||
for (i = 32; i; i >>= 1)
|
|
||||||
if (!(mnt >> (64 - i))) {
|
|
||||||
mnt <<= i;
|
|
||||||
exp -= i;
|
|
||||||
}
|
|
||||||
x.x0 = mnt << 49;
|
|
||||||
x.x1 = (uint64_t)sgn << 63 | (uint64_t)exp << 48 | mnt << 1 >> 16;
|
|
||||||
}
|
|
||||||
return x.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
long double __floatunsitf(uint32_t a)
|
|
||||||
{
|
|
||||||
int exp = 16414;
|
|
||||||
uint32_t mnt = a;
|
|
||||||
u128_t x = { 0, 0 };
|
|
||||||
int i;
|
|
||||||
if (a) {
|
|
||||||
for (i = 16; i; i >>= 1)
|
|
||||||
if (!(mnt >> (32 - i))) {
|
|
||||||
mnt <<= i;
|
|
||||||
exp -= i;
|
|
||||||
}
|
|
||||||
x.x1 = (uint64_t)exp << 48 | (uint64_t)(mnt << 1) << 16;
|
|
||||||
}
|
|
||||||
return x.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
long double __floatunditf(uint64_t a)
|
|
||||||
{
|
|
||||||
int exp = 16446;
|
|
||||||
uint64_t mnt = a;
|
|
||||||
u128_t x = { 0, 0 };
|
|
||||||
long double f;
|
|
||||||
int i;
|
|
||||||
if (a) {
|
|
||||||
for (i = 32; i; i >>= 1)
|
|
||||||
if (!(mnt >> (64 - i))) {
|
|
||||||
mnt <<= i;
|
|
||||||
exp -= i;
|
|
||||||
}
|
|
||||||
x.x0 = mnt << 49;
|
|
||||||
x.x1 = (uint64_t)exp << 48 | mnt << 1 >> 16;
|
|
||||||
}
|
|
||||||
return x.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int f3_cmp(long double fa, long double fb)
|
|
||||||
{
|
|
||||||
u128_t a, b;
|
|
||||||
a.f = fa;
|
|
||||||
b.f = fb;
|
|
||||||
return (!(a.x0 | a.x1 << 1 | b.x0 | b.x1 << 1) ? 0 :
|
|
||||||
((a.x1 << 1 >> 49 == 0x7fff && (a.x0 | a.x1 << 16)) ||
|
|
||||||
(b.x1 << 1 >> 49 == 0x7fff && (b.x0 | b.x1 << 16))) ? 2 :
|
|
||||||
a.x1 >> 63 != b.x1 >> 63 ? (int)(b.x1 >> 63) - (int)(a.x1 >> 63) :
|
|
||||||
a.x1 < b.x1 ? (int)(a.x1 >> 63 << 1) - 1 :
|
|
||||||
a.x1 > b.x1 ? 1 - (int)(a.x1 >> 63 << 1) :
|
|
||||||
a.x0 < b.x0 ? (int)(a.x1 >> 63 << 1) - 1 :
|
|
||||||
b.x0 < a.x0 ? 1 - (int)(a.x1 >> 63 << 1) : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int __eqtf2(long double a, long double b)
|
|
||||||
{
|
|
||||||
return !!f3_cmp(a, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
int __netf2(long double a, long double b)
|
|
||||||
{
|
|
||||||
return !!f3_cmp(a, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
int __lttf2(long double a, long double b)
|
|
||||||
{
|
|
||||||
return f3_cmp(a, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
int __letf2(long double a, long double b)
|
|
||||||
{
|
|
||||||
return f3_cmp(a, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
int __gttf2(long double a, long double b)
|
|
||||||
{
|
|
||||||
return -f3_cmp(b, a);
|
|
||||||
}
|
|
||||||
|
|
||||||
int __getf2(long double a, long double b)
|
|
||||||
{
|
|
||||||
return -f3_cmp(b, a);
|
|
||||||
}
|
|
||||||
@ -1,20 +0,0 @@
|
|||||||
/*
|
|
||||||
* TCC runtime library for riscv64.
|
|
||||||
*
|
|
||||||
* Copyright (c) 2026
|
|
||||||
*
|
|
||||||
* Copying and distribution of this file, with or without modification,
|
|
||||||
* are permitted in any medium without royalty provided the copyright
|
|
||||||
* notice and this notice are preserved. This file is offered as-is,
|
|
||||||
* without any warranty.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------- */
|
|
||||||
/* __clear_cache is used in tccrun.c. It is a built-in
|
|
||||||
intrinsic with gcc. However tcc in order to compile
|
|
||||||
itself needs this function */
|
|
||||||
|
|
||||||
void __clear_cache(void *beg, void *end)
|
|
||||||
{
|
|
||||||
__riscv64_clear_cache(beg, end);
|
|
||||||
}
|
|
||||||
39
lib/pic86.S
39
lib/pic86.S
@ -1,39 +0,0 @@
|
|||||||
/* ---------------------------------------------- */
|
|
||||||
/* get_pc_thunk.S */
|
|
||||||
|
|
||||||
#ifdef __leading_underscore
|
|
||||||
# define _(s) _##s
|
|
||||||
#else
|
|
||||||
# define _(s) s
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* ---------------------------------------------- */
|
|
||||||
.text
|
|
||||||
|
|
||||||
.globl _(__x86.get_pc_thunk.ax)
|
|
||||||
.hidden _(__x86.get_pc_thunk.ax)
|
|
||||||
_(__x86.get_pc_thunk.ax):
|
|
||||||
mov (%esp),%eax
|
|
||||||
ret
|
|
||||||
.size _(__x86.get_pc_thunk.ax), .-_(__x86.get_pc_thunk.ax)
|
|
||||||
|
|
||||||
.globl _(__x86.get_pc_thunk.bx)
|
|
||||||
.hidden _(__x86.get_pc_thunk.bx)
|
|
||||||
_(__x86.get_pc_thunk.bx):
|
|
||||||
mov (%esp),%ebx
|
|
||||||
ret
|
|
||||||
.size _(__x86.get_pc_thunk.bx), .-_(__x86.get_pc_thunk.bx)
|
|
||||||
|
|
||||||
.globl _(__x86.get_pc_thunk.cx)
|
|
||||||
.hidden _(__x86.get_pc_thunk.cx)
|
|
||||||
_(__x86.get_pc_thunk.cx):
|
|
||||||
mov (%esp),%ecx
|
|
||||||
ret
|
|
||||||
.size _(__x86.get_pc_thunk.cx), .-_(__x86.get_pc_thunk.cx)
|
|
||||||
|
|
||||||
.globl _(__x86.get_pc_thunk.dx)
|
|
||||||
.hidden _(__x86.get_pc_thunk.dx)
|
|
||||||
_(__x86.get_pc_thunk.dx):
|
|
||||||
mov (%esp),%edx
|
|
||||||
ret
|
|
||||||
.size _(__x86.get_pc_thunk.dx), .-_(__x86.get_pc_thunk.dx)
|
|
||||||
@ -1,86 +0,0 @@
|
|||||||
/* ------------------------------------------------------------- */
|
|
||||||
/* support for tcc_run() */
|
|
||||||
|
|
||||||
#ifdef __leading_underscore
|
|
||||||
# define _(s) s
|
|
||||||
#else
|
|
||||||
# define _(s) _##s
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef _WIN32
|
|
||||||
extern void (*_(_init_array_start)[]) (int argc, char **argv, char **envp);
|
|
||||||
extern void (*_(_init_array_end)[]) (int argc, char **argv, char **envp);
|
|
||||||
static void run_ctors(int argc, char **argv, char **env)
|
|
||||||
{
|
|
||||||
int i = 0;
|
|
||||||
while (&_(_init_array_start)[i] != _(_init_array_end))
|
|
||||||
(*_(_init_array_start)[i++])(argc, argv, env);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern void (*_(_fini_array_start)[]) (void);
|
|
||||||
extern void (*_(_fini_array_end)[]) (void);
|
|
||||||
static void run_dtors(void)
|
|
||||||
{
|
|
||||||
int i = 0;
|
|
||||||
while (&_(_fini_array_end)[i] != _(_fini_array_start))
|
|
||||||
(*_(_fini_array_end)[--i])();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *rt_exitfunc[32];
|
|
||||||
static void *rt_exitarg[32];
|
|
||||||
static int __rt_nr_exit;
|
|
||||||
|
|
||||||
void __run_on_exit(int ret)
|
|
||||||
{
|
|
||||||
int n = __rt_nr_exit;
|
|
||||||
while (n)
|
|
||||||
--n, ((void(*)(int,void*))rt_exitfunc[n])(ret, rt_exitarg[n]);
|
|
||||||
}
|
|
||||||
|
|
||||||
int on_exit(void *function, void *arg)
|
|
||||||
{
|
|
||||||
int n = __rt_nr_exit;
|
|
||||||
if (n < 32) {
|
|
||||||
rt_exitfunc[n] = function;
|
|
||||||
rt_exitarg[n] = arg;
|
|
||||||
__rt_nr_exit = n + 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int atexit(void (*function)(void))
|
|
||||||
{
|
|
||||||
return on_exit(function, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct rt_frame {
|
|
||||||
void *ip, *fp, *sp;
|
|
||||||
} rt_frame;
|
|
||||||
|
|
||||||
__attribute__((noreturn)) void __rt_exit(rt_frame *, int);
|
|
||||||
|
|
||||||
void exit(int code)
|
|
||||||
{
|
|
||||||
rt_frame f;
|
|
||||||
run_dtors();
|
|
||||||
__run_on_exit(code);
|
|
||||||
f.fp = 0;
|
|
||||||
f.ip = exit;
|
|
||||||
__rt_exit(&f, code);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef _WIN32
|
|
||||||
int main(int, char**, char**);
|
|
||||||
|
|
||||||
int _runmain(int argc, char **argv, char **envp)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
run_ctors(argc, argv, envp);
|
|
||||||
ret = main(argc, argv, envp);
|
|
||||||
run_dtors();
|
|
||||||
__run_on_exit(ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
104
lib/stdatomic.c
104
lib/stdatomic.c
@ -1,104 +0,0 @@
|
|||||||
// for libtcc1, avoid including files that are not part of tcc
|
|
||||||
// #include <stdint.h>
|
|
||||||
#define uint8_t unsigned char
|
|
||||||
#define uint16_t unsigned short
|
|
||||||
#define uint32_t unsigned int
|
|
||||||
#define uint64_t unsigned long long
|
|
||||||
#define bool _Bool
|
|
||||||
#define false 0
|
|
||||||
#define true 1
|
|
||||||
#define __ATOMIC_RELAXED 0
|
|
||||||
#define __ATOMIC_CONSUME 1
|
|
||||||
#define __ATOMIC_ACQUIRE 2
|
|
||||||
#define __ATOMIC_RELEASE 3
|
|
||||||
#define __ATOMIC_ACQ_REL 4
|
|
||||||
#define __ATOMIC_SEQ_CST 5
|
|
||||||
typedef __SIZE_TYPE__ size_t;
|
|
||||||
|
|
||||||
#define ATOMIC_GEN_OP(TYPE, MODE, NAME, OP, RET) \
|
|
||||||
TYPE __atomic_##NAME##_##MODE(volatile void *atom, TYPE value, int memorder) \
|
|
||||||
{ \
|
|
||||||
TYPE xchg, cmp; \
|
|
||||||
__atomic_load((TYPE *)atom, (TYPE *)&cmp, __ATOMIC_RELAXED); \
|
|
||||||
do { \
|
|
||||||
xchg = (OP); \
|
|
||||||
} while (!__atomic_compare_exchange((TYPE *)atom, &cmp, &xchg, true, \
|
|
||||||
__ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)); \
|
|
||||||
return RET; \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define ATOMIC_EXCHANGE(TYPE, MODE) \
|
|
||||||
ATOMIC_GEN_OP(TYPE, MODE, exchange, value, cmp)
|
|
||||||
#define ATOMIC_ADD_FETCH(TYPE, MODE) \
|
|
||||||
ATOMIC_GEN_OP(TYPE, MODE, add_fetch, (cmp + value), xchg)
|
|
||||||
#define ATOMIC_SUB_FETCH(TYPE, MODE) \
|
|
||||||
ATOMIC_GEN_OP(TYPE, MODE, sub_fetch, (cmp - value), xchg)
|
|
||||||
#define ATOMIC_AND_FETCH(TYPE, MODE) \
|
|
||||||
ATOMIC_GEN_OP(TYPE, MODE, and_fetch, (cmp & value), xchg)
|
|
||||||
#define ATOMIC_OR_FETCH(TYPE, MODE) \
|
|
||||||
ATOMIC_GEN_OP(TYPE, MODE, or_fetch, (cmp | value), xchg)
|
|
||||||
#define ATOMIC_XOR_FETCH(TYPE, MODE) \
|
|
||||||
ATOMIC_GEN_OP(TYPE, MODE, xor_fetch, (cmp ^ value), xchg)
|
|
||||||
#define ATOMIC_NAND_FETCH(TYPE, MODE) \
|
|
||||||
ATOMIC_GEN_OP(TYPE, MODE, nand_fetch, ~(cmp & value), xchg)
|
|
||||||
#define ATOMIC_FETCH_ADD(TYPE, MODE) \
|
|
||||||
ATOMIC_GEN_OP(TYPE, MODE, fetch_add, (cmp + value), cmp)
|
|
||||||
#define ATOMIC_FETCH_SUB(TYPE, MODE) \
|
|
||||||
ATOMIC_GEN_OP(TYPE, MODE, fetch_sub, (cmp - value), cmp)
|
|
||||||
#define ATOMIC_FETCH_AND(TYPE, MODE) \
|
|
||||||
ATOMIC_GEN_OP(TYPE, MODE, fetch_and, (cmp & value), cmp)
|
|
||||||
#define ATOMIC_FETCH_OR(TYPE, MODE) \
|
|
||||||
ATOMIC_GEN_OP(TYPE, MODE, fetch_or, (cmp | value), cmp)
|
|
||||||
#define ATOMIC_FETCH_XOR(TYPE, MODE) \
|
|
||||||
ATOMIC_GEN_OP(TYPE, MODE, fetch_xor, (cmp ^ value), cmp)
|
|
||||||
#define ATOMIC_FETCH_NAND(TYPE, MODE) \
|
|
||||||
ATOMIC_GEN_OP(TYPE, MODE, fetch_nand, ~(cmp & value), cmp)
|
|
||||||
|
|
||||||
#define ATOMIC_GEN(TYPE, SIZE) \
|
|
||||||
ATOMIC_EXCHANGE(TYPE, SIZE) \
|
|
||||||
ATOMIC_ADD_FETCH(TYPE, SIZE) \
|
|
||||||
ATOMIC_SUB_FETCH(TYPE, SIZE) \
|
|
||||||
ATOMIC_AND_FETCH(TYPE, SIZE) \
|
|
||||||
ATOMIC_OR_FETCH(TYPE, SIZE) \
|
|
||||||
ATOMIC_XOR_FETCH(TYPE, SIZE) \
|
|
||||||
ATOMIC_NAND_FETCH(TYPE, SIZE) \
|
|
||||||
ATOMIC_FETCH_ADD(TYPE, SIZE) \
|
|
||||||
ATOMIC_FETCH_SUB(TYPE, SIZE) \
|
|
||||||
ATOMIC_FETCH_AND(TYPE, SIZE) \
|
|
||||||
ATOMIC_FETCH_OR(TYPE, SIZE) \
|
|
||||||
ATOMIC_FETCH_XOR(TYPE, SIZE) \
|
|
||||||
ATOMIC_FETCH_NAND(TYPE, SIZE)
|
|
||||||
|
|
||||||
ATOMIC_GEN(uint8_t, 1)
|
|
||||||
ATOMIC_GEN(uint16_t, 2)
|
|
||||||
ATOMIC_GEN(uint32_t, 4)
|
|
||||||
ATOMIC_GEN(uint64_t, 8)
|
|
||||||
|
|
||||||
/* uses alias to allow building with gcc/clang */
|
|
||||||
#ifdef __TINYC__
|
|
||||||
#define ATOMIC(x) __atomic_##x
|
|
||||||
#else
|
|
||||||
#define ATOMIC(x) __tcc_atomic_##x
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bool ATOMIC(is_lock_free) (unsigned long size, const volatile void *ptr)
|
|
||||||
{
|
|
||||||
bool ret;
|
|
||||||
|
|
||||||
switch (size) {
|
|
||||||
case 1: ret = true; break;
|
|
||||||
case 2: ret = true; break;
|
|
||||||
case 4: ret = true; break;
|
|
||||||
#if defined __x86_64__ || defined __aarch64__ || defined __riscv
|
|
||||||
case 8: ret = true; break;
|
|
||||||
#else
|
|
||||||
case 8: ret = false; break;
|
|
||||||
#endif
|
|
||||||
default: ret = false; break;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef __TINYC__
|
|
||||||
bool __atomic_is_lock_free(unsigned long size, const volatile void *ptr) __attribute__((alias("__tcc_atomic_is_lock_free")));
|
|
||||||
#endif
|
|
||||||
428
lib/tcov.c
428
lib/tcov.c
@ -1,428 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#ifndef _WIN32
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#else
|
|
||||||
#include <windows.h>
|
|
||||||
#include <io.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* section layout (all little endian):
|
|
||||||
32bit offset to executable/so file name
|
|
||||||
filename \0
|
|
||||||
function name \0
|
|
||||||
align to 64 bits
|
|
||||||
64bit function start line
|
|
||||||
64bits end_line(28bits) / start_line(28bits) / flag=0xff(8bits)
|
|
||||||
64bits counter
|
|
||||||
\0
|
|
||||||
\0
|
|
||||||
\0
|
|
||||||
executable/so file name \0
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef struct tcov_line {
|
|
||||||
unsigned int fline;
|
|
||||||
unsigned int lline;
|
|
||||||
unsigned long long count;
|
|
||||||
} tcov_line;
|
|
||||||
|
|
||||||
typedef struct tcov_function {
|
|
||||||
char *function;
|
|
||||||
unsigned int first_line;
|
|
||||||
unsigned int n_line;
|
|
||||||
unsigned int m_line;
|
|
||||||
tcov_line *line;
|
|
||||||
} tcov_function;
|
|
||||||
|
|
||||||
typedef struct tcov_file {
|
|
||||||
char *filename;
|
|
||||||
unsigned int n_func;
|
|
||||||
unsigned int m_func;
|
|
||||||
tcov_function *func;
|
|
||||||
struct tcov_file *next;
|
|
||||||
} tcov_file;
|
|
||||||
|
|
||||||
static FILE *open_tcov_file (char *cov_filename)
|
|
||||||
{
|
|
||||||
int fd;
|
|
||||||
#ifndef _WIN32
|
|
||||||
struct flock lock;
|
|
||||||
|
|
||||||
lock.l_type = F_WRLCK;
|
|
||||||
lock.l_whence = SEEK_SET;
|
|
||||||
lock.l_start = 0;
|
|
||||||
lock.l_len = 0; /* Until EOF. */
|
|
||||||
lock.l_pid = getpid ();
|
|
||||||
#endif
|
|
||||||
fd = open (cov_filename, O_RDWR | O_CREAT, 0666);
|
|
||||||
if (fd < 0)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
#ifndef _WIN32
|
|
||||||
while (fcntl (fd, F_SETLKW, &lock) && errno == EINTR)
|
|
||||||
continue;
|
|
||||||
#else
|
|
||||||
{
|
|
||||||
OVERLAPPED overlapped = { 0 };
|
|
||||||
LockFileEx((HANDLE)_get_osfhandle(fd), LOCKFILE_EXCLUSIVE_LOCK,
|
|
||||||
0, 1, 0, &overlapped);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return fdopen (fd, "r+");
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned long long get_value(unsigned char *p, int size)
|
|
||||||
{
|
|
||||||
unsigned long long value = 0;
|
|
||||||
|
|
||||||
p += size;
|
|
||||||
while (size--)
|
|
||||||
value = (value << 8) | *--p;
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sort_func (const void *p, const void *q)
|
|
||||||
{
|
|
||||||
const tcov_function *pp = (const tcov_function *) p;
|
|
||||||
const tcov_function *pq = (const tcov_function *) q;
|
|
||||||
|
|
||||||
return pp->first_line > pq->first_line ? 1 :
|
|
||||||
pp->first_line < pq->first_line ? -1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sort_line (const void *p, const void *q)
|
|
||||||
{
|
|
||||||
const tcov_line *pp = (const tcov_line *) p;
|
|
||||||
const tcov_line *pq = (const tcov_line *) q;
|
|
||||||
|
|
||||||
return pp->fline > pq->fline ? 1 :
|
|
||||||
pp->fline < pq->fline ? -1 :
|
|
||||||
pp->count < pq->count ? 1 :
|
|
||||||
pp->count > pq->count ? -1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* sort to let inline functions work */
|
|
||||||
static tcov_file *sort_test_coverage (unsigned char *p)
|
|
||||||
{
|
|
||||||
int i, j, k;
|
|
||||||
unsigned char *start = p;
|
|
||||||
tcov_file *file = NULL;
|
|
||||||
tcov_file *nfile;
|
|
||||||
|
|
||||||
p += 4;
|
|
||||||
while (*p) {
|
|
||||||
char *filename = (char *)p;
|
|
||||||
size_t len = strlen (filename);
|
|
||||||
|
|
||||||
nfile = file;
|
|
||||||
while (nfile) {
|
|
||||||
if (strcmp (nfile->filename, filename) == 0)
|
|
||||||
break;
|
|
||||||
nfile = nfile->next;
|
|
||||||
}
|
|
||||||
if (nfile == NULL) {
|
|
||||||
nfile = malloc (sizeof(tcov_file));
|
|
||||||
if (nfile == NULL) {
|
|
||||||
fprintf (stderr, "Malloc error test_coverage\n");
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
nfile->filename = filename;
|
|
||||||
nfile->n_func = 0;
|
|
||||||
nfile->m_func = 0;
|
|
||||||
nfile->func = NULL;
|
|
||||||
nfile->next = NULL;
|
|
||||||
if (file == NULL)
|
|
||||||
file = nfile;
|
|
||||||
else {
|
|
||||||
tcov_file *lfile = file;
|
|
||||||
|
|
||||||
while (lfile->next)
|
|
||||||
lfile = lfile->next;
|
|
||||||
lfile->next = nfile;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
p += len + 1;
|
|
||||||
while (*p) {
|
|
||||||
int i;
|
|
||||||
char *function = (char *)p;
|
|
||||||
tcov_function *func;
|
|
||||||
|
|
||||||
p += strlen (function) + 1;
|
|
||||||
p += -(p - start) & 7;
|
|
||||||
for (i = 0; i < nfile->n_func; i++) {
|
|
||||||
func = &nfile->func[i];
|
|
||||||
if (strcmp (func->function, function) == 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (i == nfile->n_func) {
|
|
||||||
if (nfile->n_func >= nfile->m_func) {
|
|
||||||
nfile->m_func = nfile->m_func == 0 ? 4 : nfile->m_func * 2;
|
|
||||||
nfile->func = realloc (nfile->func,
|
|
||||||
nfile->m_func *
|
|
||||||
sizeof (tcov_function));
|
|
||||||
if (nfile->func == NULL) {
|
|
||||||
fprintf (stderr, "Realloc error test_coverage\n");
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func = &nfile->func[nfile->n_func++];
|
|
||||||
func->function = function;
|
|
||||||
func->first_line = get_value (p, 8);
|
|
||||||
func->n_line = 0;
|
|
||||||
func->m_line = 0;
|
|
||||||
func->line = NULL;
|
|
||||||
}
|
|
||||||
p += 8;
|
|
||||||
while (*p) {
|
|
||||||
tcov_line *line;
|
|
||||||
unsigned long long val;
|
|
||||||
|
|
||||||
if (func->n_line >= func->m_line) {
|
|
||||||
func->m_line = func->m_line == 0 ? 4 : func->m_line * 2;
|
|
||||||
func->line = realloc (func->line,
|
|
||||||
func->m_line * sizeof (tcov_line));
|
|
||||||
if (func->line == NULL) {
|
|
||||||
fprintf (stderr, "Realloc error test_coverage\n");
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
line = &func->line[func->n_line++];
|
|
||||||
val = get_value (p, 8);
|
|
||||||
line->fline = (val >> 8) & 0xfffffffULL;
|
|
||||||
line->lline = val >> 36;
|
|
||||||
line->count = get_value (p + 8, 8);
|
|
||||||
p += 16;
|
|
||||||
}
|
|
||||||
p++;
|
|
||||||
}
|
|
||||||
p++;
|
|
||||||
}
|
|
||||||
nfile = file;
|
|
||||||
while (nfile) {
|
|
||||||
qsort (nfile->func, nfile->n_func, sizeof (tcov_function), sort_func);
|
|
||||||
for (i = 0; i < nfile->n_func; i++) {
|
|
||||||
tcov_function *func = &nfile->func[i];
|
|
||||||
qsort (func->line, func->n_line, sizeof (tcov_line), sort_line);
|
|
||||||
}
|
|
||||||
nfile = nfile->next;
|
|
||||||
}
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* merge with previous tcov file */
|
|
||||||
static void merge_test_coverage (tcov_file *file, FILE *fp,
|
|
||||||
unsigned int *pruns)
|
|
||||||
{
|
|
||||||
unsigned int runs;
|
|
||||||
char *p;
|
|
||||||
char str[10000];
|
|
||||||
|
|
||||||
*pruns = 1;
|
|
||||||
if (fp == NULL)
|
|
||||||
return;
|
|
||||||
if (fgets(str, sizeof(str), fp) &&
|
|
||||||
(p = strrchr (str, ':')) &&
|
|
||||||
(sscanf (p + 1, "%u", &runs) == 1))
|
|
||||||
*pruns = runs + 1;
|
|
||||||
while (file) {
|
|
||||||
int i;
|
|
||||||
size_t len = strlen (file->filename);
|
|
||||||
|
|
||||||
while (fgets(str, sizeof(str), fp) &&
|
|
||||||
(p = strstr(str, "0:File:")) == NULL) {}
|
|
||||||
if ((p = strstr(str, "0:File:")) == NULL ||
|
|
||||||
strncmp (p + strlen("0:File:"), file->filename, len) != 0 ||
|
|
||||||
p[strlen("0:File:") + len] != ' ')
|
|
||||||
break;
|
|
||||||
for (i = 0; i < file->n_func; i++) {
|
|
||||||
int j;
|
|
||||||
tcov_function *func = &file->func[i];
|
|
||||||
unsigned int next_zero = 0;
|
|
||||||
unsigned int curline = 0;
|
|
||||||
|
|
||||||
for (j = 0; j < func->n_line; j++) {
|
|
||||||
tcov_line *line = &func->line[j];
|
|
||||||
unsigned int fline = line->fline;
|
|
||||||
unsigned long long count;
|
|
||||||
unsigned int tmp;
|
|
||||||
char c;
|
|
||||||
|
|
||||||
while (curline < fline &&
|
|
||||||
fgets(str, sizeof(str), fp))
|
|
||||||
if ((p = strchr(str, ':')) &&
|
|
||||||
sscanf (p + 1, "%u", &tmp) == 1)
|
|
||||||
curline = tmp;
|
|
||||||
if (sscanf (str, "%llu%c\n", &count, &c) == 2) {
|
|
||||||
if (next_zero == 0)
|
|
||||||
line->count += count;
|
|
||||||
next_zero = c == '*';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file = file->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* store tcov data in file */
|
|
||||||
void __store_test_coverage (unsigned char * p)
|
|
||||||
{
|
|
||||||
int i, j;
|
|
||||||
unsigned int files;
|
|
||||||
unsigned int funcs;
|
|
||||||
unsigned int blocks;
|
|
||||||
unsigned int blocks_run;
|
|
||||||
unsigned int runs;
|
|
||||||
char *cov_filename = (char *)p + get_value (p, 4);
|
|
||||||
FILE *fp;
|
|
||||||
char *q;
|
|
||||||
tcov_file *file;
|
|
||||||
tcov_file *nfile;
|
|
||||||
tcov_function *func;
|
|
||||||
|
|
||||||
fp = open_tcov_file (cov_filename);
|
|
||||||
if (fp == NULL) {
|
|
||||||
fprintf (stderr, "Cannot create coverage file: %s\n", cov_filename);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
file = sort_test_coverage (p);
|
|
||||||
merge_test_coverage (file, fp, &runs);
|
|
||||||
fseek (fp, 0, SEEK_SET);
|
|
||||||
fprintf (fp, " -: 0:Runs:%u\n", runs);
|
|
||||||
files = 0;
|
|
||||||
funcs = 0;
|
|
||||||
blocks = 0;
|
|
||||||
blocks_run = 0;
|
|
||||||
nfile = file;
|
|
||||||
while (nfile) {
|
|
||||||
files++;
|
|
||||||
for (i = 0; i < nfile->n_func; i++) {
|
|
||||||
func = &nfile->func[i];
|
|
||||||
funcs++;
|
|
||||||
for (j = 0; j < func->n_line; j++) {
|
|
||||||
blocks++;
|
|
||||||
blocks_run += func->line[j].count != 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
nfile = nfile->next;
|
|
||||||
}
|
|
||||||
if (blocks == 0)
|
|
||||||
blocks = 1;
|
|
||||||
fprintf (fp, " -: 0:All:%s Files:%u Functions:%u %.02f%%\n",
|
|
||||||
cov_filename, files, funcs, 100.0 * (double) blocks_run / blocks);
|
|
||||||
nfile = file;
|
|
||||||
while (nfile) {
|
|
||||||
FILE *src = fopen (nfile->filename, "r");
|
|
||||||
unsigned int curline = 1;
|
|
||||||
char str[10000];
|
|
||||||
|
|
||||||
if (src == NULL)
|
|
||||||
goto next;
|
|
||||||
funcs = 0;
|
|
||||||
blocks = 0;
|
|
||||||
blocks_run = 0;
|
|
||||||
for (i = 0; i < nfile->n_func; i++) {
|
|
||||||
func = &nfile->func[i];
|
|
||||||
funcs++;
|
|
||||||
for (j = 0; j < func->n_line; j++) {
|
|
||||||
blocks++;
|
|
||||||
blocks_run += func->line[j].count != 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (blocks == 0)
|
|
||||||
blocks = 1;
|
|
||||||
fprintf (fp, " -: 0:File:%s Functions:%u %.02f%%\n",
|
|
||||||
nfile->filename, funcs, 100.0 * (double) blocks_run / blocks);
|
|
||||||
for (i = 0; i < nfile->n_func; i++) {
|
|
||||||
func = &nfile->func[i];
|
|
||||||
|
|
||||||
while (curline < func->first_line &&
|
|
||||||
fgets(str, sizeof(str), src))
|
|
||||||
fprintf (fp, " -:%5u:%s", curline++, str);
|
|
||||||
blocks = 0;
|
|
||||||
blocks_run = 0;
|
|
||||||
for (j = 0; j < func->n_line; j++) {
|
|
||||||
blocks++;
|
|
||||||
blocks_run += func->line[j].count != 0;
|
|
||||||
}
|
|
||||||
if (blocks == 0)
|
|
||||||
blocks = 1;
|
|
||||||
fprintf (fp, " -: 0:Function:%s %.02f%%\n",
|
|
||||||
func->function, 100.0 * (double) blocks_run / blocks);
|
|
||||||
#if 0
|
|
||||||
for (j = 0; j < func->n_line; j++) {
|
|
||||||
unsigned int fline = func->line[j].fline;
|
|
||||||
unsigned int lline = func->line[j].lline;
|
|
||||||
unsigned long long count = func->line[j].count;
|
|
||||||
|
|
||||||
fprintf (fp, "%u %u %llu\n", fline, lline, count);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
for (j = 0; j < func->n_line;) {
|
|
||||||
unsigned int fline = func->line[j].fline;
|
|
||||||
unsigned int lline = func->line[j].lline;
|
|
||||||
unsigned long long count = func->line[j].count;
|
|
||||||
unsigned int has_zero = 0;
|
|
||||||
unsigned int same_line = fline == lline;
|
|
||||||
|
|
||||||
j++;
|
|
||||||
while (j < func->n_line) {
|
|
||||||
unsigned int nfline = func->line[j].fline;
|
|
||||||
unsigned int nlline = func->line[j].lline;
|
|
||||||
unsigned long long ncount = func->line[j].count;
|
|
||||||
|
|
||||||
if (fline == nfline) {
|
|
||||||
if (ncount == 0)
|
|
||||||
has_zero = 1;
|
|
||||||
else if (ncount > count)
|
|
||||||
count = ncount;
|
|
||||||
same_line = nfline == nlline;
|
|
||||||
lline = nlline;
|
|
||||||
j++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (same_line)
|
|
||||||
lline++;
|
|
||||||
|
|
||||||
while (curline < fline &&
|
|
||||||
fgets(str, sizeof(str), src))
|
|
||||||
fprintf (fp, " -:%5u:%s", curline++, str);
|
|
||||||
while (curline < lline &&
|
|
||||||
fgets(str, sizeof(str), src)) {
|
|
||||||
if (count == 0)
|
|
||||||
fprintf (fp, " #####:%5u:%s",
|
|
||||||
curline, str);
|
|
||||||
else if (has_zero)
|
|
||||||
fprintf (fp, "%8llu*:%5u:%s",
|
|
||||||
count, curline, str);
|
|
||||||
else
|
|
||||||
fprintf (fp, "%9llu:%5u:%s",
|
|
||||||
count, curline, str);
|
|
||||||
curline++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while (fgets(str, sizeof(str), src))
|
|
||||||
fprintf (fp, " -:%5u:%s", curline++, str);
|
|
||||||
fclose (src);
|
|
||||||
next:
|
|
||||||
nfile = nfile->next;
|
|
||||||
}
|
|
||||||
while (file) {
|
|
||||||
for (i = 0; i < file->n_func; i++) {
|
|
||||||
func = &file->func[i];
|
|
||||||
free (func->line);
|
|
||||||
}
|
|
||||||
free (file->func);
|
|
||||||
nfile = file;
|
|
||||||
file = file->next;
|
|
||||||
free (nfile);
|
|
||||||
}
|
|
||||||
fclose (fp);
|
|
||||||
}
|
|
||||||
@ -1,67 +0,0 @@
|
|||||||
/* va_list.c - tinycc support for va_list on X86_64 */
|
|
||||||
|
|
||||||
#if defined __x86_64__
|
|
||||||
|
|
||||||
/* Avoid include files, they may not be available when cross compiling */
|
|
||||||
extern void abort(void);
|
|
||||||
|
|
||||||
/* This should be in sync with our include/stdarg.h */
|
|
||||||
enum __va_arg_type {
|
|
||||||
__va_gen_reg, __va_float_reg, __va_stack
|
|
||||||
};
|
|
||||||
|
|
||||||
/* GCC compatible definition of va_list. */
|
|
||||||
/*predefined by TCC (tcc_predefs.h):
|
|
||||||
typedef struct {
|
|
||||||
unsigned int gp_offset;
|
|
||||||
unsigned int fp_offset;
|
|
||||||
union {
|
|
||||||
unsigned int overflow_offset;
|
|
||||||
char *overflow_arg_area;
|
|
||||||
};
|
|
||||||
char *reg_save_area;
|
|
||||||
} __builtin_va_list[1];
|
|
||||||
*/
|
|
||||||
|
|
||||||
extern void *memcpy(void *dest, const void *src, unsigned long n);
|
|
||||||
|
|
||||||
void *__va_arg(__builtin_va_list ap,
|
|
||||||
int arg_type,
|
|
||||||
int size, int align)
|
|
||||||
{
|
|
||||||
size = (size + 7) & ~7;
|
|
||||||
align = (align + 7) & ~7;
|
|
||||||
switch ((enum __va_arg_type)arg_type) {
|
|
||||||
case __va_gen_reg:
|
|
||||||
if (ap->gp_offset + size <= 48) {
|
|
||||||
ap->gp_offset += size;
|
|
||||||
return ap->reg_save_area + ap->gp_offset - size;
|
|
||||||
}
|
|
||||||
goto use_overflow_area;
|
|
||||||
|
|
||||||
case __va_float_reg:
|
|
||||||
if (ap->fp_offset < 128 + 48) {
|
|
||||||
ap->fp_offset += 16;
|
|
||||||
if (size == 8)
|
|
||||||
return ap->reg_save_area + ap->fp_offset - 16;
|
|
||||||
if (ap->fp_offset < 128 + 48) {
|
|
||||||
memcpy(ap->reg_save_area + ap->fp_offset - 8,
|
|
||||||
ap->reg_save_area + ap->fp_offset, 8);
|
|
||||||
ap->fp_offset += 16;
|
|
||||||
return ap->reg_save_area + ap->fp_offset - 32;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
goto use_overflow_area;
|
|
||||||
|
|
||||||
case __va_stack:
|
|
||||||
use_overflow_area:
|
|
||||||
ap->overflow_arg_area += size;
|
|
||||||
ap->overflow_arg_area = (char*)((long long)(ap->overflow_arg_area + align - 1) & -align);
|
|
||||||
return ap->overflow_arg_area - size;
|
|
||||||
|
|
||||||
default: /* should never happen */
|
|
||||||
abort();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
95
libtcc.h
95
libtcc.h
@ -1,113 +1,90 @@
|
|||||||
#ifndef LIBTCC_H
|
#ifndef LIBTCC_H
|
||||||
#define LIBTCC_H
|
#define LIBTCC_H
|
||||||
|
|
||||||
#ifndef LIBTCCAPI
|
|
||||||
# define LIBTCCAPI
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*****************************/
|
struct TCCState;
|
||||||
/* set custom allocator for all allocations (optional), NULL for default. */
|
|
||||||
typedef void *TCCReallocFunc(void *ptr, unsigned long size);
|
|
||||||
LIBTCCAPI void tcc_set_realloc(TCCReallocFunc *my_realloc);
|
|
||||||
|
|
||||||
/*****************************/
|
|
||||||
typedef struct TCCState TCCState;
|
typedef struct TCCState TCCState;
|
||||||
|
|
||||||
/* create a new TCC compilation context */
|
/* create a new TCC compilation context */
|
||||||
LIBTCCAPI TCCState *tcc_new(void);
|
TCCState *tcc_new(void);
|
||||||
|
|
||||||
/* free a TCC compilation context */
|
/* free a TCC compilation context */
|
||||||
LIBTCCAPI void tcc_delete(TCCState *s);
|
void tcc_delete(TCCState *s);
|
||||||
|
|
||||||
/* set CONFIG_TCCDIR at runtime */
|
/* add debug information in the generated code */
|
||||||
LIBTCCAPI void tcc_set_lib_path(TCCState *s, const char *path);
|
void tcc_enable_debug(TCCState *s);
|
||||||
|
|
||||||
/* set error/warning callback (optional) */
|
/* set error/warning display callback */
|
||||||
typedef void TCCErrorFunc(void *opaque, const char *msg);
|
void tcc_set_error_func(TCCState *s, void *error_opaque,
|
||||||
LIBTCCAPI void tcc_set_error_func(TCCState *s, void *error_opaque, TCCErrorFunc *error_func);
|
void (*error_func)(void *opaque, const char *msg));
|
||||||
|
|
||||||
/* set options as from command line (multiple supported) */
|
/* set/reset a warning */
|
||||||
LIBTCCAPI int tcc_set_options(TCCState *s, const char *str);
|
int tcc_set_warning(TCCState *s, const char *warning_name, int value);
|
||||||
|
|
||||||
/*****************************/
|
/*****************************/
|
||||||
/* preprocessor */
|
/* preprocessor */
|
||||||
|
|
||||||
/* add include path */
|
/* add include path */
|
||||||
LIBTCCAPI int tcc_add_include_path(TCCState *s, const char *pathname);
|
int tcc_add_include_path(TCCState *s, const char *pathname);
|
||||||
|
|
||||||
/* add in system include path */
|
/* add in system include path */
|
||||||
LIBTCCAPI int tcc_add_sysinclude_path(TCCState *s, const char *pathname);
|
int tcc_add_sysinclude_path(TCCState *s, const char *pathname);
|
||||||
|
|
||||||
/* define preprocessor symbol 'sym'. value can be NULL, sym can be "sym=val" */
|
/* define preprocessor symbol 'sym'. Can put optional value */
|
||||||
LIBTCCAPI void tcc_define_symbol(TCCState *s, const char *sym, const char *value);
|
void tcc_define_symbol(TCCState *s, const char *sym, const char *value);
|
||||||
|
|
||||||
/* undefine preprocess symbol 'sym' */
|
/* undefine preprocess symbol 'sym' */
|
||||||
LIBTCCAPI void tcc_undefine_symbol(TCCState *s, const char *sym);
|
void tcc_undefine_symbol(TCCState *s, const char *sym);
|
||||||
|
|
||||||
/*****************************/
|
/*****************************/
|
||||||
/* compiling */
|
/* compiling */
|
||||||
|
|
||||||
/* add a file (C file, dll, object, library, ld script). Return -1 if error. */
|
/* add a file (either a C file, dll, an object, a library or an ld
|
||||||
LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename);
|
script). Return -1 if error. */
|
||||||
|
int tcc_add_file(TCCState *s, const char *filename);
|
||||||
|
|
||||||
/* compile a string containing a C source. Return -1 if error. */
|
/* compile a string containing a C source. Return non zero if
|
||||||
LIBTCCAPI int tcc_compile_string(TCCState *s, const char *buf);
|
error. */
|
||||||
|
int tcc_compile_string(TCCState *s, const char *buf);
|
||||||
/* Tip: to have more specific errors/warnings from tcc_compile_string(),
|
|
||||||
you can prefix the string with "#line <num> \"<filename>\"\n" */
|
|
||||||
|
|
||||||
/*****************************/
|
/*****************************/
|
||||||
/* linking commands */
|
/* linking commands */
|
||||||
|
|
||||||
/* set output type. MUST BE CALLED before any compilation */
|
/* set output type. MUST BE CALLED before any compilation */
|
||||||
LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type);
|
#define TCC_OUTPUT_MEMORY 0 /* output will be ran in memory (no
|
||||||
#define TCC_OUTPUT_MEMORY 1 /* output will be run in memory */
|
output file) (default) */
|
||||||
#define TCC_OUTPUT_EXE 2 /* executable file */
|
#define TCC_OUTPUT_EXE 1 /* executable file */
|
||||||
#define TCC_OUTPUT_DLL 4 /* dynamic library */
|
#define TCC_OUTPUT_DLL 2 /* dynamic library */
|
||||||
#define TCC_OUTPUT_OBJ 3 /* object file */
|
#define TCC_OUTPUT_OBJ 3 /* object file */
|
||||||
#define TCC_OUTPUT_PREPROCESS 5 /* only preprocess */
|
int tcc_set_output_type(TCCState *s, int output_type);
|
||||||
|
|
||||||
/* equivalent to -Lpath option */
|
/* equivalent to -Lpath option */
|
||||||
LIBTCCAPI int tcc_add_library_path(TCCState *s, const char *pathname);
|
int tcc_add_library_path(TCCState *s, const char *pathname);
|
||||||
|
|
||||||
/* the library name is the same as the argument of the '-l' option */
|
/* the library name is the same as the argument of the '-l' option */
|
||||||
LIBTCCAPI int tcc_add_library(TCCState *s, const char *libraryname);
|
int tcc_add_library(TCCState *s, const char *libraryname);
|
||||||
|
|
||||||
/* add a symbol to the compiled program */
|
/* add a symbol to the compiled program */
|
||||||
LIBTCCAPI int tcc_add_symbol(TCCState *s, const char *name, const void *val);
|
int tcc_add_symbol(TCCState *s, const char *name, unsigned long val);
|
||||||
|
|
||||||
/* output an executable, library or object file. DO NOT call
|
/* output an executable, library or object file. DO NOT call
|
||||||
tcc_relocate() before. */
|
tcc_relocate() before. */
|
||||||
LIBTCCAPI int tcc_output_file(TCCState *s, const char *filename);
|
int tcc_output_file(TCCState *s, const char *filename);
|
||||||
|
|
||||||
/* link and run main() function and return its value. DO NOT call
|
/* link and run main() function and return its value. DO NOT call
|
||||||
tcc_relocate() before. */
|
tcc_relocate() before. */
|
||||||
LIBTCCAPI int tcc_run(TCCState *s, int argc, char **argv);
|
int tcc_run(TCCState *s, int argc, char **argv);
|
||||||
|
|
||||||
/* do all relocations (needed before using tcc_get_symbol()) */
|
/* do all relocations (needed before using tcc_get_symbol()). Return
|
||||||
LIBTCCAPI int tcc_relocate(TCCState *s1);
|
non zero if link error. */
|
||||||
|
int tcc_relocate(TCCState *s);
|
||||||
|
|
||||||
/* return symbol value or NULL if not found */
|
/* return symbol value. return 0 if OK, -1 if symbol not found */
|
||||||
LIBTCCAPI void *tcc_get_symbol(TCCState *s, const char *name);
|
int tcc_get_symbol(TCCState *s, unsigned long *pval, const char *name);
|
||||||
|
|
||||||
/* list all (global) symbols and their values via 'symbol_cb()' */
|
|
||||||
LIBTCCAPI void tcc_list_symbols(TCCState *s, void *ctx,
|
|
||||||
void (*symbol_cb)(void *ctx, const char *name, const void *val));
|
|
||||||
|
|
||||||
/* experimental/advanced section (see libtcc_test_mt.c for an example) */
|
|
||||||
|
|
||||||
/* catch runtime exceptions (optionally limit backtraces at top_func),
|
|
||||||
when using tcc_set_options("-bt") and when not using tcc_run() */
|
|
||||||
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))
|
|
||||||
|
|
||||||
/* custom error printer for runtime exceptions. Returning 0 stops backtrace */
|
|
||||||
typedef int TCCBtFunc(void *udata, void *pc, const char *file, int line, const char* func, const char *msg);
|
|
||||||
LIBTCCAPI void tcc_set_backtrace_func(TCCState *s1, void* userdata, TCCBtFunc*);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@ -89,13 +89,13 @@ union double_long {
|
|||||||
double d;
|
double d;
|
||||||
#if 1
|
#if 1
|
||||||
struct {
|
struct {
|
||||||
unsigned int lower;
|
unsigned long lower;
|
||||||
int upper;
|
long upper;
|
||||||
} l;
|
} l;
|
||||||
#else
|
#else
|
||||||
struct {
|
struct {
|
||||||
int upper;
|
long upper;
|
||||||
unsigned int lower;
|
unsigned long lower;
|
||||||
} l;
|
} l;
|
||||||
#endif
|
#endif
|
||||||
long long ll;
|
long long ll;
|
||||||
@ -103,13 +103,11 @@ union double_long {
|
|||||||
|
|
||||||
union float_long {
|
union float_long {
|
||||||
float f;
|
float f;
|
||||||
unsigned int l;
|
long l;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* XXX: we don't support several builtin supports for now */
|
|
||||||
#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)), \
|
||||||
@ -138,6 +136,9 @@ 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 */
|
||||||
|
|
||||||
@ -158,7 +159,7 @@ static UDWtype __udivmoddi4 (UDWtype n, UDWtype d, UDWtype *rp)
|
|||||||
n0 = nn.s.low;
|
n0 = nn.s.low;
|
||||||
n1 = nn.s.high;
|
n1 = nn.s.high;
|
||||||
|
|
||||||
#if !defined(UDIV_NEEDS_NORMALIZATION)
|
#if !UDIV_NEEDS_NORMALIZATION
|
||||||
if (d1 == 0)
|
if (d1 == 0)
|
||||||
{
|
{
|
||||||
if (d0 > n1)
|
if (d0 > n1)
|
||||||
@ -398,7 +399,7 @@ long long __moddi3(long long u, long long v)
|
|||||||
if (vv.s.high < 0)
|
if (vv.s.high < 0)
|
||||||
vv.ll = __negdi2 (vv.ll);
|
vv.ll = __negdi2 (vv.ll);
|
||||||
|
|
||||||
__udivmoddi4 (uu.ll, vv.ll, (UDWtype *) &w);
|
__udivmoddi4 (uu.ll, vv.ll, &w);
|
||||||
if (c)
|
if (c)
|
||||||
w = __negdi2 (w);
|
w = __negdi2 (w);
|
||||||
return w;
|
return w;
|
||||||
@ -418,7 +419,7 @@ unsigned long long __umoddi3(unsigned long long u, unsigned long long v)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* XXX: fix tcc's code generator to do this instead */
|
/* XXX: fix tcc's code generator to do this instead */
|
||||||
long long __ashrdi3(long long a, int b)
|
long long __sardi3(long long a, int b)
|
||||||
{
|
{
|
||||||
#ifdef __TINYC__
|
#ifdef __TINYC__
|
||||||
DWunion u;
|
DWunion u;
|
||||||
@ -437,7 +438,7 @@ long long __ashrdi3(long long a, int b)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* XXX: fix tcc's code generator to do this instead */
|
/* XXX: fix tcc's code generator to do this instead */
|
||||||
unsigned long long __lshrdi3(unsigned long long a, int b)
|
unsigned long long __shrdi3(unsigned long long a, int b)
|
||||||
{
|
{
|
||||||
#ifdef __TINYC__
|
#ifdef __TINYC__
|
||||||
DWunion u;
|
DWunion u;
|
||||||
@ -456,7 +457,7 @@ unsigned long long __lshrdi3(unsigned long long a, int b)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* XXX: fix tcc's code generator to do this instead */
|
/* XXX: fix tcc's code generator to do this instead */
|
||||||
long long __ashldi3(long long a, int b)
|
long long __shldi3(long long a, int b)
|
||||||
{
|
{
|
||||||
#ifdef __TINYC__
|
#ifdef __TINYC__
|
||||||
DWunion u;
|
DWunion u;
|
||||||
@ -465,7 +466,7 @@ long long __ashldi3(long long a, int b)
|
|||||||
u.s.high = (unsigned)u.s.low << (b - 32);
|
u.s.high = (unsigned)u.s.low << (b - 32);
|
||||||
u.s.low = 0;
|
u.s.low = 0;
|
||||||
} else if (b != 0) {
|
} else if (b != 0) {
|
||||||
u.s.high = ((unsigned)u.s.high << b) | ((unsigned)u.s.low >> (32 - b));
|
u.s.high = ((unsigned)u.s.high << b) | (u.s.low >> (32 - b));
|
||||||
u.s.low = (unsigned)u.s.low << b;
|
u.s.low = (unsigned)u.s.low << b;
|
||||||
}
|
}
|
||||||
return u.ll;
|
return u.ll;
|
||||||
@ -474,10 +475,15 @@ long long __ashldi3(long long a, int b)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* __i386__ */
|
#if defined(__i386__)
|
||||||
|
/* FPU control word for rounding to nearest mode */
|
||||||
|
unsigned short __tcc_fpu_control = 0x137f;
|
||||||
|
/* FPU control word for round to zero mode for int conversion */
|
||||||
|
unsigned short __tcc_int_fpu_control = 0x137f | 0x0c00;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* 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 __ulltof(unsigned long long a)
|
||||||
{
|
{
|
||||||
DWunion uu;
|
DWunion uu;
|
||||||
XFtype r;
|
XFtype r;
|
||||||
@ -492,7 +498,7 @@ float __floatundisf(unsigned long long a)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
double __floatundidf(unsigned long long a)
|
double __ulltod(unsigned long long a)
|
||||||
{
|
{
|
||||||
DWunion uu;
|
DWunion uu;
|
||||||
XFtype r;
|
XFtype r;
|
||||||
@ -507,7 +513,7 @@ double __floatundidf(unsigned long long a)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
long double __floatundixf(unsigned long long a)
|
long double __ulltold(unsigned long long a)
|
||||||
{
|
{
|
||||||
DWunion uu;
|
DWunion uu;
|
||||||
XFtype r;
|
XFtype r;
|
||||||
@ -526,7 +532,7 @@ unsigned long long __fixunssfdi (float a1)
|
|||||||
{
|
{
|
||||||
register union float_long fl1;
|
register union float_long fl1;
|
||||||
register int exp;
|
register int exp;
|
||||||
register unsigned long long l;
|
register unsigned long l;
|
||||||
|
|
||||||
fl1.f = a1;
|
fl1.f = a1;
|
||||||
|
|
||||||
@ -534,26 +540,16 @@ unsigned long long __fixunssfdi (float a1)
|
|||||||
return (0);
|
return (0);
|
||||||
|
|
||||||
exp = EXP (fl1.l) - EXCESS - 24;
|
exp = EXP (fl1.l) - EXCESS - 24;
|
||||||
|
|
||||||
l = MANT(fl1.l);
|
l = MANT(fl1.l);
|
||||||
|
|
||||||
if (exp >= 41)
|
if (exp >= 41)
|
||||||
return 1ULL << 63;
|
return (unsigned long long)-1;
|
||||||
else if (exp >= 0)
|
else if (exp >= 0)
|
||||||
l <<= exp;
|
return (unsigned long long)l << exp;
|
||||||
else if (exp >= -23)
|
else if (exp >= -23)
|
||||||
l >>= -exp;
|
return l >> -exp;
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
if (SIGN(fl1.l))
|
|
||||||
l = (unsigned long long)-l;
|
|
||||||
return l;
|
|
||||||
}
|
|
||||||
|
|
||||||
long long __fixsfdi (float a1)
|
|
||||||
{
|
|
||||||
long long ret; int s;
|
|
||||||
ret = __fixunssfdi((s = a1 >= 0) ? a1 : -a1);
|
|
||||||
return s ? ret : -ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long long __fixunsdfdi (double a1)
|
unsigned long long __fixunsdfdi (double a1)
|
||||||
@ -568,29 +564,19 @@ unsigned long long __fixunsdfdi (double a1)
|
|||||||
return (0);
|
return (0);
|
||||||
|
|
||||||
exp = EXPD (dl1) - EXCESSD - 53;
|
exp = EXPD (dl1) - EXCESSD - 53;
|
||||||
|
|
||||||
l = MANTD_LL(dl1);
|
l = MANTD_LL(dl1);
|
||||||
|
|
||||||
if (exp >= 12)
|
if (exp >= 12)
|
||||||
return 1ULL << 63; /* overflow result (like gcc, somewhat) */
|
return (unsigned long long)-1;
|
||||||
else if (exp >= 0)
|
else if (exp >= 0)
|
||||||
l <<= exp;
|
return l << exp;
|
||||||
else if (exp >= -52)
|
else if (exp >= -52)
|
||||||
l >>= -exp;
|
return l >> -exp;
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
if (SIGND(dl1))
|
|
||||||
l = (unsigned long long)-l;
|
|
||||||
return l;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
long long __fixdfdi (double a1)
|
|
||||||
{
|
|
||||||
long long ret; int s;
|
|
||||||
ret = __fixunsdfdi((s = a1 >= 0) ? a1 : -a1);
|
|
||||||
return s ? ret : -ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef __arm__
|
|
||||||
unsigned long long __fixunsxfdi (long double a1)
|
unsigned long long __fixunsxfdi (long double a1)
|
||||||
{
|
{
|
||||||
register union ldouble_long dl1;
|
register union ldouble_long dl1;
|
||||||
@ -603,21 +589,14 @@ unsigned long long __fixunsxfdi (long double a1)
|
|||||||
return (0);
|
return (0);
|
||||||
|
|
||||||
exp = EXPLD (dl1) - EXCESSLD - 64;
|
exp = EXPLD (dl1) - EXCESSLD - 64;
|
||||||
|
|
||||||
l = dl1.l.lower;
|
l = dl1.l.lower;
|
||||||
|
|
||||||
if (exp > 0)
|
if (exp > 0)
|
||||||
return 1ULL << 63;
|
return (unsigned long long)-1;
|
||||||
if (exp < -63)
|
else if (exp >= -63)
|
||||||
|
return l >> -exp;
|
||||||
|
else
|
||||||
return 0;
|
return 0;
|
||||||
l >>= -exp;
|
|
||||||
if (SIGNLD(dl1))
|
|
||||||
l = (unsigned long long)-l;
|
|
||||||
return l;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
long long __fixxfdi (long double a1)
|
|
||||||
{
|
|
||||||
long long ret; int s;
|
|
||||||
ret = __fixunsxfdi((s = a1 >= 0) ? a1 : -a1);
|
|
||||||
return s ? ret : -ret;
|
|
||||||
}
|
|
||||||
#endif /* !ARM */
|
|
||||||
65
libtcc_test.c
Normal file
65
libtcc_test.c
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* Simple Test program for libtcc
|
||||||
|
*
|
||||||
|
* libtcc can be useful to use tcc as a "backend" for a code generator.
|
||||||
|
*/
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <libtcc.h>
|
||||||
|
|
||||||
|
/* this function is called by the generated code */
|
||||||
|
int add(int a, int b)
|
||||||
|
{
|
||||||
|
return a + b;
|
||||||
|
}
|
||||||
|
|
||||||
|
char my_program[] =
|
||||||
|
"int fib(int n)\n"
|
||||||
|
"{\n"
|
||||||
|
" if (n <= 2)\n"
|
||||||
|
" return 1;\n"
|
||||||
|
" else\n"
|
||||||
|
" return fib(n-1) + fib(n-2);\n"
|
||||||
|
"}\n"
|
||||||
|
"\n"
|
||||||
|
"int foo(int n)\n"
|
||||||
|
"{\n"
|
||||||
|
" printf(\"Hello World!\\n\");\n"
|
||||||
|
" printf(\"fib(%d) = %d\\n\", n, fib(n));\n"
|
||||||
|
" printf(\"add(%d, %d) = %d\\n\", n, 2 * n, add(n, 2 * n));\n"
|
||||||
|
" return 0;\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
TCCState *s;
|
||||||
|
int (*func)(int);
|
||||||
|
unsigned long val;
|
||||||
|
|
||||||
|
s = tcc_new();
|
||||||
|
if (!s) {
|
||||||
|
fprintf(stderr, "Could not create tcc state\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* MUST BE CALLED before any compilation or file loading */
|
||||||
|
tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
|
||||||
|
|
||||||
|
tcc_compile_string(s, my_program);
|
||||||
|
|
||||||
|
/* as a test, we add a symbol that the compiled program can be
|
||||||
|
linked with. You can have a similar result by opening a dll
|
||||||
|
with tcc_add_dll(() and using its symbols directly. */
|
||||||
|
tcc_add_symbol(s, "add", (unsigned long)&add);
|
||||||
|
|
||||||
|
tcc_relocate(s);
|
||||||
|
|
||||||
|
tcc_get_symbol(s, &val, "foo");
|
||||||
|
func = (void *)val;
|
||||||
|
|
||||||
|
func(32);
|
||||||
|
|
||||||
|
tcc_delete(s);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
3059
riscv64-asm.c
3059
riscv64-asm.c
File diff suppressed because it is too large
Load Diff
1496
riscv64-gen.c
1496
riscv64-gen.c
File diff suppressed because it is too large
Load Diff
440
riscv64-link.c
440
riscv64-link.c
@ -1,440 +0,0 @@
|
|||||||
#ifdef TARGET_DEFS_ONLY
|
|
||||||
|
|
||||||
#define EM_TCC_TARGET EM_RISCV
|
|
||||||
|
|
||||||
#define R_DATA_32 R_RISCV_32
|
|
||||||
#define R_DATA_PTR R_RISCV_64
|
|
||||||
#define R_JMP_SLOT R_RISCV_JUMP_SLOT
|
|
||||||
#define R_GLOB_DAT R_RISCV_64
|
|
||||||
#define R_COPY R_RISCV_COPY
|
|
||||||
#define R_RELATIVE R_RISCV_RELATIVE
|
|
||||||
|
|
||||||
#define R_NUM R_RISCV_NUM
|
|
||||||
|
|
||||||
#define ELF_START_ADDR 0x00010000
|
|
||||||
#define ELF_PAGE_SIZE 0x1000
|
|
||||||
|
|
||||||
#define PCRELATIVE_DLLPLT 1
|
|
||||||
#define RELOCATE_DLLPLT 1
|
|
||||||
|
|
||||||
#else /* !TARGET_DEFS_ONLY */
|
|
||||||
|
|
||||||
//#define DEBUG_RELOC
|
|
||||||
#include "tcc.h"
|
|
||||||
|
|
||||||
/* Returns 1 for a code relocation, 0 for a data relocation. For unknown
|
|
||||||
relocations, returns -1. */
|
|
||||||
ST_FUNC int code_reloc (int reloc_type)
|
|
||||||
{
|
|
||||||
switch (reloc_type) {
|
|
||||||
|
|
||||||
case R_RISCV_BRANCH:
|
|
||||||
case R_RISCV_CALL:
|
|
||||||
case R_RISCV_JAL:
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
case R_RISCV_GOT_HI20:
|
|
||||||
case R_RISCV_PCREL_HI20:
|
|
||||||
case R_RISCV_PCREL_LO12_I:
|
|
||||||
case R_RISCV_PCREL_LO12_S:
|
|
||||||
case R_RISCV_32_PCREL:
|
|
||||||
case R_RISCV_SET6:
|
|
||||||
case R_RISCV_SET8:
|
|
||||||
case R_RISCV_SET16:
|
|
||||||
case R_RISCV_SUB6:
|
|
||||||
case R_RISCV_ADD16:
|
|
||||||
case R_RISCV_ADD32:
|
|
||||||
case R_RISCV_ADD64:
|
|
||||||
case R_RISCV_SUB8:
|
|
||||||
case R_RISCV_SUB16:
|
|
||||||
case R_RISCV_SUB32:
|
|
||||||
case R_RISCV_SUB64:
|
|
||||||
case R_RISCV_32:
|
|
||||||
case R_RISCV_64:
|
|
||||||
case R_RISCV_SET_ULEB128:
|
|
||||||
case R_RISCV_SUB_ULEB128:
|
|
||||||
case R_RISCV_TPREL_HI20:
|
|
||||||
case R_RISCV_TPREL_LO12_I:
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case R_RISCV_CALL_PLT:
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Returns an enumerator to describe whether and when the relocation needs a
|
|
||||||
GOT and/or PLT entry to be created. See tcc.h for a description of the
|
|
||||||
different values. */
|
|
||||||
ST_FUNC int gotplt_entry_type (int reloc_type)
|
|
||||||
{
|
|
||||||
switch (reloc_type) {
|
|
||||||
case R_RISCV_ALIGN:
|
|
||||||
case R_RISCV_RELAX:
|
|
||||||
case R_RISCV_RVC_BRANCH:
|
|
||||||
case R_RISCV_RVC_JUMP:
|
|
||||||
case R_RISCV_JUMP_SLOT:
|
|
||||||
case R_RISCV_SET6:
|
|
||||||
case R_RISCV_SET8:
|
|
||||||
case R_RISCV_SET16:
|
|
||||||
case R_RISCV_SUB6:
|
|
||||||
case R_RISCV_ADD16:
|
|
||||||
case R_RISCV_SUB8:
|
|
||||||
case R_RISCV_SUB16:
|
|
||||||
case R_RISCV_SET_ULEB128:
|
|
||||||
case R_RISCV_SUB_ULEB128:
|
|
||||||
return NO_GOTPLT_ENTRY;
|
|
||||||
|
|
||||||
case R_RISCV_BRANCH:
|
|
||||||
case R_RISCV_CALL:
|
|
||||||
case R_RISCV_PCREL_HI20:
|
|
||||||
case R_RISCV_PCREL_LO12_I:
|
|
||||||
case R_RISCV_PCREL_LO12_S:
|
|
||||||
case R_RISCV_32_PCREL:
|
|
||||||
case R_RISCV_ADD32:
|
|
||||||
case R_RISCV_ADD64:
|
|
||||||
case R_RISCV_SUB32:
|
|
||||||
case R_RISCV_SUB64:
|
|
||||||
case R_RISCV_32:
|
|
||||||
case R_RISCV_64:
|
|
||||||
case R_RISCV_JAL:
|
|
||||||
case R_RISCV_CALL_PLT:
|
|
||||||
return AUTO_GOTPLT_ENTRY;
|
|
||||||
|
|
||||||
case R_RISCV_GOT_HI20:
|
|
||||||
return ALWAYS_GOTPLT_ENTRY;
|
|
||||||
|
|
||||||
case R_RISCV_TPREL_HI20:
|
|
||||||
case R_RISCV_TPREL_LO12_I:
|
|
||||||
return NO_GOTPLT_ENTRY;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_attr *attr)
|
|
||||||
{
|
|
||||||
Section *plt = s1->plt;
|
|
||||||
uint8_t *p;
|
|
||||||
unsigned plt_offset;
|
|
||||||
|
|
||||||
if (plt->data_offset == 0)
|
|
||||||
section_ptr_add(plt, 32);
|
|
||||||
plt_offset = plt->data_offset;
|
|
||||||
|
|
||||||
p = section_ptr_add(plt, 16);
|
|
||||||
write64le(p, got_offset);
|
|
||||||
return plt_offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* relocate the PLT: compute addresses and offsets in the PLT now that final
|
|
||||||
address for PLT and GOT are known (see fill_program_header) */
|
|
||||||
ST_FUNC void relocate_plt(TCCState *s1)
|
|
||||||
{
|
|
||||||
uint8_t *p, *p_end;
|
|
||||||
|
|
||||||
if (!s1->plt)
|
|
||||||
return;
|
|
||||||
|
|
||||||
p = s1->plt->data;
|
|
||||||
p_end = p + s1->plt->data_offset;
|
|
||||||
|
|
||||||
if (p < p_end) {
|
|
||||||
uint64_t plt = s1->plt->sh_addr;
|
|
||||||
uint64_t got = s1->got->sh_addr;
|
|
||||||
uint64_t off = (got - plt + 0x800) >> 12;
|
|
||||||
if ((off + ((uint32_t)1 << 20)) >> 21)
|
|
||||||
tcc_error_noabort("Failed relocating PLT (off=0x%lx, got=0x%lx, plt=0x%lx)", (long)off, (long)got, (long)plt);
|
|
||||||
write32le(p, 0x397 | (off << 12)); // auipc t2, %pcrel_hi(got)
|
|
||||||
write32le(p + 4, 0x41c30333); // sub t1, t1, t3
|
|
||||||
write32le(p + 8, 0x0003be03 // ld t3, %pcrel_lo(got)(t2)
|
|
||||||
| (((got - plt) & 0xfff) << 20));
|
|
||||||
write32le(p + 12, 0xfd430313); // addi t1, t1, -(32+12)
|
|
||||||
write32le(p + 16, 0x00038293 // addi t0, t2, %pcrel_lo(got)
|
|
||||||
| (((got - plt) & 0xfff) << 20));
|
|
||||||
write32le(p + 20, 0x00135313); // srli t1, t1, log2(16/PTRSIZE)
|
|
||||||
write32le(p + 24, 0x0082b283); // ld t0, PTRSIZE(t0)
|
|
||||||
write32le(p + 28, 0x000e0067); // jr t3
|
|
||||||
p += 32;
|
|
||||||
while (p < p_end) {
|
|
||||||
uint64_t pc = plt + (p - s1->plt->data);
|
|
||||||
uint64_t addr = got + read64le(p);
|
|
||||||
uint64_t off = (addr - pc + 0x800) >> 12;
|
|
||||||
if ((off + ((uint32_t)1 << 20)) >> 21)
|
|
||||||
tcc_error_noabort("Failed relocating PLT (off=0x%lx, addr=0x%lx, pc=0x%lx)", (long)off, (long)addr, (long)pc);
|
|
||||||
write32le(p, 0xe17 | (off << 12)); // auipc t3, %pcrel_hi(func@got)
|
|
||||||
write32le(p + 4, 0x000e3e03 // ld t3, %pcrel_lo(func@got)(t3)
|
|
||||||
| (((addr - pc) & 0xfff) << 20));
|
|
||||||
write32le(p + 8, 0x000e0367); // jalr t1, t3
|
|
||||||
write32le(p + 12, 0x00000013); // nop
|
|
||||||
p += 16;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s1->plt->reloc) {
|
|
||||||
ElfW_Rel *rel;
|
|
||||||
p = s1->got->data;
|
|
||||||
for_each_elem(s1->plt->reloc, 0, rel, ElfW_Rel) {
|
|
||||||
write64le(p + rel->r_offset, s1->plt->sh_addr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void riscv64_record_pcrel_hi(TCCState *s1, addr_t addr, addr_t val)
|
|
||||||
{
|
|
||||||
struct pcrel_hi *entry = tcc_malloc(sizeof *entry);
|
|
||||||
entry->addr = addr;
|
|
||||||
entry->val = val;
|
|
||||||
dynarray_add(&s1->pcrel_hi_entries, &s1->nb_pcrel_hi_entries, entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int riscv64_lookup_pcrel_hi(TCCState *s1, addr_t hi_addr, addr_t *hi_val)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for (i = s1->nb_pcrel_hi_entries; i > 0; ) {
|
|
||||||
struct pcrel_hi *entry = s1->pcrel_hi_entries[--i];
|
|
||||||
if (entry->addr == hi_addr) {
|
|
||||||
*hi_val = entry->val;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return tcc_error_noabort("unsupported hi/lo pcrel reloc scheme");
|
|
||||||
}
|
|
||||||
|
|
||||||
ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
|
|
||||||
addr_t addr, addr_t val)
|
|
||||||
{
|
|
||||||
uint64_t off64;
|
|
||||||
uint32_t off32;
|
|
||||||
int sym_index = ELFW(R_SYM)(rel->r_info), esym_index;
|
|
||||||
ElfW(Sym) *sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
|
|
||||||
|
|
||||||
switch(type) {
|
|
||||||
case R_RISCV_ALIGN:
|
|
||||||
case R_RISCV_RELAX:
|
|
||||||
return;
|
|
||||||
|
|
||||||
case R_RISCV_BRANCH:
|
|
||||||
off64 = val - addr;
|
|
||||||
if ((off64 + (1 << 12)) & ~(uint64_t)0x1ffe)
|
|
||||||
tcc_error_noabort("R_RISCV_BRANCH relocation failed"
|
|
||||||
" (val=%lx, addr=%lx)", (long)val, (long)addr);
|
|
||||||
off32 = off64 >> 1;
|
|
||||||
write32le(ptr, (read32le(ptr) & ~0xfe000f80)
|
|
||||||
| ((off32 & 0x800) << 20)
|
|
||||||
| ((off32 & 0x3f0) << 21)
|
|
||||||
| ((off32 & 0x00f) << 8)
|
|
||||||
| ((off32 & 0x400) >> 3));
|
|
||||||
return;
|
|
||||||
case R_RISCV_JAL:
|
|
||||||
off64 = val - addr;
|
|
||||||
if ((off64 + (1 << 21)) & ~(((uint64_t)1 << 22) - 2))
|
|
||||||
tcc_error_noabort("R_RISCV_JAL relocation failed"
|
|
||||||
" (val=%lx, addr=%lx)", (long)val, (long)addr);
|
|
||||||
off32 = off64;
|
|
||||||
write32le(ptr, (read32le(ptr) & 0xfff)
|
|
||||||
| (((off32 >> 12) & 0xff) << 12)
|
|
||||||
| (((off32 >> 11) & 1) << 20)
|
|
||||||
| (((off32 >> 1) & 0x3ff) << 21)
|
|
||||||
| (((off32 >> 20) & 1) << 31));
|
|
||||||
return;
|
|
||||||
case R_RISCV_CALL:
|
|
||||||
case R_RISCV_CALL_PLT:
|
|
||||||
write32le(ptr, (read32le(ptr) & 0xfff)
|
|
||||||
| ((val - addr + 0x800) & ~0xfff));
|
|
||||||
write32le(ptr + 4, (read32le(ptr + 4) & 0xfffff)
|
|
||||||
| (((val - addr) & 0xfff) << 20));
|
|
||||||
return;
|
|
||||||
case R_RISCV_PCREL_HI20:
|
|
||||||
#ifdef DEBUG_RELOC
|
|
||||||
printf("PCREL_HI20: val=%lx addr=%lx\n", (long)val, (long)addr);
|
|
||||||
#endif
|
|
||||||
off64 = (int64_t)(val - addr + 0x800) >> 12;
|
|
||||||
if ((off64 + ((uint64_t)1 << 20)) >> 21)
|
|
||||||
tcc_error_noabort("R_RISCV_PCREL_HI20 relocation failed: off=%lx cond=%lx sym=%s",
|
|
||||||
(long)off64, (long)((int64_t)(off64 + ((uint64_t)1 << 20)) >> 21),
|
|
||||||
symtab_section->link->data + sym->st_name);
|
|
||||||
write32le(ptr, (read32le(ptr) & 0xfff)
|
|
||||||
| ((off64 & 0xfffff) << 12));
|
|
||||||
riscv64_record_pcrel_hi(s1, addr, val);
|
|
||||||
return;
|
|
||||||
case R_RISCV_GOT_HI20:
|
|
||||||
val = s1->got->sh_addr + get_sym_attr(s1, sym_index, 0)->got_offset;
|
|
||||||
off64 = (int64_t)(val - addr + 0x800) >> 12;
|
|
||||||
if ((off64 + ((uint64_t)1 << 20)) >> 21)
|
|
||||||
tcc_error_noabort("R_RISCV_GOT_HI20 relocation failed");
|
|
||||||
write32le(ptr, (read32le(ptr) & 0xfff)
|
|
||||||
| ((off64 & 0xfffff) << 12));
|
|
||||||
riscv64_record_pcrel_hi(s1, addr, val);
|
|
||||||
return;
|
|
||||||
case R_RISCV_PCREL_LO12_I:
|
|
||||||
#ifdef DEBUG_RELOC
|
|
||||||
printf("PCREL_LO12_I: val=%lx addr=%lx\n", (long)val, (long)addr);
|
|
||||||
#endif
|
|
||||||
addr = val;
|
|
||||||
riscv64_lookup_pcrel_hi(s1, addr, &val);
|
|
||||||
write32le(ptr, (read32le(ptr) & 0xfffff)
|
|
||||||
| (((val - addr) & 0xfff) << 20));
|
|
||||||
return;
|
|
||||||
case R_RISCV_PCREL_LO12_S:
|
|
||||||
addr = val;
|
|
||||||
riscv64_lookup_pcrel_hi(s1, addr, &val);
|
|
||||||
off32 = val - addr;
|
|
||||||
write32le(ptr, (read32le(ptr) & ~0xfe000f80)
|
|
||||||
| ((off32 & 0xfe0) << 20)
|
|
||||||
| ((off32 & 0x01f) << 7));
|
|
||||||
return;
|
|
||||||
|
|
||||||
case R_RISCV_RVC_BRANCH:
|
|
||||||
off64 = (val - addr);
|
|
||||||
if ((off64 + (1 << 8)) & ~(uint64_t)0x1fe)
|
|
||||||
tcc_error_noabort("R_RISCV_RVC_BRANCH relocation failed"
|
|
||||||
" (val=%lx, addr=%lx)", (long)val, (long)addr);
|
|
||||||
off32 = off64;
|
|
||||||
write16le(ptr, (read16le(ptr) & 0xe383)
|
|
||||||
| (((off32 >> 5) & 1) << 2)
|
|
||||||
| (((off32 >> 1) & 3) << 3)
|
|
||||||
| (((off32 >> 6) & 3) << 5)
|
|
||||||
| (((off32 >> 3) & 3) << 10)
|
|
||||||
| (((off32 >> 8) & 1) << 12));
|
|
||||||
return;
|
|
||||||
case R_RISCV_RVC_JUMP:
|
|
||||||
off64 = (val - addr);
|
|
||||||
if ((off64 + (1 << 11)) & ~(uint64_t)0xffe)
|
|
||||||
tcc_error_noabort("R_RISCV_RVC_BRANCH relocation failed"
|
|
||||||
" (val=%lx, addr=%lx)", (long)val, (long)addr);
|
|
||||||
off32 = off64;
|
|
||||||
write16le(ptr, (read16le(ptr) & 0xe003)
|
|
||||||
| (((off32 >> 5) & 1) << 2)
|
|
||||||
| (((off32 >> 1) & 7) << 3)
|
|
||||||
| (((off32 >> 7) & 1) << 6)
|
|
||||||
| (((off32 >> 6) & 1) << 7)
|
|
||||||
| (((off32 >> 10) & 1) << 8)
|
|
||||||
| (((off32 >> 8) & 3) << 9)
|
|
||||||
| (((off32 >> 4) & 1) << 11)
|
|
||||||
| (((off32 >> 11) & 1) << 12));
|
|
||||||
return;
|
|
||||||
|
|
||||||
case R_RISCV_32:
|
|
||||||
if (s1->output_type & TCC_OUTPUT_DYN) {
|
|
||||||
/* XXX: this logic may depend on TCC's codegen
|
|
||||||
now TCC uses R_RISCV_RELATIVE even for a 64bit pointer */
|
|
||||||
qrel->r_offset = rel->r_offset;
|
|
||||||
qrel->r_info = ELFW(R_INFO)(0, R_RISCV_RELATIVE);
|
|
||||||
/* Use sign extension! */
|
|
||||||
qrel->r_addend = (int)read32le(ptr) + val;
|
|
||||||
qrel++;
|
|
||||||
}
|
|
||||||
add32le(ptr, val);
|
|
||||||
return;
|
|
||||||
case R_RISCV_64:
|
|
||||||
if (s1->output_type & TCC_OUTPUT_DYN) {
|
|
||||||
esym_index = get_sym_attr(s1, sym_index, 0)->dyn_index;
|
|
||||||
qrel->r_offset = rel->r_offset;
|
|
||||||
if (esym_index) {
|
|
||||||
qrel->r_info = ELFW(R_INFO)(esym_index, R_RISCV_64);
|
|
||||||
qrel->r_addend = rel->r_addend;
|
|
||||||
qrel++;
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
qrel->r_info = ELFW(R_INFO)(0, R_RISCV_RELATIVE);
|
|
||||||
qrel->r_addend = read64le(ptr) + val;
|
|
||||||
qrel++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case R_RISCV_JUMP_SLOT:
|
|
||||||
add64le(ptr, val);
|
|
||||||
return;
|
|
||||||
case R_RISCV_ADD64:
|
|
||||||
write64le(ptr, read64le(ptr) + val);
|
|
||||||
return;
|
|
||||||
case R_RISCV_ADD32:
|
|
||||||
write32le(ptr, read32le(ptr) + val);
|
|
||||||
return;
|
|
||||||
case R_RISCV_SUB64:
|
|
||||||
write64le(ptr, read64le(ptr) - val);
|
|
||||||
return;
|
|
||||||
case R_RISCV_SUB32:
|
|
||||||
write32le(ptr, read32le(ptr) - val);
|
|
||||||
return;
|
|
||||||
case R_RISCV_ADD16:
|
|
||||||
write16le(ptr, read16le(ptr) + val);
|
|
||||||
return;
|
|
||||||
case R_RISCV_SUB8:
|
|
||||||
*ptr -= val;
|
|
||||||
return;
|
|
||||||
case R_RISCV_SUB16:
|
|
||||||
write16le(ptr, read16le(ptr) - val);
|
|
||||||
return;
|
|
||||||
case R_RISCV_SET6:
|
|
||||||
*ptr = (*ptr & ~0x3f) | (val & 0x3f);
|
|
||||||
return;
|
|
||||||
case R_RISCV_SET8:
|
|
||||||
*ptr = (*ptr & ~0xff) | (val & 0xff);
|
|
||||||
return;
|
|
||||||
case R_RISCV_SET16:
|
|
||||||
write16le(ptr, val);
|
|
||||||
return;
|
|
||||||
case R_RISCV_SUB6:
|
|
||||||
*ptr = (*ptr & ~0x3f) | ((*ptr - val) & 0x3f);
|
|
||||||
return;
|
|
||||||
case R_RISCV_32_PCREL:
|
|
||||||
if (s1->output_type & TCC_OUTPUT_DYN) {
|
|
||||||
/* DLL relocation */
|
|
||||||
esym_index = get_sym_attr(s1, sym_index, 0)->dyn_index;
|
|
||||||
if (esym_index) {
|
|
||||||
qrel->r_offset = rel->r_offset;
|
|
||||||
qrel->r_info = ELFW(R_INFO)(esym_index, R_RISCV_32_PCREL);
|
|
||||||
/* Use sign extension! */
|
|
||||||
qrel->r_addend = (int)read32le(ptr) + rel->r_addend;
|
|
||||||
qrel++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
add32le(ptr, val - addr);
|
|
||||||
return;
|
|
||||||
case R_RISCV_SET_ULEB128:
|
|
||||||
case R_RISCV_SUB_ULEB128:
|
|
||||||
/* ignore. used in section .debug_loclists */
|
|
||||||
return;
|
|
||||||
case R_RISCV_COPY:
|
|
||||||
/* XXX */
|
|
||||||
return;
|
|
||||||
case R_RISCV_RELATIVE:
|
|
||||||
/* R_RISCV_RELATIVE value is already applied in R_RISCV_32/64
|
|
||||||
dynamic output paths, but we need this case for incoming
|
|
||||||
RELATIVE relocations from object files. */
|
|
||||||
return;
|
|
||||||
|
|
||||||
case R_RISCV_TPREL_HI20:
|
|
||||||
case R_RISCV_TPREL_LO12_I: {
|
|
||||||
addr_t tls_start = 0;
|
|
||||||
int64_t tp_offset;
|
|
||||||
int i;
|
|
||||||
for (i = 1; i < s1->nb_sections; i++) {
|
|
||||||
Section *s = s1->sections[i];
|
|
||||||
if (s->sh_flags & SHF_TLS && s->sh_size) {
|
|
||||||
if (!tls_start || s->sh_addr < tls_start)
|
|
||||||
tls_start = s->sh_addr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tp_offset = val - tls_start;
|
|
||||||
if (type == R_RISCV_TPREL_HI20) {
|
|
||||||
off64 = (int64_t)(tp_offset + 0x800) >> 12;
|
|
||||||
if ((off64 + ((uint64_t)1 << 20)) >> 21)
|
|
||||||
tcc_error_noabort("R_RISCV_TPREL_HI20 relocation failed");
|
|
||||||
write32le(ptr, (read32le(ptr) & 0xfff)
|
|
||||||
| ((off64 & 0xfffff) << 12));
|
|
||||||
} else {
|
|
||||||
write32le(ptr, (read32le(ptr) & 0xfffff)
|
|
||||||
| (((tp_offset) & 0xfff) << 20));
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
fprintf(stderr, "FIXME: handle reloc type %x at %x [%p] to %x\n",
|
|
||||||
type, (unsigned)addr, ptr, (unsigned)val);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
612
riscv64-tok.h
612
riscv64-tok.h
@ -1,612 +0,0 @@
|
|||||||
/* ------------------------------------------------------------------ */
|
|
||||||
/* WARNING: relative order of tokens is important. */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The specifications are available under https://riscv.org/technical/specifications/
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define DEF_ASM_WITH_SUFFIX(x, y) \
|
|
||||||
DEF(TOK_ASM_ ## x ## _ ## y, #x "." #y)
|
|
||||||
|
|
||||||
#define DEF_ASM_WITH_SUFFIXES(x, y, z) \
|
|
||||||
DEF(TOK_ASM_ ## x ## _ ## y ## _ ## z, #x "." #y "." #z)
|
|
||||||
|
|
||||||
#define DEF_ASM_FENCE(x) \
|
|
||||||
DEF(TOK_ASM_ ## x ## _fence, #x)
|
|
||||||
|
|
||||||
/* register */
|
|
||||||
/* integer */
|
|
||||||
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)
|
|
||||||
DEF_ASM(x31)
|
|
||||||
/* float */
|
|
||||||
DEF_ASM(f0)
|
|
||||||
DEF_ASM(f1)
|
|
||||||
DEF_ASM(f2)
|
|
||||||
DEF_ASM(f3)
|
|
||||||
DEF_ASM(f4)
|
|
||||||
DEF_ASM(f5)
|
|
||||||
DEF_ASM(f6)
|
|
||||||
DEF_ASM(f7)
|
|
||||||
DEF_ASM(f8)
|
|
||||||
DEF_ASM(f9)
|
|
||||||
DEF_ASM(f10)
|
|
||||||
DEF_ASM(f11)
|
|
||||||
DEF_ASM(f12)
|
|
||||||
DEF_ASM(f13)
|
|
||||||
DEF_ASM(f14)
|
|
||||||
DEF_ASM(f15)
|
|
||||||
DEF_ASM(f16)
|
|
||||||
DEF_ASM(f17)
|
|
||||||
DEF_ASM(f18)
|
|
||||||
DEF_ASM(f19)
|
|
||||||
DEF_ASM(f20)
|
|
||||||
DEF_ASM(f21)
|
|
||||||
DEF_ASM(f22)
|
|
||||||
DEF_ASM(f23)
|
|
||||||
DEF_ASM(f24)
|
|
||||||
DEF_ASM(f25)
|
|
||||||
DEF_ASM(f26)
|
|
||||||
DEF_ASM(f27)
|
|
||||||
DEF_ASM(f28)
|
|
||||||
DEF_ASM(f29)
|
|
||||||
DEF_ASM(f30)
|
|
||||||
DEF_ASM(f31)
|
|
||||||
|
|
||||||
/* register ABI mnemonics, refer to RISC-V ABI 1.0 */
|
|
||||||
/* integer */
|
|
||||||
DEF_ASM(zero)
|
|
||||||
DEF_ASM(ra)
|
|
||||||
DEF_ASM(sp)
|
|
||||||
DEF_ASM(gp)
|
|
||||||
DEF_ASM(tp)
|
|
||||||
DEF_ASM(t0)
|
|
||||||
DEF_ASM(t1)
|
|
||||||
DEF_ASM(t2)
|
|
||||||
DEF_ASM(s0)
|
|
||||||
DEF_ASM(s1)
|
|
||||||
DEF_ASM(a0)
|
|
||||||
DEF_ASM(a1)
|
|
||||||
DEF_ASM(a2)
|
|
||||||
DEF_ASM(a3)
|
|
||||||
DEF_ASM(a4)
|
|
||||||
DEF_ASM(a5)
|
|
||||||
DEF_ASM(a6)
|
|
||||||
DEF_ASM(a7)
|
|
||||||
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(t3)
|
|
||||||
DEF_ASM(t4)
|
|
||||||
DEF_ASM(t5)
|
|
||||||
DEF_ASM(t6)
|
|
||||||
/* float */
|
|
||||||
DEF_ASM(ft0)
|
|
||||||
DEF_ASM(ft1)
|
|
||||||
DEF_ASM(ft2)
|
|
||||||
DEF_ASM(ft3)
|
|
||||||
DEF_ASM(ft4)
|
|
||||||
DEF_ASM(ft5)
|
|
||||||
DEF_ASM(ft6)
|
|
||||||
DEF_ASM(ft7)
|
|
||||||
DEF_ASM(fs0)
|
|
||||||
DEF_ASM(fs1)
|
|
||||||
DEF_ASM(fa0)
|
|
||||||
DEF_ASM(fa1)
|
|
||||||
DEF_ASM(fa2)
|
|
||||||
DEF_ASM(fa3)
|
|
||||||
DEF_ASM(fa4)
|
|
||||||
DEF_ASM(fa5)
|
|
||||||
DEF_ASM(fa6)
|
|
||||||
DEF_ASM(fa7)
|
|
||||||
DEF_ASM(fs2)
|
|
||||||
DEF_ASM(fs3)
|
|
||||||
DEF_ASM(fs4)
|
|
||||||
DEF_ASM(fs5)
|
|
||||||
DEF_ASM(fs6)
|
|
||||||
DEF_ASM(fs7)
|
|
||||||
DEF_ASM(fs8)
|
|
||||||
DEF_ASM(fs9)
|
|
||||||
DEF_ASM(fs10)
|
|
||||||
DEF_ASM(fs11)
|
|
||||||
DEF_ASM(ft8)
|
|
||||||
DEF_ASM(ft9)
|
|
||||||
DEF_ASM(ft10)
|
|
||||||
DEF_ASM(ft11)
|
|
||||||
/* not in the ABI */
|
|
||||||
DEF_ASM(pc)
|
|
||||||
|
|
||||||
/* Loads */
|
|
||||||
|
|
||||||
DEF_ASM(lb)
|
|
||||||
DEF_ASM(lh)
|
|
||||||
DEF_ASM(lw)
|
|
||||||
DEF_ASM(lbu)
|
|
||||||
DEF_ASM(lhu)
|
|
||||||
/* RV64 */
|
|
||||||
DEF_ASM(ld)
|
|
||||||
DEF_ASM(lwu)
|
|
||||||
|
|
||||||
/* Stores */
|
|
||||||
|
|
||||||
DEF_ASM(sb)
|
|
||||||
DEF_ASM(sh)
|
|
||||||
DEF_ASM(sw)
|
|
||||||
/* RV64 */
|
|
||||||
DEF_ASM(sd)
|
|
||||||
|
|
||||||
/* Shifts */
|
|
||||||
|
|
||||||
DEF_ASM(sll)
|
|
||||||
DEF_ASM(srl)
|
|
||||||
DEF_ASM(sra)
|
|
||||||
/* RV64 */
|
|
||||||
DEF_ASM(slli)
|
|
||||||
DEF_ASM(srli)
|
|
||||||
DEF_ASM(sllw)
|
|
||||||
DEF_ASM(slliw)
|
|
||||||
DEF_ASM(srlw)
|
|
||||||
DEF_ASM(srliw)
|
|
||||||
DEF_ASM(srai)
|
|
||||||
DEF_ASM(sraw)
|
|
||||||
DEF_ASM(sraiw)
|
|
||||||
|
|
||||||
/* Arithmetic */
|
|
||||||
|
|
||||||
DEF_ASM(add)
|
|
||||||
DEF_ASM(addi)
|
|
||||||
DEF_ASM(sub)
|
|
||||||
DEF_ASM(lui)
|
|
||||||
DEF_ASM(auipc)
|
|
||||||
/* RV64 */
|
|
||||||
DEF_ASM(addw)
|
|
||||||
DEF_ASM(addiw)
|
|
||||||
DEF_ASM(subw)
|
|
||||||
|
|
||||||
/* Logical */
|
|
||||||
|
|
||||||
DEF_ASM(xor)
|
|
||||||
DEF_ASM(xori)
|
|
||||||
DEF_ASM(or)
|
|
||||||
DEF_ASM(ori)
|
|
||||||
DEF_ASM(and)
|
|
||||||
DEF_ASM(andi)
|
|
||||||
|
|
||||||
/* Compare */
|
|
||||||
|
|
||||||
DEF_ASM(slt)
|
|
||||||
DEF_ASM(slti)
|
|
||||||
DEF_ASM(sltu)
|
|
||||||
DEF_ASM(sltiu)
|
|
||||||
|
|
||||||
/* Branch */
|
|
||||||
|
|
||||||
DEF_ASM(beq)
|
|
||||||
DEF_ASM(bne)
|
|
||||||
DEF_ASM(blt)
|
|
||||||
DEF_ASM(bge)
|
|
||||||
DEF_ASM(bltu)
|
|
||||||
DEF_ASM(bgeu)
|
|
||||||
|
|
||||||
/* Jump */
|
|
||||||
|
|
||||||
DEF_ASM(jal)
|
|
||||||
DEF_ASM(jalr)
|
|
||||||
|
|
||||||
/* Sync */
|
|
||||||
|
|
||||||
DEF_ASM(fence)
|
|
||||||
/* Zifencei extension */
|
|
||||||
DEF_ASM_WITH_SUFFIX(fence, i)
|
|
||||||
|
|
||||||
/* System call */
|
|
||||||
|
|
||||||
/* used to be called scall and sbreak */
|
|
||||||
DEF_ASM(ecall)
|
|
||||||
DEF_ASM(ebreak)
|
|
||||||
|
|
||||||
/* Counters */
|
|
||||||
|
|
||||||
DEF_ASM(rdcycle)
|
|
||||||
DEF_ASM(rdcycleh)
|
|
||||||
DEF_ASM(rdtime)
|
|
||||||
DEF_ASM(rdtimeh)
|
|
||||||
DEF_ASM(rdinstret)
|
|
||||||
DEF_ASM(rdinstreth)
|
|
||||||
|
|
||||||
/* “M” Standard Extension for Integer Multiplication and Division, V2.0 */
|
|
||||||
DEF_ASM(mul)
|
|
||||||
DEF_ASM(mulh)
|
|
||||||
DEF_ASM(mulhsu)
|
|
||||||
DEF_ASM(mulhu)
|
|
||||||
DEF_ASM(div)
|
|
||||||
DEF_ASM(divu)
|
|
||||||
DEF_ASM(rem)
|
|
||||||
DEF_ASM(remu)
|
|
||||||
/* RV64 */
|
|
||||||
DEF_ASM(mulw)
|
|
||||||
DEF_ASM(divw)
|
|
||||||
DEF_ASM(divuw)
|
|
||||||
DEF_ASM(remw)
|
|
||||||
DEF_ASM(remuw)
|
|
||||||
|
|
||||||
/* "F"/"D" Extension for Single/Double-Precision Floating Point Arithmetic, V2.2 */
|
|
||||||
/* enough implemented for musl */
|
|
||||||
DEF_ASM_WITH_SUFFIX(fsgnj, s)
|
|
||||||
DEF_ASM_WITH_SUFFIX(fsgnj, d)
|
|
||||||
DEF_ASM_WITH_SUFFIX(fadd, s)
|
|
||||||
DEF_ASM_WITH_SUFFIX(fadd, d)
|
|
||||||
DEF_ASM_WITH_SUFFIX(fsub, s)
|
|
||||||
DEF_ASM_WITH_SUFFIX(fsub, d)
|
|
||||||
DEF_ASM_WITH_SUFFIX(fmul, s)
|
|
||||||
DEF_ASM_WITH_SUFFIX(fmul, d)
|
|
||||||
DEF_ASM_WITH_SUFFIX(fdiv, s)
|
|
||||||
DEF_ASM_WITH_SUFFIX(fdiv, d)
|
|
||||||
DEF_ASM_WITH_SUFFIX(fmadd, s)
|
|
||||||
DEF_ASM_WITH_SUFFIX(fmadd, d)
|
|
||||||
DEF_ASM_WITH_SUFFIX(fmax, s)
|
|
||||||
DEF_ASM_WITH_SUFFIX(fmax, d)
|
|
||||||
DEF_ASM_WITH_SUFFIX(fmin, s)
|
|
||||||
DEF_ASM_WITH_SUFFIX(fmin, d)
|
|
||||||
DEF_ASM_WITH_SUFFIX(fsqrt, s)
|
|
||||||
DEF_ASM_WITH_SUFFIX(fsqrt, d)
|
|
||||||
|
|
||||||
/* F/D comparison and conversion (not needed by musl, added for completeness) */
|
|
||||||
DEF_ASM_WITH_SUFFIX(feq, s)
|
|
||||||
DEF_ASM_WITH_SUFFIX(feq, d)
|
|
||||||
DEF_ASM_WITH_SUFFIX(flt, s)
|
|
||||||
DEF_ASM_WITH_SUFFIX(flt, d)
|
|
||||||
DEF_ASM_WITH_SUFFIX(fle, s)
|
|
||||||
DEF_ASM_WITH_SUFFIX(fle, d)
|
|
||||||
DEF_ASM_WITH_SUFFIX(fclass, s)
|
|
||||||
DEF_ASM_WITH_SUFFIX(fclass, d)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(fcvt, w, s)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(fcvt, wu, s)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(fcvt, l, s)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(fcvt, lu, s)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(fcvt, s, w)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(fcvt, s, wu)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(fcvt, s, l)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(fcvt, s, lu)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(fcvt, w, d)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(fcvt, wu, d)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(fcvt, l, d)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(fcvt, lu, d)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(fcvt, d, w)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(fcvt, d, wu)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(fcvt, d, l)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(fcvt, d, lu)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(fcvt, s, d)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(fcvt, d, s)
|
|
||||||
|
|
||||||
/* "C" Extension for Compressed Instructions, V2.0 */
|
|
||||||
DEF_ASM_WITH_SUFFIX(c, nop)
|
|
||||||
/* Loads */
|
|
||||||
DEF_ASM_WITH_SUFFIX(c, li)
|
|
||||||
DEF_ASM_WITH_SUFFIX(c, lw)
|
|
||||||
DEF_ASM_WITH_SUFFIX(c, lwsp)
|
|
||||||
/* single float */
|
|
||||||
DEF_ASM_WITH_SUFFIX(c, flw)
|
|
||||||
DEF_ASM_WITH_SUFFIX(c, flwsp)
|
|
||||||
/* double float */
|
|
||||||
DEF_ASM_WITH_SUFFIX(c, fld)
|
|
||||||
DEF_ASM_WITH_SUFFIX(c, fldsp)
|
|
||||||
/* RV64 */
|
|
||||||
DEF_ASM_WITH_SUFFIX(c, ld)
|
|
||||||
DEF_ASM_WITH_SUFFIX(c, ldsp)
|
|
||||||
|
|
||||||
/* Stores */
|
|
||||||
|
|
||||||
DEF_ASM_WITH_SUFFIX(c, sw)
|
|
||||||
DEF_ASM_WITH_SUFFIX(c, sd)
|
|
||||||
DEF_ASM_WITH_SUFFIX(c, swsp)
|
|
||||||
DEF_ASM_WITH_SUFFIX(c, sdsp)
|
|
||||||
/* single float */
|
|
||||||
DEF_ASM_WITH_SUFFIX(c, fsw)
|
|
||||||
DEF_ASM_WITH_SUFFIX(c, fswsp)
|
|
||||||
/* double float */
|
|
||||||
DEF_ASM_WITH_SUFFIX(c, fsd)
|
|
||||||
DEF_ASM_WITH_SUFFIX(c, fsdsp)
|
|
||||||
|
|
||||||
/* Shifts */
|
|
||||||
DEF_ASM_WITH_SUFFIX(c, slli)
|
|
||||||
DEF_ASM_WITH_SUFFIX(c, srli)
|
|
||||||
DEF_ASM_WITH_SUFFIX(c, srai)
|
|
||||||
|
|
||||||
/* Arithmetic */
|
|
||||||
DEF_ASM_WITH_SUFFIX(c, add)
|
|
||||||
DEF_ASM_WITH_SUFFIX(c, addi)
|
|
||||||
DEF_ASM_WITH_SUFFIX(c, addi16sp)
|
|
||||||
DEF_ASM_WITH_SUFFIX(c, addi4spn)
|
|
||||||
DEF_ASM_WITH_SUFFIX(c, lui)
|
|
||||||
DEF_ASM_WITH_SUFFIX(c, sub)
|
|
||||||
DEF_ASM_WITH_SUFFIX(c, mv)
|
|
||||||
/* RV64 */
|
|
||||||
DEF_ASM_WITH_SUFFIX(c, addw)
|
|
||||||
DEF_ASM_WITH_SUFFIX(c, addiw)
|
|
||||||
DEF_ASM_WITH_SUFFIX(c, subw)
|
|
||||||
|
|
||||||
/* Logical */
|
|
||||||
DEF_ASM_WITH_SUFFIX(c, xor)
|
|
||||||
DEF_ASM_WITH_SUFFIX(c, or)
|
|
||||||
DEF_ASM_WITH_SUFFIX(c, and)
|
|
||||||
DEF_ASM_WITH_SUFFIX(c, andi)
|
|
||||||
|
|
||||||
/* Branch */
|
|
||||||
DEF_ASM_WITH_SUFFIX(c, beqz)
|
|
||||||
DEF_ASM_WITH_SUFFIX(c, bnez)
|
|
||||||
|
|
||||||
/* Jump */
|
|
||||||
DEF_ASM_WITH_SUFFIX(c, j)
|
|
||||||
DEF_ASM_WITH_SUFFIX(c, jr)
|
|
||||||
DEF_ASM_WITH_SUFFIX(c, jal)
|
|
||||||
DEF_ASM_WITH_SUFFIX(c, jalr)
|
|
||||||
|
|
||||||
/* System call */
|
|
||||||
DEF_ASM_WITH_SUFFIX(c, ebreak)
|
|
||||||
|
|
||||||
/* XXX F Extension: Single-Precision Floating Point */
|
|
||||||
/* XXX D Extension: Double-Precision Floating Point */
|
|
||||||
/* from the spec: Tables 16.5–16.7 list the RVC instructions. */
|
|
||||||
|
|
||||||
/* “Zicsr”, Control and Status Register (CSR) Instructions, V2.0 */
|
|
||||||
DEF_ASM(csrrw)
|
|
||||||
DEF_ASM(csrrs)
|
|
||||||
DEF_ASM(csrrc)
|
|
||||||
DEF_ASM(csrrwi)
|
|
||||||
DEF_ASM(csrrsi)
|
|
||||||
DEF_ASM(csrrci)
|
|
||||||
/* registers */
|
|
||||||
DEF_ASM(cycle)
|
|
||||||
DEF_ASM(fcsr)
|
|
||||||
DEF_ASM(fflags)
|
|
||||||
DEF_ASM(frm)
|
|
||||||
DEF_ASM(instret)
|
|
||||||
DEF_ASM(time)
|
|
||||||
/* RV32I-only */
|
|
||||||
DEF_ASM(cycleh)
|
|
||||||
DEF_ASM(instreth)
|
|
||||||
DEF_ASM(timeh)
|
|
||||||
/* pseudo */
|
|
||||||
DEF_ASM(csrc)
|
|
||||||
DEF_ASM(csrci)
|
|
||||||
DEF_ASM(csrr)
|
|
||||||
DEF_ASM(csrs)
|
|
||||||
DEF_ASM(csrsi)
|
|
||||||
DEF_ASM(csrw)
|
|
||||||
DEF_ASM(csrwi)
|
|
||||||
DEF_ASM(frcsr)
|
|
||||||
DEF_ASM(frflags)
|
|
||||||
DEF_ASM(frrm)
|
|
||||||
DEF_ASM(fscsr)
|
|
||||||
DEF_ASM(fsflags)
|
|
||||||
DEF_ASM(fsrm)
|
|
||||||
|
|
||||||
/* Privileged Instructions */
|
|
||||||
|
|
||||||
DEF_ASM(mrts)
|
|
||||||
DEF_ASM(mrth)
|
|
||||||
DEF_ASM(hrts)
|
|
||||||
DEF_ASM(wfi)
|
|
||||||
|
|
||||||
/* pseudoinstructions */
|
|
||||||
DEF_ASM(beqz)
|
|
||||||
DEF_ASM(bgez)
|
|
||||||
DEF_ASM(bgt)
|
|
||||||
DEF_ASM(bgtu)
|
|
||||||
DEF_ASM(bgtz)
|
|
||||||
DEF_ASM(ble)
|
|
||||||
DEF_ASM(bleu)
|
|
||||||
DEF_ASM(blez)
|
|
||||||
DEF_ASM(bltz)
|
|
||||||
DEF_ASM(bnez)
|
|
||||||
DEF_ASM(call)
|
|
||||||
DEF_ASM_WITH_SUFFIX(fabs, d)
|
|
||||||
DEF_ASM_WITH_SUFFIX(fabs, s)
|
|
||||||
DEF_ASM(fld)
|
|
||||||
DEF_ASM(flw)
|
|
||||||
DEF_ASM_WITH_SUFFIX(fmv, d)
|
|
||||||
DEF_ASM_WITH_SUFFIX(fmv, s)
|
|
||||||
DEF_ASM_WITH_SUFFIX(fneg, d)
|
|
||||||
DEF_ASM_WITH_SUFFIX(fneg, s)
|
|
||||||
DEF_ASM(fsd)
|
|
||||||
DEF_ASM(fsw)
|
|
||||||
DEF_ASM(j)
|
|
||||||
DEF_ASM(jump)
|
|
||||||
DEF_ASM(jr)
|
|
||||||
DEF_ASM(la)
|
|
||||||
DEF_ASM(li)
|
|
||||||
DEF_ASM(lla)
|
|
||||||
DEF_ASM(mv)
|
|
||||||
DEF_ASM(neg)
|
|
||||||
DEF_ASM(negw)
|
|
||||||
DEF_ASM(nop)
|
|
||||||
DEF_ASM(not)
|
|
||||||
DEF_ASM(ret)
|
|
||||||
DEF_ASM(seqz)
|
|
||||||
DEF_ASM_WITH_SUFFIX(sext, w)
|
|
||||||
DEF_ASM(sgtz)
|
|
||||||
DEF_ASM(sltz)
|
|
||||||
DEF_ASM(snez)
|
|
||||||
DEF_ASM(tail)
|
|
||||||
|
|
||||||
/* Possible values for .option directive */
|
|
||||||
DEF_ASM(arch)
|
|
||||||
DEF_ASM(rvc)
|
|
||||||
DEF_ASM(norvc)
|
|
||||||
DEF_ASM(pic)
|
|
||||||
DEF_ASM(nopic)
|
|
||||||
DEF_ASM(relax)
|
|
||||||
DEF_ASM(norelax)
|
|
||||||
DEF_ASM(push)
|
|
||||||
DEF_ASM(pop)
|
|
||||||
|
|
||||||
/* “A” Standard Extension for Atomic Instructions, Version 2.1 */
|
|
||||||
/* XXX: Atomic memory operations */
|
|
||||||
DEF_ASM_WITH_SUFFIX(lr, w)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(lr, w, aq)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(lr, w, rl)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(lr, w, aqrl)
|
|
||||||
|
|
||||||
DEF_ASM_WITH_SUFFIX(lr, d)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(lr, d, aq)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(lr, d, rl)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(lr, d, aqrl)
|
|
||||||
|
|
||||||
|
|
||||||
DEF_ASM_WITH_SUFFIX(sc, w)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(sc, w, aq)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(sc, w, rl)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(sc, w, aqrl)
|
|
||||||
|
|
||||||
DEF_ASM_WITH_SUFFIX(sc, d)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(sc, d, aq)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(sc, d, rl)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(sc, d, aqrl)
|
|
||||||
|
|
||||||
/* "A" Extension for Atomic Operations, V2.1 (base, no aq/rl suffixes) */
|
|
||||||
DEF_ASM_WITH_SUFFIX(amoadd, w)
|
|
||||||
DEF_ASM_WITH_SUFFIX(amoadd, d)
|
|
||||||
DEF_ASM_WITH_SUFFIX(amoswap, w)
|
|
||||||
DEF_ASM_WITH_SUFFIX(amoswap, d)
|
|
||||||
DEF_ASM_WITH_SUFFIX(amoand, w)
|
|
||||||
DEF_ASM_WITH_SUFFIX(amoand, d)
|
|
||||||
DEF_ASM_WITH_SUFFIX(amoor, w)
|
|
||||||
DEF_ASM_WITH_SUFFIX(amoor, d)
|
|
||||||
DEF_ASM_WITH_SUFFIX(amoxor, w)
|
|
||||||
DEF_ASM_WITH_SUFFIX(amoxor, d)
|
|
||||||
DEF_ASM_WITH_SUFFIX(amomax, w)
|
|
||||||
DEF_ASM_WITH_SUFFIX(amomax, d)
|
|
||||||
DEF_ASM_WITH_SUFFIX(amomaxu, w)
|
|
||||||
DEF_ASM_WITH_SUFFIX(amomaxu, d)
|
|
||||||
DEF_ASM_WITH_SUFFIX(amomin, w)
|
|
||||||
DEF_ASM_WITH_SUFFIX(amomin, d)
|
|
||||||
DEF_ASM_WITH_SUFFIX(amominu, w)
|
|
||||||
DEF_ASM_WITH_SUFFIX(amominu, d)
|
|
||||||
|
|
||||||
|
|
||||||
/* AMO aq/rl ordering suffixes */
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amoadd, w, aq)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amoadd, w, rl)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amoadd, w, aqrl)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amoadd, d, aq)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amoadd, d, rl)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amoadd, d, aqrl)
|
|
||||||
/* Complete AMO aq/rl ordering suffixes (all ops) */
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amoswap, w, aq)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amoswap, w, rl)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amoswap, w, aqrl)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amoswap, d, aq)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amoswap, d, rl)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amoswap, d, aqrl)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amoand, w, aq)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amoand, w, rl)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amoand, w, aqrl)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amoand, d, aq)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amoand, d, rl)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amoand, d, aqrl)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amoor, w, aq)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amoor, w, rl)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amoor, w, aqrl)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amoor, d, aq)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amoor, d, rl)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amoor, d, aqrl)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amoxor, w, aq)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amoxor, w, rl)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amoxor, w, aqrl)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amoxor, d, aq)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amoxor, d, rl)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amoxor, d, aqrl)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amomax, w, aq)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amomax, w, rl)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amomax, w, aqrl)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amomax, d, aq)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amomax, d, rl)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amomax, d, aqrl)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amomaxu, w, aq)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amomaxu, w, rl)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amomaxu, w, aqrl)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amomaxu, d, aq)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amomaxu, d, rl)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amomaxu, d, aqrl)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amomin, w, aq)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amomin, w, rl)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amomin, w, aqrl)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amomin, d, aq)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amomin, d, rl)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amomin, d, aqrl)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amominu, w, aq)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amominu, w, rl)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amominu, w, aqrl)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amominu, d, aq)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amominu, d, rl)
|
|
||||||
DEF_ASM_WITH_SUFFIXES(amominu, d, aqrl)
|
|
||||||
|
|
||||||
|
|
||||||
/* rounding mode keywords (used as fcvt operand: fcvt.w.s rd, rs1, rtz) */
|
|
||||||
DEF_ASM(rne)
|
|
||||||
DEF_ASM(rtz)
|
|
||||||
DEF_ASM(rdn)
|
|
||||||
DEF_ASM(rup)
|
|
||||||
DEF_ASM(rmm)
|
|
||||||
|
|
||||||
/* `fence` arguments */
|
|
||||||
/* NOTE: Order is important */
|
|
||||||
DEF_ASM_FENCE(w)
|
|
||||||
DEF_ASM_FENCE(r)
|
|
||||||
DEF_ASM_FENCE(rw)
|
|
||||||
|
|
||||||
DEF_ASM_FENCE(o)
|
|
||||||
DEF_ASM_FENCE(ow)
|
|
||||||
DEF_ASM_FENCE(or)
|
|
||||||
DEF_ASM_FENCE(orw)
|
|
||||||
|
|
||||||
DEF_ASM_FENCE(i)
|
|
||||||
DEF_ASM_FENCE(iw)
|
|
||||||
DEF_ASM_FENCE(ir)
|
|
||||||
DEF_ASM_FENCE(irw)
|
|
||||||
|
|
||||||
DEF_ASM_FENCE(io)
|
|
||||||
DEF_ASM_FENCE(iow)
|
|
||||||
DEF_ASM_FENCE(ior)
|
|
||||||
DEF_ASM_FENCE(iorw)
|
|
||||||
|
|
||||||
#undef DEF_ASM_FENCE
|
|
||||||
#undef DEF_ASM_WITH_SUFFIX
|
|
||||||
#undef DEF_ASM_WITH_SUFFIXES
|
|
||||||
15
stdarg.h
Normal file
15
stdarg.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef _STDARG_H
|
||||||
|
#define _STDARG_H
|
||||||
|
|
||||||
|
typedef char *va_list;
|
||||||
|
|
||||||
|
/* only correct for i386 */
|
||||||
|
#define va_start(ap,last) ap = ((char *)&(last)) + ((sizeof(last)+3)&~3)
|
||||||
|
#define va_arg(ap,type) (ap += (sizeof(type)+3)&~3, *(type *)(ap - ((sizeof(type)+3)&~3)))
|
||||||
|
#define va_end(ap)
|
||||||
|
|
||||||
|
/* fix a buggy dependency on GCC in libio.h */
|
||||||
|
typedef va_list __gnuc_va_list;
|
||||||
|
#define _VA_LIST_DEFINED
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -6,6 +6,5 @@
|
|||||||
#define bool _Bool
|
#define bool _Bool
|
||||||
#define true 1
|
#define true 1
|
||||||
#define false 0
|
#define false 0
|
||||||
#define __bool_true_false_are_defined 1
|
|
||||||
|
|
||||||
#endif /* _STDBOOL_H */
|
#endif /* _STDBOOL_H */
|
||||||
21
stddef.h
Normal file
21
stddef.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#ifndef _STDDEF_H
|
||||||
|
#define _STDDEF_H
|
||||||
|
|
||||||
|
#define NULL ((void *)0)
|
||||||
|
typedef __SIZE_TYPE__ size_t;
|
||||||
|
typedef __WCHAR_TYPE__ wchar_t;
|
||||||
|
typedef __PTRDIFF_TYPE__ ptrdiff_t;
|
||||||
|
#define offsetof(type, field) ((size_t) &((type *)0)->field)
|
||||||
|
|
||||||
|
/* need to do that because of glibc 2.1 bug (should have a way to test
|
||||||
|
presence of 'long long' without __GNUC__, or TCC should define
|
||||||
|
__GNUC__ ? */
|
||||||
|
#ifndef __int8_t_defined
|
||||||
|
#define __int8_t_defined
|
||||||
|
typedef char int8_t;
|
||||||
|
typedef short int int16_t;
|
||||||
|
typedef int int32_t;
|
||||||
|
typedef long long int int64_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
568
tcc-doc.texi
568
tcc-doc.texi
@ -2,10 +2,6 @@
|
|||||||
@c %**start of header
|
@c %**start of header
|
||||||
@setfilename tcc-doc.info
|
@setfilename tcc-doc.info
|
||||||
@settitle Tiny C Compiler Reference Documentation
|
@settitle Tiny C Compiler Reference Documentation
|
||||||
@dircategory Software development
|
|
||||||
@direntry
|
|
||||||
* TCC: (tcc-doc). The Tiny C Compiler.
|
|
||||||
@end direntry
|
|
||||||
@c %**end of header
|
@c %**end of header
|
||||||
|
|
||||||
@include config.texi
|
@include config.texi
|
||||||
@ -20,8 +16,11 @@
|
|||||||
@headings double
|
@headings double
|
||||||
@end iftex
|
@end iftex
|
||||||
|
|
||||||
|
@c @ifhtml
|
||||||
@contents
|
@contents
|
||||||
|
@c @end ifhtml
|
||||||
|
|
||||||
|
@ifnothtml
|
||||||
@node Top, Introduction, (dir), (dir)
|
@node Top, Introduction, (dir), (dir)
|
||||||
@top Tiny C Compiler Reference Documentation
|
@top Tiny C Compiler Reference Documentation
|
||||||
|
|
||||||
@ -30,14 +29,10 @@ This manual documents version @value{VERSION} of the Tiny C Compiler.
|
|||||||
@menu
|
@menu
|
||||||
* Introduction:: Introduction to tcc.
|
* Introduction:: Introduction to tcc.
|
||||||
* Invoke:: Invocation of tcc (command line, options).
|
* Invoke:: Invocation of tcc (command line, options).
|
||||||
* Clang:: ANSI C and extensions.
|
|
||||||
* asm:: Assembler syntax.
|
|
||||||
* linker:: Output file generation and supported targets.
|
|
||||||
* Bounds:: Automatic bounds-checking of C code.
|
* Bounds:: Automatic bounds-checking of C code.
|
||||||
* Libtcc:: The libtcc library.
|
* Libtcc:: The libtcc library.
|
||||||
* devel:: Guide for Developers.
|
|
||||||
@end menu
|
@end menu
|
||||||
|
@end ifnothtml
|
||||||
|
|
||||||
@node Introduction
|
@node Introduction
|
||||||
@chapter Introduction
|
@chapter Introduction
|
||||||
@ -47,7 +42,7 @@ compilers, it is meant to be self-relying: you do not need an
|
|||||||
external assembler or linker because TCC does that for you.
|
external assembler or linker because TCC does that for you.
|
||||||
|
|
||||||
TCC compiles so @emph{fast} that even for big projects @code{Makefile}s may
|
TCC compiles so @emph{fast} that even for big projects @code{Makefile}s may
|
||||||
not be necessary.
|
not be necessary.
|
||||||
|
|
||||||
TCC not only supports ANSI C, but also most of the new ISO C99
|
TCC not only supports ANSI C, but also most of the new ISO C99
|
||||||
standard and many GNUC extensions including inline assembly.
|
standard and many GNUC extensions including inline assembly.
|
||||||
@ -63,16 +58,11 @@ these checks even if non patched libraries are used.
|
|||||||
With @code{libtcc}, you can use TCC as a backend for dynamic code
|
With @code{libtcc}, you can use TCC as a backend for dynamic code
|
||||||
generation (@pxref{Libtcc}).
|
generation (@pxref{Libtcc}).
|
||||||
|
|
||||||
TCC mainly supports the i386 target on Linux and Windows. There are alpha
|
|
||||||
ports for the ARM (@code{arm-tcc}) and the TMS320C67xx targets
|
|
||||||
(@code{c67-tcc}). More information about the ARM port is available at
|
|
||||||
@url{http://lists.gnu.org/archive/html/tinycc-devel/2003-10/msg00044.html}.
|
|
||||||
|
|
||||||
For usage on Windows, see also @url{tcc-win32.txt}.
|
|
||||||
|
|
||||||
@node Invoke
|
@node Invoke
|
||||||
@chapter Command line invocation
|
@chapter Command line invocation
|
||||||
|
|
||||||
|
[This manual documents version @value{VERSION} of the Tiny C Compiler]
|
||||||
|
|
||||||
@section Quick start
|
@section Quick start
|
||||||
|
|
||||||
@example
|
@example
|
||||||
@ -83,7 +73,7 @@ usage: tcc [options] [@var{infile1} @var{infile2}@dots{}] [@option{-run} @var{in
|
|||||||
|
|
||||||
@noindent
|
@noindent
|
||||||
@c man begin DESCRIPTION
|
@c man begin DESCRIPTION
|
||||||
TCC options are very much like gcc options. The main difference is that TCC
|
TCC options are a very much like gcc options. The main difference is that TCC
|
||||||
can also execute directly the resulting program and give it runtime
|
can also execute directly the resulting program and give it runtime
|
||||||
arguments.
|
arguments.
|
||||||
|
|
||||||
@ -99,11 +89,9 @@ the @code{main()} of a.c.
|
|||||||
|
|
||||||
@item @samp{tcc a.c -run b.c arg1}
|
@item @samp{tcc a.c -run b.c arg1}
|
||||||
Compile @file{a.c} and @file{b.c}, link them together and execute them. arg1 is given
|
Compile @file{a.c} and @file{b.c}, link them together and execute them. arg1 is given
|
||||||
as first argument to the @code{main()} of the resulting program.
|
as first argument to the @code{main()} of the resulting program. Because
|
||||||
@ignore
|
multiple C files are specified, @option{--} are necessary to clearly separate the
|
||||||
Because multiple C files are specified, @option{--} are necessary to clearly
|
program arguments from the TCC options.
|
||||||
separate the program arguments from the TCC options.
|
|
||||||
@end ignore
|
|
||||||
|
|
||||||
@item @samp{tcc -o myprog a.c b.c}
|
@item @samp{tcc -o myprog a.c b.c}
|
||||||
Compile @file{a.c} and @file{b.c}, link them and generate the executable @file{myprog}.
|
Compile @file{a.c} and @file{b.c}, link them and generate the executable @file{myprog}.
|
||||||
@ -142,13 +130,6 @@ int main()
|
|||||||
return 0;
|
return 0;
|
||||||
@}
|
@}
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
TCC can read C source code from @emph{standard input} when @option{-} is used in
|
|
||||||
place of @option{infile}. Example:
|
|
||||||
|
|
||||||
@example
|
|
||||||
echo 'main()@{puts("hello");@}' | tcc -run -
|
|
||||||
@end example
|
|
||||||
@c man end
|
@c man end
|
||||||
|
|
||||||
@section Option summary
|
@section Option summary
|
||||||
@ -157,34 +138,44 @@ General Options:
|
|||||||
|
|
||||||
@c man begin OPTIONS
|
@c man begin OPTIONS
|
||||||
@table @option
|
@table @option
|
||||||
|
@item -v
|
||||||
|
Display current TCC version.
|
||||||
|
|
||||||
@item -c
|
@item -c
|
||||||
Generate an object file.
|
Generate an object file (@option{-o} option must also be given).
|
||||||
|
|
||||||
@item -o outfile
|
@item -o outfile
|
||||||
Put object file, executable, or dll into output file @file{outfile}.
|
Put object file, executable, or dll into output file @file{outfile}.
|
||||||
|
|
||||||
|
@item -Bdir
|
||||||
|
Set the path where the tcc internal libraries can be found (default is
|
||||||
|
@file{PREFIX/lib/tcc}).
|
||||||
|
|
||||||
|
@item -bench
|
||||||
|
Output compilation statistics.
|
||||||
|
|
||||||
@item -run source [args...]
|
@item -run source [args...]
|
||||||
|
|
||||||
Compile file @var{source} and run it with the command line arguments
|
Compile file @var{source} and run it with the command line arguments
|
||||||
@var{args}. In order to be able to give more than one argument to a
|
@var{args}. In order to be able to give more than one argument to a
|
||||||
script, several TCC options can be given @emph{after} the
|
script, several TCC options can be given @emph{after} the
|
||||||
@option{-run} option, separated by spaces:
|
@option{-run} option, separated by spaces. Example:
|
||||||
|
|
||||||
@example
|
@example
|
||||||
tcc "-run -L/usr/X11R6/lib -lX11" ex4.c
|
tcc "-run -L/usr/X11R6/lib -lX11" ex4.c
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
In a script, it gives the following header:
|
In a script, it gives the following header:
|
||||||
|
|
||||||
@example
|
@example
|
||||||
#!/usr/local/bin/tcc -run -L/usr/X11R6/lib -lX11
|
#!/usr/local/bin/tcc -run -L/usr/X11R6/lib -lX11
|
||||||
|
#include <stdlib.h>
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
@{
|
||||||
|
...
|
||||||
|
@}
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
@item -v
|
|
||||||
Display TCC version.
|
|
||||||
|
|
||||||
@item -vv
|
|
||||||
Show included files. As sole argument, print search dirs. -vvv shows tries too.
|
|
||||||
|
|
||||||
@item -bench
|
|
||||||
Display compilation statistics.
|
|
||||||
|
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
Preprocessor options:
|
Preprocessor options:
|
||||||
@ -199,16 +190,6 @@ include paths are: @file{/usr/local/include}, @file{/usr/include}
|
|||||||
and @file{PREFIX/lib/tcc/include}. (@file{PREFIX} is usually
|
and @file{PREFIX/lib/tcc/include}. (@file{PREFIX} is usually
|
||||||
@file{/usr} or @file{/usr/local}).
|
@file{/usr} or @file{/usr/local}).
|
||||||
|
|
||||||
@item -isystem dir
|
|
||||||
Specify a system include path to be added to the defaults.
|
|
||||||
|
|
||||||
@item -nostdinc
|
|
||||||
Do not search the default system include paths; only search include paths
|
|
||||||
provided on the command line.
|
|
||||||
|
|
||||||
@item -include file
|
|
||||||
Include @option{file} above each input file.
|
|
||||||
|
|
||||||
@item -Dsym[=val]
|
@item -Dsym[=val]
|
||||||
Define preprocessor symbol @samp{sym} to
|
Define preprocessor symbol @samp{sym} to
|
||||||
val. If val is not present, its value is @samp{1}. Function-like macros can
|
val. If val is not present, its value is @samp{1}. Function-like macros can
|
||||||
@ -216,63 +197,6 @@ also be defined: @option{-DF(a)=a+1}
|
|||||||
|
|
||||||
@item -Usym
|
@item -Usym
|
||||||
Undefine preprocessor symbol @samp{sym}.
|
Undefine preprocessor symbol @samp{sym}.
|
||||||
|
|
||||||
@item -E
|
|
||||||
Preprocess only, to stdout or file (with -o).
|
|
||||||
|
|
||||||
@item -P
|
|
||||||
Do not output @code{#line} directives.
|
|
||||||
|
|
||||||
@item -P1
|
|
||||||
Output alternative @code{#line} directives.
|
|
||||||
|
|
||||||
@item -dD, -dM
|
|
||||||
Output @code{#define} directives.
|
|
||||||
|
|
||||||
@item -Wp,-opt
|
|
||||||
Same as @option{-opt}.
|
|
||||||
|
|
||||||
@end table
|
|
||||||
|
|
||||||
Compilation flags:
|
|
||||||
|
|
||||||
Note: each of the following options has a negative form beginning with
|
|
||||||
@option{-fno-}.
|
|
||||||
|
|
||||||
@table @option
|
|
||||||
@item -funsigned-char
|
|
||||||
Let the @code{char} type be unsigned.
|
|
||||||
|
|
||||||
@item -fsigned-char
|
|
||||||
Let the @code{char} type be signed.
|
|
||||||
|
|
||||||
@item -fno-common
|
|
||||||
Do not generate common symbols for uninitialized data.
|
|
||||||
|
|
||||||
@item -fleading-underscore
|
|
||||||
Add a leading underscore at the beginning of each C symbol.
|
|
||||||
|
|
||||||
@item -fms-extensions
|
|
||||||
Allow a MS C compiler extensions to the language. Currently this
|
|
||||||
assumes a nested named structure declaration without an identifier
|
|
||||||
behaves like an unnamed one.
|
|
||||||
|
|
||||||
@item -fdollars-in-identifiers
|
|
||||||
Allow dollar signs in identifiers
|
|
||||||
|
|
||||||
@item -freverse-funcargs
|
|
||||||
Evaluate function arguments right to left.
|
|
||||||
|
|
||||||
@item -fgnu89-inline
|
|
||||||
@code{extern inline} is like @code{static inline}.
|
|
||||||
|
|
||||||
@item -fasynchronous-unwind-tables
|
|
||||||
Create eh_frame section [on]
|
|
||||||
|
|
||||||
@item -ftest-coverage
|
|
||||||
Create code coverage code. After running the resulting code an executable.tcov
|
|
||||||
or sofile.tcov file is generated with code coverage.
|
|
||||||
|
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
Warning options:
|
Warning options:
|
||||||
@ -287,27 +211,19 @@ Note: each of the following warning options has a negative form beginning with
|
|||||||
@option{-Wno-}.
|
@option{-Wno-}.
|
||||||
|
|
||||||
@table @option
|
@table @option
|
||||||
@item -Wimplicit-function-declaration
|
|
||||||
Warn about implicit function declaration (missing prototype).
|
|
||||||
|
|
||||||
@item -Wdiscarded-qualifiers
|
|
||||||
Warn when const is dropped.
|
|
||||||
|
|
||||||
@item -Wunsupported
|
@item -Wunsupported
|
||||||
Warn about unsupported GCC features that are ignored by TCC.
|
Warn about unsupported GCC features that are ignored by TCC.
|
||||||
|
|
||||||
@item -Wwrite-strings
|
@item -Wwrite-strings
|
||||||
Make string constants be of type @code{const char *} instead of @code{char
|
Make string constants being of type @code{const char *} intead of @code{char
|
||||||
*}.
|
*}.
|
||||||
|
|
||||||
@item -Werror
|
@item -Werror
|
||||||
Abort compilation if a warning is issued. Can be given an option to enable
|
Abort compilation if warnings are issued.
|
||||||
the specified warning and turn it into an error, for example
|
|
||||||
@option{-Werror=unsupported}.
|
|
||||||
|
|
||||||
@item -Wall
|
@item -Wall
|
||||||
Activate some useful warnings (@option{-Wimplicit-function-declaration},
|
Activate all warnings, except @option{-Werror}, @option{-Wunusupported} and
|
||||||
@option{-Wdiscard-qualifiers}).
|
@option{-Wwrite-strings} (currently not useful).
|
||||||
|
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
@ -321,85 +237,23 @@ default library paths are @file{/usr/local/lib}, @file{/usr/lib} and @file{/lib}
|
|||||||
@item -lxxx
|
@item -lxxx
|
||||||
Link your program with dynamic library libxxx.so or static library
|
Link your program with dynamic library libxxx.so or static library
|
||||||
libxxx.a. The library is searched in the paths specified by the
|
libxxx.a. The library is searched in the paths specified by the
|
||||||
@option{-L} option and @env{LIBRARY_PATH} variable.
|
@option{-L} option.
|
||||||
|
|
||||||
@item -Bdir
|
|
||||||
Set the path where the tcc internal libraries (and include files) can be
|
|
||||||
found (default is @file{PREFIX/lib/tcc}).
|
|
||||||
|
|
||||||
@item -shared
|
@item -shared
|
||||||
Generate a shared library instead of an executable.
|
Generate a shared library instead of an executable (@option{-o} option
|
||||||
|
must also be given).
|
||||||
@item -soname name
|
|
||||||
set name for shared library to be used at runtime
|
|
||||||
|
|
||||||
@item -static
|
@item -static
|
||||||
Generate a statically linked executable (default is a shared linked
|
Generate a statically linked executable (default is a shared linked
|
||||||
executable).
|
executable) (@option{-o} option must also be given).
|
||||||
|
|
||||||
@item -rdynamic
|
@item -rdynamic
|
||||||
Export global symbols to the dynamic linker. It is useful when a library
|
Export global symbols to the dynamic linker. It is useful when a library
|
||||||
opened with @code{dlopen()} needs to access executable symbols.
|
opened with @code{dlopen()} needs to access executable symbols.
|
||||||
|
|
||||||
@item -r
|
@item -r
|
||||||
Generate an object file combining all input files.
|
Generate an object file combining all input files (@option{-o} option must
|
||||||
|
also be given).
|
||||||
@item -nostdlib
|
|
||||||
Don't implicitly link with libc, the C runtime files, and libtcc1.
|
|
||||||
|
|
||||||
@item -Wl,-nostdlib
|
|
||||||
Don't search the default paths for libraries (@file{/usr/local/lib},
|
|
||||||
@file{/usr/lib} and @file{/lib}). Only the paths specified with @option{-L}
|
|
||||||
and @env{LIBRARY_PATH} are searched.
|
|
||||||
|
|
||||||
@item -Wl,-rpath=path
|
|
||||||
Put custom search path for dynamic libraries into executable.
|
|
||||||
|
|
||||||
@item -Wl,-Ipath
|
|
||||||
@item -Wl,--dynamic-linker=path
|
|
||||||
Set the ELF interpreter (dynamic linker). This defaults to the value of the
|
|
||||||
environment variable @env{LD_SO} if set, or a compiled-in default.
|
|
||||||
|
|
||||||
@item -Wl,--enable-new-dtags
|
|
||||||
When putting a custom search path for dynamic libraries into the executable,
|
|
||||||
create the new ELF dynamic tag DT_RUNPATH instead of the old legacy DT_RPATH.
|
|
||||||
|
|
||||||
@item -Wl,--oformat=fmt
|
|
||||||
Use @var{fmt} as output format. The supported output formats are:
|
|
||||||
@table @code
|
|
||||||
@item elf32-i386
|
|
||||||
ELF output format (default)
|
|
||||||
@item binary
|
|
||||||
Binary image (only for executable output)
|
|
||||||
@item coff
|
|
||||||
COFF output format (only for executable output for TMS320C67xx target)
|
|
||||||
@end table
|
|
||||||
|
|
||||||
@item -Wl,--export-all-symbols
|
|
||||||
@item -Wl,--export-dynamic
|
|
||||||
Export global symbols to the dynamic linker. It is useful when a library
|
|
||||||
opened with @code{dlopen()} needs to access executable symbols.
|
|
||||||
|
|
||||||
@item -Wl,-subsystem=console/gui/wince/...
|
|
||||||
Set type for PE (Windows) executables.
|
|
||||||
|
|
||||||
@item -Wl,-[Ttext=# | section-alignment=# | file-alignment=# | image-base=# | stack=#]
|
|
||||||
Modify executable layout.
|
|
||||||
|
|
||||||
@item -Wl,-[dynamicbase | nxcompat | high-entropy-va | tsaware]
|
|
||||||
@item -Wl,-[no-dynamicbase | no-nxcompat | no-high-entropy-va | no-tsaware]
|
|
||||||
@item -Wl,-[disable-dynamicbase | disable-nxcompat | disable-high-entropy-va | disable-tsaware]
|
|
||||||
Set or clear PE (Windows) executable header hardening flags. The
|
|
||||||
@option{-Wl,-high-entropy-va} option is supported on x86-64 and ARM64 PE
|
|
||||||
targets and implies @option{-Wl,-dynamicbase}. Clearing dynamicbase also
|
|
||||||
clears high-entropy-va. When @option{-Wl,-dynamicbase} is used for an
|
|
||||||
executable, TCC also enables base relocation emission for Windows ASLR.
|
|
||||||
|
|
||||||
@item -Wl,-Bsymbolic
|
|
||||||
Set DT_SYMBOLIC tag.
|
|
||||||
|
|
||||||
@item -Wl,-(no-)whole-archive
|
|
||||||
Turn on/off linking of all objects in archives.
|
|
||||||
|
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
@ -407,112 +261,24 @@ Debugger options:
|
|||||||
|
|
||||||
@table @option
|
@table @option
|
||||||
@item -g
|
@item -g
|
||||||
Generate run time stab debug information so that you get clear run time
|
Generate run time debug information so that you get clear run time
|
||||||
error messages: @code{ test.c:68: in function 'test5()': dereferencing
|
error messages: @code{ test.c:68: in function 'test5()': dereferencing
|
||||||
invalid pointer} instead of the laconic @code{Segmentation
|
invalid pointer} instead of the laconic @code{Segmentation
|
||||||
fault}.
|
fault}.
|
||||||
|
|
||||||
@item -gdwarf[-x]
|
|
||||||
Generate run time dwarf debug information instead of stab debug information.
|
|
||||||
|
|
||||||
@item -b
|
@item -b
|
||||||
Generate additional support code to check memory allocations and array/pointer
|
Generate additional support code to check
|
||||||
bounds (@pxref{Bounds}). @option{-g} is implied.
|
memory allocations and array/pointer bounds. @option{-g} is implied. Note
|
||||||
|
that the generated code is slower and bigger in this case.
|
||||||
|
|
||||||
@item -bt[N]
|
@item -bt N
|
||||||
Display N callers in stack traces. This is useful with @option{-g} or @option{-b}.
|
Display N callers in stack traces. This is useful with @option{-g} or
|
||||||
When activated, @code{__TCC_BACKTRACE__} is defined.
|
@option{-b}.
|
||||||
|
|
||||||
With executables, additional support for stack traces is included. A function
|
|
||||||
@code{ int tcc_backtrace(const char *fmt, ...); }
|
|
||||||
is provided to trigger a stack trace with a message on demand.
|
|
||||||
|
|
||||||
@end table
|
|
||||||
|
|
||||||
Misc options:
|
|
||||||
|
|
||||||
@table @option
|
|
||||||
|
|
||||||
@item -std=version
|
|
||||||
Define @code{__STDC_VERSION__}: @code{201112} if @option{version} is c11 or
|
|
||||||
gnu11; @code{199901} otherwise.
|
|
||||||
|
|
||||||
@item -x[c|a|b|n]
|
|
||||||
Specify content of next input file: respectively C, assembly, binary, or none.
|
|
||||||
|
|
||||||
@item -O[n]
|
|
||||||
Same as @option{-D__OPTIMIZE__} except for -O0.
|
|
||||||
|
|
||||||
@item -pthread
|
|
||||||
Preprocess with @option{-D_REENTRANT}, link with @option{-lpthread}.
|
|
||||||
|
|
||||||
@item -M
|
|
||||||
Just output makefile fragment with dependencies
|
|
||||||
|
|
||||||
@item -MM
|
|
||||||
Like -M except mention only user header files, not system header files.
|
|
||||||
|
|
||||||
@item -MD
|
|
||||||
Generate makefile fragment with dependencies.
|
|
||||||
|
|
||||||
@item -MMD
|
|
||||||
Like -MD except mention only user header files, not system header files.
|
|
||||||
|
|
||||||
@item -MF depfile
|
|
||||||
Use @file{depfile} as output for -MD.
|
|
||||||
|
|
||||||
@item -MP
|
|
||||||
Mention all dependencies as targets too.
|
|
||||||
|
|
||||||
@item -print-search-dirs
|
|
||||||
Print the configured installation directory and a list of library
|
|
||||||
and include directories tcc will search.
|
|
||||||
|
|
||||||
@item -dumpversion
|
|
||||||
Print version.
|
|
||||||
|
|
||||||
@item -dt
|
|
||||||
With @option{-run}/@option{-E}: auto-define 'test_...' macros
|
|
||||||
|
|
||||||
@end table
|
|
||||||
|
|
||||||
Target specific options:
|
|
||||||
|
|
||||||
@table @option
|
|
||||||
@item -mms-bitfields
|
|
||||||
Use an algorithm for bitfield alignment consistent with MSVC. Default is
|
|
||||||
gcc's algorithm.
|
|
||||||
|
|
||||||
@item -mfloat-abi (ARM only)
|
|
||||||
Select the float ABI. Possible values: @code{softfp} and @code{hard}
|
|
||||||
|
|
||||||
@item -mno-sse
|
|
||||||
Do not use sse registers on x86_64
|
|
||||||
|
|
||||||
@item -m32, -m64
|
|
||||||
Pass command line to the i386/x86_64 cross compiler.
|
|
||||||
|
|
||||||
@end table
|
|
||||||
|
|
||||||
Note: GCC options @option{-fx} and @option{-mx} are ignored.
|
|
||||||
@c man end
|
|
||||||
|
|
||||||
@c man begin ENVIRONMENT
|
|
||||||
Environment variables that affect how tcc operates.
|
|
||||||
|
|
||||||
@table @option
|
|
||||||
|
|
||||||
@item CPATH
|
|
||||||
@item C_INCLUDE_PATH
|
|
||||||
A colon-separated list of directories searched for include files,
|
|
||||||
directories given with @option{-I} are searched first.
|
|
||||||
|
|
||||||
@item LIBRARY_PATH
|
|
||||||
A colon-separated list of directories searched for libraries for the
|
|
||||||
@option{-l} option, directories given with @option{-L} are searched first.
|
|
||||||
|
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
|
Note: GCC options @option{-Ox}, @option{-fx} and @option{-mx} are
|
||||||
|
ignored.
|
||||||
@c man end
|
@c man end
|
||||||
|
|
||||||
@ignore
|
@ignore
|
||||||
@ -521,7 +287,6 @@ A colon-separated list of directories searched for libraries for the
|
|||||||
@settitle Tiny C Compiler
|
@settitle Tiny C Compiler
|
||||||
|
|
||||||
@c man begin SEEALSO
|
@c man begin SEEALSO
|
||||||
cpp(1),
|
|
||||||
gcc(1)
|
gcc(1)
|
||||||
@c man end
|
@c man end
|
||||||
|
|
||||||
@ -531,7 +296,6 @@ Fabrice Bellard
|
|||||||
|
|
||||||
@end ignore
|
@end ignore
|
||||||
|
|
||||||
@node Clang
|
|
||||||
@chapter C language support
|
@chapter C language support
|
||||||
|
|
||||||
@section ANSI C
|
@section ANSI C
|
||||||
@ -543,14 +307,13 @@ and floating point numbers (@code{long double}, @code{double}, and
|
|||||||
@section ISOC99 extensions
|
@section ISOC99 extensions
|
||||||
|
|
||||||
TCC implements many features of the new C standard: ISO C99. Currently
|
TCC implements many features of the new C standard: ISO C99. Currently
|
||||||
missing items are: complex and imaginary numbers.
|
missing items are: complex and imaginary numbers and variable length
|
||||||
|
arrays.
|
||||||
|
|
||||||
Currently implemented ISOC99 features:
|
Currently implemented ISOC99 features:
|
||||||
|
|
||||||
@itemize
|
@itemize
|
||||||
|
|
||||||
@item variable length arrays.
|
|
||||||
|
|
||||||
@item 64 bit @code{long long} types are fully supported.
|
@item 64 bit @code{long long} types are fully supported.
|
||||||
|
|
||||||
@item The boolean type @code{_Bool} is supported.
|
@item The boolean type @code{_Bool} is supported.
|
||||||
@ -634,44 +397,21 @@ instead of
|
|||||||
@}
|
@}
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
@cindex aligned attribute
|
|
||||||
@cindex packed attribute
|
|
||||||
@cindex section attribute
|
|
||||||
@cindex unused attribute
|
|
||||||
@cindex cdecl attribute
|
|
||||||
@cindex stdcall attribute
|
|
||||||
@cindex regparm attribute
|
|
||||||
@cindex dllexport attribute
|
|
||||||
@cindex nodecorate attribute
|
|
||||||
|
|
||||||
@item The keyword @code{__attribute__} is handled to specify variable or
|
@item The keyword @code{__attribute__} is handled to specify variable or
|
||||||
function attributes. The following attributes are supported:
|
function attributes. The following attributes are supported:
|
||||||
@itemize
|
@itemize
|
||||||
|
@item @code{aligned(n)}: align data to n bytes (must be a power of two).
|
||||||
|
|
||||||
@item @code{aligned(n)}: align a variable or a structure field to n bytes
|
@item @code{section(name)}: generate function or data in assembly
|
||||||
(must be a power of two).
|
section name (name is a string containing the section name) instead
|
||||||
|
of the default section.
|
||||||
@item @code{packed}: force alignment of a variable or a structure field to
|
|
||||||
1.
|
|
||||||
|
|
||||||
@item @code{section(name)}: generate function or data in assembly section
|
|
||||||
name (name is a string containing the section name) instead of the default
|
|
||||||
section.
|
|
||||||
|
|
||||||
@item @code{unused}: specify that the variable or the function is unused.
|
@item @code{unused}: specify that the variable or the function is unused.
|
||||||
|
|
||||||
@item @code{cdecl}: use standard C calling convention (default).
|
@item @code{cdecl}: use standard C calling convention.
|
||||||
|
|
||||||
@item @code{stdcall}: use Pascal-like calling convention.
|
@item @code{stdcall}: use Pascal-like calling convention.
|
||||||
|
|
||||||
@item @code{regparm(n)}: use fast i386 calling convention. @var{n} must be
|
|
||||||
between 1 and 3. The first @var{n} function parameters are respectively put in
|
|
||||||
registers @code{%eax}, @code{%edx} and @code{%ecx}.
|
|
||||||
|
|
||||||
@item @code{dllexport}: export function from dll/executable (win32 only)
|
|
||||||
|
|
||||||
@item @code{nodecorate}: do not apply any decorations that would otherwise be applied when exporting function from dll/executable (win32 only)
|
|
||||||
|
|
||||||
@end itemize
|
@end itemize
|
||||||
|
|
||||||
Here are some examples:
|
Here are some examples:
|
||||||
@ -747,29 +487,29 @@ operands are supported.
|
|||||||
@item @code{__builtin_types_compatible_p()} and @code{__builtin_constant_p()}
|
@item @code{__builtin_types_compatible_p()} and @code{__builtin_constant_p()}
|
||||||
are supported.
|
are supported.
|
||||||
|
|
||||||
@item @code{#pragma pack} is supported for win32 compatibility.
|
|
||||||
|
|
||||||
@end itemize
|
@end itemize
|
||||||
|
|
||||||
@section TinyCC extensions
|
@section TinyCC extensions
|
||||||
|
|
||||||
@itemize
|
@itemize
|
||||||
|
|
||||||
@item @code{__TINYC__} is a predefined macro to indicate that you use TCC.
|
@item @code{__TINYC__} is a predefined macro to @code{1} to
|
||||||
|
indicate that you use TCC.
|
||||||
|
|
||||||
@item @code{#!} at the start of a line is ignored to allow scripting.
|
@item @code{#!} at the start of a line is ignored to allow scripting.
|
||||||
|
|
||||||
@item Binary digits can be entered (@code{0b101} instead of
|
@item Binary digits can be entered (@code{0b101} instead of
|
||||||
@code{5}).
|
@code{5}).
|
||||||
|
|
||||||
|
@item @code{__BOUNDS_CHECKING_ON} is defined if bound checking is activated.
|
||||||
|
|
||||||
@end itemize
|
@end itemize
|
||||||
|
|
||||||
@node asm
|
|
||||||
@chapter TinyCC Assembler
|
@chapter TinyCC Assembler
|
||||||
|
|
||||||
Since version 0.9.16, TinyCC integrates its own assembler. TinyCC
|
Since version 0.9.16, TinyCC integrates its own assembler. TinyCC
|
||||||
assembler supports a gas-like syntax (GNU assembler). You can
|
assembler supports a gas-like syntax (GNU assembler). You can
|
||||||
deactivate assembler support if you want a smaller TinyCC executable
|
desactivate assembler support if you want a smaller TinyCC executable
|
||||||
(the C compiler does not rely on the assembler).
|
(the C compiler does not rely on the assembler).
|
||||||
|
|
||||||
TinyCC Assembler is used to handle files with @file{.S} (C
|
TinyCC Assembler is used to handle files with @file{.S} (C
|
||||||
@ -836,53 +576,39 @@ They can be defined several times in the same source. Use 'b'
|
|||||||
@section Directives
|
@section Directives
|
||||||
@cindex assembler directives
|
@cindex assembler directives
|
||||||
@cindex directives, assembler
|
@cindex directives, assembler
|
||||||
@cindex align directive
|
@cindex .align
|
||||||
@cindex skip directive
|
@cindex .skip
|
||||||
@cindex space directive
|
@cindex .space
|
||||||
@cindex byte directive
|
@cindex .byte
|
||||||
@cindex word directive
|
@cindex .word
|
||||||
@cindex short directive
|
@cindex .short
|
||||||
@cindex int directive
|
@cindex .int
|
||||||
@cindex long directive
|
@cindex .long
|
||||||
@cindex quad directive
|
@cindex .string
|
||||||
@cindex globl directive
|
@cindex .globl
|
||||||
@cindex global directive
|
@cindex .section
|
||||||
@cindex section directive
|
@cindex .text
|
||||||
@cindex text directive
|
@cindex .data
|
||||||
@cindex data directive
|
@cindex .bss
|
||||||
@cindex bss directive
|
|
||||||
@cindex fill directive
|
|
||||||
@cindex org directive
|
|
||||||
@cindex previous directive
|
|
||||||
@cindex string directive
|
|
||||||
@cindex asciz directive
|
|
||||||
@cindex ascii directive
|
|
||||||
|
|
||||||
All directives are preceded by a '.'. The following directives are
|
All directives are preceeded by a '.'. The following directives are
|
||||||
supported:
|
supported:
|
||||||
|
|
||||||
@itemize
|
@itemize
|
||||||
@item .align n[,value]
|
@item .align n[,value]
|
||||||
@item .skip n[,value]
|
@item .skip n[,value]
|
||||||
@item .space n[,value]
|
@item .space n[,value]
|
||||||
@item .byte value1[,...]
|
@item .byte value1[,value2...]
|
||||||
@item .word value1[,...]
|
@item .word value1[,value2...]
|
||||||
@item .short value1[,...]
|
@item .short value1[,value2...]
|
||||||
@item .int value1[,...]
|
@item .int value1[,value2...]
|
||||||
@item .long value1[,...]
|
@item .long value1[,value2...]
|
||||||
@item .quad immediate_value1[,...]
|
@item .string string
|
||||||
@item .globl symbol
|
|
||||||
@item .global symbol
|
@item .global symbol
|
||||||
@item .section section
|
@item .section section
|
||||||
@item .text
|
@item .text
|
||||||
@item .data
|
@item .data
|
||||||
@item .bss
|
@item .bss
|
||||||
@item .fill repeat[,size[,value]]
|
|
||||||
@item .org n
|
|
||||||
@item .previous
|
|
||||||
@item .string string[,...]
|
|
||||||
@item .asciz string[,...]
|
|
||||||
@item .ascii string[,...]
|
|
||||||
@end itemize
|
@end itemize
|
||||||
|
|
||||||
@section X86 Assembler
|
@section X86 Assembler
|
||||||
@ -894,7 +620,6 @@ tries to guess it from the operand sizes.
|
|||||||
|
|
||||||
Currently, MMX opcodes are supported but not SSE ones.
|
Currently, MMX opcodes are supported but not SSE ones.
|
||||||
|
|
||||||
@node linker
|
|
||||||
@chapter TinyCC Linker
|
@chapter TinyCC Linker
|
||||||
@cindex linker
|
@cindex linker
|
||||||
|
|
||||||
@ -919,14 +644,6 @@ options (@option{--start-group} and @option{--end-group}) are supported.
|
|||||||
TCC can load ELF object files, archives (.a files) and dynamic
|
TCC can load ELF object files, archives (.a files) and dynamic
|
||||||
libraries (.so).
|
libraries (.so).
|
||||||
|
|
||||||
@section PE-i386 file generation
|
|
||||||
@cindex PE-i386
|
|
||||||
|
|
||||||
TCC for Windows supports the native Win32 executable file format (PE-i386). It
|
|
||||||
generates EXE files (console and gui) and DLL files.
|
|
||||||
|
|
||||||
For usage on Windows, see also tcc-win32.txt.
|
|
||||||
|
|
||||||
@section GNU Linker Scripts
|
@section GNU Linker Scripts
|
||||||
@cindex scripts, linker
|
@cindex scripts, linker
|
||||||
@cindex linker scripts
|
@cindex linker scripts
|
||||||
@ -955,7 +672,16 @@ GROUP ( /lib/libc.so.6 /usr/lib/libc_nonshared.a )
|
|||||||
@cindex bound checks
|
@cindex bound checks
|
||||||
@cindex memory checks
|
@cindex memory checks
|
||||||
|
|
||||||
This feature is activated with the @option{-b} option (@pxref{Invoke}).
|
This feature is activated with the @option{-b} (@pxref{Invoke}).
|
||||||
|
|
||||||
|
Note that pointer size is @emph{unchanged} and that code generated
|
||||||
|
with bound checks is @emph{fully compatible} with unchecked
|
||||||
|
code. When a pointer comes from unchecked code, it is assumed to be
|
||||||
|
valid. Even very obscure C code with casts should work correctly.
|
||||||
|
|
||||||
|
For more information about the ideas behind this method, see
|
||||||
|
@url{http://www.doc.ic.ac.uk/~phjk/BoundsChecking.html}.
|
||||||
|
|
||||||
Here are some examples of caught errors:
|
Here are some examples of caught errors:
|
||||||
|
|
||||||
@table @asis
|
@table @asis
|
||||||
@ -984,7 +710,7 @@ Here are some examples of caught errors:
|
|||||||
int *tab;
|
int *tab;
|
||||||
tab = malloc(20 * sizeof(int));
|
tab = malloc(20 * sizeof(int));
|
||||||
for(i=0;i<21;i++) @{
|
for(i=0;i<21;i++) @{
|
||||||
sum += tab[i];
|
sum += tab4[i];
|
||||||
@}
|
@}
|
||||||
free(tab);
|
free(tab);
|
||||||
@}
|
@}
|
||||||
@ -997,7 +723,7 @@ Here are some examples of caught errors:
|
|||||||
tab = malloc(20 * sizeof(int));
|
tab = malloc(20 * sizeof(int));
|
||||||
free(tab);
|
free(tab);
|
||||||
for(i=0;i<20;i++) @{
|
for(i=0;i<20;i++) @{
|
||||||
sum += tab[i];
|
sum += tab4[i];
|
||||||
@}
|
@}
|
||||||
@}
|
@}
|
||||||
@end example
|
@end example
|
||||||
@ -1011,68 +737,9 @@ Here are some examples of caught errors:
|
|||||||
free(tab);
|
free(tab);
|
||||||
@}
|
@}
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
TCC defines @code{__TCC_BCHECK__} if activated.
|
|
||||||
|
|
||||||
There are five environment variables that can be used to control the behavior:
|
|
||||||
@itemize
|
|
||||||
@item TCC_BOUNDS_WARN_POINTER_ADD
|
|
||||||
- Print warning when pointer add creates an illegal pointer.
|
|
||||||
@item TCC_BOUNDS_PRINT_CALLS
|
|
||||||
- Print bound checking calls. Can be used for debugging.
|
|
||||||
@item TCC_BOUNDS_PRINT_HEAP
|
|
||||||
- Print heap objects that are not freed at exit of program.
|
|
||||||
@item TCC_BOUNDS_PRINT_STATISTIC
|
|
||||||
- Print statistic information at exit of program.
|
|
||||||
@item TCC_BOUNDS_NEVER_FATAL
|
|
||||||
- Try to continue in case of a bound checking error.
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
Also, a function @code{__bounds_checking(x)} can be used to turn off/on bounds
|
|
||||||
checking from usercode (see below).
|
|
||||||
|
|
||||||
Notes:
|
|
||||||
@itemize
|
|
||||||
@item Only available on i386 (linux and windows), x86_64 (linux and windows),
|
|
||||||
arm, arm64 and riscv64 for the moment.
|
|
||||||
@item The generated code is slower and bigger.
|
|
||||||
@item The bound checking code is not included in shared libraries. The main
|
|
||||||
executable should always be compiled with the @option{-b}.
|
|
||||||
@item Pointer size is @emph{unchanged} and code generated with bound checks is
|
|
||||||
@emph{fully compatible} with unchecked code. When a pointer comes from
|
|
||||||
unchecked code, it is assumed to be valid. Even very obscure C code with
|
|
||||||
casts should work correctly.
|
|
||||||
@item Signal handlers are not compatible with bounds checking. The
|
|
||||||
bounds checking code disables checking in signal/sigaction handlers.
|
|
||||||
The fork() function call in a multi threaded application is also a problem.
|
|
||||||
The bound checking code fixes this for the child process.
|
|
||||||
@item The reason that signals and fork have problems is that we use locking
|
|
||||||
inside the bounds checking code.
|
|
||||||
Inside a signal handler we can not use locks. Also in a multi threaded
|
|
||||||
application after a fork the child process can have the lock set
|
|
||||||
by another thread.
|
|
||||||
@item The BOUNDS_CHECKING_OFF and BOUNDS_CHECKING_ON can also be used to
|
|
||||||
disable bounds checking for some code.
|
|
||||||
@item The __bounds_checking call adds a value to a thread local value.
|
|
||||||
The value starts at 0. If the value is not 0 the code is not checked
|
|
||||||
for bounds checking errors.
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
@example
|
|
||||||
#ifdef __TCC_BCHECK__
|
|
||||||
extern void __bounds_checking (int x);
|
|
||||||
# define BOUNDS_CHECKING_OFF __bounds_checking(1)
|
|
||||||
# define BOUNDS_CHECKING_ON __bounds_checking(-1)
|
|
||||||
#else
|
|
||||||
# define BOUNDS_CHECKING_OFF
|
|
||||||
# define BOUNDS_CHECKING_ON
|
|
||||||
#endif
|
|
||||||
@end example
|
|
||||||
|
|
||||||
For more information about the ideas behind this method, see
|
|
||||||
@url{http://www.doc.ic.ac.uk/~phjk/BoundsChecking.html}.
|
|
||||||
|
|
||||||
@node Libtcc
|
@node Libtcc
|
||||||
@chapter The @code{libtcc} library
|
@chapter The @code{libtcc} library
|
||||||
|
|
||||||
@ -1086,7 +753,6 @@ The idea consists in giving a C string containing the program you want
|
|||||||
to compile directly to @code{libtcc}. Then you can access to any global
|
to compile directly to @code{libtcc}. Then you can access to any global
|
||||||
symbol (function or variable) defined.
|
symbol (function or variable) defined.
|
||||||
|
|
||||||
@node devel
|
|
||||||
@chapter Developer's guide
|
@chapter Developer's guide
|
||||||
|
|
||||||
This chapter gives some hints to understand how TCC works. You can skip
|
This chapter gives some hints to understand how TCC works. You can skip
|
||||||
@ -1127,7 +793,7 @@ reverse order, a first pass is done to reverse the argument order.
|
|||||||
|
|
||||||
@section Types
|
@section Types
|
||||||
|
|
||||||
The types are stored in a single 'int' variable. It was chosen in the
|
The types are stored in a single 'int' variable. It was choosen in the
|
||||||
first stages of development when tcc was much simpler. Now, it may not
|
first stages of development when tcc was much simpler. Now, it may not
|
||||||
be the best solution.
|
be the best solution.
|
||||||
|
|
||||||
@ -1150,13 +816,9 @@ be the best solution.
|
|||||||
#define VT_BTYPE 0x000f /* mask for basic type */
|
#define VT_BTYPE 0x000f /* mask for basic type */
|
||||||
#define VT_UNSIGNED 0x0010 /* unsigned type */
|
#define VT_UNSIGNED 0x0010 /* unsigned type */
|
||||||
#define VT_ARRAY 0x0020 /* array type (also has VT_PTR) */
|
#define VT_ARRAY 0x0020 /* array type (also has VT_PTR) */
|
||||||
#define VT_VLA 0x20000 /* VLA type (also has VT_PTR and VT_ARRAY) */
|
|
||||||
#define VT_BITFIELD 0x0040 /* bitfield modifier */
|
#define VT_BITFIELD 0x0040 /* bitfield modifier */
|
||||||
#define VT_CONSTANT 0x0800 /* const modifier */
|
|
||||||
#define VT_VOLATILE 0x1000 /* volatile modifier */
|
|
||||||
#define VT_DEFSIGN 0x2000 /* signed type */
|
|
||||||
|
|
||||||
#define VT_STRUCT_SHIFT 18 /* structure/enum name shift (14 bits left) */
|
#define VT_STRUCT_SHIFT 16 /* structure/enum name shift (16 bits left) */
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
When a reference to another type is needed (for pointers, functions and
|
When a reference to another type is needed (for pointers, functions and
|
||||||
@ -1167,8 +829,7 @@ The @code{VT_UNSIGNED} flag can be set for chars, shorts, ints and long
|
|||||||
longs.
|
longs.
|
||||||
|
|
||||||
Arrays are considered as pointers @code{VT_PTR} with the flag
|
Arrays are considered as pointers @code{VT_PTR} with the flag
|
||||||
@code{VT_ARRAY} set. Variable length arrays are considered as special
|
@code{VT_ARRAY} set.
|
||||||
arrays and have flag @code{VT_VLA} set instead of @code{VT_ARRAY}.
|
|
||||||
|
|
||||||
The @code{VT_BITFIELD} flag can be set for chars, shorts, ints and long
|
The @code{VT_BITFIELD} flag can be set for chars, shorts, ints and long
|
||||||
longs. If it is set, then the bitfield position is stored from bits
|
longs. If it is set, then the bitfield position is stored from bits
|
||||||
@ -1184,10 +845,6 @@ integer:
|
|||||||
#define VT_EXTERN 0x00000080 /* extern definition */
|
#define VT_EXTERN 0x00000080 /* extern definition */
|
||||||
#define VT_STATIC 0x00000100 /* static variable */
|
#define VT_STATIC 0x00000100 /* static variable */
|
||||||
#define VT_TYPEDEF 0x00000200 /* typedef definition */
|
#define VT_TYPEDEF 0x00000200 /* typedef definition */
|
||||||
#define VT_INLINE 0x00000400 /* inline definition */
|
|
||||||
#define VT_IMPORT 0x00004000 /* win32: extern data imported from dll */
|
|
||||||
#define VT_EXPORT 0x00008000 /* win32: data exported from dll */
|
|
||||||
#define VT_WEAK 0x00010000 /* win32: data exported from dll */
|
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
@section Symbols
|
@section Symbols
|
||||||
@ -1196,13 +853,10 @@ All symbols are stored in hashed symbol stacks. Each symbol stack
|
|||||||
contains @code{Sym} structures.
|
contains @code{Sym} structures.
|
||||||
|
|
||||||
@code{Sym.v} contains the symbol name (remember
|
@code{Sym.v} contains the symbol name (remember
|
||||||
an identifier is also a token, so a string is never necessary to store
|
an idenfier is also a token, so a string is never necessary to store
|
||||||
it). @code{Sym.t} gives the type of the symbol. @code{Sym.r} is usually
|
it). @code{Sym.t} gives the type of the symbol. @code{Sym.r} is usually
|
||||||
the register in which the corresponding variable is stored. @code{Sym.c} is
|
the register in which the corresponding variable is stored. @code{Sym.c} is
|
||||||
usually a constant associated to the symbol like its address for normal
|
usually a constant associated to the symbol.
|
||||||
symbols, and the number of entries for symbols representing arrays.
|
|
||||||
Variable length array types use @code{Sym.c} as a location on the stack
|
|
||||||
which holds the runtime sizeof for the type.
|
|
||||||
|
|
||||||
Four main symbol stacks are defined:
|
Four main symbol stacks are defined:
|
||||||
|
|
||||||
@ -1239,7 +893,7 @@ global stack.
|
|||||||
|
|
||||||
@section Sections
|
@section Sections
|
||||||
|
|
||||||
The generated code and data are written in sections. The structure
|
The generated code and datas are written in sections. The structure
|
||||||
@code{Section} contains all the necessary information for a given
|
@code{Section} contains all the necessary information for a given
|
||||||
section. @code{new_section()} creates a new section. ELF file semantics
|
section. @code{new_section()} creates a new section. ELF file semantics
|
||||||
is assumed for each section.
|
is assumed for each section.
|
||||||
@ -1264,7 +918,7 @@ are used when bound checking is activated
|
|||||||
|
|
||||||
@item stab_section
|
@item stab_section
|
||||||
@itemx stabstr_section
|
@itemx stabstr_section
|
||||||
are used when debugging is active to store debug information
|
are used when debugging is actived to store debug information
|
||||||
|
|
||||||
@item symtab_section
|
@item symtab_section
|
||||||
@itemx strtab_section
|
@itemx strtab_section
|
||||||
@ -1364,10 +1018,8 @@ if the lvalue has an integer type, then these flags give its real
|
|||||||
type. The type alone is not enough in case of cast optimisations.
|
type. The type alone is not enough in case of cast optimisations.
|
||||||
|
|
||||||
@item VT_LLOCAL
|
@item VT_LLOCAL
|
||||||
is a saved lvalue on the stack. @code{VT_LVAL} must also be set with
|
is a saved lvalue on the stack. @code{VT_LLOCAL} should be eliminated
|
||||||
@code{VT_LLOCAL}. @code{VT_LLOCAL} can arise when a @code{VT_LVAL} in
|
ASAP because its semantics are rather complicated.
|
||||||
a register has to be saved to the stack, or it can come from an
|
|
||||||
architecture-specific calling convention.
|
|
||||||
|
|
||||||
@item VT_MUSTCAST
|
@item VT_MUSTCAST
|
||||||
indicates that a cast to the value type must be performed if the value
|
indicates that a cast to the value type must be performed if the value
|
||||||
@ -1426,13 +1078,13 @@ should generate a function prolog/epilog.
|
|||||||
|
|
||||||
@item gen_opi(op)
|
@item gen_opi(op)
|
||||||
must generate the binary integer operation @var{op} on the two top
|
must generate the binary integer operation @var{op} on the two top
|
||||||
entries of the stack which are guaranteed to contain integer types.
|
entries of the stack which are guaranted to contain integer types.
|
||||||
|
|
||||||
The result value should be put on the stack.
|
The result value should be put on the stack.
|
||||||
|
|
||||||
@item gen_opf(op)
|
@item gen_opf(op)
|
||||||
same as @code{gen_opi()} for floating point operations. The two top
|
same as @code{gen_opi()} for floating point operations. The two top
|
||||||
entries of the stack are guaranteed to contain floating point values of
|
entries of the stack are guaranted to contain floating point values of
|
||||||
same types.
|
same types.
|
||||||
|
|
||||||
@item gen_cvt_itof()
|
@item gen_cvt_itof()
|
||||||
@ -1444,6 +1096,10 @@ floating point to integer conversion.
|
|||||||
@item gen_cvt_ftof()
|
@item gen_cvt_ftof()
|
||||||
floating point to floating point of different size conversion.
|
floating point to floating point of different size conversion.
|
||||||
|
|
||||||
|
@item gen_bounded_ptr_add()
|
||||||
|
@item gen_bounded_ptr_deref()
|
||||||
|
are only used for bounds checking.
|
||||||
|
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
@section Optimizations done
|
@section Optimizations done
|
||||||
|
|||||||
951
tcccoff.c
951
tcccoff.c
@ -1,951 +0,0 @@
|
|||||||
/*
|
|
||||||
* COFF file handling for TCC
|
|
||||||
*
|
|
||||||
* Copyright (c) 2003, 2004 TK
|
|
||||||
* Copyright (c) 2004 Fabrice Bellard
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "tcc.h"
|
|
||||||
|
|
||||||
/* XXX: this file uses tcc_error() to the effect of exit(1) */
|
|
||||||
#undef _tcc_error
|
|
||||||
|
|
||||||
#define MAXNSCNS 255 /* MAXIMUM NUMBER OF SECTIONS */
|
|
||||||
#define MAX_STR_TABLE 1000000
|
|
||||||
AOUTHDR o_filehdr; /* OPTIONAL (A.OUT) FILE HEADER */
|
|
||||||
|
|
||||||
SCNHDR section_header[MAXNSCNS];
|
|
||||||
|
|
||||||
#define MAX_FUNCS 1000
|
|
||||||
#define MAX_FUNC_NAME_LENGTH 128
|
|
||||||
|
|
||||||
int nFuncs;
|
|
||||||
char Func[MAX_FUNCS][MAX_FUNC_NAME_LENGTH];
|
|
||||||
char AssociatedFile[MAX_FUNCS][MAX_FUNC_NAME_LENGTH];
|
|
||||||
int LineNoFilePtr[MAX_FUNCS];
|
|
||||||
int EndAddress[MAX_FUNCS];
|
|
||||||
int LastLineNo[MAX_FUNCS];
|
|
||||||
int FuncEntries[MAX_FUNCS];
|
|
||||||
|
|
||||||
int OutputTheSection(Section * sect);
|
|
||||||
short int GetCoffFlags(const char *s);
|
|
||||||
void SortSymbolTable(TCCState *s1);
|
|
||||||
Section *FindSection(TCCState * s1, const char *sname);
|
|
||||||
|
|
||||||
int C67_main_entry_point;
|
|
||||||
|
|
||||||
int FindCoffSymbolIndex(TCCState * s1, const char *func_name);
|
|
||||||
int nb_syms;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
long tag;
|
|
||||||
long size;
|
|
||||||
long fileptr;
|
|
||||||
long nextsym;
|
|
||||||
short int dummy;
|
|
||||||
} AUXFUNC;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
long regmask;
|
|
||||||
unsigned short lineno;
|
|
||||||
unsigned short nentries;
|
|
||||||
int localframe;
|
|
||||||
int nextentry;
|
|
||||||
short int dummy;
|
|
||||||
} AUXBF;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
long dummy;
|
|
||||||
unsigned short lineno;
|
|
||||||
unsigned short dummy1;
|
|
||||||
int dummy2;
|
|
||||||
int dummy3;
|
|
||||||
unsigned short dummy4;
|
|
||||||
} AUXEF;
|
|
||||||
|
|
||||||
ST_FUNC int tcc_output_coff(TCCState *s1, FILE *f)
|
|
||||||
{
|
|
||||||
Section *tcc_sect;
|
|
||||||
SCNHDR *coff_sec;
|
|
||||||
int file_pointer;
|
|
||||||
char *Coff_str_table, *pCoff_str_table;
|
|
||||||
int CoffTextSectionNo, coff_nb_syms;
|
|
||||||
FILHDR file_hdr; /* FILE HEADER STRUCTURE */
|
|
||||||
Section *stext, *sdata, *sbss;
|
|
||||||
int i, NSectionsToOutput = 0;
|
|
||||||
|
|
||||||
Coff_str_table = pCoff_str_table = NULL;
|
|
||||||
|
|
||||||
stext = FindSection(s1, ".text");
|
|
||||||
sdata = FindSection(s1, ".data");
|
|
||||||
sbss = FindSection(s1, ".bss");
|
|
||||||
|
|
||||||
nb_syms = symtab_section->data_offset / sizeof(Elf32_Sym);
|
|
||||||
coff_nb_syms = FindCoffSymbolIndex(s1, "XXXXXXXXXX1");
|
|
||||||
|
|
||||||
file_hdr.f_magic = COFF_C67_MAGIC; /* magic number */
|
|
||||||
file_hdr.f_timdat = 0; /* time & date stamp */
|
|
||||||
file_hdr.f_opthdr = sizeof(AOUTHDR); /* sizeof(optional hdr) */
|
|
||||||
file_hdr.f_flags = 0x1143; /* flags (copied from what code composer does) */
|
|
||||||
file_hdr.f_TargetID = 0x99; /* for C6x = 0x0099 */
|
|
||||||
|
|
||||||
o_filehdr.magic = 0x0108; /* see magic.h */
|
|
||||||
o_filehdr.vstamp = 0x0190; /* version stamp */
|
|
||||||
o_filehdr.tsize = stext->data_offset; /* text size in bytes, padded to FW bdry */
|
|
||||||
o_filehdr.dsize = sdata->data_offset; /* initialized data " " */
|
|
||||||
o_filehdr.bsize = sbss->data_offset; /* uninitialized data " " */
|
|
||||||
o_filehdr.entrypt = C67_main_entry_point; /* entry pt. */
|
|
||||||
o_filehdr.text_start = stext->sh_addr; /* base of text used for this file */
|
|
||||||
o_filehdr.data_start = sdata->sh_addr; /* base of data used for this file */
|
|
||||||
|
|
||||||
|
|
||||||
// create all the section headers
|
|
||||||
|
|
||||||
file_pointer = FILHSZ + sizeof(AOUTHDR);
|
|
||||||
|
|
||||||
CoffTextSectionNo = -1;
|
|
||||||
|
|
||||||
for (i = 1; i < s1->nb_sections; i++) {
|
|
||||||
coff_sec = §ion_header[i];
|
|
||||||
tcc_sect = s1->sections[i];
|
|
||||||
|
|
||||||
if (OutputTheSection(tcc_sect)) {
|
|
||||||
NSectionsToOutput++;
|
|
||||||
|
|
||||||
if (CoffTextSectionNo == -1 && tcc_sect == stext)
|
|
||||||
CoffTextSectionNo = NSectionsToOutput; // rem which coff sect number the .text sect is
|
|
||||||
|
|
||||||
strcpy(coff_sec->s_name, tcc_sect->name); /* section name */
|
|
||||||
|
|
||||||
coff_sec->s_paddr = tcc_sect->sh_addr; /* physical address */
|
|
||||||
coff_sec->s_vaddr = tcc_sect->sh_addr; /* virtual address */
|
|
||||||
coff_sec->s_size = tcc_sect->data_offset; /* section size */
|
|
||||||
coff_sec->s_scnptr = 0; /* file ptr to raw data for section */
|
|
||||||
coff_sec->s_relptr = 0; /* file ptr to relocation */
|
|
||||||
coff_sec->s_lnnoptr = 0; /* file ptr to line numbers */
|
|
||||||
coff_sec->s_nreloc = 0; /* number of relocation entries */
|
|
||||||
coff_sec->s_flags = GetCoffFlags(coff_sec->s_name); /* flags */
|
|
||||||
coff_sec->s_reserved = 0; /* reserved byte */
|
|
||||||
coff_sec->s_page = 0; /* memory page id */
|
|
||||||
|
|
||||||
file_pointer += sizeof(SCNHDR);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
file_hdr.f_nscns = NSectionsToOutput; /* number of sections */
|
|
||||||
|
|
||||||
// now loop through and determine file pointer locations
|
|
||||||
// for the raw data
|
|
||||||
|
|
||||||
|
|
||||||
for (i = 1; i < s1->nb_sections; i++) {
|
|
||||||
coff_sec = §ion_header[i];
|
|
||||||
tcc_sect = s1->sections[i];
|
|
||||||
|
|
||||||
if (OutputTheSection(tcc_sect)) {
|
|
||||||
// put raw data
|
|
||||||
coff_sec->s_scnptr = file_pointer; /* file ptr to raw data for section */
|
|
||||||
file_pointer += coff_sec->s_size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// now loop through and determine file pointer locations
|
|
||||||
// for the relocation data
|
|
||||||
|
|
||||||
for (i = 1; i < s1->nb_sections; i++) {
|
|
||||||
coff_sec = §ion_header[i];
|
|
||||||
tcc_sect = s1->sections[i];
|
|
||||||
|
|
||||||
if (OutputTheSection(tcc_sect)) {
|
|
||||||
// put relocations data
|
|
||||||
if (coff_sec->s_nreloc > 0) {
|
|
||||||
coff_sec->s_relptr = file_pointer; /* file ptr to relocation */
|
|
||||||
file_pointer += coff_sec->s_nreloc * sizeof(struct reloc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// now loop through and determine file pointer locations
|
|
||||||
// for the line number data
|
|
||||||
|
|
||||||
for (i = 1; i < s1->nb_sections; i++) {
|
|
||||||
coff_sec = §ion_header[i];
|
|
||||||
tcc_sect = s1->sections[i];
|
|
||||||
|
|
||||||
coff_sec->s_nlnno = 0;
|
|
||||||
coff_sec->s_lnnoptr = 0;
|
|
||||||
|
|
||||||
if (s1->do_debug && tcc_sect == stext) {
|
|
||||||
// count how many line nos data
|
|
||||||
|
|
||||||
// also find association between source file name and function
|
|
||||||
// so we can sort the symbol table
|
|
||||||
|
|
||||||
|
|
||||||
Stab_Sym *sym, *sym_end;
|
|
||||||
char func_name[MAX_FUNC_NAME_LENGTH],
|
|
||||||
last_func_name[MAX_FUNC_NAME_LENGTH];
|
|
||||||
unsigned long func_addr, last_pc, pc;
|
|
||||||
const char *incl_files[INCLUDE_STACK_SIZE];
|
|
||||||
int incl_index, len, last_line_num;
|
|
||||||
const char *str, *p;
|
|
||||||
|
|
||||||
coff_sec->s_lnnoptr = file_pointer; /* file ptr to linno */
|
|
||||||
|
|
||||||
|
|
||||||
func_name[0] = '\0';
|
|
||||||
func_addr = 0;
|
|
||||||
incl_index = 0;
|
|
||||||
last_func_name[0] = '\0';
|
|
||||||
last_pc = 0xffffffff;
|
|
||||||
last_line_num = 1;
|
|
||||||
sym = (Stab_Sym *) stab_section->data + 1;
|
|
||||||
sym_end =
|
|
||||||
(Stab_Sym *) (stab_section->data +
|
|
||||||
stab_section->data_offset);
|
|
||||||
|
|
||||||
nFuncs = 0;
|
|
||||||
while (sym < sym_end) {
|
|
||||||
switch (sym->n_type) {
|
|
||||||
/* function start or end */
|
|
||||||
case N_FUN:
|
|
||||||
if (sym->n_strx == 0) {
|
|
||||||
// end of function
|
|
||||||
|
|
||||||
coff_sec->s_nlnno++;
|
|
||||||
file_pointer += LINESZ;
|
|
||||||
|
|
||||||
pc = sym->n_value + func_addr;
|
|
||||||
func_name[0] = '\0';
|
|
||||||
func_addr = 0;
|
|
||||||
EndAddress[nFuncs] = pc;
|
|
||||||
FuncEntries[nFuncs] =
|
|
||||||
(file_pointer -
|
|
||||||
LineNoFilePtr[nFuncs]) / LINESZ - 1;
|
|
||||||
LastLineNo[nFuncs++] = last_line_num + 1;
|
|
||||||
} else {
|
|
||||||
// beginning of function
|
|
||||||
|
|
||||||
LineNoFilePtr[nFuncs] = file_pointer;
|
|
||||||
coff_sec->s_nlnno++;
|
|
||||||
file_pointer += LINESZ;
|
|
||||||
|
|
||||||
str =
|
|
||||||
(const char *) stabstr_section->data +
|
|
||||||
sym->n_strx;
|
|
||||||
|
|
||||||
p = strchr(str, ':');
|
|
||||||
if (!p) {
|
|
||||||
pstrcpy(func_name, sizeof(func_name), str);
|
|
||||||
pstrcpy(Func[nFuncs], sizeof(func_name), str);
|
|
||||||
} else {
|
|
||||||
len = p - str;
|
|
||||||
if (len > sizeof(func_name) - 1)
|
|
||||||
len = sizeof(func_name) - 1;
|
|
||||||
memcpy(func_name, str, len);
|
|
||||||
memcpy(Func[nFuncs], str, len);
|
|
||||||
func_name[len] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
// save the file that it came in so we can sort later
|
|
||||||
pstrcpy(AssociatedFile[nFuncs], sizeof(func_name),
|
|
||||||
incl_files[incl_index - 1]);
|
|
||||||
|
|
||||||
func_addr = sym->n_value;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* line number info */
|
|
||||||
case N_SLINE:
|
|
||||||
pc = sym->n_value + func_addr;
|
|
||||||
|
|
||||||
last_pc = pc;
|
|
||||||
last_line_num = sym->n_desc;
|
|
||||||
|
|
||||||
/* XXX: slow! */
|
|
||||||
strcpy(last_func_name, func_name);
|
|
||||||
|
|
||||||
coff_sec->s_nlnno++;
|
|
||||||
file_pointer += LINESZ;
|
|
||||||
break;
|
|
||||||
/* include files */
|
|
||||||
case N_BINCL:
|
|
||||||
str =
|
|
||||||
(const char *) stabstr_section->data + sym->n_strx;
|
|
||||||
add_incl:
|
|
||||||
if (incl_index < INCLUDE_STACK_SIZE) {
|
|
||||||
incl_files[incl_index++] = str;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case N_EINCL:
|
|
||||||
if (incl_index > 1)
|
|
||||||
incl_index--;
|
|
||||||
break;
|
|
||||||
case N_SO:
|
|
||||||
if (sym->n_strx == 0) {
|
|
||||||
incl_index = 0; /* end of translation unit */
|
|
||||||
} else {
|
|
||||||
str =
|
|
||||||
(const char *) stabstr_section->data +
|
|
||||||
sym->n_strx;
|
|
||||||
/* do not add path */
|
|
||||||
len = strlen(str);
|
|
||||||
if (len > 0 && str[len - 1] != '/')
|
|
||||||
goto add_incl;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
sym++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
file_hdr.f_symptr = file_pointer; /* file pointer to symtab */
|
|
||||||
|
|
||||||
if (s1->do_debug)
|
|
||||||
file_hdr.f_nsyms = coff_nb_syms; /* number of symtab entries */
|
|
||||||
else
|
|
||||||
file_hdr.f_nsyms = 0;
|
|
||||||
|
|
||||||
file_pointer += file_hdr.f_nsyms * SYMNMLEN;
|
|
||||||
|
|
||||||
// OK now we are all set to write the file
|
|
||||||
|
|
||||||
|
|
||||||
fwrite(&file_hdr, FILHSZ, 1, f);
|
|
||||||
fwrite(&o_filehdr, sizeof(o_filehdr), 1, f);
|
|
||||||
|
|
||||||
// write section headers
|
|
||||||
for (i = 1; i < s1->nb_sections; i++) {
|
|
||||||
coff_sec = §ion_header[i];
|
|
||||||
tcc_sect = s1->sections[i];
|
|
||||||
|
|
||||||
if (OutputTheSection(tcc_sect)) {
|
|
||||||
fwrite(coff_sec, sizeof(SCNHDR), 1, f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// write raw data
|
|
||||||
for (i = 1; i < s1->nb_sections; i++) {
|
|
||||||
coff_sec = §ion_header[i];
|
|
||||||
tcc_sect = s1->sections[i];
|
|
||||||
|
|
||||||
if (OutputTheSection(tcc_sect)) {
|
|
||||||
fwrite(tcc_sect->data, tcc_sect->data_offset, 1, f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// write relocation data
|
|
||||||
for (i = 1; i < s1->nb_sections; i++) {
|
|
||||||
coff_sec = §ion_header[i];
|
|
||||||
tcc_sect = s1->sections[i];
|
|
||||||
|
|
||||||
if (OutputTheSection(tcc_sect)) {
|
|
||||||
// put relocations data
|
|
||||||
if (coff_sec->s_nreloc > 0) {
|
|
||||||
fwrite(tcc_sect->reloc,
|
|
||||||
coff_sec->s_nreloc * sizeof(struct reloc), 1, f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// group the symbols in order of filename, func1, func2, etc
|
|
||||||
// finally global symbols
|
|
||||||
|
|
||||||
if (s1->do_debug)
|
|
||||||
SortSymbolTable(s1);
|
|
||||||
|
|
||||||
// write line no data
|
|
||||||
|
|
||||||
for (i = 1; i < s1->nb_sections; i++) {
|
|
||||||
coff_sec = §ion_header[i];
|
|
||||||
tcc_sect = s1->sections[i];
|
|
||||||
|
|
||||||
if (s1->do_debug && tcc_sect == stext) {
|
|
||||||
// count how many line nos data
|
|
||||||
|
|
||||||
|
|
||||||
Stab_Sym *sym, *sym_end;
|
|
||||||
char func_name[128], last_func_name[128];
|
|
||||||
unsigned long func_addr, last_pc, pc;
|
|
||||||
const char *incl_files[INCLUDE_STACK_SIZE];
|
|
||||||
int incl_index, len, last_line_num;
|
|
||||||
const char *str, *p;
|
|
||||||
|
|
||||||
LINENO CoffLineNo;
|
|
||||||
|
|
||||||
func_name[0] = '\0';
|
|
||||||
func_addr = 0;
|
|
||||||
incl_index = 0;
|
|
||||||
last_func_name[0] = '\0';
|
|
||||||
last_pc = 0;
|
|
||||||
last_line_num = 1;
|
|
||||||
sym = (Stab_Sym *) stab_section->data + 1;
|
|
||||||
sym_end =
|
|
||||||
(Stab_Sym *) (stab_section->data +
|
|
||||||
stab_section->data_offset);
|
|
||||||
|
|
||||||
while (sym < sym_end) {
|
|
||||||
switch (sym->n_type) {
|
|
||||||
/* function start or end */
|
|
||||||
case N_FUN:
|
|
||||||
if (sym->n_strx == 0) {
|
|
||||||
// end of function
|
|
||||||
|
|
||||||
CoffLineNo.l_addr.l_paddr = last_pc;
|
|
||||||
CoffLineNo.l_lnno = last_line_num + 1;
|
|
||||||
fwrite(&CoffLineNo, 6, 1, f);
|
|
||||||
|
|
||||||
pc = sym->n_value + func_addr;
|
|
||||||
func_name[0] = '\0';
|
|
||||||
func_addr = 0;
|
|
||||||
} else {
|
|
||||||
// beginning of function
|
|
||||||
|
|
||||||
str =
|
|
||||||
(const char *) stabstr_section->data +
|
|
||||||
sym->n_strx;
|
|
||||||
|
|
||||||
|
|
||||||
p = strchr(str, ':');
|
|
||||||
if (!p) {
|
|
||||||
pstrcpy(func_name, sizeof(func_name), str);
|
|
||||||
} else {
|
|
||||||
len = p - str;
|
|
||||||
if (len > sizeof(func_name) - 1)
|
|
||||||
len = sizeof(func_name) - 1;
|
|
||||||
memcpy(func_name, str, len);
|
|
||||||
func_name[len] = '\0';
|
|
||||||
}
|
|
||||||
func_addr = sym->n_value;
|
|
||||||
last_pc = func_addr;
|
|
||||||
last_line_num = -1;
|
|
||||||
|
|
||||||
// output a function begin
|
|
||||||
|
|
||||||
CoffLineNo.l_addr.l_symndx =
|
|
||||||
FindCoffSymbolIndex(s1, func_name);
|
|
||||||
CoffLineNo.l_lnno = 0;
|
|
||||||
|
|
||||||
fwrite(&CoffLineNo, 6, 1, f);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* line number info */
|
|
||||||
case N_SLINE:
|
|
||||||
pc = sym->n_value + func_addr;
|
|
||||||
|
|
||||||
|
|
||||||
/* XXX: slow! */
|
|
||||||
strcpy(last_func_name, func_name);
|
|
||||||
|
|
||||||
// output a line reference
|
|
||||||
|
|
||||||
CoffLineNo.l_addr.l_paddr = last_pc;
|
|
||||||
|
|
||||||
if (last_line_num == -1) {
|
|
||||||
CoffLineNo.l_lnno = sym->n_desc;
|
|
||||||
} else {
|
|
||||||
CoffLineNo.l_lnno = last_line_num + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fwrite(&CoffLineNo, 6, 1, f);
|
|
||||||
|
|
||||||
last_pc = pc;
|
|
||||||
last_line_num = sym->n_desc;
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* include files */
|
|
||||||
case N_BINCL:
|
|
||||||
str =
|
|
||||||
(const char *) stabstr_section->data + sym->n_strx;
|
|
||||||
add_incl2:
|
|
||||||
if (incl_index < INCLUDE_STACK_SIZE) {
|
|
||||||
incl_files[incl_index++] = str;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case N_EINCL:
|
|
||||||
if (incl_index > 1)
|
|
||||||
incl_index--;
|
|
||||||
break;
|
|
||||||
case N_SO:
|
|
||||||
if (sym->n_strx == 0) {
|
|
||||||
incl_index = 0; /* end of translation unit */
|
|
||||||
} else {
|
|
||||||
str =
|
|
||||||
(const char *) stabstr_section->data +
|
|
||||||
sym->n_strx;
|
|
||||||
/* do not add path */
|
|
||||||
len = strlen(str);
|
|
||||||
if (len > 0 && str[len - 1] != '/')
|
|
||||||
goto add_incl2;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
sym++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// write symbol table
|
|
||||||
if (s1->do_debug) {
|
|
||||||
int k;
|
|
||||||
struct syment csym;
|
|
||||||
AUXFUNC auxfunc;
|
|
||||||
AUXBF auxbf;
|
|
||||||
AUXEF auxef;
|
|
||||||
int i;
|
|
||||||
Elf32_Sym *p;
|
|
||||||
const char *name;
|
|
||||||
int nstr;
|
|
||||||
int n = 0;
|
|
||||||
|
|
||||||
Coff_str_table = (char *) tcc_malloc(MAX_STR_TABLE);
|
|
||||||
pCoff_str_table = Coff_str_table;
|
|
||||||
nstr = 0;
|
|
||||||
|
|
||||||
p = (Elf32_Sym *) symtab_section->data;
|
|
||||||
|
|
||||||
|
|
||||||
for (i = 0; i < nb_syms; i++) {
|
|
||||||
|
|
||||||
name = symtab_section->link->data + p->st_name;
|
|
||||||
|
|
||||||
for (k = 0; k < 8; k++)
|
|
||||||
csym._n._n_name[k] = 0;
|
|
||||||
|
|
||||||
if (strlen(name) <= 8) {
|
|
||||||
strcpy(csym._n._n_name, name);
|
|
||||||
} else {
|
|
||||||
if (pCoff_str_table - Coff_str_table + strlen(name) >
|
|
||||||
MAX_STR_TABLE - 1)
|
|
||||||
tcc_error("String table too large");
|
|
||||||
|
|
||||||
csym._n._n_n._n_zeroes = 0;
|
|
||||||
csym._n._n_n._n_offset =
|
|
||||||
pCoff_str_table - Coff_str_table + 4;
|
|
||||||
|
|
||||||
strcpy(pCoff_str_table, name);
|
|
||||||
pCoff_str_table += strlen(name) + 1; // skip over null
|
|
||||||
nstr++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p->st_info == 4) {
|
|
||||||
// put a filename symbol
|
|
||||||
csym.n_value = 33; // ?????
|
|
||||||
csym.n_scnum = N_DEBUG;
|
|
||||||
csym.n_type = 0;
|
|
||||||
csym.n_sclass = C_FILE;
|
|
||||||
csym.n_numaux = 0;
|
|
||||||
fwrite(&csym, 18, 1, f);
|
|
||||||
n++;
|
|
||||||
|
|
||||||
} else if (p->st_info == 0x12) {
|
|
||||||
// find the function data
|
|
||||||
|
|
||||||
for (k = 0; k < nFuncs; k++) {
|
|
||||||
if (strcmp(name, Func[k]) == 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (k >= nFuncs) {
|
|
||||||
tcc_error("debug info can't find function: %s", name);
|
|
||||||
}
|
|
||||||
// put a Function Name
|
|
||||||
|
|
||||||
csym.n_value = p->st_value; // physical address
|
|
||||||
csym.n_scnum = CoffTextSectionNo;
|
|
||||||
csym.n_type = MKTYPE(T_INT, DT_FCN, 0, 0, 0, 0, 0);
|
|
||||||
csym.n_sclass = C_EXT;
|
|
||||||
csym.n_numaux = 1;
|
|
||||||
fwrite(&csym, 18, 1, f);
|
|
||||||
|
|
||||||
// now put aux info
|
|
||||||
|
|
||||||
auxfunc.tag = 0;
|
|
||||||
auxfunc.size = EndAddress[k] - p->st_value;
|
|
||||||
auxfunc.fileptr = LineNoFilePtr[k];
|
|
||||||
auxfunc.nextsym = n + 6; // tktk
|
|
||||||
auxfunc.dummy = 0;
|
|
||||||
fwrite(&auxfunc, 18, 1, f);
|
|
||||||
|
|
||||||
// put a .bf
|
|
||||||
|
|
||||||
strcpy(csym._n._n_name, ".bf");
|
|
||||||
csym.n_value = p->st_value; // physical address
|
|
||||||
csym.n_scnum = CoffTextSectionNo;
|
|
||||||
csym.n_type = 0;
|
|
||||||
csym.n_sclass = C_FCN;
|
|
||||||
csym.n_numaux = 1;
|
|
||||||
fwrite(&csym, 18, 1, f);
|
|
||||||
|
|
||||||
// now put aux info
|
|
||||||
|
|
||||||
auxbf.regmask = 0;
|
|
||||||
auxbf.lineno = 0;
|
|
||||||
auxbf.nentries = FuncEntries[k];
|
|
||||||
auxbf.localframe = 0;
|
|
||||||
auxbf.nextentry = n + 6;
|
|
||||||
auxbf.dummy = 0;
|
|
||||||
fwrite(&auxbf, 18, 1, f);
|
|
||||||
|
|
||||||
// put a .ef
|
|
||||||
|
|
||||||
strcpy(csym._n._n_name, ".ef");
|
|
||||||
csym.n_value = EndAddress[k]; // physical address
|
|
||||||
csym.n_scnum = CoffTextSectionNo;
|
|
||||||
csym.n_type = 0;
|
|
||||||
csym.n_sclass = C_FCN;
|
|
||||||
csym.n_numaux = 1;
|
|
||||||
fwrite(&csym, 18, 1, f);
|
|
||||||
|
|
||||||
// now put aux info
|
|
||||||
|
|
||||||
auxef.dummy = 0;
|
|
||||||
auxef.lineno = LastLineNo[k];
|
|
||||||
auxef.dummy1 = 0;
|
|
||||||
auxef.dummy2 = 0;
|
|
||||||
auxef.dummy3 = 0;
|
|
||||||
auxef.dummy4 = 0;
|
|
||||||
fwrite(&auxef, 18, 1, f);
|
|
||||||
|
|
||||||
n += 6;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// try an put some type info
|
|
||||||
|
|
||||||
if ((p->st_other & VT_BTYPE) == VT_DOUBLE) {
|
|
||||||
csym.n_type = T_DOUBLE; // int
|
|
||||||
csym.n_sclass = C_EXT;
|
|
||||||
} else if ((p->st_other & VT_BTYPE) == VT_FLOAT) {
|
|
||||||
csym.n_type = T_FLOAT;
|
|
||||||
csym.n_sclass = C_EXT;
|
|
||||||
} else if ((p->st_other & VT_BTYPE) == VT_INT) {
|
|
||||||
csym.n_type = T_INT; // int
|
|
||||||
csym.n_sclass = C_EXT;
|
|
||||||
} else if ((p->st_other & VT_BTYPE) == VT_SHORT) {
|
|
||||||
csym.n_type = T_SHORT;
|
|
||||||
csym.n_sclass = C_EXT;
|
|
||||||
} else if ((p->st_other & VT_BTYPE) == VT_BYTE) {
|
|
||||||
csym.n_type = T_CHAR;
|
|
||||||
csym.n_sclass = C_EXT;
|
|
||||||
} else {
|
|
||||||
csym.n_type = T_INT; // just mark as a label
|
|
||||||
csym.n_sclass = C_LABEL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
csym.n_value = p->st_value;
|
|
||||||
csym.n_scnum = 2;
|
|
||||||
csym.n_numaux = 1;
|
|
||||||
fwrite(&csym, 18, 1, f);
|
|
||||||
|
|
||||||
auxfunc.tag = 0;
|
|
||||||
auxfunc.size = 0x20;
|
|
||||||
auxfunc.fileptr = 0;
|
|
||||||
auxfunc.nextsym = 0;
|
|
||||||
auxfunc.dummy = 0;
|
|
||||||
fwrite(&auxfunc, 18, 1, f);
|
|
||||||
n++;
|
|
||||||
n++;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
p++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s1->do_debug) {
|
|
||||||
// write string table
|
|
||||||
|
|
||||||
// first write the size
|
|
||||||
i = pCoff_str_table - Coff_str_table;
|
|
||||||
fwrite(&i, 4, 1, f);
|
|
||||||
|
|
||||||
// then write the strings
|
|
||||||
fwrite(Coff_str_table, i, 1, f);
|
|
||||||
|
|
||||||
tcc_free(Coff_str_table);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// group the symbols in order of filename, func1, func2, etc
|
|
||||||
// finally global symbols
|
|
||||||
|
|
||||||
void SortSymbolTable(TCCState *s1)
|
|
||||||
{
|
|
||||||
int i, j, k, n = 0;
|
|
||||||
Elf32_Sym *p, *p2, *NewTable;
|
|
||||||
char *name, *name2;
|
|
||||||
|
|
||||||
NewTable = (Elf32_Sym *) tcc_malloc(nb_syms * sizeof(Elf32_Sym));
|
|
||||||
|
|
||||||
p = (Elf32_Sym *) symtab_section->data;
|
|
||||||
|
|
||||||
|
|
||||||
// find a file symbol, copy it over
|
|
||||||
// then scan the whole symbol list and copy any function
|
|
||||||
// symbols that match the file association
|
|
||||||
|
|
||||||
for (i = 0; i < nb_syms; i++) {
|
|
||||||
if (p->st_info == 4) {
|
|
||||||
name = (char *) symtab_section->link->data + p->st_name;
|
|
||||||
|
|
||||||
// this is a file symbol, copy it over
|
|
||||||
|
|
||||||
NewTable[n++] = *p;
|
|
||||||
|
|
||||||
p2 = (Elf32_Sym *) symtab_section->data;
|
|
||||||
|
|
||||||
for (j = 0; j < nb_syms; j++) {
|
|
||||||
if (p2->st_info == 0x12) {
|
|
||||||
// this is a func symbol
|
|
||||||
|
|
||||||
name2 =
|
|
||||||
(char *) symtab_section->link->data + p2->st_name;
|
|
||||||
|
|
||||||
// find the function data index
|
|
||||||
|
|
||||||
for (k = 0; k < nFuncs; k++) {
|
|
||||||
if (strcmp(name2, Func[k]) == 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (k >= nFuncs) {
|
|
||||||
tcc_error("debug (sort) info can't find function: %s", name2);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp(AssociatedFile[k], name) == 0) {
|
|
||||||
// yes they match copy it over
|
|
||||||
|
|
||||||
NewTable[n++] = *p2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
p2++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
p++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// now all the filename and func symbols should have been copied over
|
|
||||||
// copy all the rest over (all except file and funcs)
|
|
||||||
|
|
||||||
p = (Elf32_Sym *) symtab_section->data;
|
|
||||||
for (i = 0; i < nb_syms; i++) {
|
|
||||||
if (p->st_info != 4 && p->st_info != 0x12) {
|
|
||||||
NewTable[n++] = *p;
|
|
||||||
}
|
|
||||||
p++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (n != nb_syms)
|
|
||||||
tcc_error("Internal Compiler error, debug info");
|
|
||||||
|
|
||||||
// copy it all back
|
|
||||||
|
|
||||||
p = (Elf32_Sym *) symtab_section->data;
|
|
||||||
for (i = 0; i < nb_syms; i++) {
|
|
||||||
*p++ = NewTable[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
tcc_free(NewTable);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int FindCoffSymbolIndex(TCCState *s1, const char *func_name)
|
|
||||||
{
|
|
||||||
int i, n = 0;
|
|
||||||
Elf32_Sym *p;
|
|
||||||
char *name;
|
|
||||||
|
|
||||||
p = (Elf32_Sym *) symtab_section->data;
|
|
||||||
|
|
||||||
for (i = 0; i < nb_syms; i++) {
|
|
||||||
|
|
||||||
name = (char *) symtab_section->link->data + p->st_name;
|
|
||||||
|
|
||||||
if (p->st_info == 4) {
|
|
||||||
// put a filename symbol
|
|
||||||
n++;
|
|
||||||
} else if (p->st_info == 0x12) {
|
|
||||||
|
|
||||||
if (strcmp(func_name, name) == 0)
|
|
||||||
return n;
|
|
||||||
|
|
||||||
n += 6;
|
|
||||||
|
|
||||||
// put a Function Name
|
|
||||||
|
|
||||||
// now put aux info
|
|
||||||
|
|
||||||
// put a .bf
|
|
||||||
|
|
||||||
// now put aux info
|
|
||||||
|
|
||||||
// put a .ef
|
|
||||||
|
|
||||||
// now put aux info
|
|
||||||
|
|
||||||
} else {
|
|
||||||
n += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
p++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return n; // total number of symbols
|
|
||||||
}
|
|
||||||
|
|
||||||
int OutputTheSection(Section * sect)
|
|
||||||
{
|
|
||||||
const char *s = sect->name;
|
|
||||||
|
|
||||||
if (!strcmp(s, ".text"))
|
|
||||||
return 1;
|
|
||||||
else if (!strcmp(s, ".data"))
|
|
||||||
return 1;
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
short int GetCoffFlags(const char *s)
|
|
||||||
{
|
|
||||||
if (!strcmp(s, ".text"))
|
|
||||||
return STYP_TEXT | STYP_DATA | STYP_ALIGN | 0x400;
|
|
||||||
else if (!strcmp(s, ".data"))
|
|
||||||
return STYP_DATA;
|
|
||||||
else if (!strcmp(s, ".bss"))
|
|
||||||
return STYP_BSS;
|
|
||||||
else if (!strcmp(s, ".stack"))
|
|
||||||
return STYP_BSS | STYP_ALIGN | 0x200;
|
|
||||||
else if (!strcmp(s, ".cinit"))
|
|
||||||
return STYP_COPY | STYP_DATA | STYP_ALIGN | 0x200;
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Section *FindSection(TCCState * s1, const char *sname)
|
|
||||||
{
|
|
||||||
Section *s;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 1; i < s1->nb_sections; i++) {
|
|
||||||
s = s1->sections[i];
|
|
||||||
|
|
||||||
if (!strcmp(sname, s->name))
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
tcc_error("could not find section %s", sname);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ST_FUNC int tcc_load_coff(TCCState * s1, int fd)
|
|
||||||
{
|
|
||||||
// tktk TokenSym *ts;
|
|
||||||
|
|
||||||
FILE *f;
|
|
||||||
unsigned int str_size;
|
|
||||||
char *Coff_str_table, *name;
|
|
||||||
int i, k;
|
|
||||||
struct syment csym;
|
|
||||||
char name2[9];
|
|
||||||
FILHDR file_hdr; /* FILE HEADER STRUCTURE */
|
|
||||||
|
|
||||||
f = fdopen(fd, "rb");
|
|
||||||
if (!f) {
|
|
||||||
tcc_error("Unable to open .out file for input");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fread(&file_hdr, FILHSZ, 1, f) != 1)
|
|
||||||
tcc_error("error reading .out file for input");
|
|
||||||
|
|
||||||
if (fread(&o_filehdr, sizeof(o_filehdr), 1, f) != 1)
|
|
||||||
tcc_error("error reading .out file for input");
|
|
||||||
|
|
||||||
// first read the string table
|
|
||||||
|
|
||||||
if (fseek(f, file_hdr.f_symptr + file_hdr.f_nsyms * SYMESZ, SEEK_SET))
|
|
||||||
tcc_error("error reading .out file for input");
|
|
||||||
|
|
||||||
if (fread(&str_size, sizeof(int), 1, f) != 1)
|
|
||||||
tcc_error("error reading .out file for input");
|
|
||||||
|
|
||||||
|
|
||||||
Coff_str_table = (char *) tcc_malloc(str_size);
|
|
||||||
|
|
||||||
if (fread(Coff_str_table, str_size - 4, 1, f) != 1)
|
|
||||||
tcc_error("error reading .out file for input");
|
|
||||||
|
|
||||||
// read/process all the symbols
|
|
||||||
|
|
||||||
// seek back to symbols
|
|
||||||
|
|
||||||
if (fseek(f, file_hdr.f_symptr, SEEK_SET))
|
|
||||||
tcc_error("error reading .out file for input");
|
|
||||||
|
|
||||||
for (i = 0; i < file_hdr.f_nsyms; i++) {
|
|
||||||
if (fread(&csym, SYMESZ, 1, f) != 1)
|
|
||||||
tcc_error("error reading .out file for input");
|
|
||||||
|
|
||||||
if (csym._n._n_n._n_zeroes == 0) {
|
|
||||||
name = Coff_str_table + csym._n._n_n._n_offset - 4;
|
|
||||||
} else {
|
|
||||||
name = csym._n._n_name;
|
|
||||||
|
|
||||||
if (name[7] != 0) {
|
|
||||||
for (k = 0; k < 8; k++)
|
|
||||||
name2[k] = name[k];
|
|
||||||
|
|
||||||
name2[8] = 0;
|
|
||||||
|
|
||||||
name = name2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// if (strcmp("_DAC_Buffer",name)==0) // tktk
|
|
||||||
// name[0]=0;
|
|
||||||
|
|
||||||
if (((csym.n_type & 0x30) == 0x20 && csym.n_sclass == 0x2) || ((csym.n_type & 0x30) == 0x30 && csym.n_sclass == 0x2) || (csym.n_type == 0x4 && csym.n_sclass == 0x2) || (csym.n_type == 0x8 && csym.n_sclass == 0x2) || // structures
|
|
||||||
(csym.n_type == 0x18 && csym.n_sclass == 0x2) || // pointer to structure
|
|
||||||
(csym.n_type == 0x7 && csym.n_sclass == 0x2) || // doubles
|
|
||||||
(csym.n_type == 0x6 && csym.n_sclass == 0x2)) // floats
|
|
||||||
{
|
|
||||||
// strip off any leading underscore (except for other main routine)
|
|
||||||
|
|
||||||
if (name[0] == '_' && strcmp(name, "_main") != 0)
|
|
||||||
name++;
|
|
||||||
|
|
||||||
tcc_add_symbol(s1, name, (void*)(uintptr_t)csym.n_value);
|
|
||||||
}
|
|
||||||
// skip any aux records
|
|
||||||
|
|
||||||
if (csym.n_numaux == 1) {
|
|
||||||
if (fread(&csym, SYMESZ, 1, f) != 1)
|
|
||||||
tcc_error("error reading .out file for input");
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
5
tcclib.h
5
tcclib.h
@ -18,8 +18,6 @@ void *realloc(void *ptr, size_t size);
|
|||||||
int atoi(const char *nptr);
|
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 *alloca(size_t);
|
|
||||||
|
|
||||||
/* stdio.h */
|
/* stdio.h */
|
||||||
typedef struct __FILE FILE;
|
typedef struct __FILE FILE;
|
||||||
@ -40,8 +38,6 @@ 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 printf(const char *format, ...);
|
int printf(const char *format, ...);
|
||||||
int fprintf(FILE *stream, const char *format, ...);
|
int fprintf(FILE *stream, const char *format, ...);
|
||||||
@ -67,7 +63,6 @@ void *memcpy(void *dest, const void *src, size_t n);
|
|||||||
void *memmove(void *dest, const void *src, size_t n);
|
void *memmove(void *dest, const void *src, size_t n);
|
||||||
void *memset(void *s, int c, size_t n);
|
void *memset(void *s, int c, size_t n);
|
||||||
char *strdup(const char *s);
|
char *strdup(const char *s);
|
||||||
size_t strlen(const char *s);
|
|
||||||
|
|
||||||
/* dlfcn.h */
|
/* dlfcn.h */
|
||||||
#define RTLD_LAZY 0x001
|
#define RTLD_LAZY 0x001
|
||||||
|
|||||||
2477
tccmacho.c
2477
tccmacho.c
File diff suppressed because it is too large
Load Diff
580
tcctok.h
580
tcctok.h
@ -1,31 +1,29 @@
|
|||||||
/*********************************************************************/
|
|
||||||
/* keywords */
|
/* keywords */
|
||||||
|
DEF(TOK_INT, "int")
|
||||||
|
DEF(TOK_VOID, "void")
|
||||||
|
DEF(TOK_CHAR, "char")
|
||||||
DEF(TOK_IF, "if")
|
DEF(TOK_IF, "if")
|
||||||
DEF(TOK_ELSE, "else")
|
DEF(TOK_ELSE, "else")
|
||||||
DEF(TOK_WHILE, "while")
|
DEF(TOK_WHILE, "while")
|
||||||
DEF(TOK_FOR, "for")
|
|
||||||
DEF(TOK_DO, "do")
|
|
||||||
DEF(TOK_CONTINUE, "continue")
|
|
||||||
DEF(TOK_BREAK, "break")
|
DEF(TOK_BREAK, "break")
|
||||||
DEF(TOK_RETURN, "return")
|
DEF(TOK_RETURN, "return")
|
||||||
DEF(TOK_GOTO, "goto")
|
DEF(TOK_FOR, "for")
|
||||||
DEF(TOK_SWITCH, "switch")
|
|
||||||
DEF(TOK_CASE, "case")
|
|
||||||
DEF(TOK_DEFAULT, "default")
|
|
||||||
DEF(TOK_ASM1, "asm")
|
|
||||||
DEF(TOK_ASM2, "__asm")
|
|
||||||
DEF(TOK_ASM3, "__asm__")
|
|
||||||
|
|
||||||
DEF(TOK_EXTERN, "extern")
|
DEF(TOK_EXTERN, "extern")
|
||||||
DEF(TOK_STATIC, "static")
|
DEF(TOK_STATIC, "static")
|
||||||
DEF(TOK_UNSIGNED, "unsigned")
|
DEF(TOK_UNSIGNED, "unsigned")
|
||||||
DEF(TOK__Atomic, "_Atomic")
|
DEF(TOK_GOTO, "goto")
|
||||||
|
DEF(TOK_DO, "do")
|
||||||
|
DEF(TOK_CONTINUE, "continue")
|
||||||
|
DEF(TOK_SWITCH, "switch")
|
||||||
|
DEF(TOK_CASE, "case")
|
||||||
|
|
||||||
DEF(TOK_CONST1, "const")
|
DEF(TOK_CONST1, "const")
|
||||||
DEF(TOK_CONST2, "__const") /* gcc keyword */
|
DEF(TOK_CONST2, "__const") /* gcc keyword */
|
||||||
DEF(TOK_CONST3, "__const__") /* gcc keyword */
|
DEF(TOK_CONST3, "__const__") /* gcc keyword */
|
||||||
DEF(TOK_VOLATILE1, "volatile")
|
DEF(TOK_VOLATILE1, "volatile")
|
||||||
DEF(TOK_VOLATILE2, "__volatile") /* gcc keyword */
|
DEF(TOK_VOLATILE2, "__volatile") /* gcc keyword */
|
||||||
DEF(TOK_VOLATILE3, "__volatile__") /* gcc keyword */
|
DEF(TOK_VOLATILE3, "__volatile__") /* gcc keyword */
|
||||||
|
DEF(TOK_LONG, "long")
|
||||||
DEF(TOK_REGISTER, "register")
|
DEF(TOK_REGISTER, "register")
|
||||||
DEF(TOK_SIGNED1, "signed")
|
DEF(TOK_SIGNED1, "signed")
|
||||||
DEF(TOK_SIGNED2, "__signed") /* gcc keyword */
|
DEF(TOK_SIGNED2, "__signed") /* gcc keyword */
|
||||||
@ -38,43 +36,34 @@
|
|||||||
DEF(TOK_RESTRICT2, "__restrict")
|
DEF(TOK_RESTRICT2, "__restrict")
|
||||||
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, "__thread") /* GCC thread-local storage extension */
|
|
||||||
|
|
||||||
DEF(TOK_GENERIC, "_Generic")
|
|
||||||
DEF(TOK_STATIC_ASSERT, "_Static_assert")
|
|
||||||
|
|
||||||
DEF(TOK_VOID, "void")
|
|
||||||
DEF(TOK_CHAR, "char")
|
|
||||||
DEF(TOK_INT, "int")
|
|
||||||
DEF(TOK_FLOAT, "float")
|
DEF(TOK_FLOAT, "float")
|
||||||
DEF(TOK_DOUBLE, "double")
|
DEF(TOK_DOUBLE, "double")
|
||||||
DEF(TOK_BOOL, "_Bool")
|
DEF(TOK_BOOL, "_Bool")
|
||||||
DEF(TOK_COMPLEX, "_Complex")
|
|
||||||
DEF(TOK_SHORT, "short")
|
DEF(TOK_SHORT, "short")
|
||||||
DEF(TOK_LONG, "long")
|
|
||||||
DEF(TOK_STRUCT, "struct")
|
DEF(TOK_STRUCT, "struct")
|
||||||
DEF(TOK_UNION, "union")
|
DEF(TOK_UNION, "union")
|
||||||
DEF(TOK_TYPEDEF, "typedef")
|
DEF(TOK_TYPEDEF, "typedef")
|
||||||
|
DEF(TOK_DEFAULT, "default")
|
||||||
DEF(TOK_ENUM, "enum")
|
DEF(TOK_ENUM, "enum")
|
||||||
DEF(TOK_SIZEOF, "sizeof")
|
DEF(TOK_SIZEOF, "sizeof")
|
||||||
DEF(TOK_ATTRIBUTE1, "__attribute")
|
DEF(TOK_ATTRIBUTE1, "__attribute")
|
||||||
DEF(TOK_ATTRIBUTE2, "__attribute__")
|
DEF(TOK_ATTRIBUTE2, "__attribute__")
|
||||||
DEF(TOK_ALIGNOF1, "__alignof")
|
DEF(TOK_ALIGNOF1, "__alignof")
|
||||||
DEF(TOK_ALIGNOF2, "__alignof__")
|
DEF(TOK_ALIGNOF2, "__alignof__")
|
||||||
DEF(TOK_ALIGNOF3, "_Alignof")
|
|
||||||
DEF(TOK_ALIGNAS, "_Alignas")
|
|
||||||
DEF(TOK_TYPEOF1, "typeof")
|
DEF(TOK_TYPEOF1, "typeof")
|
||||||
DEF(TOK_TYPEOF2, "__typeof")
|
DEF(TOK_TYPEOF2, "__typeof")
|
||||||
DEF(TOK_TYPEOF3, "__typeof__")
|
DEF(TOK_TYPEOF3, "__typeof__")
|
||||||
DEF(TOK_LABEL, "__label__")
|
DEF(TOK_LABEL, "__label__")
|
||||||
|
DEF(TOK_ASM1, "asm")
|
||||||
|
DEF(TOK_ASM2, "__asm")
|
||||||
|
DEF(TOK_ASM3, "__asm__")
|
||||||
|
|
||||||
/*********************************************************************/
|
/*********************************************************************/
|
||||||
/* the following are not keywords. They are included to ease parsing */
|
/* the following are not keywords. They are included to ease parsing */
|
||||||
/* preprocessor only */
|
/* preprocessor only */
|
||||||
DEF(TOK_DEFINE, "define")
|
DEF(TOK_DEFINE, "define")
|
||||||
DEF(TOK_INCLUDE, "include")
|
DEF(TOK_INCLUDE, "include")
|
||||||
DEF(TOK_INCLUDE_NEXT, "include_next")
|
|
||||||
DEF(TOK_IFDEF, "ifdef")
|
DEF(TOK_IFDEF, "ifdef")
|
||||||
DEF(TOK_IFNDEF, "ifndef")
|
DEF(TOK_IFNDEF, "ifndef")
|
||||||
DEF(TOK_ELIF, "elif")
|
DEF(TOK_ELIF, "elif")
|
||||||
@ -91,253 +80,48 @@
|
|||||||
DEF(TOK___TIME__, "__TIME__")
|
DEF(TOK___TIME__, "__TIME__")
|
||||||
DEF(TOK___FUNCTION__, "__FUNCTION__")
|
DEF(TOK___FUNCTION__, "__FUNCTION__")
|
||||||
DEF(TOK___VA_ARGS__, "__VA_ARGS__")
|
DEF(TOK___VA_ARGS__, "__VA_ARGS__")
|
||||||
DEF(TOK___COUNTER__, "__COUNTER__")
|
|
||||||
DEF(TOK___HAS_INCLUDE, "__has_include")
|
|
||||||
DEF(TOK___HAS_INCLUDE_NEXT, "__has_include_next")
|
|
||||||
|
|
||||||
/* special identifiers */
|
/* special identifiers */
|
||||||
DEF(TOK___FUNC__, "__func__")
|
DEF(TOK___FUNC__, "__func__")
|
||||||
|
|
||||||
/* special floating point values */
|
|
||||||
DEF(TOK___NAN__, "__nan__")
|
|
||||||
DEF(TOK___SNAN__, "__snan__")
|
|
||||||
DEF(TOK___INF__, "__inf__")
|
|
||||||
|
|
||||||
/* attribute identifiers */
|
/* attribute identifiers */
|
||||||
/* XXX: handle all tokens generically since speed is not critical */
|
/* XXX: handle all tokens generically since speed is not critical */
|
||||||
DEF(TOK_SECTION1, "section")
|
DEF(TOK_SECTION1, "section")
|
||||||
DEF(TOK_SECTION2, "__section__")
|
DEF(TOK_SECTION2, "__section__")
|
||||||
DEF(TOK_ALIGNED1, "aligned")
|
DEF(TOK_ALIGNED1, "aligned")
|
||||||
DEF(TOK_ALIGNED2, "__aligned__")
|
DEF(TOK_ALIGNED2, "__aligned__")
|
||||||
DEF(TOK_PACKED1, "packed")
|
|
||||||
DEF(TOK_PACKED2, "__packed__")
|
|
||||||
DEF(TOK_WEAK1, "weak")
|
|
||||||
DEF(TOK_WEAK2, "__weak__")
|
|
||||||
DEF(TOK_ALIAS1, "alias")
|
|
||||||
DEF(TOK_ALIAS2, "__alias__")
|
|
||||||
DEF(TOK_USED1, "used")
|
|
||||||
DEF(TOK_USED2, "__used__")
|
|
||||||
DEF(TOK_UNUSED1, "unused")
|
DEF(TOK_UNUSED1, "unused")
|
||||||
DEF(TOK_UNUSED2, "__unused__")
|
DEF(TOK_UNUSED2, "__unused__")
|
||||||
DEF(TOK_FORMAT1, "format")
|
|
||||||
DEF(TOK_FORMAT2, "__format__")
|
|
||||||
DEF(TOK_NODEBUG1, "nodebug")
|
|
||||||
DEF(TOK_NODEBUG2, "__nodebug__")
|
|
||||||
DEF(TOK_CDECL1, "cdecl")
|
DEF(TOK_CDECL1, "cdecl")
|
||||||
DEF(TOK_CDECL2, "__cdecl")
|
DEF(TOK_CDECL2, "__cdecl")
|
||||||
DEF(TOK_CDECL3, "__cdecl__")
|
DEF(TOK_CDECL3, "__cdecl__")
|
||||||
DEF(TOK_STDCALL1, "stdcall")
|
DEF(TOK_STDCALL1, "stdcall")
|
||||||
DEF(TOK_STDCALL2, "__stdcall")
|
DEF(TOK_STDCALL2, "__stdcall")
|
||||||
DEF(TOK_STDCALL3, "__stdcall__")
|
DEF(TOK_STDCALL3, "__stdcall__")
|
||||||
DEF(TOK_FASTCALL1, "fastcall")
|
|
||||||
DEF(TOK_FASTCALL2, "__fastcall")
|
|
||||||
DEF(TOK_FASTCALL3, "__fastcall__")
|
|
||||||
DEF(TOK_THISCALL1, "thiscall")
|
|
||||||
DEF(TOK_THISCALL2, "__thiscall")
|
|
||||||
DEF(TOK_THISCALL3, "__thiscall__")
|
|
||||||
DEF(TOK_REGPARM1, "regparm")
|
|
||||||
DEF(TOK_REGPARM2, "__regparm__")
|
|
||||||
DEF(TOK_CLEANUP1, "cleanup")
|
|
||||||
DEF(TOK_CLEANUP2, "__cleanup__")
|
|
||||||
DEF(TOK_CONSTRUCTOR1, "constructor")
|
|
||||||
DEF(TOK_CONSTRUCTOR2, "__constructor__")
|
|
||||||
DEF(TOK_DESTRUCTOR1, "destructor")
|
|
||||||
DEF(TOK_DESTRUCTOR2, "__destructor__")
|
|
||||||
DEF(TOK_ALWAYS_INLINE1, "always_inline")
|
|
||||||
DEF(TOK_ALWAYS_INLINE2, "__always_inline__")
|
|
||||||
DEF(TOK_NOINLINE, "__noinline__")
|
|
||||||
DEF(TOK_PURE1, "pure")
|
|
||||||
DEF(TOK_PURE2, "__pure__")
|
|
||||||
|
|
||||||
DEF(TOK_MODE, "__mode__")
|
|
||||||
DEF(TOK_MODE_QI, "__QI__")
|
|
||||||
DEF(TOK_MODE_DI, "__DI__")
|
|
||||||
DEF(TOK_MODE_HI, "__HI__")
|
|
||||||
DEF(TOK_MODE_SI, "__SI__")
|
|
||||||
DEF(TOK_MODE_word, "__word__")
|
|
||||||
|
|
||||||
DEF(TOK_DLLEXPORT, "dllexport")
|
|
||||||
DEF(TOK_DLLIMPORT, "dllimport")
|
|
||||||
DEF(TOK_NODECORATE, "nodecorate")
|
|
||||||
DEF(TOK_NORETURN1, "noreturn")
|
DEF(TOK_NORETURN1, "noreturn")
|
||||||
DEF(TOK_NORETURN2, "__noreturn__")
|
DEF(TOK_NORETURN2, "__noreturn__")
|
||||||
DEF(TOK_NORETURN3, "_Noreturn")
|
|
||||||
DEF(TOK_VISIBILITY1, "visibility")
|
|
||||||
DEF(TOK_VISIBILITY2, "__visibility__")
|
|
||||||
|
|
||||||
DEF(TOK_builtin_types_compatible_p, "__builtin_types_compatible_p")
|
DEF(TOK_builtin_types_compatible_p, "__builtin_types_compatible_p")
|
||||||
DEF(TOK_builtin_choose_expr, "__builtin_choose_expr")
|
|
||||||
DEF(TOK_builtin_constant_p, "__builtin_constant_p")
|
DEF(TOK_builtin_constant_p, "__builtin_constant_p")
|
||||||
DEF(TOK_builtin_frame_address, "__builtin_frame_address")
|
|
||||||
DEF(TOK_builtin_return_address, "__builtin_return_address")
|
|
||||||
DEF(TOK_builtin_expect, "__builtin_expect")
|
|
||||||
DEF(TOK_builtin_unreachable, "__builtin_unreachable")
|
|
||||||
/*DEF(TOK_builtin_va_list, "__builtin_va_list")*/
|
|
||||||
#if defined TCC_TARGET_PE && defined TCC_TARGET_X86_64
|
|
||||||
DEF(TOK_builtin_va_start, "__builtin_va_start")
|
|
||||||
#elif defined TCC_TARGET_X86_64
|
|
||||||
DEF(TOK_builtin_va_arg_types, "__builtin_va_arg_types")
|
|
||||||
#elif defined TCC_TARGET_ARM64
|
|
||||||
DEF(TOK_builtin_va_start, "__builtin_va_start")
|
|
||||||
DEF(TOK_builtin_va_arg, "__builtin_va_arg")
|
|
||||||
#elif defined TCC_TARGET_RISCV64
|
|
||||||
DEF(TOK_builtin_va_start, "__builtin_va_start")
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* atomic operations */
|
|
||||||
#define DEF_ATOMIC(ID) DEF(TOK_##__##ID, "__"#ID)
|
|
||||||
DEF_ATOMIC(atomic_store)
|
|
||||||
DEF_ATOMIC(atomic_load)
|
|
||||||
DEF_ATOMIC(atomic_exchange)
|
|
||||||
DEF_ATOMIC(atomic_compare_exchange)
|
|
||||||
DEF_ATOMIC(atomic_fetch_add)
|
|
||||||
DEF_ATOMIC(atomic_fetch_sub)
|
|
||||||
DEF_ATOMIC(atomic_fetch_or)
|
|
||||||
DEF_ATOMIC(atomic_fetch_xor)
|
|
||||||
DEF_ATOMIC(atomic_fetch_and)
|
|
||||||
DEF_ATOMIC(atomic_fetch_nand)
|
|
||||||
DEF_ATOMIC(atomic_add_fetch)
|
|
||||||
DEF_ATOMIC(atomic_sub_fetch)
|
|
||||||
DEF_ATOMIC(atomic_or_fetch)
|
|
||||||
DEF_ATOMIC(atomic_xor_fetch)
|
|
||||||
DEF_ATOMIC(atomic_and_fetch)
|
|
||||||
DEF_ATOMIC(atomic_nand_fetch)
|
|
||||||
|
|
||||||
/* pragma */
|
|
||||||
DEF(TOK_pack, "pack")
|
|
||||||
#if !defined(TCC_TARGET_I386) && !defined(TCC_TARGET_X86_64) && \
|
|
||||||
!defined(TCC_TARGET_ARM) && !defined(TCC_TARGET_ARM64) && \
|
|
||||||
!defined(TCC_TARGET_RISCV64)
|
|
||||||
/* already defined for assembler */
|
|
||||||
DEF(TOK_ASM_push, "push")
|
|
||||||
DEF(TOK_ASM_pop, "pop")
|
|
||||||
#endif
|
|
||||||
DEF(TOK_comment, "comment")
|
|
||||||
DEF(TOK_lib, "lib")
|
|
||||||
DEF(TOK_push_macro, "push_macro")
|
|
||||||
DEF(TOK_pop_macro, "pop_macro")
|
|
||||||
DEF(TOK_once, "once")
|
|
||||||
DEF(TOK_option, "option")
|
|
||||||
|
|
||||||
/* builtin functions or variables */
|
/* builtin functions or variables */
|
||||||
#ifndef TCC_ARM_EABI
|
|
||||||
DEF(TOK_memcpy, "memcpy")
|
DEF(TOK_memcpy, "memcpy")
|
||||||
DEF(TOK_memmove, "memmove")
|
|
||||||
DEF(TOK_memset, "memset")
|
DEF(TOK_memset, "memset")
|
||||||
|
DEF(TOK_alloca, "alloca")
|
||||||
DEF(TOK___divdi3, "__divdi3")
|
DEF(TOK___divdi3, "__divdi3")
|
||||||
DEF(TOK___moddi3, "__moddi3")
|
DEF(TOK___moddi3, "__moddi3")
|
||||||
DEF(TOK___udivdi3, "__udivdi3")
|
DEF(TOK___udivdi3, "__udivdi3")
|
||||||
DEF(TOK___umoddi3, "__umoddi3")
|
DEF(TOK___umoddi3, "__umoddi3")
|
||||||
DEF(TOK___ashrdi3, "__ashrdi3")
|
DEF(TOK___sardi3, "__sardi3")
|
||||||
DEF(TOK___lshrdi3, "__lshrdi3")
|
DEF(TOK___shrdi3, "__shrdi3")
|
||||||
DEF(TOK___ashldi3, "__ashldi3")
|
DEF(TOK___shldi3, "__shldi3")
|
||||||
DEF(TOK___floatundisf, "__floatundisf")
|
DEF(TOK___tcc_int_fpu_control, "__tcc_int_fpu_control")
|
||||||
DEF(TOK___floatundidf, "__floatundidf")
|
DEF(TOK___tcc_fpu_control, "__tcc_fpu_control")
|
||||||
# ifndef TCC_ARM_VFP
|
DEF(TOK___ulltof, "__ulltof")
|
||||||
DEF(TOK___floatundixf, "__floatundixf")
|
DEF(TOK___ulltod, "__ulltod")
|
||||||
DEF(TOK___fixunsxfdi, "__fixunsxfdi")
|
DEF(TOK___ulltold, "__ulltold")
|
||||||
# endif
|
|
||||||
DEF(TOK___fixunssfdi, "__fixunssfdi")
|
DEF(TOK___fixunssfdi, "__fixunssfdi")
|
||||||
DEF(TOK___fixunsdfdi, "__fixunsdfdi")
|
DEF(TOK___fixunsdfdi, "__fixunsdfdi")
|
||||||
#endif
|
DEF(TOK___fixunsxfdi, "__fixunsxfdi")
|
||||||
|
|
||||||
#if defined TCC_TARGET_ARM
|
|
||||||
# ifdef TCC_ARM_EABI
|
|
||||||
DEF(TOK_memcpy, "__aeabi_memcpy")
|
|
||||||
DEF(TOK_memmove, "__aeabi_memmove")
|
|
||||||
DEF(TOK_memmove4, "__aeabi_memmove4")
|
|
||||||
DEF(TOK_memmove8, "__aeabi_memmove8")
|
|
||||||
DEF(TOK_memset, "__aeabi_memset")
|
|
||||||
DEF(TOK___aeabi_ldivmod, "__aeabi_ldivmod")
|
|
||||||
DEF(TOK___aeabi_uldivmod, "__aeabi_uldivmod")
|
|
||||||
DEF(TOK___aeabi_idivmod, "__aeabi_idivmod")
|
|
||||||
DEF(TOK___aeabi_uidivmod, "__aeabi_uidivmod")
|
|
||||||
DEF(TOK___divsi3, "__aeabi_idiv")
|
|
||||||
DEF(TOK___udivsi3, "__aeabi_uidiv")
|
|
||||||
DEF(TOK___floatdisf, "__aeabi_l2f")
|
|
||||||
DEF(TOK___floatdidf, "__aeabi_l2d")
|
|
||||||
DEF(TOK___fixsfdi, "__aeabi_f2lz")
|
|
||||||
DEF(TOK___fixdfdi, "__aeabi_d2lz")
|
|
||||||
DEF(TOK___ashrdi3, "__aeabi_lasr")
|
|
||||||
DEF(TOK___lshrdi3, "__aeabi_llsr")
|
|
||||||
DEF(TOK___ashldi3, "__aeabi_llsl")
|
|
||||||
DEF(TOK___floatundisf, "__aeabi_ul2f")
|
|
||||||
DEF(TOK___floatundidf, "__aeabi_ul2d")
|
|
||||||
DEF(TOK___fixunssfdi, "__aeabi_f2ulz")
|
|
||||||
DEF(TOK___fixunsdfdi, "__aeabi_d2ulz")
|
|
||||||
# else
|
|
||||||
DEF(TOK___modsi3, "__modsi3")
|
|
||||||
DEF(TOK___umodsi3, "__umodsi3")
|
|
||||||
DEF(TOK___divsi3, "__divsi3")
|
|
||||||
DEF(TOK___udivsi3, "__udivsi3")
|
|
||||||
DEF(TOK___floatdisf, "__floatdisf")
|
|
||||||
DEF(TOK___floatdidf, "__floatdidf")
|
|
||||||
# ifndef TCC_ARM_VFP
|
|
||||||
DEF(TOK___floatdixf, "__floatdixf")
|
|
||||||
DEF(TOK___fixunssfsi, "__fixunssfsi")
|
|
||||||
DEF(TOK___fixunsdfsi, "__fixunsdfsi")
|
|
||||||
DEF(TOK___fixunsxfsi, "__fixunsxfsi")
|
|
||||||
DEF(TOK___fixxfdi, "__fixxfdi")
|
|
||||||
# endif
|
|
||||||
DEF(TOK___fixsfdi, "__fixsfdi")
|
|
||||||
DEF(TOK___fixdfdi, "__fixdfdi")
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined TCC_TARGET_C67
|
|
||||||
DEF(TOK__divi, "_divi")
|
|
||||||
DEF(TOK__divu, "_divu")
|
|
||||||
DEF(TOK__divf, "_divf")
|
|
||||||
DEF(TOK__divd, "_divd")
|
|
||||||
DEF(TOK__remi, "_remi")
|
|
||||||
DEF(TOK__remu, "_remu")
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined TCC_TARGET_I386
|
|
||||||
DEF(TOK___fixsfdi, "__fixsfdi")
|
|
||||||
DEF(TOK___fixdfdi, "__fixdfdi")
|
|
||||||
DEF(TOK___fixxfdi, "__fixxfdi")
|
|
||||||
#endif
|
|
||||||
#if defined TCC_TARGET_X86_64
|
|
||||||
DEF(TOK___fixxfdi, "__fixxfdi")
|
|
||||||
#endif
|
|
||||||
|
|
||||||
DEF(TOK_alloca, "alloca")
|
|
||||||
|
|
||||||
#if defined TCC_TARGET_PE
|
|
||||||
DEF(TOK___chkstk, "__chkstk")
|
|
||||||
#endif
|
|
||||||
#ifdef TCC_TARGET_ARM64
|
|
||||||
DEF(TOK___arm64_clear_cache, "__arm64_clear_cache")
|
|
||||||
#endif
|
|
||||||
#ifdef TCC_TARGET_RISCV64
|
|
||||||
DEF(TOK___riscv64_clear_cache, "__riscv64_clear_cache")
|
|
||||||
#endif
|
|
||||||
#if defined TCC_TARGET_ARM64 || defined TCC_TARGET_RISCV64
|
|
||||||
DEF(TOK___addtf3, "__addtf3")
|
|
||||||
DEF(TOK___subtf3, "__subtf3")
|
|
||||||
DEF(TOK___multf3, "__multf3")
|
|
||||||
DEF(TOK___divtf3, "__divtf3")
|
|
||||||
DEF(TOK___extendsftf2, "__extendsftf2")
|
|
||||||
DEF(TOK___extenddftf2, "__extenddftf2")
|
|
||||||
DEF(TOK___trunctfsf2, "__trunctfsf2")
|
|
||||||
DEF(TOK___trunctfdf2, "__trunctfdf2")
|
|
||||||
DEF(TOK___negtf2, "__negtf2")
|
|
||||||
DEF(TOK___fixtfsi, "__fixtfsi")
|
|
||||||
DEF(TOK___fixtfdi, "__fixtfdi")
|
|
||||||
DEF(TOK___fixunstfsi, "__fixunstfsi")
|
|
||||||
DEF(TOK___fixunstfdi, "__fixunstfdi")
|
|
||||||
DEF(TOK___floatsitf, "__floatsitf")
|
|
||||||
DEF(TOK___floatditf, "__floatditf")
|
|
||||||
DEF(TOK___floatunsitf, "__floatunsitf")
|
|
||||||
DEF(TOK___floatunditf, "__floatunditf")
|
|
||||||
DEF(TOK___eqtf2, "__eqtf2")
|
|
||||||
DEF(TOK___netf2, "__netf2")
|
|
||||||
DEF(TOK___lttf2, "__lttf2")
|
|
||||||
DEF(TOK___letf2, "__letf2")
|
|
||||||
DEF(TOK___gttf2, "__gttf2")
|
|
||||||
DEF(TOK___getf2, "__getf2")
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* bound checking symbols */
|
/* bound checking symbols */
|
||||||
#ifdef CONFIG_TCC_BCHECK
|
#ifdef CONFIG_TCC_BCHECK
|
||||||
@ -348,94 +132,244 @@
|
|||||||
DEF(TOK___bound_ptr_indir8, "__bound_ptr_indir8")
|
DEF(TOK___bound_ptr_indir8, "__bound_ptr_indir8")
|
||||||
DEF(TOK___bound_ptr_indir12, "__bound_ptr_indir12")
|
DEF(TOK___bound_ptr_indir12, "__bound_ptr_indir12")
|
||||||
DEF(TOK___bound_ptr_indir16, "__bound_ptr_indir16")
|
DEF(TOK___bound_ptr_indir16, "__bound_ptr_indir16")
|
||||||
DEF(TOK___bound_main_arg, "__bound_main_arg")
|
|
||||||
DEF(TOK___bound_local_new, "__bound_local_new")
|
DEF(TOK___bound_local_new, "__bound_local_new")
|
||||||
DEF(TOK___bound_local_delete, "__bound_local_delete")
|
DEF(TOK___bound_local_delete, "__bound_local_delete")
|
||||||
DEF(TOK___bound_setjmp, "__bound_setjmp")
|
DEF(TOK_malloc, "malloc")
|
||||||
DEF(TOK___bound_longjmp, "__bound_longjmp")
|
DEF(TOK_free, "free")
|
||||||
DEF(TOK___bound_new_region, "__bound_new_region")
|
DEF(TOK_realloc, "realloc")
|
||||||
# ifdef TCC_TARGET_PE
|
DEF(TOK_memalign, "memalign")
|
||||||
# ifdef TCC_TARGET_X86_64
|
DEF(TOK_calloc, "calloc")
|
||||||
DEF(TOK___bound_alloca_nr, "__bound_alloca_nr")
|
DEF(TOK_memmove, "memmove")
|
||||||
# endif
|
DEF(TOK_strlen, "strlen")
|
||||||
# else
|
DEF(TOK_strcpy, "strcpy")
|
||||||
DEF(TOK_sigsetjmp, "sigsetjmp")
|
|
||||||
DEF(TOK___sigsetjmp, "__sigsetjmp")
|
|
||||||
DEF(TOK_siglongjmp, "siglongjmp")
|
|
||||||
# endif
|
|
||||||
DEF(TOK_setjmp, "setjmp")
|
|
||||||
DEF(TOK__setjmp, "_setjmp")
|
|
||||||
DEF(TOK_longjmp, "longjmp")
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*********************************************************************/
|
|
||||||
/* Tiny Assembler */
|
/* Tiny Assembler */
|
||||||
#define DEF_ASM(x) DEF(TOK_ASM_ ## x, #x)
|
|
||||||
#define DEF_ASMDIR(x) DEF(TOK_ASMDIR_ ## x, "." #x)
|
|
||||||
#define TOK_ASM_int TOK_INT
|
|
||||||
|
|
||||||
#define TOK_ASMDIR_FIRST TOK_ASMDIR_byte
|
DEF_ASM(byte)
|
||||||
#define TOK_ASMDIR_LAST TOK_ASMDIR_section
|
DEF_ASM(align)
|
||||||
|
DEF_ASM(skip)
|
||||||
|
DEF_ASM(space)
|
||||||
|
DEF_ASM(string)
|
||||||
|
DEF_ASM(globl)
|
||||||
|
DEF_ASM(text)
|
||||||
|
DEF_ASM(data)
|
||||||
|
DEF_ASM(bss)
|
||||||
|
|
||||||
DEF_ASMDIR(byte) /* must be first directive */
|
#ifdef TCC_TARGET_I386
|
||||||
DEF_ASMDIR(word)
|
|
||||||
DEF_ASMDIR(align)
|
|
||||||
DEF_ASMDIR(balign)
|
|
||||||
DEF_ASMDIR(p2align)
|
|
||||||
DEF_ASMDIR(set)
|
|
||||||
DEF_ASMDIR(skip)
|
|
||||||
DEF_ASMDIR(space)
|
|
||||||
DEF_ASMDIR(string)
|
|
||||||
DEF_ASMDIR(asciz)
|
|
||||||
DEF_ASMDIR(ascii)
|
|
||||||
DEF_ASMDIR(file)
|
|
||||||
DEF_ASMDIR(globl)
|
|
||||||
DEF_ASMDIR(global)
|
|
||||||
DEF_ASMDIR(weak)
|
|
||||||
DEF_ASMDIR(hidden)
|
|
||||||
DEF_ASMDIR(ident)
|
|
||||||
DEF_ASMDIR(size)
|
|
||||||
DEF_ASMDIR(type)
|
|
||||||
DEF_ASMDIR(text)
|
|
||||||
DEF_ASMDIR(data)
|
|
||||||
DEF_ASMDIR(bss)
|
|
||||||
DEF_ASMDIR(previous)
|
|
||||||
DEF_ASMDIR(pushsection)
|
|
||||||
DEF_ASMDIR(popsection)
|
|
||||||
DEF_ASMDIR(fill)
|
|
||||||
DEF_ASMDIR(rept)
|
|
||||||
DEF_ASMDIR(endr)
|
|
||||||
DEF_ASMDIR(org)
|
|
||||||
DEF_ASMDIR(quad)
|
|
||||||
#if PTR_SIZE == 4
|
|
||||||
DEF_ASMDIR(code16)
|
|
||||||
DEF_ASMDIR(code32)
|
|
||||||
#else
|
|
||||||
DEF_ASMDIR(code64)
|
|
||||||
#endif
|
|
||||||
#if defined(TCC_TARGET_RISCV64)
|
|
||||||
DEF_ASMDIR(option)
|
|
||||||
#endif
|
|
||||||
DEF_ASMDIR(short)
|
|
||||||
DEF_ASMDIR(long)
|
|
||||||
DEF_ASMDIR(int)
|
|
||||||
DEF_ASMDIR(symver)
|
|
||||||
DEF_ASMDIR(reloc)
|
|
||||||
DEF_ASMDIR(section) /* must be last directive */
|
|
||||||
|
|
||||||
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
|
/* WARNING: relative order of tokens is important. */
|
||||||
#include "i386-tok.h"
|
DEF_ASM(al)
|
||||||
#endif
|
DEF_ASM(cl)
|
||||||
|
DEF_ASM(dl)
|
||||||
|
DEF_ASM(bl)
|
||||||
|
DEF_ASM(ah)
|
||||||
|
DEF_ASM(ch)
|
||||||
|
DEF_ASM(dh)
|
||||||
|
DEF_ASM(bh)
|
||||||
|
DEF_ASM(ax)
|
||||||
|
DEF_ASM(cx)
|
||||||
|
DEF_ASM(dx)
|
||||||
|
DEF_ASM(bx)
|
||||||
|
DEF_ASM(sp)
|
||||||
|
DEF_ASM(bp)
|
||||||
|
DEF_ASM(si)
|
||||||
|
DEF_ASM(di)
|
||||||
|
DEF_ASM(eax)
|
||||||
|
DEF_ASM(ecx)
|
||||||
|
DEF_ASM(edx)
|
||||||
|
DEF_ASM(ebx)
|
||||||
|
DEF_ASM(esp)
|
||||||
|
DEF_ASM(ebp)
|
||||||
|
DEF_ASM(esi)
|
||||||
|
DEF_ASM(edi)
|
||||||
|
DEF_ASM(mm0)
|
||||||
|
DEF_ASM(mm1)
|
||||||
|
DEF_ASM(mm2)
|
||||||
|
DEF_ASM(mm3)
|
||||||
|
DEF_ASM(mm4)
|
||||||
|
DEF_ASM(mm5)
|
||||||
|
DEF_ASM(mm6)
|
||||||
|
DEF_ASM(mm7)
|
||||||
|
DEF_ASM(xmm0)
|
||||||
|
DEF_ASM(xmm1)
|
||||||
|
DEF_ASM(xmm2)
|
||||||
|
DEF_ASM(xmm3)
|
||||||
|
DEF_ASM(xmm4)
|
||||||
|
DEF_ASM(xmm5)
|
||||||
|
DEF_ASM(xmm6)
|
||||||
|
DEF_ASM(xmm7)
|
||||||
|
DEF_ASM(cr0)
|
||||||
|
DEF_ASM(cr1)
|
||||||
|
DEF_ASM(cr2)
|
||||||
|
DEF_ASM(cr3)
|
||||||
|
DEF_ASM(cr4)
|
||||||
|
DEF_ASM(cr5)
|
||||||
|
DEF_ASM(cr6)
|
||||||
|
DEF_ASM(cr7)
|
||||||
|
DEF_ASM(tr0)
|
||||||
|
DEF_ASM(tr1)
|
||||||
|
DEF_ASM(tr2)
|
||||||
|
DEF_ASM(tr3)
|
||||||
|
DEF_ASM(tr4)
|
||||||
|
DEF_ASM(tr5)
|
||||||
|
DEF_ASM(tr6)
|
||||||
|
DEF_ASM(tr7)
|
||||||
|
DEF_ASM(db0)
|
||||||
|
DEF_ASM(db1)
|
||||||
|
DEF_ASM(db2)
|
||||||
|
DEF_ASM(db3)
|
||||||
|
DEF_ASM(db4)
|
||||||
|
DEF_ASM(db5)
|
||||||
|
DEF_ASM(db6)
|
||||||
|
DEF_ASM(db7)
|
||||||
|
DEF_ASM(dr0)
|
||||||
|
DEF_ASM(dr1)
|
||||||
|
DEF_ASM(dr2)
|
||||||
|
DEF_ASM(dr3)
|
||||||
|
DEF_ASM(dr4)
|
||||||
|
DEF_ASM(dr5)
|
||||||
|
DEF_ASM(dr6)
|
||||||
|
DEF_ASM(dr7)
|
||||||
|
DEF_ASM(es)
|
||||||
|
DEF_ASM(cs)
|
||||||
|
DEF_ASM(ss)
|
||||||
|
DEF_ASM(ds)
|
||||||
|
DEF_ASM(fs)
|
||||||
|
DEF_ASM(gs)
|
||||||
|
DEF_ASM(st)
|
||||||
|
|
||||||
#if defined TCC_TARGET_ARM
|
DEF_BWL(mov)
|
||||||
#include "arm-tok.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined TCC_TARGET_ARM64
|
/* generic two operands */
|
||||||
#include "arm64-tok.h"
|
DEF_BWL(add)
|
||||||
#endif
|
DEF_BWL(or)
|
||||||
|
DEF_BWL(adc)
|
||||||
|
DEF_BWL(sbb)
|
||||||
|
DEF_BWL(and)
|
||||||
|
DEF_BWL(sub)
|
||||||
|
DEF_BWL(xor)
|
||||||
|
DEF_BWL(cmp)
|
||||||
|
|
||||||
|
/* unary ops */
|
||||||
|
DEF_BWL(inc)
|
||||||
|
DEF_BWL(dec)
|
||||||
|
DEF_BWL(not)
|
||||||
|
DEF_BWL(neg)
|
||||||
|
DEF_BWL(mul)
|
||||||
|
DEF_BWL(imul)
|
||||||
|
DEF_BWL(div)
|
||||||
|
DEF_BWL(idiv)
|
||||||
|
|
||||||
|
DEF_BWL(xchg)
|
||||||
|
DEF_BWL(test)
|
||||||
|
|
||||||
|
/* shifts */
|
||||||
|
DEF_BWL(rol)
|
||||||
|
DEF_BWL(ror)
|
||||||
|
DEF_BWL(rcl)
|
||||||
|
DEF_BWL(rcr)
|
||||||
|
DEF_BWL(shl)
|
||||||
|
DEF_BWL(shr)
|
||||||
|
DEF_BWL(sar)
|
||||||
|
|
||||||
|
DEF_ASM(shldw)
|
||||||
|
DEF_ASM(shldl)
|
||||||
|
DEF_ASM(shld)
|
||||||
|
DEF_ASM(shrdw)
|
||||||
|
DEF_ASM(shrdl)
|
||||||
|
DEF_ASM(shrd)
|
||||||
|
|
||||||
|
DEF_ASM(pushw)
|
||||||
|
DEF_ASM(pushl)
|
||||||
|
DEF_ASM(push)
|
||||||
|
DEF_ASM(popw)
|
||||||
|
DEF_ASM(popl)
|
||||||
|
DEF_ASM(pop)
|
||||||
|
DEF_BWL(in)
|
||||||
|
DEF_BWL(out)
|
||||||
|
|
||||||
|
DEF_WL(movzb)
|
||||||
|
|
||||||
|
DEF_ASM(movzwl)
|
||||||
|
DEF_ASM(movsbw)
|
||||||
|
DEF_ASM(movsbl)
|
||||||
|
DEF_ASM(movswl)
|
||||||
|
|
||||||
|
DEF_WL(lea)
|
||||||
|
|
||||||
|
DEF_ASM(les)
|
||||||
|
DEF_ASM(lds)
|
||||||
|
DEF_ASM(lss)
|
||||||
|
DEF_ASM(lfs)
|
||||||
|
DEF_ASM(lgs)
|
||||||
|
|
||||||
|
DEF_ASM(call)
|
||||||
|
DEF_ASM(jmp)
|
||||||
|
DEF_ASM(lcall)
|
||||||
|
DEF_ASM(ljmp)
|
||||||
|
|
||||||
|
DEF_ASMTEST(j)
|
||||||
|
|
||||||
|
DEF_ASMTEST(set)
|
||||||
|
DEF_ASMTEST(cmov)
|
||||||
|
|
||||||
|
DEF_WL(bsf)
|
||||||
|
DEF_WL(bsr)
|
||||||
|
DEF_WL(bt)
|
||||||
|
DEF_WL(bts)
|
||||||
|
DEF_WL(btr)
|
||||||
|
DEF_WL(btc)
|
||||||
|
|
||||||
|
DEF_WL(lsl)
|
||||||
|
|
||||||
|
/* generic FP ops */
|
||||||
|
DEF_FP(add)
|
||||||
|
DEF_FP(mul)
|
||||||
|
|
||||||
|
DEF_ASM(fcom)
|
||||||
|
DEF_ASM(fcom_1) /* non existant op, just to have a regular table */
|
||||||
|
DEF_FP1(com)
|
||||||
|
|
||||||
|
DEF_FP(comp)
|
||||||
|
DEF_FP(sub)
|
||||||
|
DEF_FP(subr)
|
||||||
|
DEF_FP(div)
|
||||||
|
DEF_FP(divr)
|
||||||
|
|
||||||
|
DEF_BWL(xadd)
|
||||||
|
DEF_BWL(cmpxchg)
|
||||||
|
|
||||||
|
/* string ops */
|
||||||
|
DEF_BWL(cmps)
|
||||||
|
DEF_BWL(scmp)
|
||||||
|
DEF_BWL(ins)
|
||||||
|
DEF_BWL(outs)
|
||||||
|
DEF_BWL(lods)
|
||||||
|
DEF_BWL(slod)
|
||||||
|
DEF_BWL(movs)
|
||||||
|
DEF_BWL(smov)
|
||||||
|
DEF_BWL(scas)
|
||||||
|
DEF_BWL(ssca)
|
||||||
|
DEF_BWL(stos)
|
||||||
|
DEF_BWL(ssto)
|
||||||
|
|
||||||
|
/* generic asm ops */
|
||||||
|
|
||||||
|
#define ALT(x)
|
||||||
|
#define DEF_ASM_OP0(name, opcode) DEF_ASM(name)
|
||||||
|
#define DEF_ASM_OP0L(name, opcode, group, instr_type)
|
||||||
|
#define DEF_ASM_OP1(name, opcode, group, instr_type, op0)
|
||||||
|
#define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1)
|
||||||
|
#define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2)
|
||||||
|
#include "i386-asm.h"
|
||||||
|
|
||||||
|
#define ALT(x)
|
||||||
|
#define DEF_ASM_OP0(name, opcode)
|
||||||
|
#define DEF_ASM_OP0L(name, opcode, group, instr_type) DEF_ASM(name)
|
||||||
|
#define DEF_ASM_OP1(name, opcode, group, instr_type, op0) DEF_ASM(name)
|
||||||
|
#define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1) DEF_ASM(name)
|
||||||
|
#define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2) DEF_ASM(name)
|
||||||
|
#include "i386-asm.h"
|
||||||
|
|
||||||
#if defined TCC_TARGET_RISCV64
|
|
||||||
#include "riscv64-tok.h"
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
651
tcctools.c
651
tcctools.c
@ -1,651 +0,0 @@
|
|||||||
/* -------------------------------------------------------------- */
|
|
||||||
/*
|
|
||||||
* TCC - Tiny C Compiler
|
|
||||||
*
|
|
||||||
* tcctools.c - extra tools and and -m32/64 support
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------- */
|
|
||||||
/*
|
|
||||||
* This program is for making libtcc1.a without ar
|
|
||||||
* tiny_libmaker - tiny elf lib maker
|
|
||||||
* usage: tiny_libmaker [lib] files...
|
|
||||||
* Copyright (c) 2007 Timppa
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "tcc.h"
|
|
||||||
|
|
||||||
//#define ARMAG "!<arch>\n"
|
|
||||||
#define ARFMAG "`\n"
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char ar_name[16];
|
|
||||||
char ar_date[12];
|
|
||||||
char ar_uid[6];
|
|
||||||
char ar_gid[6];
|
|
||||||
char ar_mode[8];
|
|
||||||
char ar_size[10];
|
|
||||||
char ar_fmag[2];
|
|
||||||
} ArHdr;
|
|
||||||
|
|
||||||
static unsigned long le2belong(unsigned long ul) {
|
|
||||||
return ((ul & 0xFF0000)>>8)+((ul & 0xFF000000)>>24) +
|
|
||||||
((ul & 0xFF)<<24)+((ul & 0xFF00)<<8);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ar_usage(int ret) {
|
|
||||||
fprintf(stderr, "usage: tcc -ar [crstvx] lib [files]\n");
|
|
||||||
fprintf(stderr, "create library ([abdiopN] not supported).\n");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
ST_FUNC int tcc_tool_ar(int argc, char **argv)
|
|
||||||
{
|
|
||||||
static const ArHdr arhdr_init = {
|
|
||||||
"/ ",
|
|
||||||
"0 ",
|
|
||||||
"0 ",
|
|
||||||
"0 ",
|
|
||||||
"0 ",
|
|
||||||
"0 ",
|
|
||||||
ARFMAG
|
|
||||||
};
|
|
||||||
|
|
||||||
ArHdr arhdr = arhdr_init;
|
|
||||||
ArHdr arhdro = arhdr_init;
|
|
||||||
|
|
||||||
FILE *fi, *fh = NULL, *fo = NULL;
|
|
||||||
const char *created_file = NULL; // must delete on error
|
|
||||||
ElfW(Ehdr) *ehdr;
|
|
||||||
ElfW(Shdr) *shdr;
|
|
||||||
ElfW(Sym) *sym;
|
|
||||||
int i, fsize, i_lib, i_obj;
|
|
||||||
char *buf, *shstr, *symtab, *strtab;
|
|
||||||
int symtabsize = 0;//, strtabsize = 0;
|
|
||||||
char *anames = NULL;
|
|
||||||
int *afpos = NULL;
|
|
||||||
int istrlen, strpos = 0, fpos = 0, funccnt = 0, funcmax, hofs;
|
|
||||||
char tfile[260], stmp[20];
|
|
||||||
char *file, *name;
|
|
||||||
int ret = 2;
|
|
||||||
const char *ops_conflict = "habdiopN"; // unsupported but destructive if ignored.
|
|
||||||
int extract = 0;
|
|
||||||
int table = 0;
|
|
||||||
int verbose = 0;
|
|
||||||
|
|
||||||
i_lib = 0; i_obj = 0; // will hold the index of the lib and first obj
|
|
||||||
for (i = 1; i < argc; i++) {
|
|
||||||
const char *a = argv[i];
|
|
||||||
if (*a == '-' && strchr(a, '.'))
|
|
||||||
ret = 1; // -x.y is always invalid (same as gnu ar)
|
|
||||||
if ((*a == '-') || (i == 1 && !strchr(a, '.'))) { // options argument
|
|
||||||
if (strpbrk(a, ops_conflict))
|
|
||||||
ret = 1;
|
|
||||||
if (strchr(a, 'x'))
|
|
||||||
extract = 1;
|
|
||||||
if (strchr(a, 't'))
|
|
||||||
table = 1;
|
|
||||||
if (strchr(a, 'v'))
|
|
||||||
verbose = 1;
|
|
||||||
} else { // lib or obj files: don't abort - keep validating all args.
|
|
||||||
if (!i_lib) // first file is the lib
|
|
||||||
i_lib = i;
|
|
||||||
else if (!i_obj) // second file is the first obj
|
|
||||||
i_obj = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!i_lib) // i_obj implies also i_lib.
|
|
||||||
ret = 1;
|
|
||||||
i_obj = i_obj ? i_obj : argc; // An empty archive will be generated if no input file is given
|
|
||||||
|
|
||||||
if (ret == 1)
|
|
||||||
return ar_usage(ret);
|
|
||||||
|
|
||||||
if (extract || table) {
|
|
||||||
if ((fh = fopen(argv[i_lib], "rb")) == NULL)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "tcc: ar: can't open file %s\n", argv[i_lib]);
|
|
||||||
goto finish;
|
|
||||||
}
|
|
||||||
fread(stmp, 1, 8, fh);
|
|
||||||
if (memcmp(stmp,ARMAG,8))
|
|
||||||
{
|
|
||||||
no_ar:
|
|
||||||
fprintf(stderr, "tcc: ar: not an ar archive %s\n", argv[i_lib]);
|
|
||||||
goto finish;
|
|
||||||
}
|
|
||||||
while (fread(&arhdr, 1, sizeof(arhdr), fh) == sizeof(arhdr)) {
|
|
||||||
char *p, *e;
|
|
||||||
|
|
||||||
if (memcmp(arhdr.ar_fmag, ARFMAG, 2))
|
|
||||||
goto no_ar;
|
|
||||||
p = arhdr.ar_name;
|
|
||||||
for (e = p + sizeof arhdr.ar_name; e > p && e[-1] == ' ';)
|
|
||||||
e--;
|
|
||||||
*e = '\0';
|
|
||||||
arhdr.ar_size[sizeof arhdr.ar_size-1] = 0;
|
|
||||||
fsize = atoi(arhdr.ar_size);
|
|
||||||
buf = tcc_malloc(fsize + 1);
|
|
||||||
fread(buf, fsize, 1, fh);
|
|
||||||
if (strcmp(arhdr.ar_name,"/") && strcmp(arhdr.ar_name,"/SYM64/")) {
|
|
||||||
if (e > p && e[-1] == '/')
|
|
||||||
e[-1] = '\0';
|
|
||||||
/* tv not implemented */
|
|
||||||
if (table || verbose)
|
|
||||||
printf("%s%s\n", extract ? "x - " : "", arhdr.ar_name);
|
|
||||||
if (extract) {
|
|
||||||
if ((fo = fopen(arhdr.ar_name, "wb")) == NULL)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "tcc: ar: can't create file %s\n",
|
|
||||||
arhdr.ar_name);
|
|
||||||
tcc_free(buf);
|
|
||||||
goto finish;
|
|
||||||
}
|
|
||||||
fwrite(buf, fsize, 1, fo);
|
|
||||||
fclose(fo);
|
|
||||||
/* ignore date/uid/gid/mode */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (fsize & 1)
|
|
||||||
fgetc(fh);
|
|
||||||
tcc_free(buf);
|
|
||||||
}
|
|
||||||
ret = 0;
|
|
||||||
finish:
|
|
||||||
if (fh)
|
|
||||||
fclose(fh);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((fh = fopen(argv[i_lib], "wb")) == NULL)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "tcc: ar: can't create file %s\n", argv[i_lib]);
|
|
||||||
goto the_end;
|
|
||||||
}
|
|
||||||
created_file = argv[i_lib];
|
|
||||||
|
|
||||||
sprintf(tfile, "%s.tmp", argv[i_lib]);
|
|
||||||
if ((fo = fopen(tfile, "wb+")) == NULL)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "tcc: ar: can't create temporary file %s\n", tfile);
|
|
||||||
goto the_end;
|
|
||||||
}
|
|
||||||
|
|
||||||
funcmax = 250;
|
|
||||||
afpos = tcc_realloc(NULL, funcmax * sizeof *afpos); // 250 func
|
|
||||||
memcpy(&arhdro.ar_mode, "100644", 6);
|
|
||||||
|
|
||||||
// i_obj = first input object file
|
|
||||||
while (i_obj < argc)
|
|
||||||
{
|
|
||||||
if (*argv[i_obj] == '-') { // by now, all options start with '-'
|
|
||||||
i_obj++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if ((fi = fopen(argv[i_obj], "rb")) == NULL) {
|
|
||||||
fprintf(stderr, "tcc: ar: can't open file %s \n", argv[i_obj]);
|
|
||||||
goto the_end;
|
|
||||||
}
|
|
||||||
if (verbose)
|
|
||||||
printf("a - %s\n", argv[i_obj]);
|
|
||||||
|
|
||||||
fseek(fi, 0, SEEK_END);
|
|
||||||
fsize = ftell(fi);
|
|
||||||
fseek(fi, 0, SEEK_SET);
|
|
||||||
buf = tcc_malloc(fsize + 1);
|
|
||||||
fread(buf, fsize, 1, fi);
|
|
||||||
fclose(fi);
|
|
||||||
|
|
||||||
// elf header
|
|
||||||
ehdr = (ElfW(Ehdr) *)buf;
|
|
||||||
if (ehdr->e_ident[4] != ELFCLASSW)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "tcc: ar: Unsupported Elf Class: %s\n", argv[i_obj]);
|
|
||||||
goto the_end;
|
|
||||||
}
|
|
||||||
|
|
||||||
shdr = (ElfW(Shdr) *) (buf + ehdr->e_shoff + ehdr->e_shstrndx * ehdr->e_shentsize);
|
|
||||||
shstr = (char *)(buf + shdr->sh_offset);
|
|
||||||
symtab = strtab = NULL;
|
|
||||||
for (i = 0; i < ehdr->e_shnum; i++)
|
|
||||||
{
|
|
||||||
shdr = (ElfW(Shdr) *) (buf + ehdr->e_shoff + i * ehdr->e_shentsize);
|
|
||||||
if (!shdr->sh_offset)
|
|
||||||
continue;
|
|
||||||
if (shdr->sh_type == SHT_SYMTAB)
|
|
||||||
{
|
|
||||||
symtab = (char *)(buf + shdr->sh_offset);
|
|
||||||
symtabsize = shdr->sh_size;
|
|
||||||
}
|
|
||||||
if (shdr->sh_type == SHT_STRTAB)
|
|
||||||
{
|
|
||||||
if (!strcmp(shstr + shdr->sh_name, ".strtab"))
|
|
||||||
{
|
|
||||||
strtab = (char *)(buf + shdr->sh_offset);
|
|
||||||
//strtabsize = shdr->sh_size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (symtab && strtab)
|
|
||||||
{
|
|
||||||
int nsym = symtabsize / sizeof(ElfW(Sym));
|
|
||||||
//printf("symtab: info size shndx name\n");
|
|
||||||
for (i = 1; i < nsym; i++)
|
|
||||||
{
|
|
||||||
sym = (ElfW(Sym) *) (symtab + i * sizeof(ElfW(Sym)));
|
|
||||||
if (sym->st_shndx &&
|
|
||||||
(sym->st_info == 0x10
|
|
||||||
|| sym->st_info == 0x11
|
|
||||||
|| sym->st_info == 0x12
|
|
||||||
|| sym->st_info == 0x20
|
|
||||||
|| sym->st_info == 0x21
|
|
||||||
|| sym->st_info == 0x22
|
|
||||||
)) {
|
|
||||||
//printf("symtab: %2Xh %4Xh %2Xh %s\n", sym->st_info, sym->st_size, sym->st_shndx, strtab + sym->st_name);
|
|
||||||
istrlen = strlen(strtab + sym->st_name)+1;
|
|
||||||
anames = tcc_realloc(anames, strpos+istrlen);
|
|
||||||
strcpy(anames + strpos, strtab + sym->st_name);
|
|
||||||
strpos += istrlen;
|
|
||||||
if (++funccnt >= funcmax) {
|
|
||||||
funcmax += 250;
|
|
||||||
afpos = tcc_realloc(afpos, funcmax * sizeof *afpos); // 250 func more
|
|
||||||
}
|
|
||||||
afpos[funccnt] = fpos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
file = argv[i_obj];
|
|
||||||
for (name = strchr(file, 0);
|
|
||||||
name > file && name[-1] != '/' && name[-1] != '\\';
|
|
||||||
--name);
|
|
||||||
istrlen = strlen(name);
|
|
||||||
if (istrlen >= sizeof(arhdro.ar_name))
|
|
||||||
istrlen = sizeof(arhdro.ar_name) - 1;
|
|
||||||
memset(arhdro.ar_name, ' ', sizeof(arhdro.ar_name));
|
|
||||||
memcpy(arhdro.ar_name, name, istrlen);
|
|
||||||
arhdro.ar_name[istrlen] = '/';
|
|
||||||
sprintf(stmp, "%-10d", fsize);
|
|
||||||
memcpy(&arhdro.ar_size, stmp, 10);
|
|
||||||
fwrite(&arhdro, sizeof(arhdro), 1, fo);
|
|
||||||
fwrite(buf, fsize, 1, fo);
|
|
||||||
tcc_free(buf);
|
|
||||||
i_obj++;
|
|
||||||
fpos += (fsize + sizeof(arhdro));
|
|
||||||
if (fpos & 1)
|
|
||||||
fputc(0, fo), ++fpos;
|
|
||||||
}
|
|
||||||
hofs = 8 + sizeof(arhdr) + strpos + (funccnt+1) * sizeof(int);
|
|
||||||
fpos = 0;
|
|
||||||
if ((hofs & 1)) // align
|
|
||||||
hofs++, fpos = 1;
|
|
||||||
// write header
|
|
||||||
fwrite(ARMAG, 8, 1, fh);
|
|
||||||
// create an empty archive
|
|
||||||
if (!funccnt) {
|
|
||||||
ret = 0;
|
|
||||||
goto the_end;
|
|
||||||
}
|
|
||||||
sprintf(stmp, "%-10d", (int)(strpos + (funccnt+1) * sizeof(int)) + fpos);
|
|
||||||
memcpy(&arhdr.ar_size, stmp, 10);
|
|
||||||
fwrite(&arhdr, sizeof(arhdr), 1, fh);
|
|
||||||
afpos[0] = le2belong(funccnt);
|
|
||||||
for (i=1; i<=funccnt; i++)
|
|
||||||
afpos[i] = le2belong(afpos[i] + hofs);
|
|
||||||
fwrite(afpos, (funccnt+1) * sizeof(int), 1, fh);
|
|
||||||
fwrite(anames, strpos, 1, fh);
|
|
||||||
if (fpos)
|
|
||||||
fwrite("", 1, 1, fh);
|
|
||||||
// write objects
|
|
||||||
fseek(fo, 0, SEEK_END);
|
|
||||||
fsize = ftell(fo);
|
|
||||||
fseek(fo, 0, SEEK_SET);
|
|
||||||
buf = tcc_malloc(fsize + 1);
|
|
||||||
fread(buf, fsize, 1, fo);
|
|
||||||
fwrite(buf, fsize, 1, fh);
|
|
||||||
tcc_free(buf);
|
|
||||||
ret = 0;
|
|
||||||
the_end:
|
|
||||||
if (anames)
|
|
||||||
tcc_free(anames);
|
|
||||||
if (afpos)
|
|
||||||
tcc_free(afpos);
|
|
||||||
if (fh)
|
|
||||||
fclose(fh);
|
|
||||||
if (created_file && ret != 0)
|
|
||||||
remove(created_file);
|
|
||||||
if (fo)
|
|
||||||
fclose(fo), remove(tfile);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------- */
|
|
||||||
/*
|
|
||||||
* tiny_impdef creates an export definition file (.def) from a dll
|
|
||||||
* on MS-Windows. Usage: tiny_impdef library.dll [-o outputfile]"
|
|
||||||
*
|
|
||||||
* Copyright (c) 2005,2007 grischka
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef TCC_TARGET_PE
|
|
||||||
|
|
||||||
ST_FUNC int tcc_tool_impdef(int argc, char **argv)
|
|
||||||
{
|
|
||||||
int ret, v, i;
|
|
||||||
char infile[260];
|
|
||||||
char outfile[260];
|
|
||||||
|
|
||||||
const char *file;
|
|
||||||
char *p, *q;
|
|
||||||
FILE *fp, *op;
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
char path[260];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
infile[0] = outfile[0] = 0;
|
|
||||||
fp = op = NULL;
|
|
||||||
ret = 1;
|
|
||||||
p = NULL;
|
|
||||||
v = 0;
|
|
||||||
|
|
||||||
for (i = 1; i < argc; ++i) {
|
|
||||||
const char *a = argv[i];
|
|
||||||
if ('-' == a[0]) {
|
|
||||||
if (0 == strcmp(a, "-v")) {
|
|
||||||
v = 1;
|
|
||||||
} else if (0 == strcmp(a, "-o")) {
|
|
||||||
if (++i == argc)
|
|
||||||
goto usage;
|
|
||||||
strcpy(outfile, argv[i]);
|
|
||||||
} else
|
|
||||||
goto usage;
|
|
||||||
} else if (0 == infile[0])
|
|
||||||
strcpy(infile, a);
|
|
||||||
else
|
|
||||||
goto usage;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (0 == infile[0]) {
|
|
||||||
usage:
|
|
||||||
fprintf(stderr,
|
|
||||||
"usage: tcc -impdef library.dll [-v] [-o outputfile]\n"
|
|
||||||
"create export definition file (.def) from dll\n"
|
|
||||||
);
|
|
||||||
goto the_end;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (0 == outfile[0]) {
|
|
||||||
strcpy(outfile, tcc_basename(infile));
|
|
||||||
q = strrchr(outfile, '.');
|
|
||||||
if (NULL == q)
|
|
||||||
q = strchr(outfile, 0);
|
|
||||||
strcpy(q, ".def");
|
|
||||||
}
|
|
||||||
|
|
||||||
file = infile;
|
|
||||||
#ifdef _WIN32
|
|
||||||
if (SearchPath(NULL, file, ".dll", sizeof path, path, NULL))
|
|
||||||
file = path;
|
|
||||||
#endif
|
|
||||||
ret = tcc_get_dllexports(file, &p);
|
|
||||||
if (ret || !p) {
|
|
||||||
fprintf(stderr, "tcc: impdef: %s '%s'\n",
|
|
||||||
ret == -1 ? "can't find file" :
|
|
||||||
ret == 1 ? "can't read symbols" :
|
|
||||||
ret == 0 ? "no symbols found in" :
|
|
||||||
"unknown file type", file);
|
|
||||||
ret = 1;
|
|
||||||
goto the_end;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (v)
|
|
||||||
printf("-> %s\n", file);
|
|
||||||
|
|
||||||
op = fopen(outfile, "wb");
|
|
||||||
if (NULL == op) {
|
|
||||||
fprintf(stderr, "tcc: impdef: could not create output file: %s\n", outfile);
|
|
||||||
goto the_end;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(op, "LIBRARY %s\n\nEXPORTS\n", tcc_basename(file));
|
|
||||||
for (q = p, i = 0; *q; ++i) {
|
|
||||||
fprintf(op, "%s\n", q);
|
|
||||||
q += strlen(q) + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (v)
|
|
||||||
printf("<- %s (%d symbol%s)\n", outfile, i, &"s"[i<2]);
|
|
||||||
|
|
||||||
ret = 0;
|
|
||||||
|
|
||||||
the_end:
|
|
||||||
if (p)
|
|
||||||
tcc_free(p);
|
|
||||||
if (fp)
|
|
||||||
fclose(fp);
|
|
||||||
if (op)
|
|
||||||
fclose(op);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* TCC_TARGET_PE */
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------- */
|
|
||||||
/*
|
|
||||||
* TCC - Tiny C Compiler
|
|
||||||
*
|
|
||||||
* Copyright (c) 2001-2004 Fabrice Bellard
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* re-execute the i386/x86_64 cross-compilers with tcc -m32/-m64: */
|
|
||||||
|
|
||||||
#if !defined TCC_TARGET_I386 && !defined TCC_TARGET_X86_64
|
|
||||||
|
|
||||||
ST_FUNC int tcc_tool_cross(char **argv, int option)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "tcc -m%d not implemented\n", option);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
#ifdef _WIN32
|
|
||||||
#include <process.h>
|
|
||||||
|
|
||||||
/* - Empty argument or with space/tab (not newline) requires quoting.
|
|
||||||
* - Double-quotes at the value require '\'-escape, regardless of quoting.
|
|
||||||
* - Consecutive (or 1) backslashes at the value all need '\'-escape only if
|
|
||||||
* followed by [escaped] double quote, else taken literally, e.g. <x\\y\>
|
|
||||||
* remains literal without quoting or esc, but <x\\"y\> becomes <x\\\\\"y\>.
|
|
||||||
* - This "before double quote" rule applies also before delimiting quoting,
|
|
||||||
* e.g. <x\y \"z\> becomes <"x\y \\\"z\\"> (quoting required because space).
|
|
||||||
*
|
|
||||||
* https://learn.microsoft.com/en-us/cpp/c-language/parsing-c-command-line-arguments
|
|
||||||
*/
|
|
||||||
static char *quote_win32(const char *s)
|
|
||||||
{
|
|
||||||
char *o, *r = tcc_malloc(2 * strlen(s) + 3); /* max-esc, quotes, \0 */
|
|
||||||
int cbs = 0, quoted = !*s; /* consecutive backslashes before current */
|
|
||||||
|
|
||||||
for (o = r; *s; *o++ = *s++) {
|
|
||||||
quoted |= *s == ' ' || *s == '\t';
|
|
||||||
if (*s == '\\' || *s == '"')
|
|
||||||
*o++ = '\\';
|
|
||||||
else
|
|
||||||
o -= cbs; /* undo cbs escapes, if any (not followed by DQ) */
|
|
||||||
cbs = *s == '\\' ? cbs + 1 : 0;
|
|
||||||
}
|
|
||||||
if (quoted) {
|
|
||||||
memmove(r + 1, r, o++ - r);
|
|
||||||
*r = *o++ = '"';
|
|
||||||
} else {
|
|
||||||
o -= cbs;
|
|
||||||
}
|
|
||||||
|
|
||||||
*o = 0;
|
|
||||||
return r; /* don't bother with realloc(r, o-r+1) */
|
|
||||||
}
|
|
||||||
|
|
||||||
static int execvp_win32(const char *prog, char **argv)
|
|
||||||
{
|
|
||||||
int ret; char **p;
|
|
||||||
/* replace all " by \" */
|
|
||||||
for (p = argv; *p; ++p)
|
|
||||||
*p = quote_win32(*p);
|
|
||||||
ret = _spawnvp(P_NOWAIT, prog, (const char *const*)argv);
|
|
||||||
if (-1 == ret)
|
|
||||||
return ret;
|
|
||||||
_cwait(&ret, ret, WAIT_CHILD);
|
|
||||||
exit(ret);
|
|
||||||
}
|
|
||||||
#define execvp execvp_win32
|
|
||||||
#endif /* _WIN32 */
|
|
||||||
|
|
||||||
ST_FUNC int tcc_tool_cross(char **argv, int target)
|
|
||||||
{
|
|
||||||
char program[4096];
|
|
||||||
char *a0 = argv[0];
|
|
||||||
int prefix = tcc_basename(a0) - a0;
|
|
||||||
|
|
||||||
snprintf(program, sizeof program,
|
|
||||||
"%.*s%s"
|
|
||||||
#ifdef TCC_TARGET_PE
|
|
||||||
"-win32"
|
|
||||||
#endif
|
|
||||||
"-tcc"
|
|
||||||
#ifdef _WIN32
|
|
||||||
".exe"
|
|
||||||
#endif
|
|
||||||
, prefix, a0, target == 64 ? "x86_64" : "i386");
|
|
||||||
|
|
||||||
if (strcmp(a0, program))
|
|
||||||
execvp(argv[0] = program, argv);
|
|
||||||
fprintf(stderr, "tcc: could not run '%s'\n", program);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* TCC_TARGET_I386 && TCC_TARGET_X86_64 */
|
|
||||||
/* -------------------------------------------------------------- */
|
|
||||||
/* enable commandline wildcard expansion (tcc -o x.exe *.c) */
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
const int _CRT_glob = 1;
|
|
||||||
#ifndef _CRT_glob
|
|
||||||
const int _dowildcard = 1;
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------- */
|
|
||||||
/* generate xxx.d file */
|
|
||||||
|
|
||||||
static char *escape_target_dep(const char *s) {
|
|
||||||
char *res = tcc_malloc(strlen(s) * 2 + 1);
|
|
||||||
int j;
|
|
||||||
for (j = 0; *s; s++, j++) {
|
|
||||||
if (is_space(*s)) {
|
|
||||||
res[j++] = '\\';
|
|
||||||
}
|
|
||||||
res[j] = *s;
|
|
||||||
}
|
|
||||||
res[j] = '\0';
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
ST_FUNC int gen_makedeps(TCCState *s1, const char *target, const char *filename)
|
|
||||||
{
|
|
||||||
FILE *depout;
|
|
||||||
char buf[1024];
|
|
||||||
char **escaped_targets;
|
|
||||||
int i, k, num_targets;
|
|
||||||
|
|
||||||
if (!filename) {
|
|
||||||
/* compute filename automatically: dir/file.o -> dir/file.d */
|
|
||||||
snprintf(buf, sizeof buf, "%.*s.d",
|
|
||||||
(int)(tcc_fileextension(target) - target), target);
|
|
||||||
filename = buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!strcmp(filename, "-"))
|
|
||||||
depout = fdopen(1, "w");
|
|
||||||
else
|
|
||||||
/* XXX return err codes instead of error() ? */
|
|
||||||
depout = fopen(filename, "w");
|
|
||||||
if (!depout)
|
|
||||||
return tcc_error_noabort("could not open '%s'", filename);
|
|
||||||
if (s1->verbose)
|
|
||||||
printf("<- %s\n", filename);
|
|
||||||
|
|
||||||
escaped_targets = tcc_malloc(s1->nb_target_deps * sizeof(*escaped_targets));
|
|
||||||
num_targets = 0;
|
|
||||||
for (i = 0; i<s1->nb_target_deps; ++i) {
|
|
||||||
for (k = 0; k < i; ++k)
|
|
||||||
if (0 == strcmp(s1->target_deps[i], s1->target_deps[k]))
|
|
||||||
goto next;
|
|
||||||
escaped_targets[num_targets++] = escape_target_dep(s1->target_deps[i]);
|
|
||||||
next:;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(depout, "%s:", target);
|
|
||||||
for (i = 0; i < num_targets; ++i)
|
|
||||||
fprintf(depout, " \\\n %s", escaped_targets[i]);
|
|
||||||
fprintf(depout, "\n");
|
|
||||||
if (s1->gen_phony_deps) {
|
|
||||||
/* Skip first file, which is the c file.
|
|
||||||
* Only works for single file give on command-line,
|
|
||||||
* but other compilers have the same limitation */
|
|
||||||
for (i = 1; i < num_targets; ++i)
|
|
||||||
fprintf(depout, "%s:\n", escaped_targets[i]);
|
|
||||||
}
|
|
||||||
for (i = 0; i < num_targets; ++i)
|
|
||||||
tcc_free(escaped_targets[i]);
|
|
||||||
tcc_free(escaped_targets);
|
|
||||||
fclose(depout);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------- */
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
/* This file is to test compute #include directives. It's named so
|
|
||||||
that it starts with a pre-processing number which isn't a valid
|
|
||||||
number (42test.h). Including this must work. */
|
|
||||||
#ifndef INC42_FIRST
|
|
||||||
int have_included_42test_h;
|
|
||||||
#define INC42_FIRST
|
|
||||||
#elif !defined INC42_SECOND
|
|
||||||
#define INC42_SECOND
|
|
||||||
int have_included_42test_h_second;
|
|
||||||
#else
|
|
||||||
#define INC42_THIRD
|
|
||||||
int have_included_42test_h_third;
|
|
||||||
#endif
|
|
||||||
351
tests/Makefile
351
tests/Makefile
@ -1,351 +0,0 @@
|
|||||||
#
|
|
||||||
# Tiny C Compiler Makefile - tests
|
|
||||||
#
|
|
||||||
|
|
||||||
TOP = ..
|
|
||||||
include $(TOP)/Makefile
|
|
||||||
VPATH = $(TOPSRC)/tests $(TOPSRC)
|
|
||||||
CFLAGS := $(filter-out -g% -O%,$(CFLAGS)) -I$(TOPSRC) -I$(TOP) $(LDFLAGS)
|
|
||||||
|
|
||||||
# what tests to run
|
|
||||||
TESTS = \
|
|
||||||
hello-exe \
|
|
||||||
hello-run \
|
|
||||||
libtest \
|
|
||||||
libtest_mt \
|
|
||||||
test3 \
|
|
||||||
abitest \
|
|
||||||
asm-c-connect-test \
|
|
||||||
vla_test-run \
|
|
||||||
tests2-dir \
|
|
||||||
pp-dir \
|
|
||||||
memtest \
|
|
||||||
dlltest \
|
|
||||||
cross-test
|
|
||||||
|
|
||||||
# test4_static -- Not all relocation types are implemented yet.
|
|
||||||
# asmtest / asmtest2 -- minor differences with gcc
|
|
||||||
|
|
||||||
ifeq ($(CONFIG_backtrace),no)
|
|
||||||
TESTS := $(filter-out libtest_mt, $(TESTS))
|
|
||||||
else ifneq ($(CONFIG_bcheck),no)
|
|
||||||
TESTS += btest test1b tccb
|
|
||||||
endif
|
|
||||||
ifeq ($(CONFIG_dll),no)
|
|
||||||
TESTS := $(filter-out dlltest, $(TESTS))
|
|
||||||
endif
|
|
||||||
ifeq (-$(CONFIG_arm_eabi)-$(CONFIG_arm_vfp)-,-yes--)
|
|
||||||
TESTS := $(filter-out test3 test1b,$(TESTS))
|
|
||||||
endif
|
|
||||||
ifeq (,$(filter i386 x86_64,$(ARCH)))
|
|
||||||
TESTS := $(filter-out asm-c-connect-test,$(TESTS))
|
|
||||||
endif
|
|
||||||
ifeq ($(OS),Windows_NT) # for libtcc_test to find libtcc.dll
|
|
||||||
PATH := $(CURDIR)/$(TOP)$(if $(findstring ;,$(PATH)),;,:)$(PATH)
|
|
||||||
endif
|
|
||||||
ifdef CONFIG_OSX
|
|
||||||
LIBS += $(LINK_LIBTCC)
|
|
||||||
endif
|
|
||||||
ifeq ($(ARCH),arm)
|
|
||||||
# tcctest refers to the alignment of functions, and with thumb mode
|
|
||||||
# the low bit of code addresses selects the mode, so the "alignment"
|
|
||||||
# of functions via bit masking comes out as 1. Just disable thumb.
|
|
||||||
test.ref: CFLAGS+=-marm
|
|
||||||
endif
|
|
||||||
ifeq ($(ARCH)$(CONFIG_WIN32),i386)
|
|
||||||
# tcctest.c:get_asm_string uses a construct that is checked too strictly
|
|
||||||
# by GCC in 32bit mode when PIC is enabled.
|
|
||||||
test.ref: CFLAGS+=-fno-PIC -fno-PIE -Wl,-z,notext
|
|
||||||
endif
|
|
||||||
ifeq ($(CC_NAME),msvc)
|
|
||||||
test.ref abitest : CC = gcc
|
|
||||||
endif
|
|
||||||
ifeq ($(TARGETOS),OpenBSD)
|
|
||||||
dlltest: CFLAGS+=-fno-stack-protector
|
|
||||||
endif
|
|
||||||
ifneq (,$(filter FreeBSD NetBSD,$(TARGETOS)))
|
|
||||||
# test3 has dlsym problems
|
|
||||||
TESTS := $(filter-out test3,$(TESTS))
|
|
||||||
TESTS += test1
|
|
||||||
endif
|
|
||||||
|
|
||||||
RUN_TCC = -run $(TOPSRC)/tcc.c $(TCCFLAGS)
|
|
||||||
DISAS = objdump -d
|
|
||||||
ifdef CONFIG_OSX
|
|
||||||
DUMPTCC = (set -x; $(TCC_LOCAL) -vv; otool -L $(TCC_LOCAL); exit 1)
|
|
||||||
else
|
|
||||||
DUMPTCC = (set -x; $(TCC_LOCAL) -vv; ldd $(TCC_LOCAL); exit 1)
|
|
||||||
endif
|
|
||||||
|
|
||||||
all test :
|
|
||||||
@echo ------------ version ------------
|
|
||||||
@$(TCC_LOCAL) -v
|
|
||||||
@$(MAKE) --no-print-directory -s clean
|
|
||||||
@$(MAKE) --no-print-directory -s -r _all
|
|
||||||
@echo ------- ALL TESTS PASSED --------
|
|
||||||
|
|
||||||
_all : $(TESTS)
|
|
||||||
|
|
||||||
hello-exe: ../examples/ex1.c
|
|
||||||
@echo ------------ $@ ------------
|
|
||||||
$(TCC) $< -o hello$(EXESUF) && ./hello$(EXESUF) || $(DUMPTCC)
|
|
||||||
|
|
||||||
hello-run: ../examples/ex1.c
|
|
||||||
@echo ------------ $@ ------------
|
|
||||||
$(TCC) -run $< || $(DUMPTCC)
|
|
||||||
|
|
||||||
libtes%: libtcc_tes%$(EXESUF)
|
|
||||||
@echo ------------ $@ ------------
|
|
||||||
./libtcc_tes$*$(EXESUF) $(TOPSRC)/tcc.c $(TCCFLAGS)
|
|
||||||
|
|
||||||
libtcc_test$(EXESUF): libtcc_test.c
|
|
||||||
$(CC) -o $@ $< $(CFLAGS) $(-LTCC) $(LIBS)
|
|
||||||
|
|
||||||
libtcc_test_mt$(EXESUF): libtcc_test_mt.c
|
|
||||||
$(CC) -o $@ $< $(CFLAGS) $(-LTCC) $(LIBS)
|
|
||||||
|
|
||||||
%-dir:
|
|
||||||
@echo ------------ $@ ------------
|
|
||||||
$(MAKE) -k -C $*
|
|
||||||
|
|
||||||
# test.ref - generate using cc
|
|
||||||
test.ref: tcctest.c
|
|
||||||
$(CC) -o tcctest.gcc$(EXESUF) $< $(CFLAGS) -w -O0 -std=gnu99 -fno-omit-frame-pointer
|
|
||||||
./tcctest.gcc$(EXESUF) > $@
|
|
||||||
|
|
||||||
# auto test
|
|
||||||
test1 test1b: tcctest.c test.ref
|
|
||||||
@echo ------------ $@ ------------
|
|
||||||
$(TCC) $(RUN_TCC) -w -run $< > test.out1
|
|
||||||
@diff -u test.ref test.out1 && echo "$(AUTO_TEST) OK"
|
|
||||||
|
|
||||||
# iterated test2 (compile tcc then compile tcctest.c !)
|
|
||||||
test2 test2b: tcctest.c test.ref
|
|
||||||
@echo ------------ $@ ------------
|
|
||||||
$(TCC) $(RUN_TCC) $(RUN_TCC) -w -run $< > test.out2
|
|
||||||
@diff -u test.ref test.out2 && echo "$(AUTO_TEST)2 OK"
|
|
||||||
|
|
||||||
# iterated test3 (compile tcc then compile tcc then compile tcctest.c !)
|
|
||||||
test3 test3b: tcctest.c test.ref
|
|
||||||
@echo ------------ $@ ------------
|
|
||||||
$(TCC) $(RUN_TCC) $(RUN_TCC) $(RUN_TCC) -w -run $< > test.out3
|
|
||||||
@diff -u test.ref test.out3 && echo "$(AUTO_TEST)3 OK"
|
|
||||||
|
|
||||||
AUTO_TEST = Auto Test
|
|
||||||
test%b : TCCFLAGS += -b -bt1
|
|
||||||
test%b : AUTO_TEST = Auto Bound-Test
|
|
||||||
|
|
||||||
# binary output test
|
|
||||||
test4: tcctest.c test.ref
|
|
||||||
@echo ------------ $@ ------------
|
|
||||||
# object + link output
|
|
||||||
$(TCC) -c -o tcctest3.o $<
|
|
||||||
$(TCC) -o tcctest3 tcctest3.o
|
|
||||||
./tcctest3 > test3.out
|
|
||||||
@if diff -u test.ref test3.out ; then echo "Object $(AUTO_TEST) OK"; fi
|
|
||||||
# dynamic output
|
|
||||||
$(TCC) -o tcctest1 $<
|
|
||||||
./tcctest1 > test1.out
|
|
||||||
@if diff -u test.ref test1.out ; then echo "Dynamic $(AUTO_TEST) OK"; fi
|
|
||||||
# dynamic output + bound check
|
|
||||||
$(TCC) -b -o tcctest4 $<
|
|
||||||
./tcctest4 > test4.out
|
|
||||||
@if diff -u test.ref test4.out ; then echo "BCheck $(AUTO_TEST) OK"; fi
|
|
||||||
|
|
||||||
test4_static: tcctest.c test.ref
|
|
||||||
@echo ------------ $@ ------------
|
|
||||||
# static output.
|
|
||||||
$(TCC) -static -o tcctest2 $<
|
|
||||||
./tcctest2 > test2.out
|
|
||||||
@if diff -u test.ref test2.out ; then echo "Static $(AUTO_TEST) OK"; fi
|
|
||||||
|
|
||||||
# use tcc to create libtcc.so/.dll and the tcc(.exe) frontend and run them
|
|
||||||
dlltest:
|
|
||||||
@echo ------------ $@ ------------
|
|
||||||
$(TCC) -DLIBTCC_AS_DLL $(TOPSRC)/libtcc.c $(LIBS) -shared -o libtcc2$(DLLSUF)
|
|
||||||
$(TCC) -DONE_SOURCE=0 $(TOPSRC)/tcc.c libtcc2$(DLLSUF) $(LIBS) -Wl,-rpath=. -o tcc2$(EXESUF)
|
|
||||||
./tcc2$(EXESUF) $(TCCFLAGS) $(RUN_TCC) -run $(TOPSRC)/examples/ex1.c
|
|
||||||
ifeq (,$(filter Darwin WIN32,$(TARGETOS)))
|
|
||||||
@echo ------------ $@ with PIC ------------
|
|
||||||
$(CC) $(CFLAGS) -fPIC -DLIBTCC_AS_DLL -c $(TOPSRC)/libtcc.c
|
|
||||||
$(TCC) libtcc.o $(LIBS) -shared -o libtcc2$(DLLSUF)
|
|
||||||
$(TCC) -DONE_SOURCE=0 $(TOPSRC)/tcc.c libtcc2$(DLLSUF) $(LIBS) -Wl,-rpath=. -o tcc2$(EXESUF)
|
|
||||||
./tcc2$(EXESUF) $(TCCFLAGS) $(RUN_TCC) -run $(TOPSRC)/examples/ex1.c
|
|
||||||
endif
|
|
||||||
@rm tcc2$(EXESUF) libtcc2$(DLLSUF)
|
|
||||||
|
|
||||||
memtest:
|
|
||||||
@echo ------------ $@ ------------
|
|
||||||
$(CC) $(CFLAGS) -DMEM_DEBUG=2 $(TOPSRC)/tcc.c $(LIBS) -o memtest-tcc$(EXESUF)
|
|
||||||
./memtest-tcc$(EXESUF) $(TCCFLAGS) $(TOPSRC)/tcc.c $(LIBS)
|
|
||||||
./memtest-tcc$(EXESUF) $(TCCFLAGS) -run $(TOPSRC)/tcc.c $(TCCFLAGS) -w $(TOPSRC)/tests/tcctest.c
|
|
||||||
@echo OK
|
|
||||||
|
|
||||||
# memory and bound check auto test
|
|
||||||
BOUNDS_OK = 1 4 8 10 14 16
|
|
||||||
BOUNDS_FAIL= 2 5 6 7 9 11 12 13 15 17 18
|
|
||||||
|
|
||||||
btest: boundtest.c
|
|
||||||
@echo ------------ $@ ------------
|
|
||||||
@for i in $(BOUNDS_OK); do \
|
|
||||||
if $(TCC) -b -run $< $$i >/dev/null 2>&1 ; then \
|
|
||||||
echo "Test $$i succeeded as expected" ; \
|
|
||||||
else\
|
|
||||||
echo "Failed positive test $$i" ; exit 1 ; \
|
|
||||||
fi ;\
|
|
||||||
done ;\
|
|
||||||
for i in $(BOUNDS_FAIL); do \
|
|
||||||
if $(TCC) -b -bt1 -run $< $$i >/dev/null 2>&1 ; then \
|
|
||||||
echo "Failed negative test $$i" ; exit 1 ;\
|
|
||||||
else\
|
|
||||||
echo "Test $$i failed as expected" ; \
|
|
||||||
fi ;\
|
|
||||||
done ;\
|
|
||||||
echo Bound-Test OK
|
|
||||||
|
|
||||||
tccb:
|
|
||||||
@echo ------------ $@ ------------
|
|
||||||
$(TCC) -b $(TOPSRC)/tcc.c $(TCCFLAGS) $(LIBS) -o tccb1.exe
|
|
||||||
mv tccb1.exe tccb2.exe
|
|
||||||
./tccb2.exe -b $(TOPSRC)/tcc.c $(TCCFLAGS) $(LIBS) -o tccb1.exe
|
|
||||||
cmp -s tccb1.exe tccb2.exe && echo "Exe Bound-Test OK"
|
|
||||||
|
|
||||||
|
|
||||||
# speed test
|
|
||||||
speedtest: ex2 ex3
|
|
||||||
@echo ------------ $@ ------------
|
|
||||||
time ./ex2 1238 2 3 4 10 13 4
|
|
||||||
time $(TCC) -run $(TOPSRC)/examples/ex2.c 1238 2 3 4 10 13 4
|
|
||||||
time ./ex3 35
|
|
||||||
time $(TCC) -run $(TOPSRC)/examples/ex3.c 35
|
|
||||||
|
|
||||||
weaktest: tcctest.c test.ref
|
|
||||||
@echo ------------ $@ ------------
|
|
||||||
$(TCC) -c $< -o weaktest.tcc.o
|
|
||||||
$(CC) -c $< -o weaktest.gcc.o $(CFLAGS) -w -O0 -std=gnu99 -fno-omit-frame-pointer
|
|
||||||
objdump -t weaktest.tcc.o | grep ' w ' | sed -e 's/.* \([a-zA-Z0-9_]*\)$$/\1/' | LC_ALL=C sort > weaktest.tcc.o.txt
|
|
||||||
objdump -t weaktest.gcc.o | grep ' w ' | sed -e 's/.* \([a-zA-Z0-9_]*\)$$/\1/' | LC_ALL=C sort > weaktest.gcc.o.txt
|
|
||||||
diff weaktest.gcc.o.txt weaktest.tcc.o.txt && echo "Weak Auto Test OK"
|
|
||||||
|
|
||||||
ex%: $(TOPSRC)/examples/ex%.c
|
|
||||||
$(CC) -o $@ $< $(CFLAGS)
|
|
||||||
|
|
||||||
# tiny assembler testing
|
|
||||||
asmtest.ref: asmtest.S
|
|
||||||
$(CC) -Wa,-W -Wa,-mx86-used-note=no -o asmtest.ref.o -c asmtest.S
|
|
||||||
objdump -D asmtest.ref.o > asmtest.ref
|
|
||||||
|
|
||||||
ifeq ($(ARCH),arm)
|
|
||||||
asmtest asmtest2:
|
|
||||||
TCC="${TCC}" ./arm-asm-testsuite.sh
|
|
||||||
else
|
|
||||||
asmtest asmtest2: asmtest.ref
|
|
||||||
@echo ------------ $@ ------------
|
|
||||||
$(TCC) $(MAYBE_RUN_TCC) -c asmtest.S
|
|
||||||
objdump -D asmtest.o > asmtest.out
|
|
||||||
@if diff -u --ignore-matching-lines="file format" asmtest.ref asmtest.out ; then echo "ASM Auto Test OK"; fi
|
|
||||||
endif
|
|
||||||
|
|
||||||
# test assembler with tcc compiled by itself
|
|
||||||
asmtest2: MAYBE_RUN_TCC = $(RUN_TCC)
|
|
||||||
|
|
||||||
# Check that code generated by libtcc is binary compatible with
|
|
||||||
# that generated by CC
|
|
||||||
abitest-cc.exe: abitest.c
|
|
||||||
$(CC) -o $@ $^ $(CFLAGS) $(-LTCC) $(LIBS) -w
|
|
||||||
|
|
||||||
abitest-tcc.exe: abitest.c libtcc.c
|
|
||||||
$(TCC) -o $@ $^ $(LIBS)
|
|
||||||
|
|
||||||
abitest-% : abitest-%.exe
|
|
||||||
@echo ------------ $@ ------------
|
|
||||||
./$< $(TCCFLAGS)
|
|
||||||
|
|
||||||
abitest: abitest-cc
|
|
||||||
ifneq (-$(CONFIG_arm_eabi)-$(CONFIG_arm_vfp)-,-yes--)
|
|
||||||
abitest: abitest-tcc
|
|
||||||
endif
|
|
||||||
|
|
||||||
vla_test$(EXESUF): vla_test.c
|
|
||||||
$(TCC) -o $@ $^
|
|
||||||
|
|
||||||
vla_test-run: vla_test$(EXESUF)
|
|
||||||
@echo ------------ $@ ------------
|
|
||||||
./vla_test$(EXESUF)
|
|
||||||
|
|
||||||
.PHONY: abitest vla_test tccb
|
|
||||||
|
|
||||||
asm-c-connect$(EXESUF): asm-c-connect-1.c asm-c-connect-2.c
|
|
||||||
$(TCC) -o $@ $^
|
|
||||||
|
|
||||||
asm-c-connect-%.o: asm-c-connect-%.c
|
|
||||||
$(TCC) -c -o $@ $<
|
|
||||||
|
|
||||||
asm-c-connect-sep$(EXESUF): asm-c-connect-1.o asm-c-connect-2.o
|
|
||||||
$(TCC) -o $@ $^
|
|
||||||
|
|
||||||
asm-c-connect-test: asm-c-connect$(EXESUF) asm-c-connect-sep$(EXESUF)
|
|
||||||
@echo ------------ $@ ------------
|
|
||||||
./asm-c-connect$(EXESUF) > asm-c-connect.out1 && cat asm-c-connect.out1
|
|
||||||
./asm-c-connect-sep$(EXESUF) > asm-c-connect.out2 && cat asm-c-connect.out2
|
|
||||||
@diff -u asm-c-connect.out1 asm-c-connect.out2 || (echo "error"; exit 1)
|
|
||||||
|
|
||||||
# quick sanity check for cross-compilers
|
|
||||||
cross-test : tcctest.c examples/ex3.c
|
|
||||||
@echo ------------ $@ ------------
|
|
||||||
$(foreach T,$(CROSS-TGTS),$(call CROSS-COMPILE,$T))
|
|
||||||
|
|
||||||
CROSS-TGTS = \
|
|
||||||
i386 \
|
|
||||||
i386-win32 \
|
|
||||||
i386-OpenBSD \
|
|
||||||
x86_64 \
|
|
||||||
x86_64-win32 \
|
|
||||||
x86_64-osx \
|
|
||||||
x86_64-FreeBSD \
|
|
||||||
x86_64-NetBSD \
|
|
||||||
x86_64-OpenBSD \
|
|
||||||
arm-fpa \
|
|
||||||
arm-eabihf \
|
|
||||||
arm-NetBSD \
|
|
||||||
arm-wince \
|
|
||||||
arm64 \
|
|
||||||
arm64-win32 \
|
|
||||||
arm64-osx \
|
|
||||||
arm64-FreeBSD \
|
|
||||||
arm64-NetBSD \
|
|
||||||
arm64-OpenBSD \
|
|
||||||
riscv64 \
|
|
||||||
c67
|
|
||||||
|
|
||||||
define CROSS-COMPILE
|
|
||||||
@echo " . $(1)"
|
|
||||||
$(TCC) $(DEF-$1) -DTCC_CROSS_TEST -run $(TOPSRC)/tcc.c \
|
|
||||||
-c $(if $(findstring c67,$1),$(filter %/ex3.c,$^),$<) -w $(TCCFLAGS)
|
|
||||||
|
|
||||||
endef
|
|
||||||
|
|
||||||
# targets for development
|
|
||||||
%.bin: %.c tcc
|
|
||||||
$(TCC) -g -o $@ $<
|
|
||||||
$(DISAS) $@
|
|
||||||
|
|
||||||
instr: instr.o
|
|
||||||
objdump -d instr.o
|
|
||||||
|
|
||||||
instr.o: instr.S
|
|
||||||
$(CC) -o $@ -c $< -O2 -Wall -g
|
|
||||||
|
|
||||||
cache: tcc_g
|
|
||||||
cachegrind ./tcc_g -o /tmp/linpack -lm bench/linpack.c
|
|
||||||
vg_annotate tcc.c > /tmp/linpack.cache.log
|
|
||||||
|
|
||||||
# clean
|
|
||||||
clean:
|
|
||||||
rm -f *~ *.o *.a *.bin *.i *.ref *.out *.out? *.out?b *.cc *.gcc
|
|
||||||
rm -f *-cc *-gcc *-tcc *.exe hello libtcc_test vla_test tcctest[1234]
|
|
||||||
rm -f asm-c-connect asm-c-connect-sep
|
|
||||||
rm -f ex? tcc_g weaktest.*.txt *.def *.pdb *.obj libtcc_test_mt
|
|
||||||
@$(MAKE) -C tests2 $@
|
|
||||||
@$(MAKE) -C pp $@
|
|
||||||
|
|
||||||
691
tests/abitest.c
691
tests/abitest.c
@ -1,691 +0,0 @@
|
|||||||
#include <libtcc.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
|
|
||||||
// MinGW has 80-bit rather than 64-bit long double which isn't compatible with TCC or MSVC
|
|
||||||
#if defined(_WIN32) && defined(__GNUC__)
|
|
||||||
#define LONG_DOUBLE double
|
|
||||||
#define LONG_DOUBLE_LITERAL(x) x
|
|
||||||
#else
|
|
||||||
#define LONG_DOUBLE long double
|
|
||||||
#define LONG_DOUBLE_LITERAL(x) x ## L
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int g_argc;
|
|
||||||
static char **g_argv;
|
|
||||||
|
|
||||||
static void set_options(TCCState *s, int argc, char **argv)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef int (*callback_type) (void*);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Compile source code and call a callback with a pointer to the symbol "f".
|
|
||||||
*/
|
|
||||||
static int run_callback(const char *src, callback_type callback) {
|
|
||||||
TCCState *s;
|
|
||||||
int result;
|
|
||||||
void *ptr;
|
|
||||||
|
|
||||||
s = tcc_new();
|
|
||||||
if (!s)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
set_options(s, g_argc, g_argv);
|
|
||||||
|
|
||||||
if (tcc_set_output_type(s, TCC_OUTPUT_MEMORY) == -1)
|
|
||||||
return -1;
|
|
||||||
if (tcc_compile_string(s, src) == -1)
|
|
||||||
return -1;
|
|
||||||
if (tcc_relocate(s) == -1)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
ptr = tcc_get_symbol(s, "f");
|
|
||||||
if (!ptr)
|
|
||||||
return -1;
|
|
||||||
result = callback(ptr);
|
|
||||||
|
|
||||||
tcc_delete(s);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define STR2(x) #x
|
|
||||||
#define STR(x) STR2(x)
|
|
||||||
|
|
||||||
#define RET_PRIMITIVE_TEST(name, type, val) \
|
|
||||||
static int ret_ ## name ## _test_callback(void *ptr) { \
|
|
||||||
type (*callback) (type) = (type(*)(type))ptr; \
|
|
||||||
type x = val; \
|
|
||||||
type y = callback(x); \
|
|
||||||
return (y == x+x) ? 0 : -1; \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
static int ret_ ## name ## _test(void) { \
|
|
||||||
const char *src = STR(type) " f(" STR(type) " x) {return x+x;}"; \
|
|
||||||
return run_callback(src, ret_ ## name ## _test_callback); \
|
|
||||||
}
|
|
||||||
|
|
||||||
RET_PRIMITIVE_TEST(int, int, 70000)
|
|
||||||
RET_PRIMITIVE_TEST(longlong, long long, 4333369356528LL)
|
|
||||||
RET_PRIMITIVE_TEST(float, float, 63.0)
|
|
||||||
RET_PRIMITIVE_TEST(double, double, 14789798.0)
|
|
||||||
RET_PRIMITIVE_TEST(longdouble, LONG_DOUBLE, LONG_DOUBLE_LITERAL(378943892.0))
|
|
||||||
|
|
||||||
/*
|
|
||||||
* ret_2float_test:
|
|
||||||
*
|
|
||||||
* On x86-64, a struct with 2 floats should be packed into a single
|
|
||||||
* SSE register (VT_DOUBLE is used for this purpose).
|
|
||||||
*/
|
|
||||||
typedef struct ret_2float_test_type_s {float x, y;} ret_2float_test_type;
|
|
||||||
typedef ret_2float_test_type (*ret_2float_test_function_type) (ret_2float_test_type);
|
|
||||||
|
|
||||||
static int ret_2float_test_callback(void *ptr) {
|
|
||||||
ret_2float_test_function_type f = (ret_2float_test_function_type)ptr;
|
|
||||||
ret_2float_test_type a = {10, 35};
|
|
||||||
ret_2float_test_type r;
|
|
||||||
r = f(a);
|
|
||||||
return ((r.x == a.x*5) && (r.y == a.y*3)) ? 0 : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ret_2float_test(void) {
|
|
||||||
const char *src =
|
|
||||||
"typedef struct ret_2float_test_type_s {float x, y;} ret_2float_test_type;"
|
|
||||||
"ret_2float_test_type f(ret_2float_test_type a) {\n"
|
|
||||||
" ret_2float_test_type r = {a.x*5, a.y*3};\n"
|
|
||||||
" return r;\n"
|
|
||||||
"}\n";
|
|
||||||
|
|
||||||
return run_callback(src, ret_2float_test_callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* ret_2double_test:
|
|
||||||
*
|
|
||||||
* On x86-64, a struct with 2 doubles should be passed in two SSE
|
|
||||||
* registers.
|
|
||||||
*/
|
|
||||||
typedef struct ret_2double_test_type_s {double x, y;} ret_2double_test_type;
|
|
||||||
typedef ret_2double_test_type (*ret_2double_test_function_type) (ret_2double_test_type);
|
|
||||||
|
|
||||||
static int ret_2double_test_callback(void *ptr) {
|
|
||||||
ret_2double_test_function_type f = (ret_2double_test_function_type)ptr;
|
|
||||||
ret_2double_test_type a = {10, 35};
|
|
||||||
ret_2double_test_type r;
|
|
||||||
r = f(a);
|
|
||||||
return ((r.x == a.x*5) && (r.y == a.y*3)) ? 0 : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ret_2double_test(void) {
|
|
||||||
const char *src =
|
|
||||||
"typedef struct ret_2double_test_type_s {double x, y;} ret_2double_test_type;"
|
|
||||||
"ret_2double_test_type f(ret_2double_test_type a) {\n"
|
|
||||||
" ret_2double_test_type r = {a.x*5, a.y*3};\n"
|
|
||||||
" return r;\n"
|
|
||||||
"}\n";
|
|
||||||
|
|
||||||
return run_callback(src, ret_2double_test_callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* ret_8plus2double_test:
|
|
||||||
*
|
|
||||||
* This catches a corner case in the x86_64 ABI code: the first 7
|
|
||||||
* arguments fit into registers, the 8th doesn't, but the 9th argument
|
|
||||||
* fits into the 8th XMM register.
|
|
||||||
*
|
|
||||||
* Note that the purpose of the 10th argument is to avoid a situation
|
|
||||||
* in which gcc would accidentally put the double at the right
|
|
||||||
* address, thus causing a success message even though TCC actually
|
|
||||||
* generated incorrect code.
|
|
||||||
*/
|
|
||||||
typedef ret_2double_test_type (*ret_8plus2double_test_function_type) (double, double, double, double, double, double, double, ret_2double_test_type, double, double);
|
|
||||||
|
|
||||||
static int ret_8plus2double_test_callback(void *ptr) {
|
|
||||||
ret_8plus2double_test_function_type f = (ret_8plus2double_test_function_type)ptr;
|
|
||||||
ret_2double_test_type a = {10, 35};
|
|
||||||
ret_2double_test_type r;
|
|
||||||
r = f(0, 0, 0, 0, 0, 0, 0, a, 37, 38);
|
|
||||||
return ((r.x == 37) && (r.y == 37)) ? 0 : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ret_8plus2double_test(void) {
|
|
||||||
const char *src =
|
|
||||||
"typedef struct ret_2double_test_type_s {double x, y;} ret_2double_test_type;"
|
|
||||||
"ret_2double_test_type f(double x1, double x2, double x3, double x4, double x5, double x6, double x7, ret_2double_test_type a, double x8, double x9) {\n"
|
|
||||||
" ret_2double_test_type r = { x8, x8 };\n"
|
|
||||||
" return r;\n"
|
|
||||||
"}\n";
|
|
||||||
|
|
||||||
return run_callback(src, ret_8plus2double_test_callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* ret_mixed_test:
|
|
||||||
*
|
|
||||||
* On x86-64, a struct with a double and a 64-bit integer should be
|
|
||||||
* passed in one SSE register and one integer register.
|
|
||||||
*/
|
|
||||||
typedef struct ret_mixed_test_type_s {double x; long long y;} ret_mixed_test_type;
|
|
||||||
typedef ret_mixed_test_type (*ret_mixed_test_function_type) (ret_mixed_test_type);
|
|
||||||
|
|
||||||
static int ret_mixed_test_callback(void *ptr) {
|
|
||||||
ret_mixed_test_function_type f = (ret_mixed_test_function_type)ptr;
|
|
||||||
ret_mixed_test_type a = {10, 35};
|
|
||||||
ret_mixed_test_type r;
|
|
||||||
r = f(a);
|
|
||||||
return ((r.x == a.x*5) && (r.y == a.y*3)) ? 0 : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ret_mixed_test(void) {
|
|
||||||
const char *src =
|
|
||||||
"typedef struct ret_mixed_test_type_s {double x; long long y;} ret_mixed_test_type;"
|
|
||||||
"ret_mixed_test_type f(ret_mixed_test_type a) {\n"
|
|
||||||
" ret_mixed_test_type r = {a.x*5, a.y*3};\n"
|
|
||||||
" return r;\n"
|
|
||||||
"}\n";
|
|
||||||
|
|
||||||
return run_callback(src, ret_mixed_test_callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* ret_mixed2_test:
|
|
||||||
*
|
|
||||||
* On x86-64, a struct with two floats and two 32-bit integers should
|
|
||||||
* be passed in one SSE register and one integer register.
|
|
||||||
*/
|
|
||||||
typedef struct ret_mixed2_test_type_s {float x,x2; int y,y2;} ret_mixed2_test_type;
|
|
||||||
typedef ret_mixed2_test_type (*ret_mixed2_test_function_type) (ret_mixed2_test_type);
|
|
||||||
|
|
||||||
static int ret_mixed2_test_callback(void *ptr) {
|
|
||||||
ret_mixed2_test_function_type f = (ret_mixed2_test_function_type)ptr;
|
|
||||||
ret_mixed2_test_type a = {10, 5, 35, 7 };
|
|
||||||
ret_mixed2_test_type r;
|
|
||||||
r = f(a);
|
|
||||||
return ((r.x == a.x*5) && (r.y == a.y*3)) ? 0 : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ret_mixed2_test(void) {
|
|
||||||
const char *src =
|
|
||||||
"typedef struct ret_mixed2_test_type_s {float x, x2; int y,y2;} ret_mixed2_test_type;"
|
|
||||||
"ret_mixed2_test_type f(ret_mixed2_test_type a) {\n"
|
|
||||||
" ret_mixed2_test_type r = {a.x*5, 0, a.y*3, 0};\n"
|
|
||||||
" return r;\n"
|
|
||||||
"}\n";
|
|
||||||
|
|
||||||
return run_callback(src, ret_mixed2_test_callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* ret_mixed3_test:
|
|
||||||
*
|
|
||||||
* On x86-64, this struct should be passed in two integer registers.
|
|
||||||
*/
|
|
||||||
typedef struct ret_mixed3_test_type_s {float x; int y; float x2; int y2;} ret_mixed3_test_type;
|
|
||||||
typedef ret_mixed3_test_type (*ret_mixed3_test_function_type) (ret_mixed3_test_type);
|
|
||||||
|
|
||||||
static int ret_mixed3_test_callback(void *ptr) {
|
|
||||||
ret_mixed3_test_function_type f = (ret_mixed3_test_function_type)ptr;
|
|
||||||
ret_mixed3_test_type a = {10, 5, 35, 7 };
|
|
||||||
ret_mixed3_test_type r;
|
|
||||||
r = f(a);
|
|
||||||
return ((r.x == a.x*5) && (r.y2 == a.y*3)) ? 0 : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ret_mixed3_test(void) {
|
|
||||||
const char *src =
|
|
||||||
"typedef struct ret_mixed3_test_type_s {float x; int y; float x2; int y2;} ret_mixed3_test_type;"
|
|
||||||
"ret_mixed3_test_type f(ret_mixed3_test_type a) {\n"
|
|
||||||
" ret_mixed3_test_type r = {a.x*5, 0, 0, a.y*3};\n"
|
|
||||||
" return r;\n"
|
|
||||||
"}\n";
|
|
||||||
|
|
||||||
return run_callback(src, ret_mixed3_test_callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* reg_pack_test: return a small struct which should be packed into
|
|
||||||
* registers (Win32) during return.
|
|
||||||
*/
|
|
||||||
typedef struct reg_pack_test_type_s {int x, y;} reg_pack_test_type;
|
|
||||||
typedef reg_pack_test_type (*reg_pack_test_function_type) (reg_pack_test_type);
|
|
||||||
|
|
||||||
static int reg_pack_test_callback(void *ptr) {
|
|
||||||
reg_pack_test_function_type f = (reg_pack_test_function_type)ptr;
|
|
||||||
reg_pack_test_type a = {10, 35};
|
|
||||||
reg_pack_test_type r;
|
|
||||||
r = f(a);
|
|
||||||
return ((r.x == a.x*5) && (r.y == a.y*3)) ? 0 : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int reg_pack_test(void) {
|
|
||||||
const char *src =
|
|
||||||
"typedef struct reg_pack_test_type_s {int x, y;} reg_pack_test_type;"
|
|
||||||
"reg_pack_test_type f(reg_pack_test_type a) {\n"
|
|
||||||
" reg_pack_test_type r = {a.x*5, a.y*3};\n"
|
|
||||||
" return r;\n"
|
|
||||||
"}\n";
|
|
||||||
|
|
||||||
return run_callback(src, reg_pack_test_callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* reg_pack_longlong_test: return a small struct which should be packed into
|
|
||||||
* registers (x86-64) during return.
|
|
||||||
*/
|
|
||||||
typedef struct reg_pack_longlong_test_type_s {long long x, y;} reg_pack_longlong_test_type;
|
|
||||||
typedef reg_pack_longlong_test_type (*reg_pack_longlong_test_function_type) (reg_pack_longlong_test_type);
|
|
||||||
|
|
||||||
static int reg_pack_longlong_test_callback(void *ptr) {
|
|
||||||
reg_pack_longlong_test_function_type f = (reg_pack_longlong_test_function_type)ptr;
|
|
||||||
reg_pack_longlong_test_type a = {10, 35};
|
|
||||||
reg_pack_longlong_test_type r;
|
|
||||||
r = f(a);
|
|
||||||
return ((r.x == a.x*5) && (r.y == a.y*3)) ? 0 : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int reg_pack_longlong_test(void) {
|
|
||||||
const char *src =
|
|
||||||
"typedef struct reg_pack_longlong_test_type_s {long long x, y;} reg_pack_longlong_test_type;"
|
|
||||||
"reg_pack_longlong_test_type f(reg_pack_longlong_test_type a) {\n"
|
|
||||||
" reg_pack_longlong_test_type r = {a.x*5, a.y*3};\n"
|
|
||||||
" return r;\n"
|
|
||||||
"}\n";
|
|
||||||
|
|
||||||
return run_callback(src, reg_pack_longlong_test_callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* ret_6plus2longlong_test:
|
|
||||||
*
|
|
||||||
* This catches a corner case in the x86_64 ABI code: the first 5
|
|
||||||
* arguments fit into registers, the 6th doesn't, but the 7th argument
|
|
||||||
* fits into the 6th argument integer register, %r9.
|
|
||||||
*
|
|
||||||
* Note that the purpose of the 10th argument is to avoid a situation
|
|
||||||
* in which gcc would accidentally put the longlong at the right
|
|
||||||
* address, thus causing a success message even though TCC actually
|
|
||||||
* generated incorrect code.
|
|
||||||
*/
|
|
||||||
typedef reg_pack_longlong_test_type (*ret_6plus2longlong_test_function_type) (long long, long long, long long, long long, long long, reg_pack_longlong_test_type, long long, long long);
|
|
||||||
|
|
||||||
static int ret_6plus2longlong_test_callback(void *ptr) {
|
|
||||||
ret_6plus2longlong_test_function_type f = (ret_6plus2longlong_test_function_type)ptr;
|
|
||||||
reg_pack_longlong_test_type a = {10, 35};
|
|
||||||
reg_pack_longlong_test_type r;
|
|
||||||
r = f(0, 0, 0, 0, 0, a, 37, 38);
|
|
||||||
return ((r.x == 37) && (r.y == 37)) ? 0 : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ret_6plus2longlong_test(void) {
|
|
||||||
const char *src =
|
|
||||||
"typedef struct reg_pack_longlong_test_type_s {long long x, y;} reg_pack_longlong_test_type;"
|
|
||||||
"reg_pack_longlong_test_type f(long long x1, long long x2, long long x3, long long x4, long long x5, reg_pack_longlong_test_type a, long long x8, long long x9) {\n"
|
|
||||||
" reg_pack_longlong_test_type r = { x8, x8 };\n"
|
|
||||||
" return r;\n"
|
|
||||||
"}\n";
|
|
||||||
|
|
||||||
return run_callback(src, ret_6plus2longlong_test_callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* sret_test: Create a struct large enough to be returned via sret
|
|
||||||
* (hidden pointer as first function argument)
|
|
||||||
*/
|
|
||||||
typedef struct sret_test_type_s {long long a, b, c;} sret_test_type;
|
|
||||||
typedef sret_test_type (*sret_test_function_type) (sret_test_type);
|
|
||||||
|
|
||||||
static int sret_test_callback(void *ptr) {
|
|
||||||
sret_test_function_type f = (sret_test_function_type)(ptr);
|
|
||||||
sret_test_type x = {5436LL, 658277698LL, 43878957LL};
|
|
||||||
sret_test_type r = f(x);
|
|
||||||
return ((r.a==x.a*35)&&(r.b==x.b*19)&&(r.c==x.c*21)) ? 0 : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sret_test(void) {
|
|
||||||
const char *src =
|
|
||||||
"typedef struct sret_test_type_s {long long a, b, c;} sret_test_type;\n"
|
|
||||||
"sret_test_type f(sret_test_type x) {\n"
|
|
||||||
" sret_test_type r = {x.a*35, x.b*19, x.c*21};\n"
|
|
||||||
" return r;\n"
|
|
||||||
"}\n";
|
|
||||||
|
|
||||||
return run_callback(src, sret_test_callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* one_member_union_test:
|
|
||||||
*
|
|
||||||
* In the x86-64 ABI a union should always be passed on the stack. However
|
|
||||||
* it appears that a single member union is treated by GCC as its member.
|
|
||||||
*/
|
|
||||||
typedef union one_member_union_test_type_u {int x;} one_member_union_test_type;
|
|
||||||
typedef one_member_union_test_type (*one_member_union_test_function_type) (one_member_union_test_type);
|
|
||||||
|
|
||||||
static int one_member_union_test_callback(void *ptr) {
|
|
||||||
one_member_union_test_function_type f = (one_member_union_test_function_type)ptr;
|
|
||||||
one_member_union_test_type a, b;
|
|
||||||
a.x = 34;
|
|
||||||
b = f(a);
|
|
||||||
return (b.x == a.x*2) ? 0 : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int one_member_union_test(void) {
|
|
||||||
const char *src =
|
|
||||||
"typedef union one_member_union_test_type_u {int x;} one_member_union_test_type;\n"
|
|
||||||
"one_member_union_test_type f(one_member_union_test_type a) {\n"
|
|
||||||
" one_member_union_test_type b;\n"
|
|
||||||
" b.x = a.x * 2;\n"
|
|
||||||
" return b;\n"
|
|
||||||
"}\n";
|
|
||||||
return run_callback(src, one_member_union_test_callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* two_member_union_test:
|
|
||||||
*
|
|
||||||
* In the x86-64 ABI a union should always be passed on the stack.
|
|
||||||
*/
|
|
||||||
typedef union two_member_union_test_type_u {int x; long y;} two_member_union_test_type;
|
|
||||||
typedef two_member_union_test_type (*two_member_union_test_function_type) (two_member_union_test_type);
|
|
||||||
|
|
||||||
static int two_member_union_test_callback(void *ptr) {
|
|
||||||
two_member_union_test_function_type f = (two_member_union_test_function_type)ptr;
|
|
||||||
two_member_union_test_type a, b;
|
|
||||||
a.x = 34;
|
|
||||||
b = f(a);
|
|
||||||
return (b.x == a.x*2) ? 0 : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int two_member_union_test(void) {
|
|
||||||
const char *src =
|
|
||||||
"typedef union two_member_union_test_type_u {int x; long y;} two_member_union_test_type;\n"
|
|
||||||
"two_member_union_test_type f(two_member_union_test_type a) {\n"
|
|
||||||
" two_member_union_test_type b;\n"
|
|
||||||
" b.x = a.x * 2;\n"
|
|
||||||
" return b;\n"
|
|
||||||
"}\n";
|
|
||||||
return run_callback(src, two_member_union_test_callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Win64 calling convention test.
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef struct many_struct_test_type_s {long long a, b, c;} many_struct_test_type;
|
|
||||||
typedef many_struct_test_type (*many_struct_test_function_type) (many_struct_test_type,many_struct_test_type,many_struct_test_type,many_struct_test_type,many_struct_test_type,many_struct_test_type);
|
|
||||||
|
|
||||||
static int many_struct_test_callback(void *ptr) {
|
|
||||||
many_struct_test_function_type f = (many_struct_test_function_type)ptr;
|
|
||||||
many_struct_test_type v = {1, 2, 3};
|
|
||||||
many_struct_test_type r = f(v,v,v,v,v,v);
|
|
||||||
return ((r.a == 6) && (r.b == 12) && (r.c == 18))?0:-1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int many_struct_test(void) {
|
|
||||||
const char *src =
|
|
||||||
"typedef struct many_struct_test_type_s {long long a, b, c;} many_struct_test_type;\n"
|
|
||||||
"many_struct_test_type f(many_struct_test_type x1, many_struct_test_type x2, many_struct_test_type x3, many_struct_test_type x4, many_struct_test_type x5, many_struct_test_type x6) {\n"
|
|
||||||
" many_struct_test_type y;\n"
|
|
||||||
" y.a = x1.a + x2.a + x3.a + x4.a + x5.a + x6.a;\n"
|
|
||||||
" y.b = x1.b + x2.b + x3.b + x4.b + x5.b + x6.b;\n"
|
|
||||||
" y.c = x1.c + x2.c + x3.c + x4.c + x5.c + x6.c;\n"
|
|
||||||
" return y;\n"
|
|
||||||
"}\n";
|
|
||||||
return run_callback(src, many_struct_test_callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Win64 calling convention test.
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef struct many_struct_test_2_type_s {int a, b;} many_struct_test_2_type;
|
|
||||||
typedef many_struct_test_2_type (*many_struct_test_2_function_type) (many_struct_test_2_type,many_struct_test_2_type,many_struct_test_2_type,many_struct_test_2_type,many_struct_test_2_type,many_struct_test_2_type);
|
|
||||||
|
|
||||||
static int many_struct_test_2_callback(void *ptr) {
|
|
||||||
many_struct_test_2_function_type f = (many_struct_test_2_function_type)ptr;
|
|
||||||
many_struct_test_2_type v = {1,2};
|
|
||||||
many_struct_test_2_type r = f(v,v,v,v,v,v);
|
|
||||||
return ((r.a == 6) && (r.b == 12))?0:-1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int many_struct_test_2(void) {
|
|
||||||
const char *src =
|
|
||||||
"typedef struct many_struct_test_2_type_s {int a, b;} many_struct_test_2_type;\n"
|
|
||||||
"many_struct_test_2_type f(many_struct_test_2_type x1, many_struct_test_2_type x2, many_struct_test_2_type x3, many_struct_test_2_type x4, many_struct_test_2_type x5, many_struct_test_2_type x6) {\n"
|
|
||||||
" many_struct_test_2_type y;\n"
|
|
||||||
" y.a = x1.a + x2.a + x3.a + x4.a + x5.a + x6.a;\n"
|
|
||||||
" y.b = x1.b + x2.b + x3.b + x4.b + x5.b + x6.b;\n"
|
|
||||||
" return y;\n"
|
|
||||||
"}\n";
|
|
||||||
return run_callback(src, many_struct_test_2_callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Win64 calling convention test.
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef struct many_struct_test_3_type_s {int a, b;} many_struct_test_3_type;
|
|
||||||
typedef many_struct_test_3_type (*many_struct_test_3_function_type) (many_struct_test_3_type,many_struct_test_3_type,many_struct_test_3_type,many_struct_test_3_type,many_struct_test_3_type,many_struct_test_3_type, ...);
|
|
||||||
typedef struct many_struct_test_3_struct_type { many_struct_test_3_function_type f; many_struct_test_3_function_type *f2; } many_struct_test_3_struct_type;
|
|
||||||
|
|
||||||
static void many_struct_test_3_dummy(double d, ...)
|
|
||||||
{
|
|
||||||
volatile double x = d;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int many_struct_test_3_callback(void *ptr) {
|
|
||||||
many_struct_test_3_struct_type s = { ptr, };
|
|
||||||
many_struct_test_3_struct_type *s2 = &s;
|
|
||||||
s2->f2 = &s2->f;
|
|
||||||
many_struct_test_3_dummy(1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, &s2);
|
|
||||||
many_struct_test_3_function_type f = *(s2->f2);
|
|
||||||
many_struct_test_3_type v = {1,2};
|
|
||||||
many_struct_test_3_type r = (*((s2->f2=&f)+0))(v,v,v,v,v,v,1.0);
|
|
||||||
return ((r.a == 6) && (r.b == 12))?0:-1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int many_struct_test_3(void) {
|
|
||||||
const char *src =
|
|
||||||
"typedef struct many_struct_test_3_type_s {int a, b;} many_struct_test_3_type;\n"
|
|
||||||
"many_struct_test_3_type f(many_struct_test_3_type x1, many_struct_test_3_type x2, many_struct_test_3_type x3, many_struct_test_3_type x4, many_struct_test_3_type x5, many_struct_test_3_type x6, ...) {\n"
|
|
||||||
" many_struct_test_3_type y;\n"
|
|
||||||
" y.a = x1.a + x2.a + x3.a + x4.a + x5.a + x6.a;\n"
|
|
||||||
" y.b = x1.b + x2.b + x3.b + x4.b + x5.b + x6.b;\n"
|
|
||||||
" return y;\n"
|
|
||||||
"}\n";
|
|
||||||
return run_callback(src, many_struct_test_3_callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* stdarg_test: Test variable argument list ABI
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef struct {long long a, b, c;} stdarg_test_struct_type;
|
|
||||||
typedef void (*stdarg_test_function_type) (int,int,int,...);
|
|
||||||
|
|
||||||
static int stdarg_test_callback(void *ptr) {
|
|
||||||
stdarg_test_function_type f = (stdarg_test_function_type)ptr;
|
|
||||||
int x;
|
|
||||||
double y;
|
|
||||||
stdarg_test_struct_type z = {1, 2, 3}, w;
|
|
||||||
f(10, 10, 5,
|
|
||||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, &x,
|
|
||||||
1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, &y,
|
|
||||||
z, z, z, z, z, &w);
|
|
||||||
return ((x == 55) && (y == 55) && (w.a == 5) && (w.b == 10) && (w.c == 15)) ? 0 : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int stdarg_test(void) {
|
|
||||||
const char *src =
|
|
||||||
"#include <stdarg.h>\n"
|
|
||||||
"typedef struct {long long a, b, c;} stdarg_test_struct_type;\n"
|
|
||||||
"void f(int n_int, int n_float, int n_struct, ...) {\n"
|
|
||||||
" int i, ti = 0;\n"
|
|
||||||
" double td = 0.0;\n"
|
|
||||||
" stdarg_test_struct_type ts = {0,0,0}, tmp;\n"
|
|
||||||
" va_list ap;\n"
|
|
||||||
" va_start(ap, n_struct);\n"
|
|
||||||
" for (i = 0, ti = 0; i < n_int; ++i)\n"
|
|
||||||
" ti += va_arg(ap, int);\n"
|
|
||||||
" *va_arg(ap, int*) = ti;\n"
|
|
||||||
" for (i = 0, td = 0; i < n_float; ++i)\n"
|
|
||||||
" td += va_arg(ap, double);\n"
|
|
||||||
" *va_arg(ap, double*) = td;\n"
|
|
||||||
" for (i = 0; i < n_struct; ++i) {\n"
|
|
||||||
" tmp = va_arg(ap, stdarg_test_struct_type);\n"
|
|
||||||
" ts.a += tmp.a; ts.b += tmp.b; ts.c += tmp.c;"
|
|
||||||
" }\n"
|
|
||||||
" *va_arg(ap, stdarg_test_struct_type*) = ts;\n"
|
|
||||||
" va_end(ap);"
|
|
||||||
"}\n";
|
|
||||||
return run_callback(src, stdarg_test_callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct {long long a, b;} stdarg_many_test_struct_type;
|
|
||||||
typedef void (*stdarg_many_test_function_type) (int, int, int, int, int,
|
|
||||||
stdarg_many_test_struct_type,
|
|
||||||
int, int, ...);
|
|
||||||
|
|
||||||
static int stdarg_many_test_callback(void *ptr)
|
|
||||||
{
|
|
||||||
stdarg_many_test_function_type f = (stdarg_many_test_function_type)ptr;
|
|
||||||
int x;
|
|
||||||
stdarg_many_test_struct_type l = {10, 11};
|
|
||||||
f(1, 2, 3, 4, 5, l, 6, 7, &x, 44);
|
|
||||||
return x == 44 ? 0 : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int stdarg_many_test(void)
|
|
||||||
{
|
|
||||||
const char *src =
|
|
||||||
"#include <stdarg.h>\n"
|
|
||||||
"typedef struct {long long a, b;} stdarg_many_test_struct_type;\n"
|
|
||||||
"void f (int a, int b, int c, int d, int e, stdarg_many_test_struct_type l, int f, int g, ...){\n"
|
|
||||||
" va_list ap;\n"
|
|
||||||
" int *p;\n"
|
|
||||||
" va_start (ap, g);\n"
|
|
||||||
" p = va_arg(ap, int*);\n"
|
|
||||||
" *p = va_arg(ap, int);\n"
|
|
||||||
" va_end (ap);\n"
|
|
||||||
"}\n";
|
|
||||||
return run_callback(src, stdarg_many_test_callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Test Win32 stdarg handling, since the calling convention will pass a pointer
|
|
||||||
* to the struct and the stdarg pointer must point to that pointer initially.
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef struct {long long a, b, c;} stdarg_struct_test_struct_type;
|
|
||||||
typedef int (*stdarg_struct_test_function_type) (stdarg_struct_test_struct_type a, ...);
|
|
||||||
|
|
||||||
static int stdarg_struct_test_callback(void *ptr) {
|
|
||||||
stdarg_struct_test_function_type f = (stdarg_struct_test_function_type)ptr;
|
|
||||||
stdarg_struct_test_struct_type v = {10, 35, 99};
|
|
||||||
int x = f(v, 234);
|
|
||||||
return (x == 378) ? 0 : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int stdarg_struct_test(void) {
|
|
||||||
const char *src =
|
|
||||||
"#include <stdarg.h>\n"
|
|
||||||
"typedef struct {long long a, b, c;} stdarg_struct_test_struct_type;\n"
|
|
||||||
"int f(stdarg_struct_test_struct_type a, ...) {\n"
|
|
||||||
" va_list ap;\n"
|
|
||||||
" va_start(ap, a);\n"
|
|
||||||
" int z = va_arg(ap, int);\n"
|
|
||||||
" va_end(ap);\n"
|
|
||||||
" return z + a.a + a.b + a.c;\n"
|
|
||||||
"}\n";
|
|
||||||
return run_callback(src, stdarg_struct_test_callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Test that x86-64 arranges the stack correctly for arguments with alignment >8 bytes */
|
|
||||||
|
|
||||||
typedef LONG_DOUBLE (*arg_align_test_callback_type) (LONG_DOUBLE,int,LONG_DOUBLE,int,LONG_DOUBLE);
|
|
||||||
|
|
||||||
static int arg_align_test_callback(void *ptr) {
|
|
||||||
arg_align_test_callback_type f = (arg_align_test_callback_type)ptr;
|
|
||||||
long double x = f(12, 0, 25, 0, 37);
|
|
||||||
return (x == 74) ? 0 : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int arg_align_test(void) {
|
|
||||||
const char *src =
|
|
||||||
"long double f(long double a, int b, long double c, int d, long double e) {\n"
|
|
||||||
" return a + c + e;\n"
|
|
||||||
"}\n";
|
|
||||||
return run_callback(src, arg_align_test_callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define RUN_TEST(t) \
|
|
||||||
if (!testname || (strcmp(#t, testname) == 0)) { \
|
|
||||||
fputs(#t "... ", stdout); \
|
|
||||||
fflush(stdout); \
|
|
||||||
if (t() == 0) { \
|
|
||||||
fputs("success\n", stdout); \
|
|
||||||
} else { \
|
|
||||||
fputs("failure\n", stdout); \
|
|
||||||
retval = EXIT_FAILURE; \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
|
||||||
int i;
|
|
||||||
const char *testname = NULL;
|
|
||||||
int retval = EXIT_SUCCESS;
|
|
||||||
|
|
||||||
/* if tcclib.h and libtcc1.a are not installed, where can we find them */
|
|
||||||
for (i = 1; i < argc; ++i) {
|
|
||||||
if (!memcmp(argv[i], "run_test=", 9))
|
|
||||||
testname = argv[i] + 9;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_argv = argv, g_argc = argc;
|
|
||||||
|
|
||||||
RUN_TEST(ret_int_test);
|
|
||||||
RUN_TEST(ret_longlong_test);
|
|
||||||
RUN_TEST(ret_float_test);
|
|
||||||
RUN_TEST(ret_double_test);
|
|
||||||
RUN_TEST(ret_longdouble_test);
|
|
||||||
RUN_TEST(ret_2float_test);
|
|
||||||
RUN_TEST(ret_2double_test);
|
|
||||||
RUN_TEST(ret_8plus2double_test);
|
|
||||||
RUN_TEST(ret_6plus2longlong_test);
|
|
||||||
#if !defined __x86_64__ || defined _WIN32
|
|
||||||
/* currently broken on x86_64 linux */
|
|
||||||
RUN_TEST(ret_mixed_test);
|
|
||||||
RUN_TEST(ret_mixed2_test);
|
|
||||||
#endif
|
|
||||||
RUN_TEST(ret_mixed3_test);
|
|
||||||
RUN_TEST(reg_pack_test);
|
|
||||||
RUN_TEST(reg_pack_longlong_test);
|
|
||||||
RUN_TEST(sret_test);
|
|
||||||
RUN_TEST(one_member_union_test);
|
|
||||||
RUN_TEST(two_member_union_test);
|
|
||||||
RUN_TEST(many_struct_test);
|
|
||||||
RUN_TEST(many_struct_test_2);
|
|
||||||
RUN_TEST(many_struct_test_3);
|
|
||||||
RUN_TEST(stdarg_test);
|
|
||||||
RUN_TEST(stdarg_many_test);
|
|
||||||
RUN_TEST(stdarg_struct_test);
|
|
||||||
RUN_TEST(arg_align_test);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
@ -1,243 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# Note: "{r3}" is definitely different--but would complicate the assembler.
|
|
||||||
|
|
||||||
state="`mktemp -d`"
|
|
||||||
cat ../arm-tok.h | \
|
|
||||||
grep DEF_ASM | \
|
|
||||||
grep -v 'not useful' | \
|
|
||||||
grep -v '#define' | \
|
|
||||||
grep -v '/[*]' | \
|
|
||||||
grep -v 'DEF_ASM_CONDED_WITH_SUFFIX(x' | \
|
|
||||||
sed -e 's;^[ ]*DEF_ASM_CONDED_VFP_F32_F64[^(]*(\(.*\)).*$; DEF_ASM_CONDED(\1.f32)\
|
|
||||||
DEF_ASM_CONDED(\1.f64);g' | \
|
|
||||||
sed -e 's;^[ ]*DEF_ASM[^(]*(\(.*\)).*$;\1;g' -e 's;, ;.;g' | \
|
|
||||||
egrep -v '^((r|c|p|s|d)[0-9]+|fp|ip|sp|lr|pc|asl|apsr_nzcv|fpsid|fpscr|fpexc)$' | while read s
|
|
||||||
do
|
|
||||||
as_opts=""
|
|
||||||
if [ "${s#v}" != "${s}" ]
|
|
||||||
then
|
|
||||||
if grep -q "CONFIG_arm_vfp=yes" ../config.mak
|
|
||||||
then
|
|
||||||
as_opts="${as_opts} -mfpu=vfp"
|
|
||||||
else
|
|
||||||
echo "note: skipping VFP instruction: $s (because VFP is disabled)">&2
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
ok=0
|
|
||||||
for args in "r3, r4, r5, r6" \
|
|
||||||
"r3, r4, r5" \
|
|
||||||
"r3, r4, r5, asl #7" \
|
|
||||||
"r3, r4, r5, lsl #7" \
|
|
||||||
"r3, r4, r5, asr #7" \
|
|
||||||
"r3, r4, r5, lsr #7" \
|
|
||||||
"r3, r4, r5, ror #7" \
|
|
||||||
"r3, r4, r5, rrx" \
|
|
||||||
"r3, r4, r5, asl r6" \
|
|
||||||
"r3, r4, r5, lsl r6" \
|
|
||||||
"r3, r4, r5, asr r6" \
|
|
||||||
"r3, r4, r5, lsr r6" \
|
|
||||||
"r3, r4, r5, ror r6" \
|
|
||||||
"r3, r4, #5, asl #7" \
|
|
||||||
"r3, r4, #5, lsl #7" \
|
|
||||||
"r3, r4, #5, asr #7" \
|
|
||||||
"r3, r4, #5, lsr #7" \
|
|
||||||
"r3, r4, #5, ror #7" \
|
|
||||||
"r3, r4, #5, rrx" \
|
|
||||||
"r3, #5, r4" \
|
|
||||||
"r3, #4, #8" \
|
|
||||||
"r3, r4, asl #5" \
|
|
||||||
"r3, r4, lsl #5" \
|
|
||||||
"r3, r4, asr #5" \
|
|
||||||
"r3, r4, lsr #5" \
|
|
||||||
"r3, r4, ror #5" \
|
|
||||||
"r3, r4, ror #8" \
|
|
||||||
"r3, r4, asl r5" \
|
|
||||||
"r3, r4, lsl r5" \
|
|
||||||
"r3, r4, asr r5" \
|
|
||||||
"r3, r4, lsr r5" \
|
|
||||||
"r3, r4, ror r5" \
|
|
||||||
"r3, r4, ror #8" \
|
|
||||||
"r3, r4, ror #16" \
|
|
||||||
"r3, r4, ror #24" \
|
|
||||||
"r3, r4, rrx" \
|
|
||||||
"r3, #4, asl #5" \
|
|
||||||
"r3, #4, lsl #5" \
|
|
||||||
"r3, #4, asr #5" \
|
|
||||||
"r3, #4, lsr #5" \
|
|
||||||
"r3, #4, ror #5" \
|
|
||||||
"r3, r4, rrx" \
|
|
||||||
"r3, r4" \
|
|
||||||
"r3" \
|
|
||||||
"{r3,r4,r5}" \
|
|
||||||
"{r3,r5,r4}" \
|
|
||||||
"r2!, {r3,r4,r5}" \
|
|
||||||
"r2!, {r3,r5,r4}" \
|
|
||||||
"r2, {r3,r4,r5}" \
|
|
||||||
"r2, {r3,r5,r4}" \
|
|
||||||
"r2, [r3, r4]" \
|
|
||||||
"r2, [r3, r4]!" \
|
|
||||||
"r2, [r3, -r4]" \
|
|
||||||
"r2, [r3, -r4]!" \
|
|
||||||
"r2, [r3], r4" \
|
|
||||||
"r2, [r3], -r4" \
|
|
||||||
"r2, [r3]" \
|
|
||||||
"r2, r3, [r4, lsl# 2]" \
|
|
||||||
"r2, [r3, r4, lsr# 1]" \
|
|
||||||
"r2, [r3, r4, lsr# 2]!" \
|
|
||||||
"r2, [r3, -r4, ror# 3]" \
|
|
||||||
"r2, [r3, -r4, lsl# 1]!" \
|
|
||||||
"r2, [r3], r4, lsl# 3" \
|
|
||||||
"r2, [r3], -r4, asr# 31" \
|
|
||||||
"r2, [r3], -r4, asl# 1" \
|
|
||||||
"r2, [r3], -r4, rrx" \
|
|
||||||
"r2, [r3]" \
|
|
||||||
"r2, r3, [r4]" \
|
|
||||||
"r2, [r3, #4]" \
|
|
||||||
"r2, [r3, #-4]" \
|
|
||||||
"r2, [r3, #0x45]" \
|
|
||||||
"r2, [r3, #-0x45]" \
|
|
||||||
"r2, r3, #4" \
|
|
||||||
"r2, r3, #-4" \
|
|
||||||
"p10, #7, c2, c0, c1, #4" \
|
|
||||||
"p10, #7, r2, c0, c1, #4" \
|
|
||||||
"p10, #0, c2, c0, c1, #4" \
|
|
||||||
"p10, #0, r2, c0, c1, #4" \
|
|
||||||
"r2, #4" \
|
|
||||||
"r2, #-4" \
|
|
||||||
"r2, #0xEFFF" \
|
|
||||||
"r3, #0x0000" \
|
|
||||||
"r4, #0x0201" \
|
|
||||||
"r4, #0xFFFFFF00" \
|
|
||||||
"r2, #-4" \
|
|
||||||
"p10, #7, c2, c0, c1, #4" \
|
|
||||||
"p10, #7, r2, c0, c1, #4" \
|
|
||||||
"#4" \
|
|
||||||
"#-4" \
|
|
||||||
"p5, c2, [r3]" \
|
|
||||||
"p5, c3, [r4]" \
|
|
||||||
"p5, c2, [r3, #4]" \
|
|
||||||
"p5, c2, [r3, #-4]" \
|
|
||||||
"p5, c2, [r3, #0x45]" \
|
|
||||||
"p5, c2, [r3, #-0x45]" \
|
|
||||||
"s2, [r3]" \
|
|
||||||
"s3, [r4]" \
|
|
||||||
"s2, [r3, #4]" \
|
|
||||||
"s2, [r3, #-4]" \
|
|
||||||
"s2, [r3, #0x45]" \
|
|
||||||
"s2, [r3, #-0x45]" \
|
|
||||||
"r1, {d3-d4}" \
|
|
||||||
"r1!, {d3-d4}" \
|
|
||||||
"r2, {d4-d15}" \
|
|
||||||
"r3!, {d4-d15}" \
|
|
||||||
"r3!, {d4}" \
|
|
||||||
"r2, {s4-s31}" \
|
|
||||||
"r3!, {s4}" \
|
|
||||||
"{d3-d4}" \
|
|
||||||
"{d4-d15}" \
|
|
||||||
"{d4}" \
|
|
||||||
"{s4-s31}" \
|
|
||||||
"{s4}" \
|
|
||||||
"s2, s3, s4" \
|
|
||||||
"s2, s3" \
|
|
||||||
"d2, d3, d4" \
|
|
||||||
"d2, d3" \
|
|
||||||
"s2, #0" \
|
|
||||||
"d2, #0" \
|
|
||||||
"s3, #0.0" \
|
|
||||||
"d3, #0.0" \
|
|
||||||
"s4, #-0.1796875" \
|
|
||||||
"d4, #0.1796875" \
|
|
||||||
"r2, r3, d1" \
|
|
||||||
"d1, r2, r3" \
|
|
||||||
"s1, r2" \
|
|
||||||
"r2, s1" \
|
|
||||||
"r2, fpexc" \
|
|
||||||
"r2, fpscr" \
|
|
||||||
"r2, fpsid" \
|
|
||||||
"apsr_nzcv, fpscr" \
|
|
||||||
"fpexc, r2" \
|
|
||||||
"fpscr, r2" \
|
|
||||||
"fpsid, r2" \
|
|
||||||
"s3, d4" \
|
|
||||||
"d4, s3" \
|
|
||||||
""
|
|
||||||
do
|
|
||||||
#echo ".syntax unified" > a.s
|
|
||||||
err="`mktemp --suffix=-stderr.log`"
|
|
||||||
as_object="${state}/as-$s $args.o"
|
|
||||||
tcc_object="${state}/tcc-$s $args.o"
|
|
||||||
expected="${state}/expected-$s $args"
|
|
||||||
got="${state}/got-$s $args"
|
|
||||||
if echo "$s $args" | "${CROSS_COMPILE}as" -mlittle-endian ${as_opts} -o "${as_object}" - 2>"${err}"
|
|
||||||
then
|
|
||||||
cat "${err}"
|
|
||||||
rm -f "${err}"
|
|
||||||
total_count=`expr $total_count + 1`
|
|
||||||
"${CROSS_COMPILE}objdump" -S "${as_object}" |grep "^[ ]*0:" >"${expected}"
|
|
||||||
|
|
||||||
#echo '__asm__("'"$s ${args}"'");' > "${csource}"
|
|
||||||
if echo '__asm__("'"$s ${args}"'");'| ${TCC} -o "${tcc_object}" -c -
|
|
||||||
then
|
|
||||||
"${CROSS_COMPILE}objdump" -S "${tcc_object}" |grep "^[ ]*0:" >"${got}"
|
|
||||||
if diff -u "${got}" "${expected}"
|
|
||||||
then
|
|
||||||
touch "${state}/ok-$s $args"
|
|
||||||
else
|
|
||||||
echo "warning: '$s $args' did not work in tcc (see above)">&2
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
rm -f "${tcc_object}"
|
|
||||||
echo "warning: '$s $args' did not work in tcc">&2
|
|
||||||
fi
|
|
||||||
ok=1
|
|
||||||
else # GNU as can't do it either--so we don't care
|
|
||||||
rm -f "${as_object}"
|
|
||||||
fi
|
|
||||||
rm -f "${err}"
|
|
||||||
done
|
|
||||||
if [ "${ok}" -eq "0" ]
|
|
||||||
then
|
|
||||||
echo "warning: $s could not be used.">&2
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
successful_count="$(ls -1 "${state}/ok-"* |wc -l)"
|
|
||||||
total_count="$(ls -1 "${state}/as-"*.o |wc -l)"
|
|
||||||
echo "${successful_count} of ${total_count} tests succeeded.">&2
|
|
||||||
if [ "${successful_count}" -eq "${total_count}" ]
|
|
||||||
then
|
|
||||||
rm -rf "${state}"
|
|
||||||
exit 0
|
|
||||||
else
|
|
||||||
status=0
|
|
||||||
for s in "${state}/as-"*.o
|
|
||||||
do
|
|
||||||
test="$(basename "$s")"
|
|
||||||
test="${test%.o}"
|
|
||||||
test="${test#as-}"
|
|
||||||
t="${state}/ok-${test}"
|
|
||||||
if [ ! -f "$t" ]
|
|
||||||
then
|
|
||||||
case "${test}" in
|
|
||||||
"bl r3"|"b r3"|"mov r2, #0xEFFF"|"mov r4, #0x0201")
|
|
||||||
known_failure=" (known failure)"
|
|
||||||
;;
|
|
||||||
"vmov.f32 r2, r3, d1"|"vmov.f32 d1, r2, r3") # GNU as bug
|
|
||||||
known_failure=" (known failure)"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
known_failure=""
|
|
||||||
status=1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
echo "Failed test: ${test}${known_failure}">&2
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
rm -rf "${state}"
|
|
||||||
exit "${status}"
|
|
||||||
fi
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user