mirror of
https://github.com/mirror/tinycc.git
synced 2026-08-26 11:43:27 +08:00
Compare commits
54 Commits
release_0_
...
release_0_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f22e961f80 | ||
|
|
a327c7a552 | ||
|
|
4d9aaacc85 | ||
|
|
cd24bd05b4 | ||
|
|
9bcc0b970b | ||
|
|
88b3cb570e | ||
|
|
6ed868c51c | ||
|
|
e2c89576c7 | ||
|
|
c6537d11cb | ||
|
|
2eaa1104f7 | ||
|
|
265dddbecf | ||
|
|
3667408a57 | ||
|
|
5342b32eef | ||
|
|
adb1456472 | ||
|
|
6c96c41ee4 | ||
|
|
f466577673 | ||
|
|
34140dd627 | ||
|
|
b0d40c12da | ||
|
|
f99d3de221 | ||
|
|
2de1b2d14c | ||
|
|
2bcb964694 | ||
|
|
3e8b9e6d10 | ||
|
|
d778bde7f9 | ||
|
|
54bf8c0556 | ||
|
|
2bcc187b1b | ||
|
|
d13aa5426a | ||
|
|
7097268ac5 | ||
|
|
84f4e99635 | ||
|
|
8b0c4c6582 | ||
|
|
fb2c34f8cd | ||
|
|
65b974e396 | ||
|
|
365d0ad545 | ||
|
|
52b7254b9c | ||
|
|
0bea5c7f21 | ||
|
|
24a19cc37e | ||
|
|
38d2e8b9d8 | ||
|
|
3b8cd565be | ||
|
|
200b58dad8 | ||
|
|
6ca0299e5b | ||
|
|
5487bc23c8 | ||
|
|
aee0da0b17 | ||
|
|
6d66b5a971 | ||
|
|
8ba48f84fe | ||
|
|
62c5a5466a | ||
|
|
7bc5e51847 | ||
|
|
7b8e283980 | ||
|
|
e9c64e3f47 | ||
|
|
81f957ae09 | ||
|
|
3ba1190eb4 | ||
|
|
6f8b8887b1 | ||
|
|
bb24eb9de4 | ||
|
|
44738b516a | ||
|
|
c42532c37d | ||
|
|
b0b8ac13ce |
75
Changelog
75
Changelog
@@ -1,3 +1,78 @@
|
||||
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)
|
||||
|
||||
39
Makefile
39
Makefile
@@ -3,9 +3,12 @@
|
||||
#
|
||||
include config.mak
|
||||
|
||||
CFLAGS=-O2 -g -Wall
|
||||
CFLAGS+=-g -Wall
|
||||
ifndef CONFIG_WIN32
|
||||
LIBS=-ldl
|
||||
LIBS=-lm
|
||||
ifndef CONFIG_NOLDL
|
||||
LIBS+=-ldl
|
||||
endif
|
||||
BCHECK_O=bcheck.o
|
||||
endif
|
||||
CFLAGS_P=$(CFLAGS) -pg -static -DCONFIG_TCC_STATIC
|
||||
@@ -16,6 +19,9 @@ ifeq ($(GCC_MAJOR),2)
|
||||
CFLAGS+=-m386 -malign-functions=0
|
||||
else
|
||||
CFLAGS+=-march=i386 -falign-functions=0 -fno-strict-aliasing
|
||||
ifneq ($(GCC_MAJOR),3)
|
||||
CFLAGS+=-Wno-pointer-sign -Wno-sign-compare
|
||||
endif
|
||||
endif
|
||||
|
||||
DISAS=objdump -d
|
||||
@@ -26,7 +32,7 @@ PROGS=tcc$(EXESUF)
|
||||
ifdef CONFIG_CROSS
|
||||
PROGS+=c67-tcc$(EXESUF) arm-tcc$(EXESUF)
|
||||
endif
|
||||
PROGS+=tiny_impdef$(EXESUF)
|
||||
PROGS+=tiny_impdef$(EXESUF) tiny_libmaker$(EXESUF)
|
||||
else
|
||||
ifeq ($(ARCH),i386)
|
||||
PROGS=tcc$(EXESUF)
|
||||
@@ -60,7 +66,7 @@ test: test.ref test.out
|
||||
@if diff -u test.ref test.out ; then echo "Auto Test OK"; fi
|
||||
|
||||
tcctest.ref: tcctest.c
|
||||
$(CC) $(CFLAGS) -I. -o $@ $<
|
||||
$(CC) $(CFLAGS) -w -I. -o $@ $<
|
||||
|
||||
test.ref: tcctest.ref
|
||||
./tcctest.ref > $@
|
||||
@@ -158,24 +164,29 @@ c67-tcc$(EXESUF): tcc.c c67-gen.c tccelf.c tccasm.c tcctok.h libtcc.h tcccoff.c
|
||||
$(CC) $(CFLAGS) -DTCC_TARGET_C67 -o $@ $< $(LIBS)
|
||||
|
||||
arm-tcc$(EXESUF): tcc.c arm-gen.c tccelf.c tccasm.c tcctok.h libtcc.h
|
||||
$(CC) $(CFLAGS) -DTCC_TARGET_ARM -o $@ $< $(LIBS)
|
||||
$(CC) $(CFLAGS) -DTCC_TARGET_ARM -DTCC_ARM_EABI -o $@ $< $(LIBS)
|
||||
|
||||
i386-win32-tcc$(EXESUF): tcc.c i386-gen.c tccelf.c tccasm.c i386-asm.c tcctok.h libtcc.h i386-asm.h tccpe.c
|
||||
$(CC) $(CFLAGS) -DTCC_TARGET_PE -o $@ $< $(LIBS)
|
||||
|
||||
# windows utilities
|
||||
tiny_impdef$(EXESUF): tiny_impdef.c
|
||||
tiny_impdef$(EXESUF): win32/tools/tiny_impdef.c
|
||||
$(CC) $(CFLAGS) -o $@ $< -lkernel32
|
||||
tiny_libmaker$(EXESUF): win32/tools/tiny_libmaker.c
|
||||
$(CC) $(CFLAGS) -o $@ $< -lkernel32
|
||||
|
||||
# TinyCC runtime libraries
|
||||
ifdef CONFIG_WIN32
|
||||
# for windows, we must use TCC because we generate ELF objects
|
||||
LIBTCC1_OBJS=$(addprefix win32/lib/, crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o) libtcc1.o
|
||||
LIBTCC1_CC=./tcc.exe -Bwin32
|
||||
LIBTCC1_CC=./tcc.exe -Bwin32 -DTCC_TARGET_PE
|
||||
else
|
||||
LIBTCC1_OBJS=libtcc1.o
|
||||
LIBTCC1_CC=$(CC)
|
||||
endif
|
||||
ifeq ($(ARCH),i386)
|
||||
LIBTCC1_OBJS+=alloca86.o alloca86-bt.o
|
||||
endif
|
||||
|
||||
%.o: %.c
|
||||
$(LIBTCC1_CC) -O2 -Wall -c -o $@ $<
|
||||
@@ -191,7 +202,7 @@ bcheck.o: bcheck.c
|
||||
|
||||
install: tcc_install libinstall
|
||||
|
||||
tcc_install: $(PROGS) tcc.1 libtcc1.a $(BCHECK_O) tcc-doc.html tcc.1
|
||||
tcc_install: $(PROGS) tcc.1 libtcc1.a $(BCHECK_O) tcc-doc.html
|
||||
mkdir -p "$(bindir)"
|
||||
$(INSTALL) -s -m755 $(PROGS) "$(bindir)"
|
||||
ifndef CONFIG_WIN32
|
||||
@@ -217,7 +228,7 @@ ifdef CONFIG_WIN32
|
||||
endif
|
||||
|
||||
clean:
|
||||
rm -f *~ *.o *.a tcc tcc1 tcct tcc_g tcctest.ref *.bin *.i ex2 \
|
||||
rm -f *~ *.o *.a tcc tcct tcc_g tcctest.ref *.bin *.i ex2 \
|
||||
core gmon.out test.out test.ref a.out tcc_p \
|
||||
*.exe *.lib tcc.pod libtcc_test \
|
||||
tcctest[1234] test[1234].out $(PROGS) win32/lib/*.o
|
||||
@@ -237,7 +248,11 @@ libinstall: libtcc.a
|
||||
$(INSTALL) -m644 libtcc.h "$(includedir)"
|
||||
|
||||
libtcc.o: tcc.c i386-gen.c Makefile
|
||||
ifdef CONFIG_WIN32
|
||||
$(CC) $(CFLAGS) -DTCC_TARGET_PE -DLIBTCC -c -o $@ $<
|
||||
else
|
||||
$(CC) $(CFLAGS) -DLIBTCC -c -o $@ $<
|
||||
endif
|
||||
|
||||
libtcc.a: libtcc.o
|
||||
$(AR) rcs $@ $^
|
||||
@@ -282,11 +297,11 @@ cache: tcc_g
|
||||
|
||||
# documentation and man page
|
||||
tcc-doc.html: tcc-doc.texi
|
||||
texi2html -monolithic -number $<
|
||||
-texi2html -monolithic -number $<
|
||||
|
||||
tcc.1: tcc-doc.texi
|
||||
./texi2pod.pl $< tcc.pod
|
||||
pod2man --section=1 --center=" " --release=" " tcc.pod > $@
|
||||
-./texi2pod.pl $< tcc.pod
|
||||
-pod2man --section=1 --center=" " --release=" " tcc.pod > $@
|
||||
|
||||
FILE=tcc-$(shell cat VERSION)
|
||||
|
||||
|
||||
82
TODO
82
TODO
@@ -1,61 +1,65 @@
|
||||
TODO list:
|
||||
|
||||
- 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
|
||||
Bugs:
|
||||
|
||||
- fix macro substitution with nested definitions (ShangHongzhang)
|
||||
- FPU st(0) is left unclean (kwisatz haderach). Incompatible with
|
||||
optimized gcc/msc code
|
||||
|
||||
- constructors
|
||||
- cast bug (Peter Wang)
|
||||
- define incomplete type if defined several times (Peter Wang).
|
||||
- long long constant evaluation
|
||||
- configure --cc=tcc (still one bug in libtcc1.c)
|
||||
- disable-asm and disable-bcheck options
|
||||
- test binutils/gcc compile
|
||||
- add alloca(), __builtin_expect()
|
||||
- gcc '-E' option.
|
||||
- optimize VT_LOCAL + const
|
||||
- tci patch + argument.
|
||||
- '-b' bug.
|
||||
- atexit (Nigel Horne)
|
||||
- see -lxxx bug (Michael Charity).
|
||||
- see transparent union pb in /urs/include/sys/socket.h
|
||||
- precise behaviour of typeof with arrays ? (__put_user macro)
|
||||
- #include_next support for /usr/include/limits ?
|
||||
but should suffice for most cases)
|
||||
- handle '? x, y : z' in unsized variable initialization (',' is
|
||||
considered incorrectly as separator in preparser)
|
||||
- function pointers/lvalues in ? : (linux kernel net/core/dev.c)
|
||||
- transform functions to function pointers in function parameters (net/ipv4/ip_output.c)
|
||||
- transform functions to function pointers in function parameters
|
||||
(net/ipv4/ip_output.c)
|
||||
- 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
|
||||
- fix invalid cast in comparison 'if (v == (int8_t)v)'
|
||||
- packed attribute
|
||||
- finish varargs.h support (gcc 3.2 testsuite issue)
|
||||
- fix static functions declared inside block
|
||||
- fix multiple unions init
|
||||
- sizeof, alignof, typeof can still generate code in some cases.
|
||||
- Fix the remaining libtcc memory leaks.
|
||||
- make libtcc fully reentrant (except for the compilation stage itself).
|
||||
|
||||
Bound checking:
|
||||
|
||||
- '-b' bug.
|
||||
- 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()
|
||||
- improve '-E' option.
|
||||
- add '-MD' option
|
||||
- atexit (Nigel Horne)
|
||||
- packed attribute
|
||||
- C99: add variable size arrays (gcc 3.2 testsuite issue)
|
||||
- C99: add complex types (gcc 3.2 testsuite issue)
|
||||
- postfix compound literals (see 20010124-1.c)
|
||||
- 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:
|
||||
|
||||
- suppress specific anonymous symbol handling
|
||||
- more parse optimizations (=even faster compilation)
|
||||
- memory alloc optimizations (=even faster compilation)
|
||||
- optimize VT_LOCAL + const
|
||||
- better local variables handling (needed for other targets)
|
||||
|
||||
Not critical:
|
||||
|
||||
@@ -71,11 +75,21 @@ Not critical:
|
||||
- add portable byte code generator and interpreter for other
|
||||
unsupported architectures.
|
||||
- C++: variable declaration in for, minimal 'class' support.
|
||||
- win32: add __stdcall, __intxx. use resolve for bchecked malloc et
|
||||
al. check GetModuleHandle for dlls. check exception code (exception
|
||||
filter func).
|
||||
- win32: __intxx. use resolve for bchecked malloc et al.
|
||||
check exception code (exception filter func).
|
||||
- handle void (__attribute__() *ptr)()
|
||||
|
||||
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.
|
||||
|
||||
45
alloca86-bt.S
Normal file
45
alloca86-bt.S
Normal file
@@ -0,0 +1,45 @@
|
||||
/* ---------------------------------------------- */
|
||||
/* alloca86b.S */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
.globl __bound__alloca
|
||||
|
||||
__bound__alloca:
|
||||
pop %edx
|
||||
pop %eax
|
||||
mov %eax, %ecx
|
||||
add $3,%eax
|
||||
and $-4,%eax
|
||||
jz p6
|
||||
|
||||
#ifdef TCC_TARGET_PE
|
||||
p4:
|
||||
cmp $4096,%eax
|
||||
jle p5
|
||||
sub $4096,%esp
|
||||
sub $4096,%eax
|
||||
test %eax,(%esp)
|
||||
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
|
||||
|
||||
/* ---------------------------------------------- */
|
||||
33
alloca86.S
Normal file
33
alloca86.S
Normal file
@@ -0,0 +1,33 @@
|
||||
/* ---------------------------------------------- */
|
||||
/* alloca86.S */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
.globl _alloca
|
||||
|
||||
_alloca:
|
||||
pop %edx
|
||||
pop %eax
|
||||
add $3,%eax
|
||||
and $-4,%eax
|
||||
jz p3
|
||||
|
||||
#ifdef TCC_TARGET_PE
|
||||
p1:
|
||||
cmp $4096,%eax
|
||||
jle p2
|
||||
sub $4096,%esp
|
||||
sub $4096,%eax
|
||||
test %eax,(%esp)
|
||||
jmp p1
|
||||
p2:
|
||||
#endif
|
||||
|
||||
sub %eax,%esp
|
||||
mov %esp,%eax
|
||||
p3:
|
||||
push %edx
|
||||
push %edx
|
||||
ret
|
||||
|
||||
/* ---------------------------------------------- */
|
||||
446
arm-gen.c
446
arm-gen.c
@@ -20,8 +20,17 @@
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifdef TCC_ARM_EABI
|
||||
#define TCC_ARM_VFP
|
||||
#endif
|
||||
|
||||
|
||||
/* number of available registers */
|
||||
#ifdef TCC_ARM_VFP
|
||||
#define NB_REGS 13
|
||||
#else
|
||||
#define NB_REGS 9
|
||||
#endif
|
||||
|
||||
/* a register can belong to several classes. The classes must be
|
||||
sorted from more general to more precise (see gv2() code which does
|
||||
@@ -37,6 +46,12 @@
|
||||
#define RC_F1 0x0100
|
||||
#define RC_F2 0x0200
|
||||
#define RC_F3 0x0400
|
||||
#ifdef TCC_ARM_VFP
|
||||
#define RC_F4 0x0800
|
||||
#define RC_F5 0x1000
|
||||
#define RC_F6 0x2000
|
||||
#define RC_F7 0x4000
|
||||
#endif
|
||||
#define RC_IRET RC_R0 /* function return: integer register */
|
||||
#define RC_LRET RC_R1 /* function return: second integer register */
|
||||
#define RC_FRET RC_F0 /* function return: float register */
|
||||
@@ -52,6 +67,12 @@ enum {
|
||||
TREG_F1,
|
||||
TREG_F2,
|
||||
TREG_F3,
|
||||
#ifdef TCC_ARM_VFP
|
||||
TREG_F4,
|
||||
TREG_F5,
|
||||
TREG_F6,
|
||||
TREG_F7,
|
||||
#endif
|
||||
};
|
||||
|
||||
int reg_classes[NB_REGS] = {
|
||||
@@ -64,6 +85,12 @@ int reg_classes[NB_REGS] = {
|
||||
/* f1 */ RC_FLOAT | RC_F1,
|
||||
/* f2 */ RC_FLOAT | RC_F2,
|
||||
/* f3 */ RC_FLOAT | RC_F3,
|
||||
#ifdef TCC_ARM_VFP
|
||||
/* d4/s8 */ RC_FLOAT | RC_F4,
|
||||
/* d5/s10 */ RC_FLOAT | RC_F5,
|
||||
/* d6/s12 */ RC_FLOAT | RC_F6,
|
||||
/* d7/s14 */ RC_FLOAT | RC_F7,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int two2mask(int a,int b) {
|
||||
@@ -74,6 +101,10 @@ static int regmask(int r) {
|
||||
return reg_classes[r]&~(RC_INT|RC_FLOAT);
|
||||
}
|
||||
|
||||
#ifdef TCC_ARM_VFP
|
||||
#define T2CPR(t) (((t) & VT_BTYPE) != VT_FLOAT ? 0x100 : 0)
|
||||
#endif
|
||||
|
||||
/* return registers for function */
|
||||
#define REG_IRET TREG_R0 /* single word int return register */
|
||||
#define REG_LRET TREG_R1 /* second word return register (for long long) */
|
||||
@@ -86,12 +117,28 @@ static int regmask(int r) {
|
||||
are directly pushed on stack. */
|
||||
//#define FUNC_STRUCT_PARAM_AS_PTR
|
||||
|
||||
#if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP)
|
||||
static CType float_type, double_type, func_float_type, func_double_type;
|
||||
#endif
|
||||
|
||||
/* pointer size, in bytes */
|
||||
#define PTR_SIZE 4
|
||||
|
||||
/* long double size and alignment, in bytes */
|
||||
#ifdef TCC_ARM_VFP
|
||||
#define LDOUBLE_SIZE 8
|
||||
#endif
|
||||
|
||||
#ifndef LDOUBLE_SIZE
|
||||
#define LDOUBLE_SIZE 8
|
||||
#endif
|
||||
|
||||
#ifdef TCC_ARM_EABI
|
||||
#define LDOUBLE_ALIGN 8
|
||||
#else
|
||||
#define LDOUBLE_ALIGN 4
|
||||
#endif
|
||||
|
||||
/* maximum alignment (for aligned attribute support) */
|
||||
#define MAX_ALIGN 8
|
||||
|
||||
@@ -112,6 +159,7 @@ static int regmask(int r) {
|
||||
|
||||
/******************************************************/
|
||||
static unsigned long func_sub_sp_offset,last_itod_magic;
|
||||
static int leaffunc;
|
||||
|
||||
void o(unsigned long i)
|
||||
{
|
||||
@@ -287,19 +335,28 @@ void gsym(int t)
|
||||
gsym_addr(t, ind);
|
||||
}
|
||||
|
||||
#ifdef TCC_ARM_VFP
|
||||
static unsigned long vfpr(int r)
|
||||
{
|
||||
if(r<TREG_F0 || r>TREG_F7)
|
||||
error("compiler error! register %i is no vfp register",r);
|
||||
return r-5;
|
||||
}
|
||||
#else
|
||||
static unsigned long fpr(int r)
|
||||
{
|
||||
if(r<TREG_F0 || r>TREG_F3)
|
||||
error("compiler error! register %i is no fp register\n",r);
|
||||
error("compiler error! register %i is no fpa register",r);
|
||||
return r-5;
|
||||
}
|
||||
#endif
|
||||
|
||||
static unsigned long intr(int r)
|
||||
{
|
||||
if(r==4)
|
||||
return 12;
|
||||
if((r<0 || r>4) && r!=14)
|
||||
error("compiler error! register %i is no int register\n",r);
|
||||
error("compiler error! register %i is no int register",r);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -335,28 +392,32 @@ static unsigned long mapcc(int cc)
|
||||
switch(cc)
|
||||
{
|
||||
case TOK_ULT:
|
||||
return 0x30000000;
|
||||
return 0x30000000; /* CC/LO */
|
||||
case TOK_UGE:
|
||||
return 0x20000000;
|
||||
return 0x20000000; /* CS/HS */
|
||||
case TOK_EQ:
|
||||
return 0x00000000;
|
||||
return 0x00000000; /* EQ */
|
||||
case TOK_NE:
|
||||
return 0x10000000;
|
||||
return 0x10000000; /* NE */
|
||||
case TOK_ULE:
|
||||
return 0x90000000;
|
||||
return 0x90000000; /* LS */
|
||||
case TOK_UGT:
|
||||
return 0x80000000;
|
||||
return 0x80000000; /* HI */
|
||||
case TOK_Nset:
|
||||
return 0x40000000; /* MI */
|
||||
case TOK_Nclear:
|
||||
return 0x50000000; /* PL */
|
||||
case TOK_LT:
|
||||
return 0xB0000000;
|
||||
return 0xB0000000; /* LT */
|
||||
case TOK_GE:
|
||||
return 0xA0000000;
|
||||
return 0xA0000000; /* GE */
|
||||
case TOK_LE:
|
||||
return 0xD0000000;
|
||||
return 0xD0000000; /* LE */
|
||||
case TOK_GT:
|
||||
return 0xC0000000;
|
||||
return 0xC0000000; /* GT */
|
||||
}
|
||||
error("unexpected condition code");
|
||||
return 0xE0000000;
|
||||
return 0xE0000000; /* AL */
|
||||
}
|
||||
|
||||
static int negcc(int cc)
|
||||
@@ -375,6 +436,10 @@ static int negcc(int cc)
|
||||
return TOK_UGT;
|
||||
case TOK_UGT:
|
||||
return TOK_ULE;
|
||||
case TOK_Nset:
|
||||
return TOK_Nclear;
|
||||
case TOK_Nclear:
|
||||
return TOK_Nset;
|
||||
case TOK_LT:
|
||||
return TOK_GE;
|
||||
case TOK_GE:
|
||||
@@ -432,6 +497,14 @@ void load(int r, SValue *sv)
|
||||
if(v == VT_LOCAL) {
|
||||
if(is_float(ft)) {
|
||||
calcaddr(&base,&fc,&sign,1020,2);
|
||||
#ifdef TCC_ARM_VFP
|
||||
op=0xED100A00; /* flds */
|
||||
if(!sign)
|
||||
op|=0x800000;
|
||||
if ((ft & VT_BTYPE) != VT_FLOAT)
|
||||
op|=0x100; /* flds -> fldd */
|
||||
o(op|(vfpr(r)<<12)|(fc>>2)|(base<<16));
|
||||
#else
|
||||
op=0xED100100;
|
||||
if(!sign)
|
||||
op|=0x800000;
|
||||
@@ -445,7 +518,9 @@ void load(int r, SValue *sv)
|
||||
op|=0x400000;
|
||||
#endif
|
||||
o(op|(fpr(r)<<12)|(fc>>2)|(base<<16));
|
||||
} else if((ft & VT_TYPE) == VT_BYTE || (ft & VT_BTYPE) == VT_SHORT) {
|
||||
#endif
|
||||
} else if((ft & (VT_BTYPE|VT_UNSIGNED)) == VT_BYTE
|
||||
|| (ft & VT_BTYPE) == VT_SHORT) {
|
||||
calcaddr(&base,&fc,&sign,255,0);
|
||||
op=0xE1500090;
|
||||
if ((ft & VT_BTYPE) == VT_SHORT)
|
||||
@@ -504,7 +579,11 @@ void load(int r, SValue *sv)
|
||||
return;
|
||||
} else if (v < VT_CONST) {
|
||||
if(is_float(ft))
|
||||
#ifdef TCC_ARM_VFP
|
||||
o(0xEEB00A40|(vfpr(r)<<12)|vfpr(v)|T2CPR(ft)); /* fcpyX */
|
||||
#else
|
||||
o(0xEE008180|(fpr(r)<<12)|fpr(v));
|
||||
#endif
|
||||
else
|
||||
o(0xE1A00000|(intr(r)<<12)|intr(v));
|
||||
return;
|
||||
@@ -550,6 +629,14 @@ void store(int r, SValue *sv)
|
||||
if(v == VT_LOCAL) {
|
||||
if(is_float(ft)) {
|
||||
calcaddr(&base,&fc,&sign,1020,2);
|
||||
#ifdef TCC_ARM_VFP
|
||||
op=0xED000A00; /* fsts */
|
||||
if(!sign)
|
||||
op|=0x800000;
|
||||
if ((ft & VT_BTYPE) != VT_FLOAT)
|
||||
op|=0x100; /* fsts -> fstd */
|
||||
o(op|(vfpr(r)<<12)|(fc>>2)|(base<<16));
|
||||
#else
|
||||
op=0xED000100;
|
||||
if(!sign)
|
||||
op|=0x800000;
|
||||
@@ -563,6 +650,7 @@ void store(int r, SValue *sv)
|
||||
op|=0x400000;
|
||||
#endif
|
||||
o(op|(fpr(r)<<12)|(fc>>2)|(base<<16));
|
||||
#endif
|
||||
return;
|
||||
} else if((ft & VT_BTYPE) == VT_SHORT) {
|
||||
calcaddr(&base,&fc,&sign,255,0);
|
||||
@@ -635,19 +723,44 @@ void gfunc_call(int nb_args)
|
||||
r = vtop->r & VT_VALMASK;
|
||||
if (r == VT_CMP || (r & ~1) == VT_JMP)
|
||||
gv(RC_INT);
|
||||
#ifdef TCC_ARM_EABI
|
||||
if((vtop[-nb_args].type.ref->type.t & VT_BTYPE) == VT_STRUCT
|
||||
&& type_size(&vtop[-nb_args].type, &align) <= 4) {
|
||||
SValue tmp;
|
||||
tmp=vtop[-nb_args];
|
||||
vtop[-nb_args]=vtop[-nb_args+1];
|
||||
vtop[-nb_args+1]=tmp;
|
||||
--nb_args;
|
||||
}
|
||||
|
||||
vpushi(0);
|
||||
vtop->type.t = VT_LLONG;
|
||||
args_size = 0;
|
||||
for(i = nb_args + 1 ; i-- ;) {
|
||||
size = type_size(&vtop[-i].type, &align);
|
||||
if(args_size & (align-1)) {
|
||||
vpushi(0);
|
||||
vtop->type.t = VT_VOID; /* padding */
|
||||
vrott(i+2);
|
||||
args_size += 4;
|
||||
++nb_args;
|
||||
}
|
||||
args_size += (size + 3) & -4;
|
||||
}
|
||||
vtop--;
|
||||
#endif
|
||||
args_size = 0;
|
||||
for(i = nb_args ; i-- && args_size < 16 ;) {
|
||||
if ((vtop[-i].type.t & VT_BTYPE) == VT_STRUCT) {
|
||||
switch(vtop[-i].type.t & VT_BTYPE) {
|
||||
case VT_STRUCT:
|
||||
case VT_FLOAT:
|
||||
case VT_DOUBLE:
|
||||
case VT_LDOUBLE:
|
||||
size = type_size(&vtop[-i].type, &align);
|
||||
size = (size + 3) & ~3;
|
||||
size = (size + 3) & -4;
|
||||
args_size += size;
|
||||
} else if ((vtop[-i].type.t & VT_BTYPE) == VT_FLOAT)
|
||||
args_size += 4;
|
||||
else if ((vtop[-i].type.t & VT_BTYPE) == VT_DOUBLE)
|
||||
args_size += 8;
|
||||
else if ((vtop[-i].type.t & VT_BTYPE) == VT_LDOUBLE)
|
||||
args_size += LDOUBLE_SIZE;
|
||||
else {
|
||||
break;
|
||||
default:
|
||||
plan[nb_args-1-i][0]=args_size/4;
|
||||
args_size += 4;
|
||||
if ((vtop[-i].type.t & VT_BTYPE) == VT_LLONG && args_size < 16) {
|
||||
@@ -662,7 +775,7 @@ void gfunc_call(int nb_args)
|
||||
if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
|
||||
size = type_size(&vtop->type, &align);
|
||||
/* align to stack align size */
|
||||
size = (size + 3) & ~3;
|
||||
size = (size + 3) & -4;
|
||||
/* allocate the necessary size on stack */
|
||||
gadd_sp(-size);
|
||||
/* generate structure store */
|
||||
@@ -674,6 +787,16 @@ void gfunc_call(int nb_args)
|
||||
vtop--;
|
||||
args_size += size;
|
||||
} else if (is_float(vtop->type.t)) {
|
||||
#ifdef TCC_ARM_VFP
|
||||
r=vfpr(gv(RC_FLOAT))<<12;
|
||||
size=4;
|
||||
if ((vtop->type.t & VT_BTYPE) != VT_FLOAT)
|
||||
{
|
||||
size=8;
|
||||
r|=0x101; /* fstms -> fstmd */
|
||||
}
|
||||
o(0xED2D0A01+r);
|
||||
#else
|
||||
r=fpr(gv(RC_FLOAT))<<12;
|
||||
if ((vtop->type.t & VT_BTYPE) == VT_FLOAT)
|
||||
size = 4;
|
||||
@@ -688,6 +811,7 @@ void gfunc_call(int nb_args)
|
||||
r|=0x8000;
|
||||
|
||||
o(0xED2D0100|r|(size>>2));
|
||||
#endif
|
||||
vtop--;
|
||||
args_size += size;
|
||||
} else {
|
||||
@@ -718,7 +842,14 @@ void gfunc_call(int nb_args)
|
||||
s=regmask(plan[nb_args-i-1][0]);
|
||||
todo&=~(1<<plan[nb_args-i-1][0]);
|
||||
}
|
||||
if(s==RC_INT) {
|
||||
#ifdef TCC_ARM_EABI
|
||||
if(vtop->type.t == VT_VOID) {
|
||||
if(s == RC_INT)
|
||||
o(0xE24DD004); /* sub sp,sp,#4 */
|
||||
vtop--;
|
||||
} else
|
||||
#endif
|
||||
if(s == RC_INT) {
|
||||
r = gv(s);
|
||||
o(0xE52D0004|(intr(r)<<12)); /* str r,[sp,#-4]! */
|
||||
vtop--;
|
||||
@@ -733,7 +864,7 @@ void gfunc_call(int nb_args)
|
||||
gv(plan2[i]);
|
||||
vrott(keep);
|
||||
}
|
||||
save_regs(keep); /* save used temporary registers */
|
||||
save_regs(keep); /* save used temporary registers */
|
||||
keep++;
|
||||
if(args_size) {
|
||||
int n;
|
||||
@@ -758,7 +889,26 @@ void gfunc_call(int nb_args)
|
||||
gcall_or_jmp(0);
|
||||
if (args_size)
|
||||
gadd_sp(args_size);
|
||||
#ifdef TCC_ARM_EABI
|
||||
if((vtop->type.ref->type.t & VT_BTYPE) == VT_STRUCT
|
||||
&& type_size(&vtop->type.ref->type, &align) <= 4)
|
||||
{
|
||||
store(REG_IRET,vtop-keep);
|
||||
++keep;
|
||||
}
|
||||
#ifdef TCC_ARM_VFP
|
||||
else if(is_float(vtop->type.ref->type.t)) {
|
||||
if((vtop->type.ref->type.t & VT_BTYPE) == VT_FLOAT) {
|
||||
o(0xEE000A10); /* fmsr s0,r0 */
|
||||
} else {
|
||||
o(0xEE000B10); /* fmdlr d0,r0 */
|
||||
o(0xEE201B10); /* fmdhr d0,r1 */
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
vtop-=keep;
|
||||
leaffunc = 0;
|
||||
}
|
||||
|
||||
/* generate function prolog of type 't' */
|
||||
@@ -770,17 +920,18 @@ void gfunc_prolog(CType *func_type)
|
||||
sym = func_type->ref;
|
||||
func_vt = sym->type;
|
||||
|
||||
n=0;
|
||||
addr=12;
|
||||
if((func_vt.t & VT_BTYPE) == VT_STRUCT) {
|
||||
n = 0;
|
||||
addr = 0;
|
||||
if((func_vt.t & VT_BTYPE) == VT_STRUCT
|
||||
&& type_size(&func_vt,&align) > 4)
|
||||
{
|
||||
func_vc = addr;
|
||||
addr += 4;
|
||||
n++;
|
||||
}
|
||||
for(sym2=sym->next;sym2 && n<4;sym2=sym2->next) {
|
||||
size = type_size(&sym2->type, &align);
|
||||
size = (size + 3) & ~3;
|
||||
n+=size/4;
|
||||
n += (size + 3) / 4;
|
||||
}
|
||||
o(0xE1A0C00D); /* mov ip,sp */
|
||||
if(func_type->ref->c == FUNC_ELLIPSIS)
|
||||
@@ -788,40 +939,63 @@ void gfunc_prolog(CType *func_type)
|
||||
if(n) {
|
||||
if(n>4)
|
||||
n=4;
|
||||
#ifdef TCC_ARM_EABI
|
||||
n=(n+1)&-2;
|
||||
#endif
|
||||
o(0xE92D0000|((1<<n)-1)); /* save r0-r4 on stack if needed */
|
||||
}
|
||||
o(0xE92D5800); /* save fp, ip, lr*/
|
||||
o(0xE1A0B00D); /* mov fp,sp */
|
||||
o(0xE92D5800); /* save fp, ip, lr */
|
||||
o(0xE28DB00C); /* add fp, sp, #12 */
|
||||
func_sub_sp_offset = ind;
|
||||
o(0xE1A00000); /* nop, leave space for stack adjustment */
|
||||
while ((sym = sym->next)) {
|
||||
CType *type;
|
||||
type = &sym->type;
|
||||
sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL, addr);
|
||||
size = type_size(type, &align);
|
||||
size = (size + 3) & ~3;
|
||||
size = (size + 3) & -4;
|
||||
#ifdef TCC_ARM_EABI
|
||||
addr = (addr + align - 1) & -align;
|
||||
#endif
|
||||
sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL, addr);
|
||||
addr += size;
|
||||
}
|
||||
last_itod_magic=0;
|
||||
loc = 0;
|
||||
leaffunc = 1;
|
||||
loc = -12;
|
||||
}
|
||||
|
||||
/* generate function epilog */
|
||||
void gfunc_epilog(void)
|
||||
{
|
||||
unsigned long x;
|
||||
o(0xE89BA800); /* restore fp, sp, pc */
|
||||
if(loc) {
|
||||
x=stuff_const(0xE24DD000, (-loc + 3) & -4); /* sub sp,sp,# */
|
||||
int diff;
|
||||
#ifdef TCC_ARM_EABI
|
||||
if(is_float(func_vt.t)) {
|
||||
if((func_vt.t & VT_BTYPE) == VT_FLOAT)
|
||||
o(0xEE100A10); /* fmrs r0, s0 */
|
||||
else {
|
||||
o(0xEE100B10); /* fmrdl r0, d0 */
|
||||
o(0xEE301B10); /* fmrdh r1, d0 */
|
||||
}
|
||||
}
|
||||
#endif
|
||||
o(0xE91BA800); /* restore fp, sp, pc */
|
||||
diff = (-loc + 3) & -4;
|
||||
#ifdef TCC_ARM_EABI
|
||||
if(!leaffunc)
|
||||
diff = (diff + 7) & -8;
|
||||
#endif
|
||||
if(diff > 12) {
|
||||
x=stuff_const(0xE24BD000, diff); /* sub sp,fp,# */
|
||||
if(x)
|
||||
*(unsigned long *)(cur_text_section->data + func_sub_sp_offset) = x;
|
||||
else {
|
||||
unsigned long addr;
|
||||
addr=ind;
|
||||
o(0xE59FC004); /* ldr ip,[pc+4] */
|
||||
o(0xE04DD00C); /* sub sp,sp,ip */
|
||||
o(0xE04BD00C); /* sub sp,fp,ip */
|
||||
o(0xE1A0F00E); /* mov pc,lr */
|
||||
o((-loc + 3) & -4);
|
||||
o(diff);
|
||||
*(unsigned long *)(cur_text_section->data + func_sub_sp_offset) = 0xE1000000|encbranch(func_sub_sp_offset,addr,1);
|
||||
}
|
||||
}
|
||||
@@ -879,7 +1053,12 @@ int gtst(int inv, int t)
|
||||
} else {
|
||||
if (is_float(vtop->type.t)) {
|
||||
r=gv(RC_FLOAT);
|
||||
o(0xEE90F118|fpr(r)<<16);
|
||||
#ifdef TCC_ARM_VFP
|
||||
o(0xEEB50A40|(vfpr(r)<<12)|T2CPR(vtop->type.t)); /* fcmpzX */
|
||||
o(0xEEF1FA10); /* fmstat */
|
||||
#else
|
||||
o(0xEE90F118|(fpr(r)<<16));
|
||||
#endif
|
||||
vtop->r = VT_CMP;
|
||||
vtop->c.i = TOK_NE;
|
||||
return gtst(inv, t);
|
||||
@@ -1058,6 +1237,110 @@ done:
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TCC_ARM_VFP
|
||||
static int is_zero(int i)
|
||||
{
|
||||
if((vtop[i].r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST)
|
||||
return 0;
|
||||
if (vtop[i].type.t == VT_FLOAT)
|
||||
return (vtop[i].c.f == 0.f);
|
||||
else if (vtop[i].type.t == VT_DOUBLE)
|
||||
return (vtop[i].c.d == 0.0);
|
||||
return (vtop[i].c.ld == 0.l);
|
||||
}
|
||||
|
||||
/* generate a floating point operation 'v = t1 op t2' instruction. The
|
||||
* two operands are guaranted to have the same floating point type */
|
||||
void gen_opf(int op)
|
||||
{
|
||||
unsigned long x;
|
||||
int fneg=0,r;
|
||||
x=0xEE000A00|T2CPR(vtop->type.t);
|
||||
switch(op) {
|
||||
case '+':
|
||||
if(is_zero(-1))
|
||||
vswap();
|
||||
if(is_zero(0)) {
|
||||
vtop--;
|
||||
return;
|
||||
}
|
||||
x|=0x300000;
|
||||
break;
|
||||
case '-':
|
||||
x|=0x300040;
|
||||
if(is_zero(0)) {
|
||||
vtop--;
|
||||
return;
|
||||
}
|
||||
if(is_zero(-1)) {
|
||||
x|=0x810000; /* fsubX -> fnegX */
|
||||
vswap();
|
||||
vtop--;
|
||||
fneg=1;
|
||||
}
|
||||
break;
|
||||
case '*':
|
||||
x|=0x200000;
|
||||
break;
|
||||
case '/':
|
||||
x|=0x800000;
|
||||
break;
|
||||
default:
|
||||
if(op < TOK_ULT && op > TOK_GT) {
|
||||
error("unknown fp op %x!",op);
|
||||
return;
|
||||
}
|
||||
if(is_zero(-1)) {
|
||||
vswap();
|
||||
switch(op) {
|
||||
case TOK_LT: op=TOK_GT; break;
|
||||
case TOK_GE: op=TOK_ULE; break;
|
||||
case TOK_LE: op=TOK_GE; break;
|
||||
case TOK_GT: op=TOK_ULT; break;
|
||||
}
|
||||
}
|
||||
x|=0xB40040; /* fcmpX */
|
||||
if(op!=TOK_EQ && op!=TOK_NE)
|
||||
x|=0x80; /* fcmpX -> fcmpeX */
|
||||
if(is_zero(0)) {
|
||||
vtop--;
|
||||
o(x|0x10000|(vfpr(gv(RC_FLOAT))<<12)); /* fcmp(e)X -> fcmp(e)zX */
|
||||
} else {
|
||||
x|=vfpr(gv(RC_FLOAT));
|
||||
vswap();
|
||||
o(x|(vfpr(gv(RC_FLOAT))<<12));
|
||||
vtop--;
|
||||
}
|
||||
o(0xEEF1FA10); /* fmstat */
|
||||
|
||||
switch(op) {
|
||||
case TOK_LE: op=TOK_ULE; break;
|
||||
case TOK_LT: op=TOK_ULT; break;
|
||||
case TOK_UGE: op=TOK_GE; break;
|
||||
case TOK_UGT: op=TOK_GT; break;
|
||||
}
|
||||
|
||||
vtop->r = VT_CMP;
|
||||
vtop->c.i = op;
|
||||
return;
|
||||
}
|
||||
r=gv(RC_FLOAT);
|
||||
x|=vfpr(r);
|
||||
r=regmask(r);
|
||||
if(!fneg) {
|
||||
int r2;
|
||||
vswap();
|
||||
r2=gv(RC_FLOAT);
|
||||
x|=vfpr(r2)<<16;
|
||||
r|=regmask(r2);
|
||||
}
|
||||
vtop->r=get_reg_ex(RC_FLOAT,r);
|
||||
if(!fneg)
|
||||
vtop--;
|
||||
o(x|(vfpr(vtop->r)<<12));
|
||||
}
|
||||
|
||||
#else
|
||||
static int is_fconst()
|
||||
{
|
||||
long double f;
|
||||
@@ -1193,24 +1476,20 @@ void gen_opf(int op)
|
||||
default:
|
||||
if(op >= TOK_ULT && op <= TOK_GT) {
|
||||
x|=0xd0f110; // cmfe
|
||||
/* bug (intention?) in Linux FPU emulator
|
||||
doesn't set carry if equal */
|
||||
switch(op) {
|
||||
case TOK_ULT:
|
||||
case TOK_UGE:
|
||||
case TOK_ULE:
|
||||
case TOK_UGT:
|
||||
fputs("unsigned comparision on floats?\n",stderr);
|
||||
error("unsigned comparision on floats?");
|
||||
break;
|
||||
case TOK_LT:
|
||||
op=TOK_ULT;
|
||||
break;
|
||||
case TOK_GE:
|
||||
op=TOK_UGE;
|
||||
op=TOK_Nset;
|
||||
break;
|
||||
case TOK_LE:
|
||||
op=TOK_ULE;
|
||||
break;
|
||||
case TOK_GT:
|
||||
op=TOK_UGT;
|
||||
op=TOK_ULE; /* correct in unordered case only if AC bit in FPSR set */
|
||||
break;
|
||||
case TOK_EQ:
|
||||
case TOK_NE:
|
||||
@@ -1221,26 +1500,20 @@ void gen_opf(int op)
|
||||
c2=c1;
|
||||
vswap();
|
||||
switch(op) {
|
||||
case TOK_ULT:
|
||||
op=TOK_UGT;
|
||||
case TOK_Nset:
|
||||
op=TOK_GT;
|
||||
break;
|
||||
case TOK_UGE:
|
||||
case TOK_GE:
|
||||
op=TOK_ULE;
|
||||
break;
|
||||
case TOK_ULE:
|
||||
op=TOK_UGE;
|
||||
op=TOK_GE;
|
||||
break;
|
||||
case TOK_UGT:
|
||||
op=TOK_ULT;
|
||||
case TOK_GT:
|
||||
op=TOK_Nset;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// bug (intention?) in Linux FPU emulator
|
||||
// doesn't set carry if equal
|
||||
if(op==TOK_ULT)
|
||||
op=TOK_LT;
|
||||
else if(op==TOK_UGE)
|
||||
op=TOK_GE;
|
||||
vswap();
|
||||
r=fpr(gv(RC_FLOAT));
|
||||
vswap();
|
||||
@@ -1254,7 +1527,7 @@ void gen_opf(int op)
|
||||
vtop[-1].r = VT_CMP;
|
||||
vtop[-1].c.i = op;
|
||||
} else {
|
||||
error("unknown fp op %x!\n",op);
|
||||
error("unknown fp op %x!",op);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1270,6 +1543,7 @@ void gen_opf(int op)
|
||||
vtop--;
|
||||
o(x|(r<<16)|(c1<<12)|r2);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* convert integers to fp 't' type. Must handle 'int', 'unsigned int'
|
||||
and 'long long' cases. */
|
||||
@@ -1279,6 +1553,14 @@ void gen_cvt_itof(int t)
|
||||
bt=vtop->type.t & VT_BTYPE;
|
||||
if(bt == VT_INT || bt == VT_SHORT || bt == VT_BYTE) {
|
||||
r=intr(gv(RC_INT));
|
||||
#ifdef TCC_ARM_VFP
|
||||
r2=vfpr(vtop->r=get_reg(RC_FLOAT));
|
||||
o(0xEE000A10|(r<<12)|(r2<<16)); /* fmsr */
|
||||
r2<<=12;
|
||||
if(!(vtop->type.t & VT_UNSIGNED))
|
||||
r2|=0x80; /* fuitoX -> fsituX */
|
||||
o(0xEEB80A40|r2|T2CPR(t)); /* fYitoX*/
|
||||
#else
|
||||
r2=fpr(vtop->r=get_reg(RC_FLOAT));
|
||||
o(0xEE000190|(r2<<16)|(r<<12));
|
||||
if((vtop->type.t & (VT_UNSIGNED|VT_BTYPE)) == (VT_UNSIGNED|VT_INT)) {
|
||||
@@ -1300,14 +1582,30 @@ void gen_cvt_itof(int t)
|
||||
}
|
||||
o(0xBE000180|(r2<<16)|(r2<<12)|r);
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
} else if(bt == VT_LLONG) {
|
||||
int func;
|
||||
CType *func_type = &func_old_type;
|
||||
#ifdef TCC_ARM_VFP
|
||||
#ifdef TCC_ARM_EABI
|
||||
func_type = &func_double_type;
|
||||
#endif
|
||||
if((t & VT_BTYPE) == VT_FLOAT) {
|
||||
#ifdef TCC_ARM_EABI
|
||||
func_type = &func_float_type;
|
||||
#endif
|
||||
if(vtop->type.t & VT_UNSIGNED)
|
||||
func=TOK___ulltof;
|
||||
else
|
||||
func=TOK___slltof;
|
||||
} else
|
||||
#endif
|
||||
if(vtop->type.t & VT_UNSIGNED)
|
||||
func=TOK___ulltold;
|
||||
else
|
||||
func=TOK___slltold;
|
||||
vpush_global_sym(&func_old_type, func);
|
||||
vpush_global_sym(func_type, func);
|
||||
vswap();
|
||||
gfunc_call(1);
|
||||
vpushi(0);
|
||||
@@ -1325,6 +1623,14 @@ void gen_cvt_ftoi(int t)
|
||||
t&=VT_BTYPE;
|
||||
r2=vtop->type.t & VT_BTYPE;
|
||||
if(t==VT_INT) {
|
||||
#ifdef TCC_ARM_VFP
|
||||
r=vfpr(gv(RC_FLOAT));
|
||||
u=u?0:0x10000;
|
||||
o(0xEEBC0A40|(r<<12)|r|T2CPR(r2)); /* ftoXiY */
|
||||
r2=intr(vtop->r=get_reg(RC_INT));
|
||||
o(0xEE100A10|(r<<16)|(r2<<12));
|
||||
return;
|
||||
#else
|
||||
if(u) {
|
||||
if(r2 == VT_FLOAT)
|
||||
func=TOK___fixunssfsi;
|
||||
@@ -1342,6 +1648,7 @@ void gen_cvt_ftoi(int t)
|
||||
o(0xEE100170|(r2<<12)|r);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
} else if(t == VT_LLONG) { // unsigned handled in gen_cvt_ftoi1
|
||||
if(r2 == VT_FLOAT)
|
||||
func=TOK___fixsfdi;
|
||||
@@ -1370,8 +1677,15 @@ void gen_cvt_ftoi(int t)
|
||||
/* convert from one floating point type to another */
|
||||
void gen_cvt_ftof(int t)
|
||||
{
|
||||
/* all we have to do on i386 and ARM is to put the float in a register */
|
||||
#ifdef TCC_ARM_VFP
|
||||
if(((vtop->type.t & VT_BTYPE) == VT_FLOAT) != ((t & VT_BTYPE) == VT_FLOAT)) {
|
||||
int r=vfpr(gv(RC_FLOAT));
|
||||
o(0xEEB70AC0|(r<<12)|r|T2CPR(vtop->type.t));
|
||||
}
|
||||
#else
|
||||
/* all we have to do on i386 and FPA ARM is to put the float in a register */
|
||||
gv(RC_FLOAT);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* computed goto support */
|
||||
|
||||
29
bcheck.c
29
bcheck.c
@@ -3,25 +3,25 @@
|
||||
*
|
||||
* 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 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 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.
|
||||
* 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 General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* 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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#ifndef __FreeBSD__
|
||||
#if !defined(__FreeBSD__) && !defined(__DragonFly__) && !defined(__OpenBSD__)
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
@@ -36,8 +36,9 @@
|
||||
|
||||
#define HAVE_MEMALIGN
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__dietlibc__)
|
||||
#warning Bound checking not fully supported on FreeBSD
|
||||
#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__dietlibc__) \
|
||||
|| defined(__UCLIBC__) || defined(__OpenBSD__)
|
||||
#warning Bound checking not fully supported in this environment.
|
||||
#undef CONFIG_TCC_MALLOC_HOOKS
|
||||
#undef HAVE_MEMALIGN
|
||||
#endif
|
||||
|
||||
40
configure
vendored
40
configure
vendored
@@ -68,6 +68,12 @@ case $targetos in
|
||||
MINGW32*)
|
||||
mingw32="yes"
|
||||
;;
|
||||
DragonFly)
|
||||
noldl="yes"
|
||||
;;
|
||||
OpenBSD)
|
||||
noldl="yes"
|
||||
;;
|
||||
*) ;;
|
||||
esac
|
||||
|
||||
@@ -142,15 +148,15 @@ if test -z "$cross_prefix" ; then
|
||||
cat > $TMPC << EOF
|
||||
#include <inttypes.h>
|
||||
int main(int argc, char ** argv){
|
||||
volatile uint32_t i=0x01234567;
|
||||
return (*((uint8_t*)(&i))) == 0x67;
|
||||
volatile uint32_t i=0x01234567;
|
||||
return (*((uint8_t*)(&i))) == 0x67;
|
||||
}
|
||||
EOF
|
||||
|
||||
if $cc -o $TMPE $TMPC 2>/dev/null ; then
|
||||
$TMPE && bigendian="yes"
|
||||
$TMPE && bigendian="yes"
|
||||
else
|
||||
echo big/little test failed
|
||||
echo big/little test failed
|
||||
fi
|
||||
|
||||
else
|
||||
@@ -175,7 +181,20 @@ EOF
|
||||
|
||||
gcc_major="2"
|
||||
if $cc -o $TMPO $TMPC 2> /dev/null ; then
|
||||
gcc_major="3"
|
||||
gcc_major="3"
|
||||
fi
|
||||
cat > $TMPC <<EOF
|
||||
int main(void) {
|
||||
#if __GNUC__ >= 4
|
||||
return 0;
|
||||
#else
|
||||
#error gcc < 4
|
||||
#endif
|
||||
}
|
||||
EOF
|
||||
|
||||
if $cc -o $TMPO $TMPC 2> /dev/null ; then
|
||||
gcc_major="4"
|
||||
fi
|
||||
|
||||
if test x"$1" = x"-h" -o x"$1" = x"--help" ; then
|
||||
@@ -194,7 +213,7 @@ echo " --bindir=DIR user executables in DIR [EPREFIX/bin]"
|
||||
echo " --libdir=DIR object code libraries in DIR [EPREFIX/lib]"
|
||||
echo " --includedir=DIR C header files in DIR [PREFIX/include]"
|
||||
echo " --mandir=DIR man documentation in DIR [PREFIX/man]"
|
||||
echo " --build-cross build cross compilers"
|
||||
echo " --enable-cross build cross compilers"
|
||||
echo ""
|
||||
echo "Advanced options (experts only):"
|
||||
echo " --source-path=PATH path of source code [$source_path]"
|
||||
@@ -302,6 +321,9 @@ else
|
||||
echo "Unsupported CPU"
|
||||
exit 1
|
||||
fi
|
||||
if test "$noldl" = "yes" ; then
|
||||
echo "CONFIG_NOLDL=yes" >> config.mak
|
||||
fi
|
||||
if test "$mingw32" = "yes" ; then
|
||||
echo "CONFIG_WIN32=yes" >> config.mak
|
||||
echo "#define CONFIG_WIN32 1" >> $TMPH
|
||||
@@ -327,7 +349,7 @@ if test "$source_path_used" = "yes" ; then
|
||||
DIRS="tests"
|
||||
FILES="Makefile tests/Makefile"
|
||||
for dir in $DIRS ; do
|
||||
mkdir -p $dir
|
||||
mkdir -p $dir
|
||||
done
|
||||
for f in $FILES ; do
|
||||
ln -sf $source_path/$f $f
|
||||
@@ -337,9 +359,9 @@ echo "SRC_PATH=$source_path" >> config.mak
|
||||
|
||||
diff $TMPH config.h >/dev/null 2>&1
|
||||
if test $? -ne 0 ; then
|
||||
mv -f $TMPH config.h
|
||||
mv -f $TMPH config.h
|
||||
else
|
||||
echo "config.h is unchanged"
|
||||
echo "config.h is unchanged"
|
||||
fi
|
||||
|
||||
rm -f $TMPO $TMPC $TMPE $TMPS $TMPH
|
||||
|
||||
34
i386-asm.c
34
i386-asm.c
@@ -109,9 +109,12 @@ typedef struct Operand {
|
||||
} Operand;
|
||||
|
||||
static const uint8_t reg_to_size[5] = {
|
||||
/*
|
||||
[OP_REG8] = 0,
|
||||
[OP_REG16] = 1,
|
||||
[OP_REG32] = 2,
|
||||
*/
|
||||
0, 0, 1, 0, 2
|
||||
};
|
||||
|
||||
#define WORD_PREFIX_OPCODE 0x66
|
||||
@@ -151,6 +154,15 @@ static const uint8_t test_bits[NB_TEST_OPCODES] = {
|
||||
0x0f, /* g */
|
||||
};
|
||||
|
||||
static const uint8_t segment_prefixes[] = {
|
||||
0x26, /* es */
|
||||
0x2e, /* cs */
|
||||
0x36, /* ss */
|
||||
0x3e, /* ds */
|
||||
0x64, /* fs */
|
||||
0x65 /* gs */
|
||||
};
|
||||
|
||||
static const ASMInstr asm_instrs[] = {
|
||||
#define ALT(x) x
|
||||
#define DEF_ASM_OP0(name, opcode)
|
||||
@@ -311,8 +323,10 @@ static void parse_operand(TCCState *s1, Operand *op)
|
||||
if (tok != ',') {
|
||||
op->reg2 = asm_parse_reg();
|
||||
}
|
||||
skip(',');
|
||||
op->shift = get_reg_shift(s1);
|
||||
if (tok == ',') {
|
||||
next();
|
||||
op->shift = get_reg_shift(s1);
|
||||
}
|
||||
}
|
||||
skip(')');
|
||||
}
|
||||
@@ -410,7 +424,7 @@ static inline void asm_modrm(int reg, Operand *op)
|
||||
static void asm_opcode(TCCState *s1, int opcode)
|
||||
{
|
||||
const ASMInstr *pa;
|
||||
int i, modrm_index, reg, v, op1, is_short_jmp;
|
||||
int i, modrm_index, reg, v, op1, is_short_jmp, seg_prefix;
|
||||
int nb_ops, s, ss;
|
||||
Operand ops[MAX_OPERANDS], *pop;
|
||||
int op_type[3]; /* decoded op type */
|
||||
@@ -418,6 +432,7 @@ static void asm_opcode(TCCState *s1, int opcode)
|
||||
/* get operands */
|
||||
pop = ops;
|
||||
nb_ops = 0;
|
||||
seg_prefix = 0;
|
||||
for(;;) {
|
||||
if (tok == ';' || tok == TOK_LINEFEED)
|
||||
break;
|
||||
@@ -425,6 +440,17 @@ static void asm_opcode(TCCState *s1, int opcode)
|
||||
error("incorrect number of operands");
|
||||
}
|
||||
parse_operand(s1, pop);
|
||||
if (tok == ':') {
|
||||
if (pop->type != OP_SEG || seg_prefix) {
|
||||
error("incorrect prefix");
|
||||
}
|
||||
seg_prefix = segment_prefixes[pop->reg];
|
||||
next();
|
||||
parse_operand(s1, pop);
|
||||
if (!(pop->type & OP_EA)) {
|
||||
error("segment prefix must be followed by memory reference");
|
||||
}
|
||||
}
|
||||
pop++;
|
||||
nb_ops++;
|
||||
if (tok != ',')
|
||||
@@ -538,6 +564,8 @@ static void asm_opcode(TCCState *s1, int opcode)
|
||||
/* now generates the operation */
|
||||
if (pa->instr_type & OPC_FWAIT)
|
||||
g(0x9b);
|
||||
if (seg_prefix)
|
||||
g(seg_prefix);
|
||||
|
||||
v = pa->opcode;
|
||||
if (v == 0x69 || v == 0x69) {
|
||||
|
||||
32
i386-gen.c
32
i386-gen.c
@@ -321,6 +321,7 @@ static void gcall_or_jmp(int is_jmp)
|
||||
}
|
||||
|
||||
static uint8_t fastcall_regs[3] = { TREG_EAX, TREG_EDX, TREG_ECX };
|
||||
static uint8_t fastcallw_regs[2] = { TREG_ECX, TREG_EDX };
|
||||
|
||||
/* Generate function call. The function address is pushed first, then
|
||||
all the parameters in call order. This functions pops all the
|
||||
@@ -379,21 +380,29 @@ void gfunc_call(int nb_args)
|
||||
}
|
||||
save_regs(0); /* save used temporary registers */
|
||||
func_sym = vtop->type.ref;
|
||||
func_call = func_sym->r;
|
||||
func_call = FUNC_CALL(func_sym->r);
|
||||
/* fast call case */
|
||||
if (func_call >= FUNC_FASTCALL1 && func_call <= FUNC_FASTCALL3) {
|
||||
if ((func_call >= FUNC_FASTCALL1 && func_call <= FUNC_FASTCALL3) ||
|
||||
func_call == FUNC_FASTCALLW) {
|
||||
int fastcall_nb_regs;
|
||||
fastcall_nb_regs = func_call - FUNC_FASTCALL1 + 1;
|
||||
uint8_t *fastcall_regs_ptr;
|
||||
if (func_call == FUNC_FASTCALLW) {
|
||||
fastcall_regs_ptr = fastcallw_regs;
|
||||
fastcall_nb_regs = 2;
|
||||
} else {
|
||||
fastcall_regs_ptr = fastcall_regs;
|
||||
fastcall_nb_regs = func_call - FUNC_FASTCALL1 + 1;
|
||||
}
|
||||
for(i = 0;i < fastcall_nb_regs; i++) {
|
||||
if (args_size <= 0)
|
||||
break;
|
||||
o(0x58 + fastcall_regs[i]); /* pop r */
|
||||
o(0x58 + fastcall_regs_ptr[i]); /* pop r */
|
||||
/* XXX: incorrect for struct/floats */
|
||||
args_size -= 4;
|
||||
}
|
||||
}
|
||||
gcall_or_jmp(0);
|
||||
if (args_size && func_sym->r != FUNC_STDCALL)
|
||||
if (args_size && func_call != FUNC_STDCALL)
|
||||
gadd_sp(args_size);
|
||||
vtop--;
|
||||
}
|
||||
@@ -409,17 +418,23 @@ void gfunc_prolog(CType *func_type)
|
||||
{
|
||||
int addr, align, size, func_call, fastcall_nb_regs;
|
||||
int param_index, param_addr;
|
||||
uint8_t *fastcall_regs_ptr;
|
||||
Sym *sym;
|
||||
CType *type;
|
||||
|
||||
sym = func_type->ref;
|
||||
func_call = sym->r;
|
||||
func_call = FUNC_CALL(sym->r);
|
||||
addr = 8;
|
||||
loc = 0;
|
||||
if (func_call >= FUNC_FASTCALL1 && func_call <= FUNC_FASTCALL3) {
|
||||
fastcall_nb_regs = func_call - FUNC_FASTCALL1 + 1;
|
||||
fastcall_regs_ptr = fastcall_regs;
|
||||
} else if (func_call == FUNC_FASTCALLW) {
|
||||
fastcall_nb_regs = 2;
|
||||
fastcall_regs_ptr = fastcallw_regs;
|
||||
} else {
|
||||
fastcall_nb_regs = 0;
|
||||
fastcall_regs_ptr = NULL;
|
||||
}
|
||||
param_index = 0;
|
||||
|
||||
@@ -449,7 +464,7 @@ void gfunc_prolog(CType *func_type)
|
||||
/* save FASTCALL register */
|
||||
loc -= 4;
|
||||
o(0x89); /* movl */
|
||||
gen_modrm(fastcall_regs[param_index], VT_LOCAL, NULL, loc);
|
||||
gen_modrm(fastcall_regs_ptr[param_index], VT_LOCAL, NULL, loc);
|
||||
param_addr = loc;
|
||||
} else {
|
||||
param_addr = addr;
|
||||
@@ -585,7 +600,8 @@ int gtst(int inv, int t)
|
||||
gsym(vtop->c.i);
|
||||
}
|
||||
} else {
|
||||
if (is_float(vtop->type.t)) {
|
||||
if (is_float(vtop->type.t) ||
|
||||
(vtop->type.t & VT_BTYPE) == VT_LLONG) {
|
||||
vpushi(0);
|
||||
gen_op(TOK_NE);
|
||||
}
|
||||
|
||||
22
il-gen.c
22
il-gen.c
@@ -3,19 +3,19 @@
|
||||
*
|
||||
* 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 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 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.
|
||||
* 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 General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* 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
|
||||
*/
|
||||
|
||||
/* number of available registers */
|
||||
|
||||
1
libtcc.h
1
libtcc.h
@@ -60,6 +60,7 @@ int tcc_compile_string(TCCState *s, const char *buf);
|
||||
#define TCC_OUTPUT_EXE 1 /* executable file */
|
||||
#define TCC_OUTPUT_DLL 2 /* dynamic library */
|
||||
#define TCC_OUTPUT_OBJ 3 /* object file */
|
||||
#define TCC_OUTPUT_PREPROCESS 4 /* preprocessed file (used internally) */
|
||||
int tcc_set_output_type(TCCState *s, int output_type);
|
||||
|
||||
#define TCC_OUTPUT_FORMAT_ELF 0 /* default output format: ELF */
|
||||
|
||||
@@ -399,7 +399,7 @@ long long __moddi3(long long u, long long v)
|
||||
if (vv.s.high < 0)
|
||||
vv.ll = __negdi2 (vv.ll);
|
||||
|
||||
__udivmoddi4 (uu.ll, vv.ll, &w);
|
||||
__udivmoddi4 (uu.ll, vv.ll, (UDWtype *) &w);
|
||||
if (c)
|
||||
w = __negdi2 (w);
|
||||
return w;
|
||||
@@ -466,7 +466,7 @@ long long __shldi3(long long a, int b)
|
||||
u.s.high = (unsigned)u.s.low << (b - 32);
|
||||
u.s.low = 0;
|
||||
} else if (b != 0) {
|
||||
u.s.high = ((unsigned)u.s.high << b) | (u.s.low >> (32 - b));
|
||||
u.s.high = ((unsigned)u.s.high << b) | ((unsigned)u.s.low >> (32 - b));
|
||||
u.s.low = (unsigned)u.s.low << b;
|
||||
}
|
||||
return u.ll;
|
||||
|
||||
1
stdarg.h
1
stdarg.h
@@ -6,6 +6,7 @@ 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_copy(dest, src) (dest) = (src)
|
||||
#define va_end(ap)
|
||||
|
||||
/* fix a buggy dependency on GCC in libio.h */
|
||||
|
||||
11
stddef.h
11
stddef.h
@@ -12,10 +12,15 @@ typedef __PTRDIFF_TYPE__ ptrdiff_t;
|
||||
__GNUC__ ? */
|
||||
#if !defined(__int8_t_defined) && !defined(__dietlibc__)
|
||||
#define __int8_t_defined
|
||||
typedef char int8_t;
|
||||
typedef short int int16_t;
|
||||
typedef int int32_t;
|
||||
typedef char int8_t;
|
||||
typedef short int int16_t;
|
||||
typedef int int32_t;
|
||||
typedef long long int int64_t;
|
||||
#endif
|
||||
|
||||
#ifdef __i386__
|
||||
void *_alloca(size_t);
|
||||
#define alloca _alloca
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
49
tcc-doc.texi
49
tcc-doc.texi
@@ -94,9 +94,11 @@ the @code{main()} of a.c.
|
||||
|
||||
@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
|
||||
as first argument to the @code{main()} of the resulting program. Because
|
||||
multiple C files are specified, @option{--} are necessary to clearly separate the
|
||||
program arguments from the TCC options.
|
||||
as first argument to the @code{main()} of the resulting program.
|
||||
@ignore
|
||||
Because multiple C files are specified, @option{--} are necessary to clearly
|
||||
separate the program arguments from the TCC options.
|
||||
@end ignore
|
||||
|
||||
@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}.
|
||||
@@ -135,6 +137,13 @@ int main()
|
||||
return 0;
|
||||
@}
|
||||
@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
|
||||
|
||||
@section Option summary
|
||||
@@ -144,7 +153,7 @@ General Options:
|
||||
@c man begin OPTIONS
|
||||
@table @option
|
||||
@item -v
|
||||
Display current TCC version.
|
||||
Display current TCC version, increase verbosity.
|
||||
|
||||
@item -c
|
||||
Generate an object file (@option{-o} option must also be given).
|
||||
@@ -160,7 +169,6 @@ Set the path where the tcc internal libraries can be found (default is
|
||||
Output compilation statistics.
|
||||
|
||||
@item -run source [args...]
|
||||
|
||||
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
|
||||
script, several TCC options can be given @emph{after} the
|
||||
@@ -406,13 +414,6 @@ is the same as writing
|
||||
@end itemize
|
||||
|
||||
@section GNU C extensions
|
||||
@cindex aligned attribute
|
||||
@cindex packed attribute
|
||||
@cindex section attribute
|
||||
@cindex unused attribute
|
||||
@cindex cdecl attribute
|
||||
@cindex stdcall attribute
|
||||
@cindex regparm attribute
|
||||
|
||||
TCC implements some GNU C extensions:
|
||||
|
||||
@@ -446,13 +447,22 @@ instead of
|
||||
@}
|
||||
@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
|
||||
|
||||
@item The keyword @code{__attribute__} is handled to specify variable or
|
||||
function attributes. The following attributes are supported:
|
||||
@itemize
|
||||
|
||||
@item @code{aligned(n)}: align a variable or a structure field to n bytes
|
||||
(must be a power of two).
|
||||
|
||||
|
||||
@item @code{packed}: force alignment of a variable or a structure field to
|
||||
1.
|
||||
|
||||
@@ -470,6 +480,8 @@ section.
|
||||
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)
|
||||
|
||||
@end itemize
|
||||
|
||||
Here are some examples:
|
||||
@@ -725,10 +737,13 @@ TCC for Windows supports the native Win32 executable file format (PE-i386). It
|
||||
generates both EXE and DLL files. DLL symbols can be imported thru DEF files
|
||||
generated with the @code{tiny_impdef} tool.
|
||||
|
||||
Currently TCC for Windows cannot generate nor read PE object files, so ELF
|
||||
object files are used for that purpose. It can be a problem if
|
||||
interoperability with MSVC is needed. Moreover, no leading underscore is
|
||||
currently generated in the ELF symbols.
|
||||
On the object file level, currently TCC supports only the ELF format, not COFF
|
||||
as used by MINGW and MSVC. It is not possible to exchange object files or
|
||||
libraries between TCC and these compilers. However libraries for TCC from objects
|
||||
by TCC can be made using the @code{tiny_libmaker} tool or MINGW's @code{ar}.
|
||||
|
||||
No leading underscore is generated in the ELF symbols. Only functions (no
|
||||
data) can be exported. Bounds checking (@option{-b}) is not supported currently.
|
||||
|
||||
@section GNU Linker Scripts
|
||||
@cindex scripts, linker
|
||||
|
||||
30
tccasm.c
30
tccasm.c
@@ -806,7 +806,7 @@ static void subst_asm_operands(ASMOperand *operands, int nb_operands,
|
||||
sv = *op->vt;
|
||||
if (op->reg >= 0) {
|
||||
sv.r = op->reg;
|
||||
if ((op->vt->r & VT_VALMASK) == VT_LLOCAL)
|
||||
if ((op->vt->r & VT_VALMASK) == VT_LLOCAL && op->is_memory)
|
||||
sv.r |= VT_LVAL;
|
||||
}
|
||||
subst_asm_operand(out_str, &sv, modifier);
|
||||
@@ -916,21 +916,23 @@ static void asm_instr(void)
|
||||
nb_outputs = nb_operands;
|
||||
if (tok == ':') {
|
||||
next();
|
||||
/* input args */
|
||||
parse_asm_operands(operands, &nb_operands, 0);
|
||||
if (tok == ':') {
|
||||
/* clobber list */
|
||||
/* XXX: handle registers */
|
||||
next();
|
||||
for(;;) {
|
||||
if (tok != TOK_STR)
|
||||
expect("string constant");
|
||||
asm_clobber(clobber_regs, tokc.cstr->data);
|
||||
if (tok != ')') {
|
||||
/* input args */
|
||||
parse_asm_operands(operands, &nb_operands, 0);
|
||||
if (tok == ':') {
|
||||
/* clobber list */
|
||||
/* XXX: handle registers */
|
||||
next();
|
||||
if (tok == ',') {
|
||||
for(;;) {
|
||||
if (tok != TOK_STR)
|
||||
expect("string constant");
|
||||
asm_clobber(clobber_regs, tokc.cstr->data);
|
||||
next();
|
||||
} else {
|
||||
break;
|
||||
if (tok == ',') {
|
||||
next();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
336
tccelf.c
336
tccelf.c
@@ -182,9 +182,11 @@ static int add_elf_sym(Section *s, unsigned long value, unsigned long size,
|
||||
{
|
||||
Elf32_Sym *esym;
|
||||
int sym_bind, sym_index, sym_type, esym_bind;
|
||||
unsigned char sym_vis, esym_vis, new_vis;
|
||||
|
||||
sym_bind = ELF32_ST_BIND(info);
|
||||
sym_type = ELF32_ST_TYPE(info);
|
||||
sym_vis = ELF32_ST_VISIBILITY(other);
|
||||
|
||||
if (sym_bind != STB_LOCAL) {
|
||||
/* we search global or weak symbols */
|
||||
@@ -194,6 +196,19 @@ static int add_elf_sym(Section *s, unsigned long value, unsigned long size,
|
||||
esym = &((Elf32_Sym *)s->data)[sym_index];
|
||||
if (esym->st_shndx != SHN_UNDEF) {
|
||||
esym_bind = ELF32_ST_BIND(esym->st_info);
|
||||
/* propagate the most constraining visibility */
|
||||
/* STV_DEFAULT(0)<STV_PROTECTED(3)<STV_HIDDEN(2)<STV_INTERNAL(1) */
|
||||
esym_vis = ELF32_ST_VISIBILITY(esym->st_other);
|
||||
if (esym_vis == STV_DEFAULT) {
|
||||
new_vis = sym_vis;
|
||||
} else if (sym_vis == STV_DEFAULT) {
|
||||
new_vis = esym_vis;
|
||||
} else {
|
||||
new_vis = (esym_vis < sym_vis) ? esym_vis : sym_vis;
|
||||
}
|
||||
esym->st_other = (esym->st_other & ~ELF32_ST_VISIBILITY(-1))
|
||||
| new_vis;
|
||||
other = esym->st_other; /* in case we have to patch esym */
|
||||
if (sh_num == SHN_UNDEF) {
|
||||
/* ignore adding of undefined symbol if the
|
||||
corresponding symbol is already defined */
|
||||
@@ -202,14 +217,20 @@ static int add_elf_sym(Section *s, unsigned long value, unsigned long size,
|
||||
goto do_patch;
|
||||
} else if (sym_bind == STB_WEAK && esym_bind == STB_GLOBAL) {
|
||||
/* weak is ignored if already global */
|
||||
} else if (sym_vis == STV_HIDDEN || sym_vis == STV_INTERNAL) {
|
||||
/* ignore hidden symbols after */
|
||||
} else if (esym->st_shndx == SHN_COMMON && sh_num < SHN_LORESERVE) {
|
||||
/* gr: Happens with 'tcc ... -static tcctest.c' on e.g. Ubuntu 6.01
|
||||
No idea if this is the correct solution ... */
|
||||
goto do_patch;
|
||||
} else if (s == tcc_state->dynsymtab_section) {
|
||||
/* we accept that two DLL define the same symbol */
|
||||
} else {
|
||||
#if 0
|
||||
printf("new_bind=%d new_shndx=%d last_bind=%d old_shndx=%d\n",
|
||||
sym_bind, sh_num, esym_bind, esym->st_shndx);
|
||||
#if 1
|
||||
printf("new_bind=%x new_shndx=%x new_vis=%x old_bind=%x old_shndx=%x old_vis=%x\n",
|
||||
sym_bind, sh_num, new_vis, esym_bind, esym->st_shndx, esym_vis);
|
||||
#endif
|
||||
/* NOTE: we accept that two DLL define the same symbol */
|
||||
if (s != tcc_state->dynsymtab_section)
|
||||
error_noabort("'%s' defined twice", name);
|
||||
error_noabort("'%s' defined twice", name);
|
||||
}
|
||||
} else {
|
||||
do_patch:
|
||||
@@ -514,9 +535,11 @@ static void relocate_section(TCCState *s1, Section *s)
|
||||
*(int *)ptr += s1->got_offsets[sym_index];
|
||||
break;
|
||||
#elif defined(TCC_TARGET_ARM)
|
||||
case R_ARM_PC24:
|
||||
case R_ARM_PLT32:
|
||||
{
|
||||
case R_ARM_PC24:
|
||||
case R_ARM_CALL:
|
||||
case R_ARM_JUMP24:
|
||||
case R_ARM_PLT32:
|
||||
{
|
||||
int x;
|
||||
x = (*(int *)ptr)&0xffffff;
|
||||
(*(int *)ptr) &= 0xff000000;
|
||||
@@ -529,28 +552,42 @@ static void relocate_section(TCCState *s1, Section *s)
|
||||
x >>= 2;
|
||||
x &= 0xffffff;
|
||||
(*(int *)ptr) |= x;
|
||||
}
|
||||
break;
|
||||
case R_ARM_ABS32:
|
||||
*(int *)ptr += val;
|
||||
break;
|
||||
case R_ARM_GOTPC:
|
||||
*(int *)ptr += s1->got->sh_addr - addr;
|
||||
break;
|
||||
case R_ARM_GOT32:
|
||||
}
|
||||
break;
|
||||
case R_ARM_PREL31:
|
||||
{
|
||||
int x;
|
||||
x = (*(int *)ptr) & 0x7fffffff;
|
||||
(*(int *)ptr) &= 0x80000000;
|
||||
x = (x * 2) / 2;
|
||||
x += val - addr;
|
||||
if((x^(x>>1))&0x40000000)
|
||||
error("can't relocate value at %x",addr);
|
||||
(*(int *)ptr) |= x & 0x7fffffff;
|
||||
}
|
||||
case R_ARM_ABS32:
|
||||
*(int *)ptr += val;
|
||||
break;
|
||||
case R_ARM_BASE_PREL:
|
||||
*(int *)ptr += s1->got->sh_addr - addr;
|
||||
break;
|
||||
case R_ARM_GOTOFF32:
|
||||
*(int *)ptr += val - s1->got->sh_addr;
|
||||
break;
|
||||
case R_ARM_GOT_BREL:
|
||||
/* we load the got offset */
|
||||
*(int *)ptr += s1->got_offsets[sym_index];
|
||||
break;
|
||||
case R_ARM_COPY:
|
||||
case R_ARM_COPY:
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,"FIXME: handle reloc type %x at %lx [%.8x] to %lx\n",
|
||||
default:
|
||||
fprintf(stderr,"FIXME: handle reloc type %x at %lx [%.8x] to %lx\n",
|
||||
type,addr,(unsigned int )ptr,val);
|
||||
break;
|
||||
#elif defined(TCC_TARGET_C67)
|
||||
case R_C60_32:
|
||||
*(int *)ptr += val;
|
||||
break;
|
||||
case R_C60_32:
|
||||
*(int *)ptr += val;
|
||||
break;
|
||||
case R_C60LO16:
|
||||
{
|
||||
uint32_t orig;
|
||||
@@ -570,7 +607,7 @@ static void relocate_section(TCCState *s1, Section *s)
|
||||
case R_C60HI16:
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,"FIXME: handle reloc type %x at %lx [%.8x] to %lx\n",
|
||||
fprintf(stderr,"FIXME: handle reloc type %x at %lx [%.8x] to %lx\n",
|
||||
type,addr,(unsigned int )ptr,val);
|
||||
break;
|
||||
#else
|
||||
@@ -751,7 +788,7 @@ static void put_got_entry(TCCState *s1,
|
||||
offset = plt->data_offset - 16;
|
||||
}
|
||||
#elif defined(TCC_TARGET_ARM)
|
||||
if (reloc_type == R_ARM_JUMP_SLOT) {
|
||||
if (reloc_type == R_ARM_JUMP_SLOT) {
|
||||
Section *plt;
|
||||
uint8_t *p;
|
||||
|
||||
@@ -764,17 +801,17 @@ static void put_got_entry(TCCState *s1,
|
||||
if (plt->data_offset == 0) {
|
||||
/* first plt entry */
|
||||
p = section_ptr_add(plt, 16);
|
||||
put32(p , 0xe52de004);
|
||||
put32(p + 4, 0xe59fe010);
|
||||
put32(p + 8, 0xe08fe00e);
|
||||
put32(p + 12, 0xe5bef008);
|
||||
put32(p , 0xe52de004);
|
||||
put32(p + 4, 0xe59fe010);
|
||||
put32(p + 8, 0xe08fe00e);
|
||||
put32(p + 12, 0xe5bef008);
|
||||
}
|
||||
|
||||
p = section_ptr_add(plt, 16);
|
||||
put32(p , 0xe59fc004);
|
||||
put32(p+4, 0xe08fc00c);
|
||||
put32(p+8, 0xe59cf000);
|
||||
put32(p+12, s1->got->data_offset);
|
||||
put32(p , 0xe59fc004);
|
||||
put32(p+4, 0xe08fc00c);
|
||||
put32(p+8, 0xe59cf000);
|
||||
put32(p+12, s1->got->data_offset);
|
||||
|
||||
/* the symbol is modified so that it will be relocated to
|
||||
the PLT */
|
||||
@@ -839,17 +876,17 @@ static void build_got_entries(TCCState *s1)
|
||||
}
|
||||
break;
|
||||
#elif defined(TCC_TARGET_ARM)
|
||||
case R_ARM_GOT32:
|
||||
case R_ARM_GOTOFF:
|
||||
case R_ARM_GOTPC:
|
||||
case R_ARM_GOT_BREL:
|
||||
case R_ARM_GOTOFF32:
|
||||
case R_ARM_BASE_PREL:
|
||||
case R_ARM_PLT32:
|
||||
if (!s1->got)
|
||||
build_got(s1);
|
||||
if (type == R_ARM_GOT32 || type == R_ARM_PLT32) {
|
||||
if (type == R_ARM_GOT_BREL || type == R_ARM_PLT32) {
|
||||
sym_index = ELF32_R_SYM(rel->r_info);
|
||||
sym = &((Elf32_Sym *)symtab_section->data)[sym_index];
|
||||
/* look at the symbol got offset. If none, then add one */
|
||||
if (type == R_ARM_GOT32)
|
||||
if (type == R_ARM_GOT_BREL)
|
||||
reloc_type = R_ARM_GLOB_DAT;
|
||||
else
|
||||
reloc_type = R_ARM_JUMP_SLOT;
|
||||
@@ -858,7 +895,7 @@ static void build_got_entries(TCCState *s1)
|
||||
}
|
||||
break;
|
||||
#elif defined(TCC_TARGET_C67)
|
||||
case R_C60_GOT32:
|
||||
case R_C60_GOT32:
|
||||
case R_C60_GOTOFF:
|
||||
case R_C60_GOTPC:
|
||||
case R_C60_PLT32:
|
||||
@@ -1064,8 +1101,12 @@ static void tcc_add_linker_symbols(TCCState *s1)
|
||||
#ifdef __FreeBSD__
|
||||
static char elf_interp[] = "/usr/libexec/ld-elf.so.1";
|
||||
#else
|
||||
#ifdef TCC_ARM_EABI
|
||||
static char elf_interp[] = "/lib/ld-linux.so.3";
|
||||
#else
|
||||
static char elf_interp[] = "/lib/ld-linux.so.2";
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static void tcc_output_binary(TCCState *s1, FILE *f,
|
||||
const int *section_order)
|
||||
@@ -1273,8 +1314,11 @@ int tcc_output_file(TCCState *s1, const char *filename)
|
||||
}
|
||||
/* XXX: currently, since we do not handle PIC code, we
|
||||
must relocate the readonly segments */
|
||||
if (file_type == TCC_OUTPUT_DLL)
|
||||
if (file_type == TCC_OUTPUT_DLL) {
|
||||
if (s1->soname)
|
||||
put_dt(dynamic, DT_SONAME, put_elf_str(dynstr, s1->soname));
|
||||
put_dt(dynamic, DT_TEXTREL, 0);
|
||||
}
|
||||
|
||||
/* add necessary space for other entries */
|
||||
saved_dynamic_data_offset = dynamic->data_offset;
|
||||
@@ -1510,13 +1554,13 @@ int tcc_output_file(TCCState *s1, const char *filename)
|
||||
p += 16;
|
||||
}
|
||||
#elif defined(TCC_TARGET_ARM)
|
||||
int x;
|
||||
x=s1->got->sh_addr - s1->plt->sh_addr - 12;
|
||||
p +=16;
|
||||
while (p < p_end) {
|
||||
put32(p + 12, x + get32(p + 12) + s1->plt->data - p);
|
||||
p += 16;
|
||||
}
|
||||
int x;
|
||||
x=s1->got->sh_addr - s1->plt->sh_addr - 12;
|
||||
p +=16;
|
||||
while (p < p_end) {
|
||||
put32(p + 12, x + get32(p + 12) + s1->plt->data - p);
|
||||
p += 16;
|
||||
}
|
||||
#elif defined(TCC_TARGET_C67)
|
||||
/* XXX: TODO */
|
||||
#else
|
||||
@@ -1620,6 +1664,8 @@ int tcc_output_file(TCCState *s1, const char *filename)
|
||||
goto fail;
|
||||
}
|
||||
f = fdopen(fd, "wb");
|
||||
if (verbose)
|
||||
printf("<- %s\n", filename);
|
||||
|
||||
#ifdef TCC_TARGET_COFF
|
||||
if (s1->output_format == TCC_OUTPUT_FORMAT_COFF) {
|
||||
@@ -1644,7 +1690,12 @@ int tcc_output_file(TCCState *s1, const char *filename)
|
||||
ehdr.e_ident[EI_OSABI] = ELFOSABI_FREEBSD;
|
||||
#endif
|
||||
#ifdef TCC_TARGET_ARM
|
||||
#ifdef TCC_ARM_EABI
|
||||
ehdr.e_ident[EI_OSABI] = 0;
|
||||
ehdr.e_flags = 4 << 24;
|
||||
#else
|
||||
ehdr.e_ident[EI_OSABI] = ELFOSABI_ARM;
|
||||
#endif
|
||||
#endif
|
||||
switch(file_type) {
|
||||
default:
|
||||
@@ -1816,6 +1867,9 @@ static int tcc_load_object_file(TCCState *s1,
|
||||
/* ignore sections types we do not handle */
|
||||
if (sh->sh_type != SHT_PROGBITS &&
|
||||
sh->sh_type != SHT_REL &&
|
||||
#ifdef TCC_ARM_EABI
|
||||
sh->sh_type != SHT_ARM_EXIDX &&
|
||||
#endif
|
||||
sh->sh_type != SHT_NOBITS)
|
||||
continue;
|
||||
if (sh->sh_addralign < 1)
|
||||
@@ -1874,7 +1928,6 @@ static int tcc_load_object_file(TCCState *s1,
|
||||
|
||||
/* second short pass to update sh_link and sh_info fields of new
|
||||
sections */
|
||||
sm = sm_table;
|
||||
for(i = 1; i < ehdr.e_shnum; i++) {
|
||||
s = sm_table[i].s;
|
||||
if (!s || !sm_table[i].new_section)
|
||||
@@ -1888,6 +1941,7 @@ static int tcc_load_object_file(TCCState *s1,
|
||||
s1->sections[s->sh_info]->reloc = s;
|
||||
}
|
||||
}
|
||||
sm = sm_table;
|
||||
|
||||
/* resolve symbols */
|
||||
old_to_new_syms = tcc_mallocz(nb_syms * sizeof(int));
|
||||
@@ -1949,9 +2003,11 @@ static int tcc_load_object_file(TCCState *s1,
|
||||
if (sym_index >= nb_syms)
|
||||
goto invalid_reloc;
|
||||
sym_index = old_to_new_syms[sym_index];
|
||||
if (!sym_index) {
|
||||
/* ignore link_once in rel section. */
|
||||
if (!sym_index && !sm->link_once) {
|
||||
invalid_reloc:
|
||||
error_noabort("Invalid relocation entry");
|
||||
error_noabort("Invalid relocation entry [%2d] '%s' @ %.8x",
|
||||
i, strsec + sh->sh_name, rel->r_offset);
|
||||
goto fail;
|
||||
}
|
||||
rel->r_info = ELF32_R_INFO(sym_index, type);
|
||||
@@ -1975,16 +2031,16 @@ static int tcc_load_object_file(TCCState *s1,
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define ARMAG "!<arch>\012" /* For COFF and a.out archives */
|
||||
#define ARMAG "!<arch>\012" /* For COFF and a.out archives */
|
||||
|
||||
typedef struct ArchiveHeader {
|
||||
char ar_name[16]; /* name of this member */
|
||||
char ar_date[12]; /* file mtime */
|
||||
char ar_uid[6]; /* owner uid; printed as decimal */
|
||||
char ar_gid[6]; /* owner gid; printed as decimal */
|
||||
char ar_mode[8]; /* file mode, printed as octal */
|
||||
char ar_size[10]; /* file size, printed as decimal */
|
||||
char ar_fmag[2]; /* should contain ARFMAG */
|
||||
char ar_name[16]; /* name of this member */
|
||||
char ar_date[12]; /* file mtime */
|
||||
char ar_uid[6]; /* owner uid; printed as decimal */
|
||||
char ar_gid[6]; /* owner gid; printed as decimal */
|
||||
char ar_mode[8]; /* file mode, printed as octal */
|
||||
char ar_size[10]; /* file size, printed as decimal */
|
||||
char ar_fmag[2]; /* should contain ARFMAG */
|
||||
} ArchiveHeader;
|
||||
|
||||
static int get_be32(const uint8_t *b)
|
||||
@@ -2009,26 +2065,26 @@ static int tcc_load_alacarte(TCCState *s1, int fd, int size)
|
||||
ar_names = ar_index + nsyms * 4;
|
||||
|
||||
do {
|
||||
bound = 0;
|
||||
for(p = ar_names, i = 0; i < nsyms; i++, p += strlen(p)+1) {
|
||||
sym_index = find_elf_sym(symtab_section, p);
|
||||
if(sym_index) {
|
||||
sym = &((Elf32_Sym *)symtab_section->data)[sym_index];
|
||||
if(sym->st_shndx == SHN_UNDEF) {
|
||||
off = get_be32(ar_index + i * 4) + sizeof(ArchiveHeader);
|
||||
bound = 0;
|
||||
for(p = ar_names, i = 0; i < nsyms; i++, p += strlen(p)+1) {
|
||||
sym_index = find_elf_sym(symtab_section, p);
|
||||
if(sym_index) {
|
||||
sym = &((Elf32_Sym *)symtab_section->data)[sym_index];
|
||||
if(sym->st_shndx == SHN_UNDEF) {
|
||||
off = get_be32(ar_index + i * 4) + sizeof(ArchiveHeader);
|
||||
#if 0
|
||||
printf("%5d\t%s\t%08x\n", i, p, sym->st_shndx);
|
||||
printf("%5d\t%s\t%08x\n", i, p, sym->st_shndx);
|
||||
#endif
|
||||
++bound;
|
||||
lseek(fd, off, SEEK_SET);
|
||||
if(tcc_load_object_file(s1, fd, off) < 0) {
|
||||
++bound;
|
||||
lseek(fd, off, SEEK_SET);
|
||||
if(tcc_load_object_file(s1, fd, off) < 0) {
|
||||
fail:
|
||||
ret = -1;
|
||||
goto the_end;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} while(bound);
|
||||
ret = 0;
|
||||
the_end:
|
||||
@@ -2072,8 +2128,8 @@ static int tcc_load_archive(TCCState *s1, int fd)
|
||||
size = (size + 1) & ~1;
|
||||
if (!strcmp(ar_name, "/")) {
|
||||
/* coff symbol table : we handle it */
|
||||
if(s1->alacarte_link)
|
||||
return tcc_load_alacarte(s1, fd, size);
|
||||
if(s1->alacarte_link)
|
||||
return tcc_load_alacarte(s1, fd, size);
|
||||
} else if (!strcmp(ar_name, "//") ||
|
||||
!strcmp(ar_name, "__.SYMDEF") ||
|
||||
!strcmp(ar_name, "__.SYMDEF/") ||
|
||||
@@ -2095,11 +2151,11 @@ static int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level)
|
||||
{
|
||||
Elf32_Ehdr ehdr;
|
||||
Elf32_Shdr *shdr, *sh, *sh1;
|
||||
int i, nb_syms, nb_dts, sym_bind, ret;
|
||||
int i, j, nb_syms, nb_dts, sym_bind, ret;
|
||||
Elf32_Sym *sym, *dynsym;
|
||||
Elf32_Dyn *dt, *dynamic;
|
||||
unsigned char *dynstr;
|
||||
const char *name, *soname, *p;
|
||||
const char *name, *soname;
|
||||
DLLReference *dllref;
|
||||
|
||||
read(fd, &ehdr, sizeof(ehdr));
|
||||
@@ -2138,10 +2194,7 @@ static int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level)
|
||||
}
|
||||
|
||||
/* compute the real library name */
|
||||
soname = filename;
|
||||
p = strrchr(soname, '/');
|
||||
if (p)
|
||||
soname = p + 1;
|
||||
soname = tcc_basename(filename);
|
||||
|
||||
for(i = 0, dt = dynamic; i < nb_dts; i++, dt++) {
|
||||
if (dt->d_tag == DT_SONAME) {
|
||||
@@ -2184,8 +2237,8 @@ static int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level)
|
||||
switch(dt->d_tag) {
|
||||
case DT_NEEDED:
|
||||
name = dynstr + dt->d_un.d_val;
|
||||
for(i = 0; i < s1->nb_loaded_dlls; i++) {
|
||||
dllref = s1->loaded_dlls[i];
|
||||
for(j = 0; j < s1->nb_loaded_dlls; j++) {
|
||||
dllref = s1->loaded_dlls[j];
|
||||
if (!strcmp(name, dllref->name))
|
||||
goto already_loaded;
|
||||
}
|
||||
@@ -2238,8 +2291,60 @@ static int ld_next(TCCState *s1, char *name, int name_size)
|
||||
goto parse_name;
|
||||
}
|
||||
break;
|
||||
case 'a' ... 'z':
|
||||
case 'A' ... 'Z':
|
||||
/* case 'a' ... 'z': */
|
||||
case 'a':
|
||||
case 'b':
|
||||
case 'c':
|
||||
case 'd':
|
||||
case 'e':
|
||||
case 'f':
|
||||
case 'g':
|
||||
case 'h':
|
||||
case 'i':
|
||||
case 'j':
|
||||
case 'k':
|
||||
case 'l':
|
||||
case 'm':
|
||||
case 'n':
|
||||
case 'o':
|
||||
case 'p':
|
||||
case 'q':
|
||||
case 'r':
|
||||
case 's':
|
||||
case 't':
|
||||
case 'u':
|
||||
case 'v':
|
||||
case 'w':
|
||||
case 'x':
|
||||
case 'y':
|
||||
case 'z':
|
||||
/* case 'A' ... 'z': */
|
||||
case 'A':
|
||||
case 'B':
|
||||
case 'C':
|
||||
case 'D':
|
||||
case 'E':
|
||||
case 'F':
|
||||
case 'G':
|
||||
case 'H':
|
||||
case 'I':
|
||||
case 'J':
|
||||
case 'K':
|
||||
case 'L':
|
||||
case 'M':
|
||||
case 'N':
|
||||
case 'O':
|
||||
case 'P':
|
||||
case 'Q':
|
||||
case 'R':
|
||||
case 'S':
|
||||
case 'T':
|
||||
case 'U':
|
||||
case 'V':
|
||||
case 'W':
|
||||
case 'X':
|
||||
case 'Y':
|
||||
case 'Z':
|
||||
case '_':
|
||||
case '\\':
|
||||
case '.':
|
||||
@@ -2277,13 +2382,49 @@ static int ld_next(TCCState *s1, char *name, int name_size)
|
||||
return c;
|
||||
}
|
||||
|
||||
static int ld_add_file_list(TCCState *s1, int as_needed)
|
||||
{
|
||||
char filename[1024];
|
||||
int t, ret;
|
||||
|
||||
t = ld_next(s1, filename, sizeof(filename));
|
||||
if (t != '(')
|
||||
expect("(");
|
||||
t = ld_next(s1, filename, sizeof(filename));
|
||||
for(;;) {
|
||||
if (t == LD_TOK_EOF) {
|
||||
error_noabort("unexpected end of file");
|
||||
return -1;
|
||||
} else if (t == ')') {
|
||||
break;
|
||||
} else if (t != LD_TOK_NAME) {
|
||||
error_noabort("filename expected");
|
||||
return -1;
|
||||
}
|
||||
if (!strcmp(filename, "AS_NEEDED")) {
|
||||
ret = ld_add_file_list(s1, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else {
|
||||
/* TODO: Implement AS_NEEDED support. Ignore it for now */
|
||||
if (!as_needed)
|
||||
tcc_add_file(s1, filename);
|
||||
}
|
||||
t = ld_next(s1, filename, sizeof(filename));
|
||||
if (t == ',') {
|
||||
t = ld_next(s1, filename, sizeof(filename));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* interpret a subset of GNU ldscripts to handle the dummy libc.so
|
||||
files */
|
||||
static int tcc_load_ldscript(TCCState *s1)
|
||||
{
|
||||
char cmd[64];
|
||||
char filename[1024];
|
||||
int t;
|
||||
int t, ret;
|
||||
|
||||
ch = file->buf_ptr[0];
|
||||
ch = handle_eob();
|
||||
@@ -2295,26 +2436,9 @@ static int tcc_load_ldscript(TCCState *s1)
|
||||
return -1;
|
||||
if (!strcmp(cmd, "INPUT") ||
|
||||
!strcmp(cmd, "GROUP")) {
|
||||
t = ld_next(s1, cmd, sizeof(cmd));
|
||||
if (t != '(')
|
||||
expect("(");
|
||||
t = ld_next(s1, filename, sizeof(filename));
|
||||
for(;;) {
|
||||
if (t == LD_TOK_EOF) {
|
||||
error_noabort("unexpected end of file");
|
||||
return -1;
|
||||
} else if (t == ')') {
|
||||
break;
|
||||
} else if (t != LD_TOK_NAME) {
|
||||
error_noabort("filename expected");
|
||||
return -1;
|
||||
}
|
||||
tcc_add_file(s1, filename);
|
||||
t = ld_next(s1, filename, sizeof(filename));
|
||||
if (t == ',') {
|
||||
t = ld_next(s1, filename, sizeof(filename));
|
||||
}
|
||||
}
|
||||
ret = ld_add_file_list(s1, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else if (!strcmp(cmd, "OUTPUT_FORMAT") ||
|
||||
!strcmp(cmd, "TARGET")) {
|
||||
/* ignore some commands */
|
||||
|
||||
37
tcctest.c
37
tcctest.c
@@ -223,7 +223,7 @@ void macro_test(void)
|
||||
#line 203 "test"
|
||||
printf("__LINE__=%d __FILE__=%s\n",
|
||||
__LINE__, __FILE__);
|
||||
#line 220 "tcctest.c"
|
||||
#line 227 "tcctest.c"
|
||||
|
||||
/* not strictly preprocessor, but we test it there */
|
||||
#ifdef C99_MACROS
|
||||
@@ -441,14 +441,21 @@ void enum_test()
|
||||
|
||||
typedef int *my_ptr;
|
||||
|
||||
typedef int mytype1;
|
||||
typedef int mytype2;
|
||||
|
||||
void typedef_test()
|
||||
{
|
||||
my_ptr a;
|
||||
mytype1 mytype2;
|
||||
int b;
|
||||
|
||||
a = &b;
|
||||
*a = 1234;
|
||||
printf("typedef:\n");
|
||||
printf("a=%d\n", *a);
|
||||
mytype2 = 2;
|
||||
printf("mytype2=%d\n", mytype2);
|
||||
}
|
||||
|
||||
void forward_test()
|
||||
@@ -1066,6 +1073,8 @@ void cast_test()
|
||||
int a;
|
||||
char c;
|
||||
char tab[10];
|
||||
unsigned b,d;
|
||||
short s;
|
||||
|
||||
printf("cast_test:\n");
|
||||
a = 0xfffff;
|
||||
@@ -1088,7 +1097,15 @@ void cast_test()
|
||||
printf("%d\n", a);
|
||||
|
||||
printf("sizeof(c) = %d, sizeof((int)c) = %d\n", sizeof(c), sizeof((int)c));
|
||||
|
||||
|
||||
/* test cast from unsigned to signed short to int */
|
||||
b = 0xf000;
|
||||
d = (short)b;
|
||||
printf("((unsigned)(short)0x%08x) = 0x%08x\n", b, d);
|
||||
b = 0xf0f0;
|
||||
d = (char)b;
|
||||
printf("((unsigned)(char)0x%08x) = 0x%08x\n", b, d);
|
||||
|
||||
/* test implicit int casting for array accesses */
|
||||
c = 0;
|
||||
tab[1] = 2;
|
||||
@@ -1803,14 +1820,14 @@ void local_label_test(void)
|
||||
{
|
||||
int a;
|
||||
goto l1;
|
||||
l2:
|
||||
a = 1 + ({
|
||||
__label__ l1, l2, l3;
|
||||
goto l4;
|
||||
l2:
|
||||
a = 1 + ({
|
||||
__label__ l1, l2, l3, l4;
|
||||
goto l1;
|
||||
l4:
|
||||
printf("aa1\n");
|
||||
goto l3;
|
||||
l2:
|
||||
l2:
|
||||
printf("aa3\n");
|
||||
goto l4;
|
||||
l1:
|
||||
@@ -1819,12 +1836,12 @@ void local_label_test(void)
|
||||
l3:;
|
||||
1;
|
||||
});
|
||||
printf("a=%d\n", a);
|
||||
printf("a=%d\n", a);
|
||||
return;
|
||||
l4:
|
||||
printf("bb1\n");
|
||||
printf("bb1\n");
|
||||
goto l2;
|
||||
l4:
|
||||
l1:
|
||||
printf("bb2\n");
|
||||
goto l4;
|
||||
}
|
||||
|
||||
38
tcctok.h
38
tcctok.h
@@ -101,6 +101,9 @@
|
||||
DEF(TOK_STDCALL1, "stdcall")
|
||||
DEF(TOK_STDCALL2, "__stdcall")
|
||||
DEF(TOK_STDCALL3, "__stdcall__")
|
||||
DEF(TOK_FASTCALL1, "fastcall")
|
||||
DEF(TOK_FASTCALL2, "__fastcall")
|
||||
DEF(TOK_FASTCALL3, "__fastcall__")
|
||||
DEF(TOK_DLLEXPORT, "dllexport")
|
||||
DEF(TOK_NORETURN1, "noreturn")
|
||||
DEF(TOK_NORETURN2, "__noreturn__")
|
||||
@@ -118,18 +121,36 @@
|
||||
#endif
|
||||
|
||||
/* builtin functions or variables */
|
||||
#ifdef TCC_ARM_EABI
|
||||
DEF(TOK_memcpy, "__aeabi_memcpy")
|
||||
DEF(TOK_memcpy4, "__aeabi_memcpy4")
|
||||
DEF(TOK_memcpy8, "__aeabi_memcpy8")
|
||||
DEF(TOK_memset, "__aeabi_memset")
|
||||
#else
|
||||
DEF(TOK_memcpy, "memcpy")
|
||||
DEF(TOK_memset, "memset")
|
||||
DEF(TOK_alloca, "alloca")
|
||||
#endif
|
||||
DEF(TOK___divdi3, "__divdi3")
|
||||
DEF(TOK___moddi3, "__moddi3")
|
||||
DEF(TOK___udivdi3, "__udivdi3")
|
||||
DEF(TOK___umoddi3, "__umoddi3")
|
||||
#if defined(TCC_TARGET_ARM)
|
||||
DEF(TOK___divsi3, "__divsi3")
|
||||
DEF(TOK___modsi3, "__modsi3")
|
||||
DEF(TOK___udivsi3, "__udivsi3")
|
||||
DEF(TOK___umodsi3, "__umodsi3")
|
||||
#ifdef TCC_ARM_EABI
|
||||
DEF(TOK___divsi3, "__aeabi_idiv")
|
||||
DEF(TOK___udivsi3, "__aeabi_uidiv")
|
||||
DEF(TOK___sardi3, "__aeabi_lasr")
|
||||
DEF(TOK___shrdi3, "__aeabi_llsr")
|
||||
DEF(TOK___shldi3, "__aeabi_llsl")
|
||||
DEF(TOK___slltof, "__aeabi_l2f")
|
||||
DEF(TOK___slltold, "__aeabi_l2d")
|
||||
DEF(TOK___fixsfdi, "__aeabi_f2lz")
|
||||
DEF(TOK___fixdfdi, "__aeabi_d2lz")
|
||||
DEF(TOK___fixxfdi, "__aeabi_d2lz")
|
||||
#else
|
||||
DEF(TOK___divsi3, "__divsi3")
|
||||
DEF(TOK___udivsi3, "__udivsi3")
|
||||
DEF(TOK___sardi3, "__ashrdi3")
|
||||
DEF(TOK___shrdi3, "__lshrdi3")
|
||||
DEF(TOK___shldi3, "__ashldi3")
|
||||
@@ -140,6 +161,7 @@
|
||||
DEF(TOK___fixsfdi, "__fixsfdi")
|
||||
DEF(TOK___fixdfdi, "__fixdfdi")
|
||||
DEF(TOK___fixxfdi, "__fixxfdi")
|
||||
#endif
|
||||
#elif defined(TCC_TARGET_C67)
|
||||
DEF(TOK__divi, "_divi")
|
||||
DEF(TOK__divu, "_divu")
|
||||
@@ -158,12 +180,21 @@
|
||||
#endif
|
||||
DEF(TOK___tcc_int_fpu_control, "__tcc_int_fpu_control")
|
||||
DEF(TOK___tcc_fpu_control, "__tcc_fpu_control")
|
||||
#ifdef TCC_ARM_EABI
|
||||
DEF(TOK___ulltof, "__aeabi_ul2f")
|
||||
DEF(TOK___ulltod, "__aeabi_ul2d")
|
||||
DEF(TOK___ulltold, "__aeabi_ul2d")
|
||||
DEF(TOK___fixunssfdi, "__aeabi_f2ulz")
|
||||
DEF(TOK___fixunsdfdi, "__aeabi_d2ulz")
|
||||
DEF(TOK___fixunsxfdi, "__aeabi_d2ulz")
|
||||
#else
|
||||
DEF(TOK___ulltof, "__ulltof")
|
||||
DEF(TOK___ulltod, "__ulltod")
|
||||
DEF(TOK___ulltold, "__ulltold")
|
||||
DEF(TOK___fixunssfdi, "__fixunssfdi")
|
||||
DEF(TOK___fixunsdfdi, "__fixunsdfdi")
|
||||
DEF(TOK___fixunsxfdi, "__fixunsxfdi")
|
||||
#endif
|
||||
DEF(TOK___chkstk, "__chkstk")
|
||||
|
||||
/* bound checking symbols */
|
||||
@@ -185,6 +216,7 @@
|
||||
DEF(TOK_memmove, "memmove")
|
||||
DEF(TOK_strlen, "strlen")
|
||||
DEF(TOK_strcpy, "strcpy")
|
||||
DEF(TOK__alloca, "_alloca")
|
||||
#endif
|
||||
|
||||
/* Tiny Assembler */
|
||||
|
||||
372
tiny_impdef.c
372
tiny_impdef.c
@@ -1,372 +0,0 @@
|
||||
/* -------------------------------------------------------------- */
|
||||
/*
|
||||
"tiny_impdef creates a .def file from a dll"
|
||||
|
||||
"Usage: tiny_impdef [-p] <library.dll> [-o outputfile]"
|
||||
"Options:"
|
||||
" -p print to stdout"
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* Offset to PE file signature */
|
||||
#define NTSIGNATURE(a) ((LPVOID)((BYTE *)a + \
|
||||
((PIMAGE_DOS_HEADER)a)->e_lfanew))
|
||||
|
||||
/* MS-OS header identifies the NT PEFile signature dword;
|
||||
the PEFILE header exists just after that dword. */
|
||||
#define PEFHDROFFSET(a) ((LPVOID)((BYTE *)a + \
|
||||
((PIMAGE_DOS_HEADER)a)->e_lfanew + \
|
||||
SIZE_OF_NT_SIGNATURE))
|
||||
|
||||
/* PE optional header is immediately after PEFile header. */
|
||||
#define OPTHDROFFSET(a) ((LPVOID)((BYTE *)a + \
|
||||
((PIMAGE_DOS_HEADER)a)->e_lfanew + \
|
||||
SIZE_OF_NT_SIGNATURE + \
|
||||
sizeof (IMAGE_FILE_HEADER)))
|
||||
|
||||
/* Section headers are immediately after PE optional header. */
|
||||
#define SECHDROFFSET(a) ((LPVOID)((BYTE *)a + \
|
||||
((PIMAGE_DOS_HEADER)a)->e_lfanew + \
|
||||
SIZE_OF_NT_SIGNATURE + \
|
||||
sizeof (IMAGE_FILE_HEADER) + \
|
||||
sizeof (IMAGE_OPTIONAL_HEADER)))
|
||||
|
||||
|
||||
#define SIZE_OF_NT_SIGNATURE 4
|
||||
|
||||
/* -------------------------------------------------------------- */
|
||||
|
||||
int WINAPI NumOfSections (
|
||||
LPVOID lpFile)
|
||||
{
|
||||
/* Number of sections is indicated in file header. */
|
||||
return (int)
|
||||
((PIMAGE_FILE_HEADER)
|
||||
PEFHDROFFSET(lpFile))->NumberOfSections;
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------------------------- */
|
||||
|
||||
LPVOID WINAPI ImageDirectoryOffset (
|
||||
LPVOID lpFile,
|
||||
DWORD dwIMAGE_DIRECTORY)
|
||||
{
|
||||
PIMAGE_OPTIONAL_HEADER poh;
|
||||
PIMAGE_SECTION_HEADER psh;
|
||||
int nSections = NumOfSections (lpFile);
|
||||
int i = 0;
|
||||
LPVOID VAImageDir;
|
||||
|
||||
/* Retrieve offsets to optional and section headers. */
|
||||
poh = (PIMAGE_OPTIONAL_HEADER)OPTHDROFFSET (lpFile);
|
||||
psh = (PIMAGE_SECTION_HEADER)SECHDROFFSET (lpFile);
|
||||
|
||||
/* Must be 0 thru (NumberOfRvaAndSizes-1). */
|
||||
if (dwIMAGE_DIRECTORY >= poh->NumberOfRvaAndSizes)
|
||||
return NULL;
|
||||
|
||||
/* Locate image directory's relative virtual address. */
|
||||
VAImageDir = (LPVOID)poh->DataDirectory
|
||||
[dwIMAGE_DIRECTORY].VirtualAddress;
|
||||
|
||||
/* Locate section containing image directory. */
|
||||
while (i++<nSections)
|
||||
{
|
||||
if (psh->VirtualAddress <= (DWORD)VAImageDir
|
||||
&& psh->VirtualAddress + psh->SizeOfRawData > (DWORD)VAImageDir)
|
||||
break;
|
||||
psh++;
|
||||
}
|
||||
|
||||
if (i > nSections)
|
||||
return NULL;
|
||||
|
||||
/* Return image import directory offset. */
|
||||
return (LPVOID)(((int)lpFile +
|
||||
(int)VAImageDir - psh->VirtualAddress) +
|
||||
(int)psh->PointerToRawData);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------- */
|
||||
|
||||
BOOL WINAPI GetSectionHdrByName (
|
||||
LPVOID lpFile,
|
||||
IMAGE_SECTION_HEADER *sh,
|
||||
char *szSection)
|
||||
{
|
||||
PIMAGE_SECTION_HEADER psh;
|
||||
int nSections = NumOfSections (lpFile);
|
||||
int i;
|
||||
|
||||
if ((psh = (PIMAGE_SECTION_HEADER)SECHDROFFSET (lpFile)) !=
|
||||
NULL)
|
||||
{
|
||||
/* find the section by name */
|
||||
for (i=0; i<nSections; i++)
|
||||
{
|
||||
if (!strcmp (psh->Name, szSection))
|
||||
{
|
||||
/* copy data to header */
|
||||
memcpy ((LPVOID)sh,
|
||||
(LPVOID)psh,
|
||||
sizeof (IMAGE_SECTION_HEADER));
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
psh++;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------- */
|
||||
|
||||
BOOL WINAPI GetSectionHdrByAddress (
|
||||
LPVOID lpFile,
|
||||
IMAGE_SECTION_HEADER *sh,
|
||||
DWORD addr)
|
||||
{
|
||||
PIMAGE_SECTION_HEADER psh;
|
||||
int nSections = NumOfSections (lpFile);
|
||||
int i;
|
||||
|
||||
if ((psh = (PIMAGE_SECTION_HEADER)SECHDROFFSET (lpFile)) !=
|
||||
NULL)
|
||||
{
|
||||
/* find the section by name */
|
||||
for (i=0; i<nSections; i++)
|
||||
{
|
||||
if (addr >= psh->VirtualAddress && addr < psh->VirtualAddress + psh->SizeOfRawData)
|
||||
{
|
||||
/* copy data to header */
|
||||
memcpy ((LPVOID)sh,
|
||||
(LPVOID)psh,
|
||||
sizeof (IMAGE_SECTION_HEADER));
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
psh++;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------- */
|
||||
|
||||
int WINAPI GetExportFunctionNames (
|
||||
LPVOID lpFile,
|
||||
HANDLE hHeap,
|
||||
char **pszFunctions)
|
||||
{
|
||||
IMAGE_SECTION_HEADER sh;
|
||||
PIMAGE_EXPORT_DIRECTORY ped;
|
||||
int *pNames, *pCnt;
|
||||
char *pSrc, *pDest;
|
||||
int i, nCnt;
|
||||
DWORD VAImageDir;
|
||||
PIMAGE_OPTIONAL_HEADER poh;
|
||||
char *pOffset;
|
||||
|
||||
/* Get section header and pointer to data directory
|
||||
for .edata section. */
|
||||
if ((ped = (PIMAGE_EXPORT_DIRECTORY)ImageDirectoryOffset
|
||||
(lpFile, IMAGE_DIRECTORY_ENTRY_EXPORT)) == NULL)
|
||||
return 0;
|
||||
|
||||
poh = (PIMAGE_OPTIONAL_HEADER)OPTHDROFFSET (lpFile);
|
||||
VAImageDir = poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
|
||||
|
||||
if (FALSE == GetSectionHdrByAddress (lpFile, &sh, VAImageDir)) return 0;
|
||||
|
||||
pOffset = (char *)lpFile + (sh.PointerToRawData - sh.VirtualAddress);
|
||||
|
||||
pNames = (int *)(pOffset + (DWORD)ped->AddressOfNames);
|
||||
|
||||
/* Figure out how much memory to allocate for all strings. */
|
||||
nCnt = 1;
|
||||
for (i=0, pCnt = pNames; i<(int)ped->NumberOfNames; i++)
|
||||
{
|
||||
pSrc = (pOffset + *pCnt++);
|
||||
if (pSrc) nCnt += strlen(pSrc)+1;
|
||||
}
|
||||
|
||||
/* Allocate memory off heap for function names. */
|
||||
pDest = *pszFunctions = HeapAlloc (hHeap, HEAP_ZERO_MEMORY, nCnt);
|
||||
|
||||
/* Copy all strings to buffer. */
|
||||
for (i=0, pCnt = pNames; i<(int)ped->NumberOfNames; i++)
|
||||
{
|
||||
pSrc = (pOffset + *pCnt++);
|
||||
if (pSrc) { strcpy(pDest, pSrc); pDest += strlen(pSrc)+1; }
|
||||
}
|
||||
*pDest = 0;
|
||||
|
||||
return ped->NumberOfNames;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------- */
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
|
||||
HANDLE hHeap; HANDLE hFile; HANDLE hMapObject; VOID *pMem;
|
||||
int nCnt, ret, argind, std;
|
||||
char *pNames;
|
||||
char infile[MAX_PATH];
|
||||
char buffer[MAX_PATH];
|
||||
char outfile[MAX_PATH];
|
||||
char libname[80];
|
||||
|
||||
hHeap = NULL;
|
||||
hFile = NULL;
|
||||
hMapObject = NULL;
|
||||
pMem = NULL;
|
||||
infile[0] = 0;
|
||||
outfile[0] = 0;
|
||||
ret = 0;
|
||||
std = 0;
|
||||
|
||||
for (argind = 1; argind < argc; ++argind)
|
||||
{
|
||||
const char *a = argv[argind];
|
||||
if ('-' == a[0])
|
||||
{
|
||||
if (0 == strcmp(a, "-p"))
|
||||
std = 1;
|
||||
else
|
||||
if (0 == strcmp(a, "-o"))
|
||||
{
|
||||
if (++argind == argc) goto usage;
|
||||
strcpy(outfile, argv[argind]);
|
||||
}
|
||||
else
|
||||
goto usage;
|
||||
}
|
||||
else
|
||||
if (0 == infile[0])
|
||||
strcpy(infile, a);
|
||||
else
|
||||
goto usage;
|
||||
}
|
||||
|
||||
if (0 == infile[0])
|
||||
{
|
||||
usage:
|
||||
fprintf(stderr,
|
||||
"tiny_impdef creates a .def file from a dll\n"
|
||||
"Usage: tiny_impdef [-p] <library.dll> [-o outputfile]\n"
|
||||
"Options:\n"
|
||||
" -p print to stdout\n"
|
||||
);
|
||||
error:
|
||||
ret = 1;
|
||||
goto the_end;
|
||||
}
|
||||
|
||||
if (SearchPath(NULL, infile, ".dll", sizeof buffer, buffer, NULL))
|
||||
strcpy(infile, buffer);
|
||||
|
||||
if (0 == outfile[0])
|
||||
{
|
||||
char *p;
|
||||
p = strrchr(strcpy(outfile, infile), '\\');
|
||||
if (NULL == p)
|
||||
p = strrchr(outfile, '/');
|
||||
if (p) strcpy(outfile, p+1);
|
||||
|
||||
p = strrchr(outfile, '.');
|
||||
if (NULL == p) p = strchr(outfile, 0);
|
||||
strcpy(p, ".def");
|
||||
}
|
||||
|
||||
hFile=CreateFile(
|
||||
infile,
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
0,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
fprintf(stderr, "file not found: %s\n", infile);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!std) printf("--> %s\n", infile);
|
||||
|
||||
hMapObject = CreateFileMapping(
|
||||
hFile,
|
||||
NULL,
|
||||
PAGE_READONLY,
|
||||
0, 0,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (NULL == hMapObject)
|
||||
{
|
||||
fprintf(stderr, "could not create file mapping.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
pMem = MapViewOfFile(
|
||||
hMapObject, // object to map view of
|
||||
FILE_MAP_READ, // read access
|
||||
0, // high offset: map from
|
||||
0, // low offset: beginning
|
||||
0); // default: map entire file
|
||||
|
||||
if (NULL == pMem)
|
||||
{
|
||||
fprintf(stderr, "could not map view of file.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
hHeap = GetProcessHeap();
|
||||
nCnt = GetExportFunctionNames(pMem, hHeap, &pNames);
|
||||
{
|
||||
FILE *op; char *p; int n;
|
||||
if (!std) printf("<-- %s\n", outfile);
|
||||
|
||||
if (std)
|
||||
op = stdout;
|
||||
else
|
||||
op = fopen(outfile, "wt");
|
||||
|
||||
if (NULL == op)
|
||||
{
|
||||
fprintf(stderr, "could not create file: %s\n", outfile);
|
||||
goto error;
|
||||
}
|
||||
|
||||
p = strrchr(infile, '\\');
|
||||
if (NULL == p)
|
||||
p = strrchr(infile, '/');
|
||||
if (NULL == p) p = infile; else ++p;
|
||||
|
||||
fprintf(op, "LIBRARY %s\n\nEXPORTS", p);
|
||||
if (std) fprintf(op, " (%d)", nCnt);
|
||||
fprintf(op, "\n");
|
||||
for (n = 0, p = pNames; n < nCnt; ++n)
|
||||
{
|
||||
fprintf(op, "%s\n", p);
|
||||
while (*p++);
|
||||
}
|
||||
if (!std) fclose(op);
|
||||
}
|
||||
|
||||
the_end:
|
||||
if (pMem) UnmapViewOfFile(pMem);
|
||||
if (hMapObject) CloseHandle(hMapObject);
|
||||
if (hFile) CloseHandle(hFile);
|
||||
return ret;
|
||||
}
|
||||
/* -------------------------------------------------------------- */
|
||||
|
||||
27
win32/build-tcc.bat
Normal file
27
win32/build-tcc.bat
Normal file
@@ -0,0 +1,27 @@
|
||||
@rem ----------------------------------------------------
|
||||
@rem batch file to build tcc using gcc and ar from mingw
|
||||
@rem ----------------------------------------------------
|
||||
:
|
||||
@echo>..\config.h #define TCC_VERSION "0.9.24"
|
||||
@echo>>..\config.h #define TCC_TARGET_PE 1
|
||||
@echo>>..\config.h #define CONFIG_TCCDIR "."
|
||||
:
|
||||
gcc -Os -fno-strict-aliasing ../tcc.c -o tcc.exe -s
|
||||
gcc -Os -fno-strict-aliasing ../tcc.c -D LIBTCC -c -o libtcc.o
|
||||
gcc -Os tools/tiny_impdef.c -o tiny_impdef.exe -s
|
||||
gcc -Os tools/tiny_libmaker.c -o tiny_libmaker.exe -s
|
||||
mkdir libtcc
|
||||
ar rcs libtcc/libtcc.a libtcc.o
|
||||
del libtcc.o
|
||||
copy ..\libtcc.h libtcc
|
||||
:
|
||||
.\tcc -c lib/crt1.c
|
||||
.\tcc -c lib/wincrt1.c
|
||||
.\tcc -c lib/dllcrt1.c
|
||||
.\tcc -c lib/dllmain.c
|
||||
.\tcc -c lib/chkstk.S
|
||||
.\tcc -c ../libtcc1.c
|
||||
.\tcc -c ../alloca86.S
|
||||
.\tcc -c ../alloca86-bt.S
|
||||
ar rcs lib/libtcc1.a crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o libtcc1.o alloca86.o alloca86-bt.o
|
||||
del *.o
|
||||
@@ -18,25 +18,26 @@
|
||||
#ifndef __MINGW_H
|
||||
#define __MINGW_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#define __int64 long long
|
||||
#define __int32 long
|
||||
#define __int16 short
|
||||
#define __int8 char
|
||||
#define __cdecl __attribute__((__cdecl__))
|
||||
#define __stdcall __attribute__((__stdcall__))
|
||||
#define __declspec(x) __attribute__((x))
|
||||
#define __int8 char
|
||||
#define __cdecl __attribute__((__cdecl__))
|
||||
#define __stdcall __attribute__((__stdcall__))
|
||||
#define __declspec(x) __attribute__((x))
|
||||
|
||||
#define __MINGW32_VERSION 2.0
|
||||
#define __MINGW32_MAJOR_VERSION 2
|
||||
#define __MINGW32_MINOR_VERSION 0
|
||||
|
||||
#define __MSVCRT__
|
||||
#define __MINGW_IMPORT extern
|
||||
#define __MSVCRT__ 1
|
||||
#define __MINGW_IMPORT extern
|
||||
#define _CRTIMP
|
||||
#define __CRT_INLINE extern __inline__
|
||||
#define __CRT_INLINE extern __inline__
|
||||
|
||||
#define _WIN32
|
||||
#define WIN32
|
||||
#define WIN32 1
|
||||
|
||||
#ifndef _WINT_T
|
||||
#define _WINT_T
|
||||
@@ -44,7 +45,8 @@ typedef unsigned int wint_t;
|
||||
#endif
|
||||
|
||||
/* for winapi */
|
||||
#define NONAMELESSUNION
|
||||
#define _ANONYMOUS_UNION
|
||||
#define _ANONYMOUS_STRUCT
|
||||
#define DECLSPEC_NORETURN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define DECLARE_STDCALL_P(type) __stdcall type
|
||||
|
||||
@@ -6,6 +6,7 @@ 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_copy(dest, src) (dest) = (src)
|
||||
#define va_end(ap)
|
||||
|
||||
/* fix a buggy dependency on GCC in libio.h */
|
||||
|
||||
@@ -12,10 +12,15 @@ typedef __PTRDIFF_TYPE__ ptrdiff_t;
|
||||
__GNUC__ ? */
|
||||
#if !defined(__int8_t_defined) && !defined(__dietlibc__)
|
||||
#define __int8_t_defined
|
||||
typedef char int8_t;
|
||||
typedef short int int16_t;
|
||||
typedef int int32_t;
|
||||
typedef char int8_t;
|
||||
typedef short int int16_t;
|
||||
typedef int int32_t;
|
||||
typedef long long int int64_t;
|
||||
#endif
|
||||
|
||||
#ifdef __i386__
|
||||
void *_alloca(size_t);
|
||||
#define alloca _alloca
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
173
win32/readme.txt
173
win32/readme.txt
@@ -1,115 +1,114 @@
|
||||
|
||||
TinyCC-PE
|
||||
---------
|
||||
TinyCC
|
||||
======
|
||||
|
||||
TinyCC (aka TCC) is a small but hyperfast C compiler,
|
||||
written by Fabrice Bellard,
|
||||
This file contains some additional information for usage of TinyCC
|
||||
under MS-Windows:
|
||||
|
||||
|
||||
TinyCC-PE is the TinyCC compiler with an extension to
|
||||
write PE executables for MS-Windows.
|
||||
Overview:
|
||||
---------
|
||||
TinyCC (aka TCC) is a small but hyperfast C compiler, written by
|
||||
Fabrice Bellard.
|
||||
|
||||
TinyCC for MS-Windows can produce console applications, native
|
||||
windows GUI programs and DLL's.
|
||||
|
||||
The package with under 300kb includes a complete C-compiler with
|
||||
header files and basic system library support.
|
||||
|
||||
With the -run switch you can run C-sources without any linking
|
||||
directly from the command line.
|
||||
|
||||
TinyCC can be used as dynamic code generator library in your own
|
||||
program.
|
||||
|
||||
TinyCC can of course compile itself.
|
||||
|
||||
|
||||
Features:
|
||||
---------
|
||||
Compilation: (omit that if you use the binary ZIP package)
|
||||
------------
|
||||
You can use the MinGW and MSYS tools available at
|
||||
http://www.mingw.org to compile TCC for Windows. Untar the TCC
|
||||
archive and type in the MSYS shell:
|
||||
|
||||
./configure
|
||||
make
|
||||
make install
|
||||
|
||||
TinyCC-PE can produce console applications, native windows
|
||||
GUI programs and DLL's.
|
||||
TCC is installed in c:\Program Files\tcc
|
||||
|
||||
Most of the features pointed out by Fabrice Bellard for the
|
||||
original version are still valid, i.e:
|
||||
|
||||
- SMALL! The package with ~400kb includes a complete C-compiler
|
||||
with header files for console and GUI applications.
|
||||
|
||||
- With the -run switch you can run C-sources without any
|
||||
linking directly from the command line.
|
||||
|
||||
- TCC can of course compile itself.
|
||||
Alternatively you can use win32\build-tcc.bat to compile TCC
|
||||
with just gcc and ar from MINGW. To install, copy the entire
|
||||
contents of the win32 directory to where you want.
|
||||
|
||||
|
||||
Compilation: (omit that if you use the binary ZIP package)
|
||||
------------
|
||||
|
||||
You must use the MinGW and MSYS tools available at
|
||||
http://www.mingw.org to compile TCC for Windows. Untar the TCC
|
||||
archive and type in the MSYS shell:
|
||||
|
||||
./configure
|
||||
make
|
||||
make install
|
||||
|
||||
TCC is installed in c:\Program Files\tcc
|
||||
|
||||
Installation: (from the binary ZIP package)
|
||||
-------------
|
||||
|
||||
Just unzip the package to a directory anywhere on your computer.
|
||||
Installation: (from the binary ZIP package)
|
||||
-------------
|
||||
Just unzip the package to a directory anywhere on your computer.
|
||||
|
||||
The binary package does not include libtcc. If you want tcc as
|
||||
dynamic code generator, please use the source code distribution.
|
||||
|
||||
|
||||
Examples:
|
||||
---------
|
||||
Examples:
|
||||
---------
|
||||
For the 'Fibonacci' console example type from the command line:
|
||||
|
||||
For the 'Fibonacci' console example type from the command line:
|
||||
tcc examples\fib.c
|
||||
|
||||
tcc examples\fib.c
|
||||
For the 'Hello Windows' GUI example:
|
||||
|
||||
tcc examples\hello_win.c
|
||||
|
||||
For the 'Hello DLL' example:
|
||||
|
||||
tcc -shared examples\dll.c
|
||||
tcc examples\hello_dll.c examples\dll.def
|
||||
|
||||
|
||||
For the 'Hello Windows' GUI example:
|
||||
Import Definition Files:
|
||||
------------------------
|
||||
To link with Windows system DLLs, TinyCC uses import definition
|
||||
files (.def) instead of libraries.
|
||||
|
||||
tcc examples\hello_win.c
|
||||
The included 'tiny_impdef' program may be used to make additional
|
||||
.def files for any DLL. For example:
|
||||
|
||||
tiny_impdef.exe opengl32.dll
|
||||
|
||||
To use it, put the opengl32.def file into the tcc/lib directory,
|
||||
and specify -lopengl32 at the tcc commandline.
|
||||
|
||||
|
||||
For the 'Hello DLL' example:
|
||||
Resource Files:
|
||||
---------------
|
||||
TinyCC-PE can now link windows resources in coff format as generated
|
||||
by MINGW's windres.exe. For example:
|
||||
|
||||
tcc -shared examples\dll.c
|
||||
tcc examples\hello_dll.c examples\dll.def
|
||||
windres -O coff app.rc -o appres.o
|
||||
tcc app.c appres.o -o app.exe
|
||||
|
||||
|
||||
Import Definitions:
|
||||
-------------------
|
||||
|
||||
TinyCC-PE searches and reads import definition files similar
|
||||
to libraries.
|
||||
|
||||
The included 'tiny_impdef' program may be used to make .def files
|
||||
for any DLL, e.g for an 'opengl32.def':
|
||||
|
||||
tiny_impdef.exe opengl32.dll
|
||||
|
||||
or to the same effect:
|
||||
|
||||
tcc -lkernel32 -run tiny_impdef.c opengl32.dll
|
||||
Tiny Libmaker:
|
||||
--------------
|
||||
The included tiny_libmaker tool by Timovj Lahde can be used as
|
||||
'ar' replacement to make a library from several object files.
|
||||
|
||||
|
||||
Header Files:
|
||||
-------------
|
||||
|
||||
The system header files, except '_mingw.h', are from the
|
||||
2.0 mingw distribution. See also: http://www.mingw.org/
|
||||
Header Files:
|
||||
-------------
|
||||
The system header files (except _mingw.h) are from the mingw
|
||||
distribution (http://www.mingw.org/).
|
||||
|
||||
|
||||
Compile TCC:
|
||||
------------
|
||||
Documentation and License:
|
||||
--------------------------
|
||||
TCC is distributed under the GNU Lesser General Public License
|
||||
(see COPYING file).
|
||||
|
||||
With TCC itself just say:
|
||||
|
||||
tcc src\tcc.c -lkernel32 -o tcc.new.exe
|
||||
|
||||
Other compilers like mingw-gcc or msvc work as well.
|
||||
To make libtcc1.a, you need 'ar' from the mingw binutils.
|
||||
|
||||
|
||||
Documentation and License:
|
||||
--------------------------
|
||||
|
||||
TCC is distributed under the GNU Lesser General Public License
|
||||
(see COPYING file).
|
||||
|
||||
Please read the original tcc-doc.html to have all the features
|
||||
of TCC. Also visit: http://fabrice.bellard.free.fr/tcc/
|
||||
|
||||
|
||||
--------------------------------------------
|
||||
09.Apr.2005 - grischka@users.sourceforge.net
|
||||
Please read tcc-doc.html to have all the features of TCC. Also
|
||||
visit: http://fabrice.bellard.free.fr/tcc/
|
||||
|
||||
|
||||
-- grischka@users.sourceforge.net
|
||||
|
||||
393
win32/tools/tiny_impdef.c
Normal file
393
win32/tools/tiny_impdef.c
Normal file
@@ -0,0 +1,393 @@
|
||||
/* -------------------------------------------------------------- */
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* Offset to PE file signature */
|
||||
#define NTSIGNATURE(a) ((LPVOID)((BYTE *)a + \
|
||||
((PIMAGE_DOS_HEADER)a)->e_lfanew))
|
||||
|
||||
/* MS-OS header identifies the NT PEFile signature dword;
|
||||
the PEFILE header exists just after that dword. */
|
||||
#define PEFHDROFFSET(a) ((LPVOID)((BYTE *)a + \
|
||||
((PIMAGE_DOS_HEADER)a)->e_lfanew + \
|
||||
SIZE_OF_NT_SIGNATURE))
|
||||
|
||||
/* PE optional header is immediately after PEFile header. */
|
||||
#define OPTHDROFFSET(a) ((LPVOID)((BYTE *)a + \
|
||||
((PIMAGE_DOS_HEADER)a)->e_lfanew + \
|
||||
SIZE_OF_NT_SIGNATURE + \
|
||||
sizeof (IMAGE_FILE_HEADER)))
|
||||
|
||||
/* Section headers are immediately after PE optional header. */
|
||||
#define SECHDROFFSET(a) ((LPVOID)((BYTE *)a + \
|
||||
((PIMAGE_DOS_HEADER)a)->e_lfanew + \
|
||||
SIZE_OF_NT_SIGNATURE + \
|
||||
sizeof (IMAGE_FILE_HEADER) + \
|
||||
sizeof (IMAGE_OPTIONAL_HEADER)))
|
||||
|
||||
|
||||
#define SIZE_OF_NT_SIGNATURE 4
|
||||
|
||||
/* -------------------------------------------------------------- */
|
||||
|
||||
int WINAPI NumOfSections (
|
||||
LPVOID lpFile)
|
||||
{
|
||||
/* Number of sections is indicated in file header. */
|
||||
return (int)
|
||||
((PIMAGE_FILE_HEADER)
|
||||
PEFHDROFFSET(lpFile))->NumberOfSections;
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------------------------- */
|
||||
|
||||
LPVOID WINAPI ImageDirectoryOffset (
|
||||
LPVOID lpFile,
|
||||
DWORD dwIMAGE_DIRECTORY)
|
||||
{
|
||||
PIMAGE_OPTIONAL_HEADER poh;
|
||||
PIMAGE_SECTION_HEADER psh;
|
||||
int nSections = NumOfSections (lpFile);
|
||||
int i = 0;
|
||||
LPVOID VAImageDir;
|
||||
|
||||
/* Retrieve offsets to optional and section headers. */
|
||||
poh = (PIMAGE_OPTIONAL_HEADER)OPTHDROFFSET (lpFile);
|
||||
psh = (PIMAGE_SECTION_HEADER)SECHDROFFSET (lpFile);
|
||||
|
||||
/* Must be 0 thru (NumberOfRvaAndSizes-1). */
|
||||
if (dwIMAGE_DIRECTORY >= poh->NumberOfRvaAndSizes)
|
||||
return NULL;
|
||||
|
||||
/* Locate image directory's relative virtual address. */
|
||||
VAImageDir = (LPVOID)poh->DataDirectory[dwIMAGE_DIRECTORY].VirtualAddress;
|
||||
|
||||
/* Locate section containing image directory. */
|
||||
while (i++<nSections)
|
||||
{
|
||||
if (psh->VirtualAddress <= (DWORD)VAImageDir
|
||||
&& psh->VirtualAddress + psh->SizeOfRawData > (DWORD)VAImageDir)
|
||||
break;
|
||||
psh++;
|
||||
}
|
||||
|
||||
if (i > nSections)
|
||||
return NULL;
|
||||
|
||||
/* Return image import directory offset. */
|
||||
return (LPVOID)(((int)lpFile +
|
||||
(int)VAImageDir - psh->VirtualAddress) +
|
||||
(int)psh->PointerToRawData);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------- */
|
||||
|
||||
BOOL WINAPI GetSectionHdrByName (
|
||||
LPVOID lpFile,
|
||||
IMAGE_SECTION_HEADER *sh,
|
||||
char *szSection)
|
||||
{
|
||||
PIMAGE_SECTION_HEADER psh;
|
||||
int nSections = NumOfSections (lpFile);
|
||||
int i;
|
||||
|
||||
if ((psh = (PIMAGE_SECTION_HEADER)SECHDROFFSET (lpFile)) != NULL)
|
||||
{
|
||||
/* find the section by name */
|
||||
for (i=0; i<nSections; i++)
|
||||
{
|
||||
if (!strcmp (psh->Name, szSection))
|
||||
{
|
||||
/* copy data to header */
|
||||
memcpy ((LPVOID)sh, (LPVOID)psh, sizeof (IMAGE_SECTION_HEADER));
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
psh++;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------- */
|
||||
|
||||
BOOL WINAPI GetSectionHdrByAddress (
|
||||
LPVOID lpFile,
|
||||
IMAGE_SECTION_HEADER *sh,
|
||||
DWORD addr)
|
||||
{
|
||||
PIMAGE_SECTION_HEADER psh;
|
||||
int nSections = NumOfSections (lpFile);
|
||||
int i;
|
||||
|
||||
if ((psh = (PIMAGE_SECTION_HEADER)SECHDROFFSET (lpFile)) != NULL)
|
||||
{
|
||||
/* find the section by name */
|
||||
for (i=0; i<nSections; i++)
|
||||
{
|
||||
if (addr >= psh->VirtualAddress
|
||||
&& addr < psh->VirtualAddress + psh->SizeOfRawData)
|
||||
{
|
||||
/* copy data to header */
|
||||
memcpy ((LPVOID)sh, (LPVOID)psh, sizeof (IMAGE_SECTION_HEADER));
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
psh++;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------- */
|
||||
|
||||
int WINAPI GetExportFunctionNames (
|
||||
LPVOID lpFile,
|
||||
HANDLE hHeap,
|
||||
char **pszFunctions)
|
||||
{
|
||||
IMAGE_SECTION_HEADER sh;
|
||||
PIMAGE_EXPORT_DIRECTORY ped;
|
||||
int *pNames, *pCnt;
|
||||
char *pSrc, *pDest;
|
||||
int i, nCnt;
|
||||
DWORD VAImageDir;
|
||||
PIMAGE_OPTIONAL_HEADER poh;
|
||||
char *pOffset;
|
||||
|
||||
/* Get section header and pointer to data directory
|
||||
for .edata section. */
|
||||
if (NULL == (ped = (PIMAGE_EXPORT_DIRECTORY)
|
||||
ImageDirectoryOffset (lpFile, IMAGE_DIRECTORY_ENTRY_EXPORT)))
|
||||
return 0;
|
||||
|
||||
poh = (PIMAGE_OPTIONAL_HEADER)OPTHDROFFSET (lpFile);
|
||||
VAImageDir = poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
|
||||
|
||||
if (FALSE == GetSectionHdrByAddress (lpFile, &sh, VAImageDir))
|
||||
return 0;
|
||||
|
||||
pOffset = (char *)lpFile + (sh.PointerToRawData - sh.VirtualAddress);
|
||||
|
||||
pNames = (int *)(pOffset + (DWORD)ped->AddressOfNames);
|
||||
|
||||
/* Figure out how much memory to allocate for all strings. */
|
||||
nCnt = 1;
|
||||
for (i=0, pCnt = pNames; i<(int)ped->NumberOfNames; i++)
|
||||
{
|
||||
pSrc = (pOffset + *pCnt++);
|
||||
if (pSrc)
|
||||
nCnt += strlen(pSrc)+1;
|
||||
}
|
||||
|
||||
/* Allocate memory off heap for function names. */
|
||||
pDest = *pszFunctions = HeapAlloc (hHeap, HEAP_ZERO_MEMORY, nCnt);
|
||||
|
||||
/* Copy all strings to buffer. */
|
||||
for (i=0, pCnt = pNames; i<(int)ped->NumberOfNames; i++)
|
||||
{
|
||||
pSrc = (pOffset + *pCnt++);
|
||||
if (pSrc) {
|
||||
strcpy(pDest, pSrc);
|
||||
pDest += strlen(pSrc)+1;
|
||||
}
|
||||
}
|
||||
*pDest = 0;
|
||||
|
||||
return ped->NumberOfNames;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------- */
|
||||
/* extract the basename of a file */
|
||||
|
||||
static char *file_basename(const char *name)
|
||||
{
|
||||
const char *p = strchr(name, 0);
|
||||
while (p > name
|
||||
&& p[-1] != '/'
|
||||
&& p[-1] != '\\'
|
||||
)
|
||||
--p;
|
||||
return (char*)p;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------- */
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
HANDLE hHeap;
|
||||
HANDLE hFile;
|
||||
HANDLE hMapObject;
|
||||
VOID *pMem;
|
||||
|
||||
int nCnt, ret, n;
|
||||
char *pNames;
|
||||
char infile[MAX_PATH];
|
||||
char buffer[MAX_PATH];
|
||||
char outfile[MAX_PATH];
|
||||
FILE *op;
|
||||
char *p;
|
||||
|
||||
hHeap = NULL;
|
||||
hFile = NULL;
|
||||
hMapObject = NULL;
|
||||
pMem = NULL;
|
||||
infile[0] = 0;
|
||||
outfile[0] = 0;
|
||||
ret = 1;
|
||||
|
||||
for (n = 1; n < argc; ++n)
|
||||
{
|
||||
const char *a = argv[n];
|
||||
if ('-' == a[0]) {
|
||||
if (0 == strcmp(a, "-o")) {
|
||||
if (++n == argc)
|
||||
goto usage;
|
||||
strcpy(outfile, argv[n]);
|
||||
}
|
||||
else
|
||||
goto usage;
|
||||
|
||||
} else if (0 == infile[0])
|
||||
strcpy(infile, a);
|
||||
else
|
||||
goto usage;
|
||||
}
|
||||
|
||||
if (0 == infile[0])
|
||||
{
|
||||
usage:
|
||||
fprintf(stderr,
|
||||
"tiny_impdef creates an export definition file (.def) from a dll\n"
|
||||
"Usage: tiny_impdef library.dll [-o outputfile]\n"
|
||||
);
|
||||
goto the_end;
|
||||
}
|
||||
|
||||
if (SearchPath(NULL, infile, ".dll", sizeof buffer, buffer, NULL))
|
||||
strcpy(infile, buffer);
|
||||
|
||||
if (0 == outfile[0])
|
||||
{
|
||||
char *p;
|
||||
strcpy(outfile, file_basename(infile));
|
||||
p = strrchr(outfile, '.');
|
||||
if (NULL == p)
|
||||
p = strchr(outfile, 0);
|
||||
strcpy(p, ".def");
|
||||
}
|
||||
|
||||
hFile = CreateFile(
|
||||
infile,
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
0,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
fprintf(stderr, "No such file: %s\n", infile);
|
||||
goto the_end;
|
||||
}
|
||||
|
||||
|
||||
hMapObject = CreateFileMapping(
|
||||
hFile,
|
||||
NULL,
|
||||
PAGE_READONLY,
|
||||
0, 0,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (NULL == hMapObject)
|
||||
{
|
||||
fprintf(stderr, "Could not create file mapping: %s\n", infile);
|
||||
goto the_end;
|
||||
}
|
||||
|
||||
pMem = MapViewOfFile(
|
||||
hMapObject, // object to map view of
|
||||
FILE_MAP_READ, // read access
|
||||
0, // high offset: map from
|
||||
0, // low offset: beginning
|
||||
0); // default: map entire file
|
||||
|
||||
if (NULL == pMem)
|
||||
{
|
||||
fprintf(stderr, "Could not map view of file: %s\n", infile);
|
||||
goto the_end;
|
||||
}
|
||||
|
||||
if (0 != strncmp(NTSIGNATURE(pMem), "PE", 2))
|
||||
{
|
||||
fprintf(stderr, "Not a PE file: %s\n", infile);
|
||||
goto the_end;
|
||||
}
|
||||
|
||||
|
||||
hHeap = GetProcessHeap();
|
||||
nCnt = GetExportFunctionNames(pMem, hHeap, &pNames);
|
||||
if (0 == nCnt) {
|
||||
fprintf(stderr, "Could not get exported function names: %s\n", infile);
|
||||
goto the_end;
|
||||
}
|
||||
|
||||
printf("--> %s\n", infile);
|
||||
|
||||
op = fopen(outfile, "w");
|
||||
if (NULL == op)
|
||||
{
|
||||
fprintf(stderr, "Could not create file: %s\n", outfile);
|
||||
goto the_end;
|
||||
}
|
||||
|
||||
printf("<-- %s\n", outfile);
|
||||
|
||||
fprintf(op, "LIBRARY %s\n\nEXPORTS\n", file_basename(infile));
|
||||
for (n = 0, p = pNames; n < nCnt; ++n)
|
||||
{
|
||||
fprintf(op, "%s\n", p);
|
||||
while (*p++);
|
||||
}
|
||||
ret = 0;
|
||||
|
||||
the_end:
|
||||
if (pMem)
|
||||
UnmapViewOfFile(pMem);
|
||||
|
||||
if (hMapObject)
|
||||
CloseHandle(hMapObject);
|
||||
|
||||
if (hFile)
|
||||
CloseHandle(hFile);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------- */
|
||||
319
win32/tools/tiny_libmaker.c
Normal file
319
win32/tools/tiny_libmaker.c
Normal file
@@ -0,0 +1,319 @@
|
||||
/*
|
||||
* 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 program is free software but WITHOUT ANY WARRANTY
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* #include "ar-elf.h" */
|
||||
/* "ar-elf.h" */
|
||||
/* ELF_v1.2.pdf */
|
||||
typedef unsigned short int Elf32_Half;
|
||||
typedef int Elf32_Sword;
|
||||
typedef unsigned int Elf32_Word;
|
||||
typedef unsigned int Elf32_Addr;
|
||||
typedef unsigned int Elf32_Off;
|
||||
typedef unsigned short int Elf32_Section;
|
||||
|
||||
#define EI_NIDENT 16
|
||||
typedef struct {
|
||||
unsigned char e_ident[EI_NIDENT];
|
||||
Elf32_Half e_type;
|
||||
Elf32_Half e_machine;
|
||||
Elf32_Word e_version;
|
||||
Elf32_Addr e_entry;
|
||||
Elf32_Off e_phoff;
|
||||
Elf32_Off e_shoff;
|
||||
Elf32_Word e_flags;
|
||||
Elf32_Half e_ehsize;
|
||||
Elf32_Half e_phentsize;
|
||||
Elf32_Half e_phnum;
|
||||
Elf32_Half e_shentsize;
|
||||
Elf32_Half e_shnum;
|
||||
Elf32_Half e_shstrndx;
|
||||
} Elf32_Ehdr;
|
||||
|
||||
typedef struct {
|
||||
Elf32_Word sh_name;
|
||||
Elf32_Word sh_type;
|
||||
Elf32_Word sh_flags;
|
||||
Elf32_Addr sh_addr;
|
||||
Elf32_Off sh_offset;
|
||||
Elf32_Word sh_size;
|
||||
Elf32_Word sh_link;
|
||||
Elf32_Word sh_info;
|
||||
Elf32_Word sh_addralign;
|
||||
Elf32_Word sh_entsize;
|
||||
} Elf32_Shdr;
|
||||
|
||||
#define SHT_NULL 0
|
||||
#define SHT_PROGBITS 1
|
||||
#define SHT_SYMTAB 2
|
||||
#define SHT_STRTAB 3
|
||||
#define SHT_RELA 4
|
||||
#define SHT_HASH 5
|
||||
#define SHT_DYNAMIC 6
|
||||
#define SHT_NOTE 7
|
||||
#define SHT_NOBITS 8
|
||||
#define SHT_REL 9
|
||||
#define SHT_SHLIB 10
|
||||
#define SHT_DYNSYM 11
|
||||
|
||||
typedef struct {
|
||||
Elf32_Word st_name;
|
||||
Elf32_Addr st_value;
|
||||
Elf32_Word st_size;
|
||||
unsigned char st_info;
|
||||
unsigned char st_other;
|
||||
Elf32_Half st_shndx;
|
||||
} Elf32_Sym;
|
||||
|
||||
#define ELF32_ST_BIND(i) ((i)>>4)
|
||||
#define ELF32_ST_TYPE(i) ((i)&0xf)
|
||||
#define ELF32_ST_INFO(b,t) (((b)<<4)+((t)&0xf))
|
||||
|
||||
#define STT_NOTYPE 0
|
||||
#define STT_OBJECT 1
|
||||
#define STT_FUNC 2
|
||||
#define STT_SECTION 3
|
||||
#define STT_FILE 4
|
||||
#define STT_LOPROC 13
|
||||
#define STT_HIPROC 15
|
||||
|
||||
#define STB_LOCAL 0
|
||||
#define STB_GLOBAL 1
|
||||
#define STB_WEAK 2
|
||||
#define STB_LOPROC 13
|
||||
#define STB_HIPROC 15
|
||||
|
||||
typedef struct {
|
||||
Elf32_Word p_type;
|
||||
Elf32_Off p_offset;
|
||||
Elf32_Addr p_vaddr;
|
||||
Elf32_Addr p_paddr;
|
||||
Elf32_Word p_filesz;
|
||||
Elf32_Word p_memsz;
|
||||
Elf32_Word p_flags;
|
||||
Elf32_Word p_align;
|
||||
} Elf32_Phdr;
|
||||
/* "ar-elf.h" ends */
|
||||
|
||||
#define ARMAG "!<arch>\n"
|
||||
#define ARFMAG "`\n"
|
||||
|
||||
typedef struct ArHdr {
|
||||
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;
|
||||
|
||||
|
||||
unsigned long le2belong(unsigned long ul) {
|
||||
return ((ul & 0xFF0000)>>8)+((ul & 0xFF000000)>>24) +
|
||||
((ul & 0xFF)<<24)+((ul & 0xFF00)<<8);
|
||||
}
|
||||
|
||||
ArHdr arhdr = {
|
||||
"/ ",
|
||||
" ",
|
||||
"0 ",
|
||||
"0 ",
|
||||
"0 ",
|
||||
" ",
|
||||
ARFMAG
|
||||
};
|
||||
|
||||
ArHdr arhdro = {
|
||||
" ",
|
||||
" ",
|
||||
"0 ",
|
||||
"0 ",
|
||||
"0 ",
|
||||
" ",
|
||||
ARFMAG
|
||||
};
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
FILE *fi, *fh, *fo;
|
||||
Elf32_Ehdr *ehdr;
|
||||
Elf32_Shdr *shdr;
|
||||
Elf32_Sym *sym;
|
||||
int i, fsize, iarg;
|
||||
char *buf, *shstr, *symtab = NULL, *strtab = NULL;
|
||||
int symtabsize = 0, strtabsize = 0;
|
||||
char *anames = NULL;
|
||||
int *afpos = NULL;
|
||||
int istrlen, strpos = 0, fpos = 0, funccnt = 0, funcmax, hofs;
|
||||
char afile[260], tfile[260], stmp[20];
|
||||
|
||||
|
||||
strcpy(afile, "ar_test.a");
|
||||
iarg = 1;
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
printf("usage: tiny_libmaker [lib] file...\n");
|
||||
return 1;
|
||||
}
|
||||
for (i=1; i<argc; i++) {
|
||||
istrlen = strlen(argv[i]);
|
||||
if (argv[i][istrlen-2] == '.') {
|
||||
if(argv[i][istrlen-1] == 'a')
|
||||
strcpy(afile, argv[i]);
|
||||
else if(argv[i][istrlen-1] == 'o') {
|
||||
iarg = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//tfile[0] = '.'; tfile[1] = '/';
|
||||
//if (tmpnam(&tfile[2])) {
|
||||
strcpy(tfile, "./XXXXXX");
|
||||
if (mktemp(tfile))
|
||||
{
|
||||
if ((fo = fopen(tfile, "wb+")) == NULL)
|
||||
{
|
||||
fprintf(stderr, "Can't open file %s \n", tfile);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
if ((fo = tmpfile()) == NULL)
|
||||
{
|
||||
fprintf(stderr, "Can't open temporary file \n");
|
||||
return 2;
|
||||
}
|
||||
*/
|
||||
if ((fh = fopen(afile, "wb")) == NULL)
|
||||
{
|
||||
fprintf(stderr, "Can't open file %s \n", afile);
|
||||
remove(tfile);
|
||||
return 2;
|
||||
}
|
||||
|
||||
funcmax = 1000;
|
||||
afpos = realloc(NULL, funcmax); // 250 func
|
||||
memcpy(&arhdro.ar_mode, "100666", 6);
|
||||
|
||||
//iarg = 1;
|
||||
while (iarg < argc)
|
||||
{
|
||||
if (!strcmp(argv[iarg], "rcs")) {
|
||||
iarg++;
|
||||
continue;
|
||||
}
|
||||
if ((fi = fopen(argv[iarg], "rb")) == NULL)
|
||||
{
|
||||
fprintf(stderr, "Can't open file %s \n", argv[iarg]);
|
||||
remove(tfile);
|
||||
return 2;
|
||||
}
|
||||
fseek(fi, 0, SEEK_END);
|
||||
fsize = ftell(fi);
|
||||
fseek(fi, 0, SEEK_SET);
|
||||
buf = malloc(fsize + 1);
|
||||
fread(buf, fsize, 1, fi);
|
||||
fclose(fi);
|
||||
|
||||
printf("%s:\n", argv[iarg]);
|
||||
// elf header
|
||||
ehdr = (Elf32_Ehdr *)buf;
|
||||
shdr = (Elf32_Shdr *) (buf + ehdr->e_shoff + ehdr->e_shstrndx * ehdr->e_shentsize);
|
||||
shstr = (char *)(buf + shdr->sh_offset);
|
||||
for (i = 0; i < ehdr->e_shnum; i++)
|
||||
{
|
||||
shdr = (Elf32_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 && symtabsize)
|
||||
{
|
||||
int nsym = symtabsize / sizeof(Elf32_Sym);
|
||||
//printf("symtab: info size shndx name\n");
|
||||
for (i = 1; i < nsym; i++)
|
||||
{
|
||||
sym = (Elf32_Sym *) (symtab + i * sizeof(Elf32_Sym));
|
||||
if (sym->st_shndx && (sym->st_info == 0x11 || sym->st_info == 0x12)) {
|
||||
//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 = realloc(anames, strpos+istrlen);
|
||||
strcpy(anames + strpos, strtab + sym->st_name);
|
||||
strpos += istrlen;
|
||||
if (funccnt >= funcmax) {
|
||||
afpos = realloc(NULL, funcmax+1000); // 250 func more
|
||||
funcmax += 1000;
|
||||
}
|
||||
afpos[++funccnt] = fpos;
|
||||
}
|
||||
}
|
||||
}
|
||||
memset(&arhdro.ar_name, ' ', sizeof(arhdr.ar_name));
|
||||
strcpy(arhdro.ar_name, argv[iarg]);
|
||||
arhdro.ar_name[strlen(argv[iarg])] = '/';
|
||||
sprintf(stmp, "%-10d", fsize);
|
||||
memcpy(&arhdro.ar_size, stmp, 10);
|
||||
fwrite(&arhdro, sizeof(arhdro), 1, fo);
|
||||
fwrite(buf, fsize, 1, fo);
|
||||
free(buf);
|
||||
iarg++;
|
||||
fpos += (fsize + sizeof(arhdro));
|
||||
}
|
||||
hofs = 8 + sizeof(arhdr) + strpos + (funccnt+1) * sizeof(int);
|
||||
if ((hofs & 1)) { // align
|
||||
hofs++;
|
||||
fpos = 1;
|
||||
} else fpos = 0;
|
||||
// write header
|
||||
fwrite("!<arch>\n", 8, 1, fh);
|
||||
sprintf(stmp, "%-10d", strpos + (funccnt+1) * sizeof(int));
|
||||
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 = malloc(fsize + 1);
|
||||
fread(buf, fsize, 1, fo);
|
||||
fclose(fo);
|
||||
fwrite(buf, fsize, 1, fh);
|
||||
fclose(fh);
|
||||
free(buf);
|
||||
if (anames)
|
||||
free(anames);
|
||||
if (afpos)
|
||||
free(afpos);
|
||||
remove(tfile);
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user