176 Commits

Author SHA1 Message Date
grischka
110a4edc15 drop alloca #define
(Because GNU's alloca.h unconditionally #undef's alloca)

Also, remove gcc specific sections in headers. and
instead change tests such that gcc does not use them.
2009-05-16 22:30:13 +02:00
grischka
68310299b6 ulibc: #define TCC_UCLIBC and load elf_interp 2009-05-16 22:29:40 +02:00
grischka
bf8d8f5f3e update Changelog, bump version: 0.9.25 2009-05-11 19:01:26 +02:00
grischka
aed6a7cb60 fix "cached include" optimization
comparing the filenames as in the #include statement can be
ambiguous if including files are in different directories.

Now caches and checks the really opened filename instead.
2009-05-11 18:55:16 +02:00
Daniel Glöckner
530b77e365 ARM: fix big immediate offset construction
The loop constructs to iterate over the non-overlapping, even
positions of two or three bytes in a word were broken.

This patch fixes the loops. It has been verified to generate the
72 combinations for two and the 80 combinations for three bytes.
2009-05-11 18:54:14 +02:00
grischka
ca4b4a52ad fix build with msvc 2009-05-11 18:53:52 +02:00
grischka
03c787d6ce fix unused/uninitalized warnings 2009-05-11 18:46:39 +02:00
grischka
40f5ce002e fix warnings with tcc_add/get_symbol 2009-05-11 18:46:25 +02:00
grischka
67aebdd5b7 enable making tcc using libtcc 2009-05-11 18:46:02 +02:00
grischka
0a35f9d66e move static prototypes to libtcc.c 2009-05-11 18:45:56 +02:00
grischka
f9181416f6 move some global variables into TCCState 2009-05-11 18:45:44 +02:00
grischka
5c6509578e make tcc from tcc.c and libtcc from libtcc.c 2009-05-05 20:41:17 +02:00
grischka
b8f6e1ae30 move minor things from libtcc.c to other files 2009-05-05 20:30:39 +02:00
grischka
92204e8818 move global variables to libtcc.c 2009-05-05 20:30:13 +02:00
grischka
9dc9cbf319 move libtcc interface and helper functions to libtcc.c 2009-05-05 20:18:53 +02:00
grischka
0d1ed74102 move parser/generator to tccgen.c 2009-05-05 20:18:10 +02:00
grischka
805990b94e move preprocessor to tccpp.c 2009-05-05 20:17:49 +02:00
grischka
ae37bd5abc move declarations to tcc.h 2009-05-05 20:17:26 +02:00
grischka
a93bcdffae new files: tcc.h libtcc.c tccpp.c tccgen.c 2009-05-05 20:17:11 +02:00
grischka
15626621fb cleanup makefiles 2009-04-19 21:24:32 +02:00
grischka
e9e89ad699 enable backtrace only when it's supported 2009-04-18 18:39:27 +02:00
Shinichiro Hamaji
859da934e0 Return value of exit should be void. 2009-04-18 23:55:51 +09:00
Shinichiro Hamaji
48ae0c0468 Fixes for tests/Makefile.
- On x86-64, we need $(TARGET) in RUN_TCC.
- s/RuN_TCC/RUN_TCC/
2009-04-18 23:53:25 +09:00
grischka
5829791ffa fix makefiles etc for subdirs 2009-04-18 15:08:03 +02:00
grischka
ea5e81bd6a new subdirs: include, lib, tests 2009-04-18 15:08:03 +02:00
grischka
e8a52a8249 win32: readme.txt->tcc-win32.txt, update tcc-doc 2009-04-18 15:08:03 +02:00
grischka
eca1fbaf92 mute strange difference in tcctest 2009-04-18 15:08:03 +02:00
grischka
b56f956247 libtcc: add support to be build as DLL 2009-04-18 15:08:03 +02:00
grischka
d165e87340 libtcc: new api tcc_set_lib_path 2009-04-18 15:08:03 +02:00
grischka
73ba078d2f tcc_relocate: return error and remove unused code 2009-04-18 15:08:03 +02:00
Shinichiro Hamaji
d36fea34e3 Call relocate_sym() before we return the offset, so user doesn't need to check the return value twice. 2009-04-18 15:08:03 +02:00
grischka
dd5630ff95 tcc -E: fix pasting empty tokens
/* test case */
#define t(x,y,z) x ## y ## z
int j[] = { t(1,2,3), t(,4,5), t(6,,7), t(8,9,),
        t(10,,), t(,11,), t(,,12), t(,,) };

tcc -E: xpected result:
int j[] = { 123, 45, 67, 89,
 10, 11, 12, };
2009-04-18 15:08:02 +02:00
grischka
0f0ed4a8bf tcc -E: preserve spaces, alternative solution
/* test case */
#define STR(x) #x
#define MKSTR(x) STR(x)
MKSTR(-A-)
MKSTR(+ B +)

tcc -E: expected result:
"-A-"
"+ B +"
2009-04-18 15:08:02 +02:00
grischka
90697c4c56 CONFIG_TCC_STATIC: add dummy for dlclose 2009-04-18 15:08:02 +02:00
grischka
d62301b050 avoid warning uninitialized 2009-04-18 15:08:02 +02:00
Shinichiro Hamaji
9a7173bf69 x86-64: Fix tcc -run. We need extra memory for PLT and GOT.
Size of the extra buffer is too large for now.
2009-04-18 15:08:02 +02:00
grischka
e6ba81b012 get rid of 8 bytes memory leak 2009-04-18 15:08:02 +02:00
grischka
b1697be691 change tcc_add/get_symbol to use void* 2009-04-18 15:08:02 +02:00
grischka
795f67428e alternative int tcc_relocate(TCCState *s1, void *ptr); 2009-04-18 15:08:02 +02:00
grischka
9a8b2912ed TOK_builtin_malloc: alternative solution 2009-04-18 15:08:02 +02:00
Shinichiro Hamaji
742cf05875 x86-64: Define make variable TARGET so that test2 and test3 use correct flag. 2009-04-18 15:08:02 +02:00
Shinichiro Hamaji
85d016b507 x86-64: Remove code for debug print.
Now, we concat buffers before relocation. So this only happens when users try creating >2GB binary.
2009-04-18 15:08:02 +02:00
Shinichiro Hamaji
39a4b859d4 x86-64: Fix cast from integers to pointers.
Now,

./tcc -run -DTCC_TARGET_X86_64 tcc.c -run tcctest.c

works!
2009-04-18 15:08:02 +02:00
Shinichiro Hamaji
51a7f163ad Work around for the issue TCC doesn't handle -2147483648 properly.
TCC produces code which is incompatible with GCC for the following code:

    printf("%lld\n", (long long)-2147483648);
    printf("%lld\n", (long long)-2147483649);

For now, just avoid using the corner value.
2009-04-18 15:08:01 +02:00
Shinichiro Hamaji
83fd36333a Fixes for issues I've just found/introduced to x86 TCC.
- Cast from pointer to long long makes TCC output an error. Use cast to int before we apply shift operation for a pointer value.
- Removed test cases for casts from pointer to char/short because they produce warning.
2009-04-18 15:08:01 +02:00
Shinichiro Hamaji
be43c8e0ed x86-64: Cast from 64bit pointer to long long must not generate movslq. 2009-04-18 15:08:01 +02:00
grischka
a9c78d04f2 win32: accept uppercase filename suffixes 2009-04-18 15:08:01 +02:00
Shinichiro Hamaji
b879ffa193 x86-64: There can be valid addresses which is greater than 0xc0000000. 2009-04-18 15:08:01 +02:00
Shinichiro Hamaji
de3f0a46fe Fix for x86-64: The first and second arguments of memcpy must be pointers. 2009-04-18 15:08:01 +02:00
Shinichiro Hamaji
2e9b57b6d0 Fix silly typos in the previous change. 2009-04-18 15:08:01 +02:00
Shinichiro Hamaji
9fe28b610e x86-64: Make ABI for long double compatible with GCC.
- Now we use x87's stack top the long double return values.
- Add rc_fret and reg_fret, wrapper functions for RC_FRET and REG_FRET.
- Add a test case to check if strto* works OK.
2009-04-18 15:08:01 +02:00
Shinichiro Hamaji
0e239e2ba5 Improve the test coverage: !val for float/double/long long f. 2009-04-18 15:08:01 +02:00
Shinichiro Hamaji
fcf2e5981f x86-64: Combine buffers of sections before we call tcc_run().
- Now we can run tcc -run tcc.c successfully, though there are some bugs.
- Remove jmp_table and got_table and use text_section for got and plt entries.
- Combine buffers in tcc_relocate().
- Use R_X86_64_64 instead of R_X86_64_32 for R_DATA_32 (now the name R_DATA_32 is inappropriate...).
2009-04-18 15:08:01 +02:00
Shinichiro Hamaji
830b7533c9 Generate PIC code so that we can create shared objects properly.
- Add got_table in TCCState. This approach is naive and the distance between executable code and GOT can be longer than 32bit.
- Handle R_X86_64_GOTPCREL properly. We use got_table for TCC_OUTPUT_MEMORY case for now.
- Fix load() and store() so that they access global variables via GOT.
2009-04-18 15:08:01 +02:00
grischka
6c10429aa5 check for absolute include paths
Suggested by Sandor Zsolt <narkoskatona@yahoo.com>
2009-04-18 15:07:28 +02:00
grischka
29c8e1545a get rid of "free_section problem" with private sections 2009-04-18 15:07:28 +02:00
grischka
c80f81c199 tiny_libmaker: fix function array overflow 2009-04-18 15:07:28 +02:00
grischka
5818945ef6 accept "restrict" in array-decl (STDC 199901) 2009-04-18 15:07:27 +02:00
grischka
0e015988cc i386: apply "align=8 for doubles ..." for PE only 2009-04-18 15:07:27 +02:00
Shinichiro Hamaji
97072b3cd7 x86-64: Now TCC can create healthy shared objects from object files generated by GCC
- Handle R_X86_64_GOTPCREL.
- Output R_X86_64_RELATIVE reloc generated from R_X86_64_64.
2009-04-18 15:07:10 +02:00
Shinichiro Hamaji
754b0beb7d x86-64 bug fix: Fix stab generation for x86-64.
The size of a stab entry is 12 bytes even in 64bit environments. We must use int instead of long to keep the size of stab entries.
2009-04-18 15:07:09 +02:00
Shinichiro Hamaji
e6db5f5fb6 x86-64 bug fix: Use stack with alignment just like 32bit environments. 2009-04-18 15:07:09 +02:00
Shinichiro Hamaji
06fa15fb99 x86-64: Save RDX and RCX before we use them as function parameters.
When the function call is indirect, these registers may be broken to load a function pointer.
2009-04-18 15:07:09 +02:00
Shinichiro Hamaji
ebb874e216 Remove multiple definition error caused by combination of x86-64 and va_list.
We need malloc and free to implement va_start and va_end.
Since malloc and free may be replaced by #define, we add __builtin_malloc and __builtin_free.
2009-04-18 15:07:09 +02:00
Shinichiro Hamaji
6512d9e2ea Add check for invalid numbers.
If there are some characters after TCC parses a number, it is an error.

This bug was reported on list:

http://www.mail-archive.com/tinycc-devel@nongnu.org/msg02014.html
2009-04-18 15:07:09 +02:00
Shinichiro Hamaji
af6cbc48d1 Fix overrun in decl_initializer_alloc.
This bug was reported on

http://lists.gnu.org/archive/html/tinycc-devel/2009-03/msg00035.html

This happens because parser of array initializer doesn't stop to read until semi-colon or comma.
2009-04-18 15:07:09 +02:00
Shinichiro Hamaji
040ef000e4 Better DLL support on x86-64.
- Add a macro TCC_OUTPUT_DLL_WITH_PLT.
-- Now, the DLL with PLT support works only on x86-64, but we may be able to support it on all architectures eventually.
- Define TCC_OUTPUT_DLL_WITH_PLT when target architecture is x86-64.
- Current status (x86-64):
-- Main program should be able to call functions in shared objects.
-- Main program should be able to use global variables in shared objects.
-- Shared objects should be able to call functions in main  program.
-- Shared objects can NOT use global variables in main program.
- To fix the last issue, we may need to add support of -fPIC option in our code generator.
2009-04-18 15:07:09 +02:00
Shinichiro Hamaji
fe8f230ab6 First naive DLL support on x86-64.
This logic depends on x86_64-gen.c and doesn't work with objects compiled by GCC.
2009-04-18 15:07:09 +02:00
Shinichiro Hamaji
b8a32d8d40 Generate PIC for addresses of symbols. 2009-04-18 15:07:09 +02:00
Shinichiro Hamaji
7db1e69df2 Suppress noisy pointer signed-ness warnings on x86-64. 2009-04-18 15:07:09 +02:00
Shinichiro Hamaji
006c907da7 Code cleaning: utilize vpushll(). 2009-04-18 15:07:09 +02:00
Shinichiro Hamaji
4f056031f4 Support long long bitfields for all architectures.
- Modified gv() and vstore(), added vpushll().
- Added a test case for long long bitfields.
- Tested on x86 and x86-64.
2009-04-18 15:07:09 +02:00
Shinichiro Hamaji
62e73da612 A uint64 bug fix on x86-64
64bit unsigned literal was handled as 32bit integer.
Added a unittest to catch this.
2009-04-18 15:07:08 +02:00
Shinichiro Hamaji
ae607280c5 Allow long long as a type of bitfields on x86-64. 2009-04-18 15:07:08 +02:00
grischka
4a8c2229ce win32: allow user segments as writable & executable 2009-04-18 15:07:08 +02:00
grischka
3116744bdd i386: align=8 for double and long long 2009-04-18 15:07:08 +02:00
grischka
b41fc95566 win32: fix for VC8Express compiler 2009-04-18 15:07:08 +02:00
Kirill Smelkov
00f0932760 tcc -E: preserve spaces (partial solution)
Recently I needed to trim storage space on an embedded distro which has
X.

X depend on cpp which is ~8MB in size as shipped in Debian, so the idea
was to remove cpp and use `tcc -E` instead where appropriate.

I've done this with the following 'hack' put inplace of /usr/bin/cpp :

    #!/bin/sh -e
    TCC=/home/kirr/local/tcc/bin/tcc
    last="${!#}"

    # hack to distinguish between '... -D...'  and '... file'
    if test -r "$last"; then
        exec $TCC -E "$@"
    else
        exec $TCC -E "$@" -
    fi

But the problem turned out to be in `tcc -E` inability to preserve
spaces between tokens. So e.g. the following ~/.Xresources

    XTerm*VT100*foreground: black
    ...

got translated to

    XTerm * VT100 * foreground : black

which is bad, bacause now X don't understand it.

Below is a newbie "fix" for the problem.

It still does not preserve spaces on macro expansion, but since the fix
cures original problem, I think it is at least one step forward.

Signed-off-by: Kirill Smelkov <kirr@landau.phys.spbu.ru>
2009-04-18 15:07:08 +02:00
Kirill Smelkov
6213d4b4b6 string_test: we should always use 'unsigned int' for b
As recently shown in fb0ac2 (s/int/unsigned/ since GCC 4.3.2 produces
code which doesn't stop)

comparing (signed) int variable to 0x80000000 is not idea for x86_64.

This is not a good idea for x86_32 either, because GCC 4.3.2 (the one in
Debian Lenny) rightly assumes that a signed int could be never
0x80000000, and thus removes the check from

    while (b != 0x80000000) {
        ...

completely.

If we want this check, we need b to be always 'unsigned'

Signed-off-by: Kirill Smelkov <kirr@landau.phys.spbu.ru>
2009-04-18 15:07:08 +02:00
Alexander Egorenkov
5a044b67bb type_size function returned incorrect size
of multi dimensional arrays if dimension is divisable by 2
2009-04-18 15:07:08 +02:00
grischka
64147b346b fix constant optimization for unsigneds 2009-04-18 15:07:08 +02:00
grischka
7c3f19c079 fix data overflow with init_putv
The simplest code to reproduce this bug seems to be
    int a[][] = {{1,1,1,1,1,1,1}};
2008-12-02 02:36:27 +01:00
Shinichiro Hamaji
aa8d22e38e Add several test cases. 2008-12-02 02:32:52 +01:00
Shinichiro Hamaji
0a9873aa22 Add support of x86-64.
Most change was done in #ifdef TCC_TARGET_X86_64. So, nothing should be broken by this change.

Summary of current status of x86-64 support:

- produces x86-64 object files and executables.
- the x86-64 code generator is based on x86's.
-- for long long integers, we use 64bit registers instead of tcc's generic implementation.
-- for float or double, we use SSE. SSE registers are not utilized well (we only use xmm0 and xmm1).
-- for long double, we use x87 FPU.
- passes make test.
- passes ./libtcc_test.
- can compile tcc.c. The compiled tcc can compile tcc.c, too. (there should be some bugs since the binary size of tcc2 and tcc3 is differ where tcc tcc.c -o tcc2 and tcc2 tcc.c -o tcc3)
- can compile links browser. It seems working.
- not tested well. I tested this work only on my linux box with few programs.
- calling convention of long-double-integer or struct is not exactly the same as GCC's x86-64 ABI.
- implementation of tcc -run is naive (tcc -run tcctest.c works, but tcc -run tcc.c doesn't work). Relocating 64bit addresses seems to be not as simple as 32bit environments.
- shared object support isn't unimplemented
- no bounds checker support
- some builtin functions such as __divdi3 aren't supported
2008-12-02 02:30:47 +01:00
Shinichiro Hamaji
fb0ac27691 s/int/unsigned/ since GCC 4.3.2 produces code which doesn't stop. 2008-12-02 02:26:42 +01:00
Shinichiro Hamaji
1e776b29d3 Suport LDOUBLE_SIZE == 16 environment. 2008-12-02 02:26:40 +01:00
Shinichiro Hamaji
ba8c95a98d silly bug fix: s/#ifdef PTR_SIZE == 4/#if PTR_SIZE == 4/ 2008-12-02 02:26:37 +01:00
Shinichiro Hamaji
27d23342ea Make tccelf.c 64bit ready.
- Use REL_SECTION_FMT instead of ".rel%s".
- Use PTR_SIZE instead of sizeof(int) for GOT entries.
- Use sizeof(ElfW(Dyn)) instead of magic number 8.
- Use TCC_ELFCLASS instead of ELFCLASS32.
2008-12-02 02:26:34 +01:00
Shinichiro Hamaji
c92daa02e4 One more s/int/long/ 2008-12-02 02:26:11 +01:00
Shinichiro Hamaji
ce8d71edbc Use int*2 instead of long*2 to hold double value.
I believe sizeof(double) is sizeof(int)*2 in most environments. On the other hand, sizeof(long) is equal to sizeof(double) in x86-64.
2008-12-02 02:26:07 +01:00
Shinichiro Hamaji
2355fc7686 Use long instead of int to hold pointer values. 2008-12-02 02:26:03 +01:00
Shinichiro Hamaji
d6072d3703 Add __builtin_frame_address(0)
Adding the GCC extension __builtin_frame_address(). We support only zero as the argument for now.
With this functionality, we can implement GCC compatible stdarg by macros in x86-64.
2008-12-02 02:25:59 +01:00
Shinichiro Hamaji
73a84cefda Imported several macros required by x86-64 2008-12-02 02:25:54 +01:00
Shinichiro Hamaji
7dd792ef51 Introduce ElfW macro and ELFW to encapsulate the difference between Elf32_* and Elf64_*. Also, introduce ElfW_Rel and SHT_RELX for difference between REL and RELA. 2008-12-02 02:25:45 +01:00
Daniel Glöckner
76b02c2a03 Futher changes to casts
nocode_wanted can't be used to enforce constant expressions, as it is
set f.ex. by __builtin_constant_p.

A null pointer is unequal to a pointer to any object or function.
Assuming symbols always point to memory, a symbol+constant cast to bool
is always true.
2008-11-30 07:21:49 +01:00
Daniel Glöckner
5fd6f7bd44 Fix get_tok_str wrt wide characters
Fixes both, character constants and string literals.
2008-11-30 07:21:46 +01:00
Daniel Glöckner
deb410710c Rewrote '?' for constants
The condition is now cast to _Bool and it now works with return
types bigger than 32 bit.
2008-11-30 07:21:42 +01:00
Daniel Glöckner
1b599ea7f8 Cast parameter of '!' to _Bool 2008-11-30 07:21:35 +01:00
Daniel Glöckner
2d9b5e0bb8 Rewrote casts
Casting of constants was done only inside functions.
I restructured the code and used intermediate types (long double/long long)
for most conversions to have less ifs.

Please review.
There are lots of cases to take care of and lots of mistakes to make.
2008-11-30 07:21:30 +01:00
grischka
83466c6151 line-numbers output for TCC -E 2008-11-30 07:21:01 +01:00
grischka
78f288bc87 win32/build-tcc.bat: define CONFIG_SYSROOT 2008-11-30 03:16:43 +01:00
grischka
7bebf1f59a was hash, not link 2008-09-15 02:07:55 +02:00
grischka
7f51aa13e7 update changelog 2008-09-15 00:12:10 +02:00
Daniel Glöckner
a80acab4fc Display error on statement expressions with complex return type
The return type of a statement expression (a GCC extention) may
involve elements on the symbol stack that have been put there by
the expression. These will be freed at the end of the expression
so that the calling block can not use them.

Contrary to the comment (written in 2003), this bug no longer shows
up in Valgrind, as freed symbols are now put onto a stack for later
reuse.
2008-09-12 22:23:02 +02:00
Daniel Glöckner
3783b33508 Fix bitfields with non-int types and in unions
The ISO C draft allow only signed/unsigned int and _Bool as base type
for bitfields. TinyCC ever since allowed a wider range of types, but
there were many bugs that shifted values when they shouldn't, etc..
The patch introduces a restriction to the layout of bitfields with
mixed types that makes it incompatible with GCC. In

struct {
  typeA x:1;
  typeB y:1;
};

y is combined with x in the same byte iff typeA is typeB (neglecting
signedness). This is done to avoid alignment issues and exceeding the
width of typeA.
2008-09-12 22:23:01 +02:00
Daniel Glöckner
43a34d354a Force null pointer exception for code outside of a function
TinyCC sometimes has problems to evaluate constant expressions at
compile time. This leads to code being generated outside of functions.
Without this patch some of these bugs are not caught, because
cur_text_section still points to the section of the last function.
Before the first function cur_text_section is uninitialized.
Setting cur_text_section to a null pointer should make TinyCC die in
all cases.
2008-09-12 22:23:00 +02:00
Daniel Glöckner
5a92536cea Optimize arithmetic with pointer to value on stack + constant 2008-09-12 22:23:00 +02:00
Daniel Glöckner
e263ee3cbf Fix gv for long longs
long long a();
long long b() {
  return a();
}

At the end of b there will be some useless register shuffling.
This is because return wants to have the result of a in REG_IRET.
gv checks if this is the case for BOTH registers of the long long.
After this test it uses REG_LRET for the second register if the
first is supposed to be REG_IRET. In other cases it uses RC_INT.

The patch compares the second register against the class it will
have in the end instead of the register class the first register
will have.

At this point I would like to remind those who pick up the patches
that there are two other mails by me with uncommitted fixes:
http://lists.gnu.org/archive/html/tinycc-devel/2003-10/msg00044.html
http://lists.gnu.org/archive/html/tinycc-devel/2008-08/msg00007.html

  Daniel
2008-09-12 22:22:59 +02:00
Daniel Glöckner
15e0dc08a6 Allow to use libgcc instead of libtcc1
This patch adds a switch --with-libgcc to configure.
When passed it prevents libtcc1.a from being built and links to
/lib/libgcc_s.so.1 instead of PREFIX/lib/tcc/libtcc1.a.

It will work on ARM when using libgcc from GCC >= 4.2.0.
Prior versions don't have the __floatun[sd]i[sdx]f functions.

It won't work on i386 because of two missing symbols emitted when
floats are cast to integers, but users can provide those symbols
(global short constants) in their code if needed.

  Daniel
2008-09-12 22:22:58 +02:00
Daniel Glöckner
256f6e6200 A prefix for default library/include search paths
This patch is useful for cross compilers. Without this patch tcc
tries to use the host's libraries, crt*.o and include files.
The patch prepends a string to all default paths. The string can
be passed to configure with --sysroot=string.

  Daniel
2008-09-12 22:22:58 +02:00
Daniel Glöckner
e8039673ad ARM related Makefile changes
- Builds all four possible ARM targets when cross compiling

- Adds some auto detection to select the target for native ARM builds

The auto detection will select EABI if it finds /lib/ld-linux.so.3.
It will select VFP floating point support when /proc/cpuinfo lists
a VFP or iWMMXt coprocessor. Intel Wireless MMX does not imply VFP,
but it conflicts with FPA, so VFP is the only choice (apart from
yet unsupported soft-float).

  Daniel
2008-09-12 22:22:57 +02:00
Daniel Glöckner
12265da6cd Runtime lib functions
Yesterday I felt the urge to change a few things in TinyCC.
This is the first and biggest change of all of them.

- use __aeabi_*divmod functions in ARM EABI to make binaries depend
  solely on standardized library functions

- refactor ARM floating point <-> integer conversion a bit

- rename long long->float and shift library functions to correspond to
  the names used by GCC

- compile more tokens conditionally to reduce the size of TinyCC

The intention is primarily to allow users of the ARM target to use
libgcc (which is usually available as a shared library) instead of
libtcc1 (which can't be compiled for ARM due to lack of an inline
assembler).

Changing the EABI target to use the divmod functions in theory allows
to use it without libtcc1 on any (not necessarily GCC based) ARM EABI
system.

  Daniel
2008-09-12 22:22:36 +02:00
Daniel Glöckner
2c657f6608 Set VT_LVAL_xxx flags for function arguments in gfunc_prolog (Daniel Glöckner) 2008-09-12 02:36:32 +02:00
Adam Sampson
8f7e3f325d Patch for DESTDIR installation (Adam Sampson) 2008-09-12 02:36:26 +02:00
grischka
2c6cd08bcc fix isidnum_table for CH_EOF (-1) 2008-09-12 02:36:05 +02:00
grischka
1300cec38c free_section bugfix 2008-09-12 02:36:01 +02:00
grischka
f9bf48d643 release loaded dlls cleanly (Sam K) 2008-05-05 22:40:49 +00:00
grischka
96bd8f2b25 enable pe-output from libtcc (Shmuel Zeigerman) 2008-05-05 22:39:43 +00:00
grischka
f2698687fb fix options in C scripts after -run 2008-04-27 18:50:35 +00:00
grischka
5247bbc2f0 fix stabstr with linked objects 2008-04-27 18:49:31 +00:00
grischka
0d598aca08 fix bogus relocations with TCC_OUTPUT_DLL 2008-04-27 18:48:19 +00:00
grischka
23594b6980 enable multiple states and fix minor memory leaks 2008-04-27 18:47:35 +00:00
grischka
f22e961f80 update manual, changelog 2008-03-31 19:50:58 +00:00
grischka
a327c7a552 added verbosity levels (-vv -vvv) 2008-03-31 19:49:14 +00:00
grischka
4d9aaacc85 Accept standard input as an inputstream (Hanzac Chen) 2008-03-31 18:42:56 +00:00
grischka
cd24bd05b4 get rid of a warning and fix .bat 2008-03-25 21:05:48 +00:00
grischka
9bcc0b970b Add -soname linker option (Marc Andre Tanner) 2008-03-25 21:04:47 +00:00
grischka
88b3cb570e Comply to c89 compilers other than gcc (Hanzac Chen) 2008-03-25 20:58:37 +00:00
grischka
6ed868c51c Enable -B option for library path on win32 2008-03-08 20:00:56 +00:00
grischka
e2c89576c7 Fix 'tcc -static' with recent glibc 2008-03-08 19:58:57 +00:00
grischka
c6537d11cb Get rid of one warning 2008-03-08 19:57:26 +00:00
grischka
2eaa1104f7 Checkin tiny_libmaker (ar replacement) by Timovj Lahde 2008-03-08 19:55:47 +00:00
grischka
265dddbecf Udated and cleaned up TODO. 2008-01-16 22:33:56 +00:00
grischka
3667408a57 Just warn about unknown directives, define __STDC_VERSION__=199901L 2008-01-16 20:16:35 +00:00
grischka
5342b32eef Switch to newer tccpe.c (includes support for resources) 2007-12-19 17:36:42 +00:00
grischka
adb1456472 Handle backslashes within #include, #error, #warning 2007-12-17 19:35:15 +00:00
grischka
6c96c41ee4 Import changesets (part 4) 428,457,460,467: defines for openbsd etc. 2007-12-16 18:24:44 +00:00
grischka
f466577673 Disable singnedness warnings with newer gcc. 2007-12-13 19:17:45 +00:00
grischka
34140dd627 Use _WIN32 for a windows hosted tcc and define it for the PE target. 2007-12-13 19:07:19 +00:00
grischka
b0d40c12da tiny_impdef.c - converted to LF line-endings (and slight cleanup) 2007-12-09 18:55:18 +00:00
grischka
f99d3de221 Import 409,410: ARM EABI by Daniel Glckner 2007-12-04 20:38:09 +00:00
grischka
2de1b2d14c Some in-between fixes (See Changelog for details). 2007-11-25 22:14:35 +00:00
grischka
2bcb964694 Fixed:
- Hanging tcc -E
- Crashes witn global 'int g_i = 1LL;'
- include & lib search paths on win32
Added quick build batch file for mingw
Reverted case label optimization
(See Changelog for details).
2007-11-25 22:13:08 +00:00
grischka
3e8b9e6d10 New files: alloca86.S alloca86-bt.S 2007-11-23 00:03:03 +00:00
grischka
d778bde7f9 Import more changesets from Rob Landley's fork (part 2) 2007-11-21 17:16:31 +00:00
grischka
54bf8c0556 Import some changesets from Rob Landley's fork (part 1) 2007-11-14 17:34:30 +00:00
grischka
2bcc187b1b Fix 'invalid relocation entry' problem on ubuntu - from Bernhard Fischer 2007-10-30 15:13:21 +00:00
bellard
d13aa5426a typos 2006-10-28 19:50:24 +00:00
bellard
7097268ac5 fixed help 2006-10-28 19:46:55 +00:00
bellard
84f4e99635 added va_copy() 2006-10-28 19:45:50 +00:00
bellard
8b0c4c6582 update 2006-10-28 14:47:46 +00:00
bellard
fb2c34f8cd fixed sign extension in some type conversions (Dave Dodge) 2006-10-28 14:47:39 +00:00
bellard
65b974e396 conversion test 2006-10-28 14:47:14 +00:00
bellard
365d0ad545 multiple typedef test 2006-10-28 14:28:33 +00:00
bellard
52b7254b9c fixed multiple typedef specifiers handling 2006-10-28 14:28:02 +00:00
bellard
0bea5c7f21 workaround for function pointers in conditional expressions (Dave Dodge) 2006-10-28 14:15:37 +00:00
bellard
24a19cc37e discard type qualifiers when comparing function parameters (Dave Dodge) 2006-10-28 14:13:28 +00:00
bellard
38d2e8b9d8 Bug fix: A long long value used as a test expression ignores the upper 32 bits at runtime (Dave Dodge) 2006-10-28 14:10:07 +00:00
bellard
3b8cd565be fixed multiple concatenation of PPNUM tokens (initial patch by Dave Dodge) 2006-10-28 14:05:19 +00:00
bellard
200b58dad8 initial implementation of -E option 2006-10-16 19:44:00 +00:00
bellard
6ca0299e5b allow (base,index) as alias to (base,index,1) 2006-02-20 21:16:10 +00:00
bellard
5487bc23c8 tcc_load_dll fix (Tao Wu) 2005-10-30 21:53:14 +00:00
bellard
aee0da0b17 avoid jumping into statement expression 2005-09-04 09:27:53 +00:00
bellard
6d66b5a971 update 2005-09-04 09:18:26 +00:00
bellard
8ba48f84fe fastcall keywords 2005-09-04 09:18:02 +00:00
bellard
62c5a5466a fixed parsing of function parameters 2005-09-03 22:51:34 +00:00
bellard
7bc5e51847 anonymous union/struct support (Filip Navara) 2005-09-03 22:33:53 +00:00
bellard
7b8e283980 support for empty input register section in asm (Filip Navara) 2005-09-03 22:23:59 +00:00
bellard
e9c64e3f47 windows style fastcall (Filip Navara) 2005-09-03 22:21:22 +00:00
bellard
81f957ae09 normalized slashes in paths (Filip Navara) 2005-09-03 22:18:51 +00:00
bellard
3ba1190eb4 segment override prefix support (Filip Navara) 2005-09-03 22:03:39 +00:00
bellard
6f8b8887b1 added support for win32 wchar_t (Filip Navara) 2005-09-03 21:54:47 +00:00
bellard
bb24eb9de4 ignore AS_NEEDED ld command 2005-09-03 21:32:06 +00:00
bellard
44738b516a fixed function type check 2005-09-03 21:07:35 +00:00
bellard
c42532c37d use CFLAGS from configure 2005-09-03 18:34:22 +00:00
bellard
b0b8ac13ce mark executable sections as executable when running in memory 2005-09-03 18:31:43 +00:00
57 changed files with 18117 additions and 13463 deletions

View File

@@ -1,3 +1,90 @@
version 0.9.25:
- first support for x86-64 target (Shinichiro Hamaji)
- support µClibc
- split tcc.c into tcc.h libtcc.c tccpp.c tccgen.c tcc.c
- improved preprocess output with linenumbers and spaces preserved
- tcc_relocate now copies code into user buffer
- fix bitfields with non-int types and in unions
- improve ARM cross-compiling (Daniel Glöckner)
- link stabstr sections from multiple objects
- better (still limited) support for multiple TCCStates
version 0.9.24:
- added verbosity levels -v, -vv, -vvv
- Accept standard input as an inputstream (Hanzac Chen)
- Support c89 compilers other than gcc (Hanzac Chen)
- -soname linker option (Marc Andre Tanner)
- Just warn about unknown directives, ignore quotes in #error/#warning
- Define __STDC_VERSION__=199901L (477)
- Switch to newer tccpe.c (includes support for resources)
- Handle backslashes within #include/#error/#warning
- Import changesets (part 4) 428,457,460,467: defines for openbsd etc.
- Use _WIN32 for a windows hosted tcc and define it for the PE target,
otherwise define __unix / __linux (Detlef Riekenberg)
- Import changesets (part 3) 409,410: ARM EABI by Daniel Glöckner
- Some in-between fixes:
TCC -E no longer hangs with macro calls involving newlines.
(next_nomacro1 now advances the read-pointer with TOK_LINEFEED)
Global cast (int g_i = 1LL;) no longer crashes tcc.
(nocode_wanted is initially 1, and only 0 for gen_function)
On win32 now tcc.exe finds 'include' & 'lib' even if itself is in 'bin'.
(new function w32_tcc_lib_path removes 'bin' if detected)
Added quick build batch file for mingw (win32/build-tcc.bat)
Last added case label optimization (455) produced wrong code. Reverted.
- Import more changesets from Rob Landley's fork (part 2):
487: Handle long long constants in gen_opic() (Rob Landley)
484: Handle parentheses within __attribute__((...)) (Rob Landley)
480: Remove a goto in decl_initializer_alloc (Rob Landley)
475: Fix dereferences in inline assembly output (Joshua Phillips)
474: Cast ptrs to ints of different sizes correctly (Joshua Phillips)
473: Fix size of structs with empty array member (Joshua Phillips)
470: No warning for && and || with mixed pointers/integers (Rob Landley)
469: Fix symbol visibility problems in the linker (Vincent Pit)
468: Allow && and || involving pointer arguments (Rob Landley)
455: Optimize case labels with no code in between (Zdenek Pavlas)
450: Implement alloca for x86 (grischka)
415: Parse unicode escape sequences (Axel Liljencrantz)
407: Add a simple va_copy() in stdarg.h (Hasso Tepper)
400: Allow typedef names as symbols (Dave Dodge)
- Import some changesets from Rob Landley's fork (part 1):
462: Use LGPL with bcheck.c and il-gen.c
458: Fix global compound literals (in unary: case '&':) (Andrew Johnson)
456: Use return code from tcc_output_file in main() (Michael Somos)
442: Fix indirections with function pointers (***fn)() (grischka)
441: Fix LL left shift in libtcc1.c:__shldi3 (grischka)
440: Pass structures and function ptrs through ?: (grischka)
439: Keep rvalue in bit assignment (bit2 = bit1 = x) (grischka)
438: Degrade nonportable pointer assignment to warning (grischka)
437: Call 'saveregs()' before jumping with logical and/or/not (grischka)
435: Put local static variables into global memory (grischka)
432/434: Cast double and ptr to bool (grischka)
420: Zero pad x87 tenbyte long doubles (Felix Nawothnig)
417: Make 'sizeof' unsigned (Rob Landley)
397: Fix save_reg for longlongs (Daniel Glöckner)
396: Fix "invalid relocation entry" problem on ubuntu - (Bernhard Fischer)
- ignore AS_NEEDED ld command
- mark executable sections as executable when running in memory
- added support for win32 wchar_t (Filip Navara)
- segment override prefix support (Filip Navara)
- normalized slashes in paths (Filip Navara)
- windows style fastcall (Filip Navara)
- support for empty input register section in asm (Filip Navara)
- anonymous union/struct support (Filip Navara)
- fixed parsing of function parameters
- workaround for function pointers in conditional expressions (Dave Dodge)
- initial '-E' option support to use the C preprocessor alone
- discard type qualifiers when comparing function parameters (Dave Dodge)
- Bug fix: A long long value used as a test expression ignores the
upper 32 bits at runtime (Dave Dodge)
- fixed multiple concatenation of PPNUM tokens (initial patch by Dave Dodge)
- fixed multiple typedef specifiers handling
- fixed sign extension in some type conversions (Dave Dodge)
version 0.9.23:
- initial PE executable format for windows version (grischka)

430
Makefile
View File

@@ -1,298 +1,272 @@
#
# Tiny C Compiler Makefile
#
include config.mak
CFLAGS=-O2 -g -Wall
ifndef CONFIG_WIN32
LIBS=-ldl
BCHECK_O=bcheck.o
endif
TOP ?= .
include $(TOP)/config.mak
CFLAGS+=-g -Wall
CFLAGS_P=$(CFLAGS) -pg -static -DCONFIG_TCC_STATIC
LIBS_P=
ifneq ($(GCC_MAJOR),2)
CFLAGS+=-fno-strict-aliasing
endif
ifeq ($(ARCH),i386)
CFLAGS+=-mpreferred-stack-boundary=2
ifeq ($(GCC_MAJOR),2)
CFLAGS+=-m386 -malign-functions=0
else
CFLAGS+=-march=i386 -falign-functions=0 -fno-strict-aliasing
CFLAGS+=-march=i386 -falign-functions=0
ifneq ($(GCC_MAJOR),3)
CFLAGS+=-Wno-pointer-sign -Wno-sign-compare -D_FORTIFY_SOURCE=0
endif
endif
endif
DISAS=objdump -d
INSTALL=install
ifeq ($(ARCH),x86-64)
CFLAGS+=-Wno-pointer-sign
endif
ifndef CONFIG_WIN32
LIBS=-lm
ifndef CONFIG_NOLDL
LIBS+=-ldl
endif
endif
ifdef CONFIG_WIN32
PROGS=tcc$(EXESUF)
ifdef CONFIG_CROSS
PROGS+=c67-tcc$(EXESUF) arm-tcc$(EXESUF)
endif
PROGS+=tiny_impdef$(EXESUF)
NATIVE_TARGET=-DTCC_TARGET_PE
LIBTCC1=libtcc1.a
else
ifeq ($(ARCH),i386)
PROGS=tcc$(EXESUF)
ifdef CONFIG_CROSS
PROGS+=arm-tcc$(EXESUF)
endif
endif
NATIVE_TARGET=-DTCC_TARGET_I386
LIBTCC1=libtcc1.a
BCHECK_O=bcheck.o
else
ifeq ($(ARCH),arm)
NATIVE_TARGET=-DTCC_TARGET_ARM
NATIVE_TARGET+=$(if $(wildcard /lib/ld-linux.so.3),-DTCC_ARM_EABI)
NATIVE_TARGET+=$(if $(shell grep -l "^Features.* \(vfp\|iwmmxt\) " /proc/cpuinfo),-DTCC_ARM_VFP)
else
ifeq ($(ARCH),x86-64)
NATIVE_TARGET=-DTCC_TARGET_X86_64
LIBTCC1=libtcc1.a
endif
endif
endif
endif
ifneq ($(wildcard /lib/ld-uClibc.so.0),)
NATIVE_TARGET+=-DTCC_UCLIBC
BCHECK_O=
endif
ifdef CONFIG_USE_LIBGCC
LIBTCC1=
endif
ifeq ($(TOP),.)
PROGS=tcc$(EXESUF)
I386_CROSS = i386-tcc$(EXESUF)
WIN32_CROSS = i386-win32-tcc$(EXESUF)
X64_CROSS = x86_64-tcc$(EXESUF)
ARM_CROSS = arm-tcc-fpa$(EXESUF) arm-tcc-fpa-ld$(EXESUF) \
arm-tcc-vfp$(EXESUF) arm-tcc-vfp-eabi$(EXESUF)
C67_CROSS = c67-tcc$(EXESUF)
CORE_FILES = tcc.c libtcc.c tccpp.c tccgen.c tccelf.c tccasm.c \
tcc.h config.h libtcc.h tcctok.h
I386_FILES = $(CORE_FILES) i386-gen.c i386-asm.c i386-asm.h
WIN32_FILES = $(CORE_FILES) i386-gen.c i386-asm.c i386-asm.h tccpe.c
X86_64_FILES = $(CORE_FILES) x86_64-gen.c
ARM_FILES = $(CORE_FILES) arm-gen.c
C67_FILES = $(CORE_FILES) c67-gen.c tcccoff.c
ifdef CONFIG_WIN32
PROGS+=tiny_impdef$(EXESUF) tiny_libmaker$(EXESUF)
NATIVE_FILES=$(WIN32_FILES)
PROGS_CROSS=$(I386_CROSS) $(X64_CROSS) $(ARM_CROSS) $(C67_CROSS)
else
ifeq ($(ARCH),i386)
NATIVE_FILES=$(I386_FILES)
PROGS_CROSS=$(X64_CROSS) $(WIN32_CROSS) $(ARM_CROSS) $(C67_CROSS)
else
ifeq ($(ARCH),x86-64)
NATIVE_FILES=$(X86_64_FILES)
PROGS_CROSS=$(I386_CROSS) $(WIN32_CROSS) $(ARM_CROSS) $(C67_CROSS)
else
ifeq ($(ARCH),arm)
NATIVE_FILES=$(ARM_FILES)
PROGS_CROSS=$(I386_CROSS) $(X64_CROSS) $(WIN32_CROSS) $(C67_CROSS)
endif
endif
endif
endif
ifdef CONFIG_CROSS
PROGS+=i386-tcc$(EXESUF)
endif
endif
ifdef CONFIG_CROSS
PROGS+=c67-tcc$(EXESUF) i386-win32-tcc$(EXESUF)
endif
PROGS+=$(PROGS_CROSS)
endif
# run local version of tcc with local libraries and includes
TCC=./tcc -B. -I.
all: $(PROGS) \
libtcc1.a $(BCHECK_O) tcc-doc.html tcc.1 libtcc.a \
libtcc_test$(EXESUF)
Makefile: config.mak
# auto test
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 $@ $<
test.ref: tcctest.ref
./tcctest.ref > $@
test.out: tcc tcctest.c
$(TCC) -run tcctest.c > $@
run: tcc tcctest.c
$(TCC) -run tcctest.c
# iterated test2 (compile tcc then compile tcctest.c !)
test2: tcc tcc.c tcctest.c test.ref
$(TCC) -run tcc.c -B. -I. -run tcctest.c > test.out2
@if diff -u test.ref test.out2 ; then echo "Auto Test2 OK"; fi
# iterated test3 (compile tcc then compile tcc then compile tcctest.c !)
test3: tcc tcc.c tcctest.c test.ref
$(TCC) -run tcc.c -B. -I. -run tcc.c -B. -I. -run tcctest.c > test.out3
@if diff -u test.ref test.out3 ; then echo "Auto Test3 OK"; fi
# binary output test
test4: tcc test.ref
# dynamic output
$(TCC) -o tcctest1 tcctest.c
./tcctest1 > test1.out
@if diff -u test.ref test1.out ; then echo "Dynamic Auto Test OK"; fi
# static output
$(TCC) -static -o tcctest2 tcctest.c
./tcctest2 > test2.out
@if diff -u test.ref test2.out ; then echo "Static Auto Test OK"; fi
# object + link output
$(TCC) -c -o tcctest3.o tcctest.c
$(TCC) -o tcctest3 tcctest3.o
./tcctest3 > test3.out
@if diff -u test.ref test3.out ; then echo "Object Auto Test OK"; fi
# dynamic output + bound check
$(TCC) -b -o tcctest4 tcctest.c
./tcctest4 > test4.out
@if diff -u test.ref test4.out ; then echo "BCheck Auto Test OK"; fi
# memory and bound check auto test
BOUNDS_OK = 1 4 8 10
BOUNDS_FAIL= 2 5 7 9 11 12 13
btest: boundtest.c tcc
@for i in $(BOUNDS_OK); do \
if $(TCC) -b -run boundtest.c $$i ; then \
/bin/true ; \
else\
echo Failed positive test $$i ; exit 1 ; \
fi ;\
done ;\
for i in $(BOUNDS_FAIL); do \
if $(TCC) -b -run boundtest.c $$i ; then \
echo Failed negative test $$i ; exit 1 ;\
else\
/bin/true ; \
fi\
done ;\
echo Bound test OK
# speed test
speed: tcc ex2 ex3
time ./ex2 1238 2 3 4 10 13 4
time ./tcc -I. ./ex2.c 1238 2 3 4 10 13 4
time ./ex3 35
time ./tcc -I. ./ex3.c 35
ex2: ex2.c
$(CC) $(CFLAGS) -o $@ $<
ex3: ex3.c
$(CC) $(CFLAGS) -o $@ $<
all: $(PROGS) $(LIBTCC1) $(BCHECK_O) libtcc.a tcc-doc.html tcc.1 libtcc_test$(EXESUF)
# Host Tiny C Compiler
ifdef CONFIG_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)
else
ifeq ($(ARCH),i386)
tcc$(EXESUF): tcc.c i386-gen.c tccelf.c tccasm.c i386-asm.c tcctok.h libtcc.h i386-asm.h
$(CC) $(CFLAGS) -o $@ $< $(LIBS)
endif
ifeq ($(ARCH),arm)
tcc$(EXESUF): tcc.c arm-gen.c tccelf.c tccasm.c tcctok.h libtcc.h
$(CC) $(CFLAGS) -DTCC_TARGET_ARM -o $@ $< $(LIBS)
endif
endif
tcc$(EXESUF): $(NATIVE_FILES)
$(CC) -o $@ $< $(NATIVE_TARGET) $(CFLAGS) $(LIBS)
# Cross Tiny C Compilers
i386-tcc$(EXESUF): tcc.c i386-gen.c tccelf.c tccasm.c i386-asm.c tcctok.h libtcc.h i386-asm.h
$(CC) $(CFLAGS) -o $@ $< $(LIBS)
i386-tcc$(EXESUF): $(I386_FILES)
$(CC) -o $@ $< -DTCC_TARGET_I386 $(CFLAGS) $(LIBS)
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)
i386-win32-tcc$(EXESUF): $(WIN32_FILES)
$(CC) -o $@ $< -DTCC_TARGET_PE $(CFLAGS) $(LIBS)
arm-tcc$(EXESUF): tcc.c arm-gen.c tccelf.c tccasm.c tcctok.h libtcc.h
$(CC) $(CFLAGS) -DTCC_TARGET_ARM -o $@ $< $(LIBS)
x86_64-tcc$(EXESUF): $(X86_64_FILES)
$(CC) -o $@ $< -DTCC_TARGET_X86_64 $(CFLAGS) $(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)
c67-tcc$(EXESUF): $(C67_FILES)
$(CC) -o $@ $< -DTCC_TARGET_C67 $(CFLAGS) $(LIBS)
arm-tcc-fpa$(EXESUF): $(ARM_FILES)
$(CC) -o $@ $< -DTCC_TARGET_ARM $(CFLAGS) $(LIBS)
arm-tcc-fpa-ld$(EXESUF): $(ARM_FILES)
$(CC) -o $@ $< -DTCC_TARGET_ARM -DLDOUBLE_SIZE=12 $(CFLAGS) $(LIBS)
arm-tcc-vfp$(EXESUF): $(ARM_FILES)
$(CC) -o $@ $< -DTCC_TARGET_ARM -DTCC_ARM_VFP $(CFLAGS) $(LIBS)
arm-tcc-vfp-eabi$(EXESUF): $(ARM_FILES)
$(CC) -o $@ $< -DTCC_TARGET_ARM -DTCC_ARM_EABI $(CFLAGS) $(LIBS)
# libtcc generation and test
libtcc.o: $(NATIVE_FILES)
$(CC) -o $@ -c libtcc.c $(NATIVE_TARGET) $(CFLAGS)
libtcc.a: libtcc.o
$(AR) rcs $@ $^
libtcc_test$(EXESUF): tests/libtcc_test.c libtcc.a
$(CC) -o $@ $^ -I. $(CFLAGS) $(LIBS)
libtest: libtcc_test$(EXESUF) $(LIBTCC1)
./libtcc_test$(EXESUF) lib_path=.
# profiling version
tcc_p$(EXESUF): $(NATIVE_FILES)
$(CC) -o $@ $< $(NATIVE_TARGET) $(CFLAGS_P) $(LIBS_P)
# windows utilities
tiny_impdef$(EXESUF): tiny_impdef.c
$(CC) $(CFLAGS) -o $@ $< -lkernel32
tiny_impdef$(EXESUF): win32/tools/tiny_impdef.c
$(CC) -o $@ $< $(CFLAGS)
tiny_libmaker$(EXESUF): win32/tools/tiny_libmaker.c
$(CC) -o $@ $< $(CFLAGS)
# 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
else
LIBTCC1_OBJS=libtcc1.o
LIBTCC1_CC=$(CC)
VPATH+=lib
ifdef CONFIG_WIN32
# for windows, we must use TCC because we generate ELF objects
LIBTCC1_OBJS+=crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o
LIBTCC1_CC=./tcc.exe -Bwin32 -DTCC_TARGET_PE
VPATH+=win32/lib
endif
ifeq ($(ARCH),i386)
LIBTCC1_OBJS+=alloca86.o alloca86-bt.o
endif
%.o: %.c
$(LIBTCC1_CC) -O2 -Wall -c -o $@ $<
$(LIBTCC1_CC) -o $@ -c $< -O2 -Wall
%.o: %.S
$(LIBTCC1_CC) -c -o $@ $<
$(LIBTCC1_CC) -o $@ -c $<
libtcc1.a: $(LIBTCC1_OBJS)
$(AR) rcs $@ $^
bcheck.o: bcheck.c
$(CC) -O2 -Wall -c -o $@ $<
$(CC) -o $@ -c $< -O2 -Wall
install: tcc_install libinstall
# install
TCC_INCLUDES = stdarg.h stddef.h stdbool.h float.h varargs.h tcclib.h
INSTALL=install
tcc_install: $(PROGS) tcc.1 libtcc1.a $(BCHECK_O) tcc-doc.html tcc.1
ifndef CONFIG_WIN32
install: $(PROGS) $(LIBTCC1) $(BCHECK_O) libtcc.a tcc.1 tcc-doc.html
mkdir -p "$(bindir)"
$(INSTALL) -s -m755 $(PROGS) "$(bindir)"
ifndef CONFIG_WIN32
mkdir -p "$(mandir)/man1"
$(INSTALL) tcc.1 "$(mandir)/man1"
endif
mkdir -p "$(tccdir)"
mkdir -p "$(tccdir)/include"
ifdef CONFIG_WIN32
mkdir -p "$(tccdir)/lib"
$(INSTALL) -m644 libtcc1.a win32/lib/*.def "$(tccdir)/lib"
cp -r win32/include/. "$(tccdir)/include"
cp -r win32/examples/. "$(tccdir)/examples"
else
$(INSTALL) -m644 libtcc1.a $(BCHECK_O) "$(tccdir)"
$(INSTALL) -m644 stdarg.h stddef.h stdbool.h float.h varargs.h \
tcclib.h "$(tccdir)/include"
ifneq ($(LIBTCC1),)
$(INSTALL) -m644 $(LIBTCC1) "$(tccdir)"
endif
ifneq ($(BCHECK_O),)
$(INSTALL) -m644 $(BCHECK_O) "$(tccdir)"
endif
$(INSTALL) -m644 $(addprefix include/,$(TCC_INCLUDES)) "$(tccdir)/include"
mkdir -p "$(docdir)"
$(INSTALL) -m644 tcc-doc.html "$(docdir)"
ifdef CONFIG_WIN32
$(INSTALL) -m644 win32/readme.txt "$(docdir)"
endif
clean:
rm -f *~ *.o *.a tcc tcc1 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
distclean: clean
rm -f config.h config.mak config.texi
# profiling version
tcc_p: tcc.c Makefile
$(CC) $(CFLAGS_P) -o $@ $< $(LIBS_P)
# libtcc generation and example
libinstall: libtcc.a
mkdir -p "$(libdir)"
$(INSTALL) -m644 libtcc.a "$(libdir)"
mkdir -p "$(includedir)"
$(INSTALL) -m644 libtcc.h "$(includedir)"
libtcc.o: tcc.c i386-gen.c Makefile
$(CC) $(CFLAGS) -DLIBTCC -c -o $@ $<
uninstall:
rm -fv $(foreach P,$(PROGS),"$(bindir)/$P")
rm -fv $(foreach P,$(LIBTCC1) $(BCHECK_O),"$(tccdir)/$P")
rm -fv $(foreach P,$(TCC_INCLUDES),"$(tccdir)/include/$P")
rm -fv "$(docdir)/tcc-doc.html" "$(mandir)/man1/tcc.1"
rm -fv "$(libdir)/libtcc.a" "$(includedir)/libtcc.h"
libtcc.a: libtcc.o
$(AR) rcs $@ $^
libtcc_test$(EXESUF): libtcc_test.c libtcc.a
$(CC) $(CFLAGS) -o $@ $< libtcc.a $(LIBS)
libtest: libtcc_test
./libtcc_test
# targets for development
%.bin: %.c tcc
$(TCC) -g -o $@ $<
$(DISAS) $@
instr: instr.o
objdump -d instr.o
# tiny assembler testing
asmtest.ref: asmtest.S
$(CC) -c -o asmtest.ref.o asmtest.S
objdump -D asmtest.ref.o > $@
# XXX: we compute tcc.c to go faster during development !
asmtest.out: asmtest.S tcc
# ./tcc tcc.c -c asmtest.S
#asmtest.out: asmtest.S tcc
./tcc -c asmtest.S
objdump -D asmtest.o > $@
asmtest: asmtest.out asmtest.ref
@if diff -u --ignore-matching-lines="file format" asmtest.ref asmtest.out ; then echo "ASM Auto Test OK"; fi
instr.o: instr.S
$(CC) -O2 -Wall -g -c -o $@ $<
cache: tcc_g
cachegrind ./tcc_g -o /tmp/linpack -lm bench/linpack.c
vg_annotate tcc.c > /tmp/linpack.cache.log
else
install: $(PROGS) $(LIBTCC1) libtcc.a tcc-doc.html
mkdir -p "$(tccdir)"
mkdir -p "$(tccdir)/lib"
mkdir -p "$(tccdir)/include"
mkdir -p "$(tccdir)/examples"
mkdir -p "$(tccdir)/doc"
mkdir -p "$(tccdir)/libtcc"
$(INSTALL) -s -m755 $(PROGS) "$(tccdir)"
$(INSTALL) -m644 $(LIBTCC1) win32/lib/*.def "$(tccdir)/lib"
cp -r win32/include/. "$(tccdir)/include"
cp -r win32/examples/. "$(tccdir)/examples"
# $(INSTALL) -m644 $(addprefix include/,$(TCC_INCLUDES)) "$(tccdir)/include"
$(INSTALL) -m644 tcc-doc.html win32/tcc-win32.txt "$(tccdir)/doc"
$(INSTALL) -m644 libtcc.a libtcc.h "$(tccdir)/libtcc"
endif
# 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 > $@
FILE=tcc-$(shell cat VERSION)
-./texi2pod.pl $< tcc.pod
-pod2man --section=1 --center=" " --release=" " tcc.pod > $@
# tar release (use 'make -k tar' on a checkouted tree)
TCC-VERSION=tcc-$(shell cat VERSION)
tar:
rm -rf /tmp/$(FILE)
cp -r . /tmp/$(FILE)
( cd /tmp ; tar zcvf ~/$(FILE).tar.gz $(FILE) --exclude CVS )
rm -rf /tmp/$(FILE)
rm -rf /tmp/$(TCC-VERSION)
cp -r . /tmp/$(TCC-VERSION)
( cd /tmp ; tar zcvf ~/$(TCC-VERSION).tar.gz $(TCC-VERSION) --exclude CVS )
rm -rf /tmp/$(TCC-VERSION)
# in tests subdir
test clean :
$(MAKE) -C tests $@
# clean
clean: local_clean
local_clean:
rm -vf $(PROGS) tcc_p$(EXESUF) tcc.pod *~ *.o *.a *.out libtcc_test$(EXESUF)
distclean: clean
rm -vf config.h config.mak config.texi tcc.1 tcc-doc.html
endif # ifeq ($(TOP),.)

5
README
View File

@@ -28,7 +28,7 @@ Features:
Documentation:
-------------
1) Installation on a i386 Linux host (for Windows read win32/readme.txt)
1) Installation on a i386 Linux host (for Windows read tcc-win32.txt)
./configure
make
@@ -79,8 +79,7 @@ when doing 'make test'.
Please read tcc-doc.html to have all the features of TCC.
Additional information is available for the Windows port in
win32/readme.txt.
Additional information is available for the Windows port in tcc-win32.txt.
License:
-------

82
TODO
View File

@@ -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.

View File

@@ -1 +1 @@
0.9.23
0.9.25

552
arm-gen.c
View File

@@ -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,11 +101,22 @@ 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) */
#define REG_FRET TREG_F0 /* float return register */
#ifdef TCC_ARM_EABI
#define TOK___divdi3 TOK___aeabi_ldivmod
#define TOK___moddi3 TOK___aeabi_ldivmod
#define TOK___udivdi3 TOK___aeabi_uldivmod
#define TOK___umoddi3 TOK___aeabi_uldivmod
#endif
/* defined if function parameters must be evaluated in reverse order */
#define INVERT_FUNC_PARAMS
@@ -86,12 +124,33 @@ 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;
#define func_ldouble_type func_double_type
#else
#define func_float_type func_old_type
#define func_double_type func_old_type
#define func_ldouble_type func_old_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 +171,7 @@ static int regmask(int r) {
/******************************************************/
static unsigned long func_sub_sp_offset,last_itod_magic;
static int leaffunc;
void o(unsigned long i)
{
@@ -200,7 +260,7 @@ void stuff_const_harder(unsigned long op,unsigned long v) {
for(i=1;i<16;i++)
a[i]=(a[i-1]>>2)|(a[i-1]<<30);
for(i=0;i<12;i++)
for(j=i+4;i<13+i;i++)
for(j=i<4?i+12:15;j>=i+4;j--)
if((v&(a[i]|a[j]))==v) {
o(stuff_const(op,v&a[i]));
o(stuff_const(o2,v&a[j]));
@@ -210,15 +270,15 @@ void stuff_const_harder(unsigned long op,unsigned long v) {
n2=o2^0xC00000;
nv=-v;
for(i=0;i<12;i++)
for(j=i+4;i<13+i;i++)
for(j=i<4?i+12:15;j>=i+4;j--)
if((nv&(a[i]|a[j]))==nv) {
o(stuff_const(no,nv&a[i]));
o(stuff_const(n2,nv&a[j]));
return;
}
for(i=0;i<8;i++)
for(j=i+4;i<12;i++)
for(k=j+4;k<13+i;i++)
for(j=i+4;j<12;j++)
for(k=i<4?i+12:15;k>=j+4;k--)
if((v&(a[i]|a[j]|a[k]))==v) {
o(stuff_const(op,v&a[i]));
o(stuff_const(o2,v&a[j]));
@@ -228,8 +288,8 @@ void stuff_const_harder(unsigned long op,unsigned long v) {
no=op^0xC00000;
nv=-v;
for(i=0;i<8;i++)
for(j=i+4;i<12;i++)
for(k=j+4;k<13+i;i++)
for(j=i+4;j<12;j++)
for(k=i<4?i+12:15;k>=j+4;k--)
if((nv&(a[i]|a[j]|a[k]))==nv) {
o(stuff_const(no,nv&a[i]));
o(stuff_const(n2,nv&a[j]));
@@ -287,19 +347,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 +404,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 +448,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 +509,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 +530,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 +591,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 +641,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 +662,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 +735,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 +787,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 +799,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 +823,7 @@ void gfunc_call(int nb_args)
r|=0x8000;
o(0xED2D0100|r|(size>>2));
#endif
vtop--;
args_size += size;
} else {
@@ -718,7 +854,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 +876,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 +901,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 +932,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 +951,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 | lvalue_type(type->t), 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 +1065,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);
@@ -904,6 +1095,7 @@ void gen_opi(int op)
{
int c, func = 0;
unsigned long opc = 0,r,fr;
unsigned short retreg = REG_IRET;
c=0;
switch(op) {
@@ -972,11 +1164,21 @@ void gen_opi(int op)
c=3;
break;
case '%':
#ifdef TCC_ARM_EABI
func=TOK___aeabi_idivmod;
retreg=REG_LRET;
#else
func=TOK___modsi3;
#endif
c=3;
break;
case TOK_UMOD:
#ifdef TCC_ARM_EABI
func=TOK___aeabi_uidivmod;
retreg=REG_LRET;
#else
func=TOK___umodsi3;
#endif
c=3;
break;
case TOK_UMULL:
@@ -1051,13 +1253,117 @@ done:
vrott(3);
gfunc_call(2);
vpushi(0);
vtop->r = REG_IRET;
vtop->r = retreg;
break;
default:
error("gen_opi %i unimplemented!",op);
}
}
#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 +1499,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 +1523,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 +1550,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,20 +1566,34 @@ 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. */
void gen_cvt_itof(int t)
void gen_cvt_itof1(int t)
{
int r,r2,bt;
bt=vtop->type.t & VT_BTYPE;
if(bt == VT_INT || bt == VT_SHORT || bt == VT_BYTE) {
#ifndef TCC_ARM_VFP
unsigned int dsize=0;
#endif
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((t & VT_BTYPE) != VT_FLOAT)
dsize=0x80; /* flts -> fltd */
o(0xEE000110|dsize|(r2<<16)|(r<<12)); /* flts */
if((vtop->type.t & (VT_UNSIGNED|VT_BTYPE)) == (VT_UNSIGNED|VT_INT)) {
unsigned int off=0;
o(0xE3500000|(r<<12));
o(0xE3500000|(r<<12)); /* cmp */
r=fpr(get_reg(RC_FLOAT));
if(last_itod_magic) {
off=ind+8-last_itod_magic;
@@ -1291,28 +1601,50 @@ void gen_cvt_itof(int t)
if(off>255)
off=0;
}
o(0xBD1F8100|(r<<12)|off);
o(0xBD1F0100|(r<<12)|off); /* ldflts */
if(!off) {
o(0xEA000001);
o(0xEA000000); /* b */
last_itod_magic=ind;
o(0x41F00000);
o(0);
o(0x4F800000); /* 4294967296.0f */
}
o(0xBE000180|(r2<<16)|(r2<<12)|r);
o(0xBE000100|dsize|(r2<<16)|(r2<<12)|r); /* adflt */
}
#endif
return;
} else if(bt == VT_LLONG) {
int func;
if(vtop->type.t & VT_UNSIGNED)
func=TOK___ulltold;
else
func=TOK___slltold;
vpush_global_sym(&func_old_type, func);
vswap();
gfunc_call(1);
vpushi(0);
vtop->r=TREG_F0;
return;
CType *func_type = 0;
if((t & VT_BTYPE) == VT_FLOAT) {
func_type = &func_float_type;
if(vtop->type.t & VT_UNSIGNED)
func=TOK___floatundisf;
else
func=TOK___floatdisf;
#if LDOUBLE_SIZE != 8
} else if((t & VT_BTYPE) == VT_LDOUBLE) {
func_type = &func_ldouble_type;
if(vtop->type.t & VT_UNSIGNED)
func=TOK___floatundixf;
else
func=TOK___floatdixf;
} else if((t & VT_BTYPE) == VT_DOUBLE) {
#else
} else if((t & VT_BTYPE) == VT_DOUBLE || (t & VT_BTYPE) == VT_LDOUBLE) {
#endif
func_type = &func_double_type;
if(vtop->type.t & VT_UNSIGNED)
func=TOK___floatundidf;
else
func=TOK___floatdidf;
}
if(func_type) {
vpush_global_sym(func_type, func);
vswap();
gfunc_call(1);
vpushi(0);
vtop->r=TREG_F0;
return;
}
}
error("unimplemented gen_cvt_itof %x!",vtop->type.t);
}
@@ -1325,35 +1657,44 @@ 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;
else if(r2 == VT_DOUBLE)
func=TOK___fixunsdfsi;
#if LDOUBLE_SIZE != 8
else if(r2 == VT_LDOUBLE)
#if LDOUBLE_SIZE == 8
func=TOK___fixunsdfsi;
#else
func=TOK___fixunsxfsi;
else if(r2 == VT_DOUBLE)
#else
else if(r2 == VT_LDOUBLE || r2 == VT_DOUBLE)
#endif
func=TOK___fixunsdfsi;
} else {
r=fpr(gv(RC_FLOAT));
r2=intr(vtop->r=get_reg(RC_INT));
o(0xEE100170|(r2<<12)|r);
return;
return;
}
#endif
} else if(t == VT_LLONG) { // unsigned handled in gen_cvt_ftoi1
if(r2 == VT_FLOAT)
func=TOK___fixsfdi;
else if(r2 == VT_DOUBLE)
func=TOK___fixdfdi;
#if LDOUBLE_SIZE != 8
else if(r2 == VT_LDOUBLE)
#if LDOUBLE_SIZE == 8
func=TOK___fixdfdi;
#else
func=TOK___fixxfdi;
else if(r2 == VT_DOUBLE)
#else
else if(r2 == VT_LDOUBLE || r2 == VT_DOUBLE)
#endif
}
func=TOK___fixdfdi;
}
if(func) {
vpush_global_sym(&func_old_type, func);
vswap();
@@ -1370,8 +1711,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 */

View File

@@ -1964,7 +1964,7 @@ void gfunc_prolog(CType * func_type)
/* define parameters */
while ((sym = sym->next) != NULL) {
type = &sym->type;
sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL, addr);
sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | lvalue_type(type->t), addr);
size = type_size(type, &align);
size = (size + 3) & ~3;

69
configure vendored
View File

@@ -19,6 +19,7 @@ TMPH="${TMPDIR1}/tcc-conf-${RANDOM}-$$-${RANDOM}.h"
# default parameters
build_cross="no"
use_libgcc="no"
prefix=""
execprefix=""
bindir=""
@@ -26,17 +27,20 @@ libdir=""
tccdir=""
includedir=""
mandir=""
sysroot=""
cross_prefix=""
cc="gcc"
host_cc="gcc"
ar="ar"
make="make"
strip="strip"
cpu=`uname -m`
case "$cpu" in
i386|i486|i586|i686|i86pc|BePC)
cpu="x86"
;;
x86_64)
cpu="x86-64"
;;
armv4l)
cpu="armv4l"
;;
@@ -68,6 +72,12 @@ case $targetos in
MINGW32*)
mingw32="yes"
;;
DragonFly)
noldl="yes"
;;
OpenBSD)
noldl="yes"
;;
*) ;;
esac
@@ -96,14 +106,14 @@ for opt do
;;
--mandir=*) mandir=`echo $opt | cut -d '=' -f 2`
;;
--sysroot=*) sysroot=`echo $opt | cut -d '=' -f 2`
;;
--source-path=*) source_path=`echo $opt | cut -d '=' -f 2`
;;
--cross-prefix=*) cross_prefix=`echo $opt | cut -d '=' -f 2`
;;
--cc=*) cc=`echo $opt | cut -d '=' -f 2`
;;
--make=*) make=`echo $opt | cut -d '=' -f 2`
;;
--extra-cflags=*) CFLAGS="${opt#--extra-cflags=}"
;;
--extra-ldflags=*) LDFLAGS="${opt#--extra-ldflags=}"
@@ -118,6 +128,8 @@ for opt do
;;
--enable-cross) build_cross="yes"
;;
--with-libgcc) use_libgcc="yes"
;;
esac
done
@@ -142,15 +154,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 +187,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,13 +219,14 @@ 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]"
echo " --cross-prefix=PREFIX use PREFIX for compile tools [$cross_prefix]"
echo " --sysroot=PREFIX prepend PREFIX to library/include paths []"
echo " --cc=CC use C compiler CC [$cc]"
echo " --make=MAKE use specified make [$make]"
echo " --with-libgcc use /lib/libgcc_s.so.1 instead of libtcc1.a"
echo ""
#echo "NOTE: The object files are build at the place where configure is launched"
exit 1
@@ -208,7 +234,7 @@ fi
if test "$mingw32" = "yes" ; then
if test -z "$prefix" ; then
prefix="/c/Program Files/tcc"
prefix="C:/Program Files/tcc"
fi
execprefix="$prefix"
bindir="$prefix"
@@ -248,13 +274,14 @@ echo "Library directory $libdir"
echo "Include directory $includedir"
echo "Manual directory $mandir"
echo "Doc directory $docdir"
echo "Target root prefix $sysroot"
echo "Source path $source_path"
echo "C compiler $cc"
echo "make $make"
echo "CPU $cpu"
echo "Big Endian $bigendian"
echo "gprof enabled $gprof"
echo "cross compilers $build_cross"
echo "use libgcc $use_libgcc"
echo "Creating config.mak and config.h"
@@ -268,8 +295,8 @@ echo "libdir=$libdir" >> config.mak
echo "includedir=$includedir" >> config.mak
echo "mandir=$mandir" >> config.mak
echo "docdir=$docdir" >> config.mak
echo "#define CONFIG_SYSROOT \"$sysroot\"" >> $TMPH
echo "#define CONFIG_TCCDIR \"$tccdir\"" >> $TMPH
echo "MAKE=$make" >> config.mak
echo "CC=$cc" >> config.mak
echo "GCC_MAJOR=$gcc_major" >> config.mak
echo "#define GCC_MAJOR $gcc_major" >> $TMPH
@@ -283,6 +310,9 @@ echo "EXESUF=$EXESUF" >> config.mak
if test "$cpu" = "x86" ; then
echo "ARCH=i386" >> config.mak
echo "#define HOST_I386 1" >> $TMPH
elif test "$cpu" = "x86-64" ; then
echo "ARCH=x86-64" >> config.mak
echo "#define HOST_X86_64 1" >> $TMPH
elif test "$cpu" = "armv4l" ; then
echo "ARCH=arm" >> config.mak
echo "#define HOST_ARM 1" >> $TMPH
@@ -302,6 +332,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
@@ -317,6 +350,10 @@ fi
if test "$build_cross" = "yes" ; then
echo "CONFIG_CROSS=yes" >> config.mak
fi
if test "$use_libgcc" = "yes" ; then
echo "#define CONFIG_USE_LIBGCC" >> $TMPH
echo "CONFIG_USE_LIBGCC=yes" >> config.mak
fi
version=`head $source_path/VERSION`
echo "VERSION=$version" >>config.mak
echo "#define TCC_VERSION \"$version\"" >> $TMPH
@@ -327,7 +364,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 +374,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

1993
elf.h

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
#! /usr/local/bin/tcc -run
#include <tcclib.h>
int main()
int main()
{
printf("Hello World\n");
return 0;

View File

@@ -1,4 +1,5 @@
#include "tcclib.h"
#include <stdlib.h>
#include <stdio.h>
#define N 20
@@ -23,7 +24,7 @@ int find(int n, int i1, int a, int b, int op)
return 1;
tab[i1] = n;
}
for(i=0;i<nb_num;i++) {
for(j=i+1;j<nb_num;j++) {
a = tab[i];
@@ -52,7 +53,7 @@ int find(int n, int i1, int a, int b, int op)
if (find(c, i, b, a, '/'))
return 1;
}
stack_ptr--;
tab[i] = a;
tab[j] = b;
@@ -66,7 +67,7 @@ int find(int n, int i1, int a, int b, int op)
int main(int argc, char **argv)
{
int i, res, p;
if (argc < 3) {
printf("usage: %s: result numbers...\n"
"Try to find result from numbers with the 4 basic operations.\n", argv[0]);
@@ -85,7 +86,7 @@ int main(int argc, char **argv)
res = find(0, 0, 0, 0, ' ');
if (res) {
for(i=0;i<=stack_ptr;i++) {
printf("%d %c %d = %d\n",
printf("%d %c %d = %d\n",
stack_res[3*i], stack_op[i],
stack_res[3*i+1], stack_res[3*i+2]);
}

View File

@@ -1,4 +1,5 @@
#include <tcclib.h>
#include <stdlib.h>
#include <stdio.h>
int fib(n)
{
@@ -8,7 +9,7 @@ int fib(n)
return fib(n-1) + fib(n-2);
}
int main(int argc, char **argv)
int main(int argc, char **argv)
{
int n;
if (argc < 2) {
@@ -16,7 +17,7 @@ int main(int argc, char **argv)
"Compute nth Fibonacci number\n");
return 1;
}
n = atoi(argv[1]);
printf("fib(%d) = %d\n", n, fib(n, 2));
return 0;

View File

@@ -1,9 +1,10 @@
#!./tcc -run -L/usr/X11R6/lib -lX11
#include <stdlib.h>
/* Yes, TCC can use X11 too ! */
#include <stdio.h>
#include <X11/Xlib.h>
/* Yes, TCC can use X11 too ! */
int main(int argc, char **argv)
{
Display *display;
@@ -16,8 +17,8 @@ int main(int argc, char **argv)
}
printf("X11 display opened.\n");
screen = XScreenOfDisplay(display, 0);
printf("width = %d\nheight = %d\ndepth = %d\n",
screen->width,
printf("width = %d\nheight = %d\ndepth = %d\n",
screen->width,
screen->height,
screen->root_depth);
XCloseDisplay(display);

View File

@@ -1,7 +1,7 @@
#include <stdlib.h>
#include <stdio.h>
int main()
int main()
{
printf("Hello World\n");
return 0;

View File

@@ -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) {

View File

@@ -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,14 +464,14 @@ 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;
addr += size;
}
sym_push(sym->v & ~SYM_FIELD, type,
VT_LOCAL | VT_LVAL, param_addr);
VT_LOCAL | lvalue_type(type->t), param_addr);
param_index++;
}
func_ret_sub = 0;
@@ -465,7 +480,7 @@ void gfunc_prolog(CType *func_type)
func_ret_sub = addr - 8;
/* leave some room for bound checking code */
if (do_bounds_check) {
if (tcc_state->do_bounds_check) {
oad(0xb8, 0); /* lbound section pointer */
oad(0xb8, 0); /* call to function */
func_bound_offset = lbounds_section->data_offset;
@@ -478,7 +493,8 @@ void gfunc_epilog(void)
int v, saved_ind;
#ifdef CONFIG_TCC_BCHECK
if (do_bounds_check && func_bound_offset != lbounds_section->data_offset) {
if (tcc_state->do_bounds_check
&& func_bound_offset != lbounds_section->data_offset) {
int saved_ind;
int *bounds_ptr;
Sym *sym, *sym_data;
@@ -585,7 +601,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);
}

View File

@@ -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 */
@@ -449,7 +449,7 @@ void gfunc_prolog(int t)
while ((sym = sym->next) != NULL) {
u = sym->t;
sym_push(sym->v & ~SYM_FIELD, u,
VT_LOCAL | VT_LVAL, addr);
VT_LOCAL | lvalue_type(sym->type.t), addr);
addr++;
}
}

67
include/stdarg.h Normal file
View File

@@ -0,0 +1,67 @@
#ifndef _STDARG_H
#define _STDARG_H
#ifdef __x86_64__
#include <stdlib.h>
/* GCC compatible definition of va_list. */
struct __va_list_struct {
unsigned int gp_offset;
unsigned int fp_offset;
union {
unsigned int overflow_offset;
char *overflow_arg_area;
};
char *reg_save_area;
};
typedef struct __va_list_struct *va_list;
/* we use __builtin_(malloc|free) to avoid #define malloc tcc_malloc */
/* XXX: this lacks the support of aggregated types. */
#define va_start(ap, last) \
(ap = (va_list)__builtin_malloc(sizeof(struct __va_list_struct)), \
*ap = *(struct __va_list_struct*)( \
(char*)__builtin_frame_address(0) - 16), \
ap->overflow_arg_area = ((char *)__builtin_frame_address(0) + \
ap->overflow_offset), \
ap->reg_save_area = (char *)__builtin_frame_address(0) - 176 - 16 \
)
#define va_arg(ap, type) \
(*(type*)(__builtin_types_compatible_p(type, long double) \
? (ap->overflow_arg_area += 16, \
ap->overflow_arg_area - 16) \
: __builtin_types_compatible_p(type, double) \
? (ap->fp_offset < 128 + 48 \
? (ap->fp_offset += 16, \
ap->reg_save_area + ap->fp_offset - 16) \
: (ap->overflow_arg_area += 8, \
ap->overflow_arg_area - 8)) \
: (ap->gp_offset < 48 \
? (ap->gp_offset += 8, \
ap->reg_save_area + ap->gp_offset - 8) \
: (ap->overflow_arg_area += 8, \
ap->overflow_arg_area - 8)) \
))
#define va_copy(dest, src) \
((dest) = (va_list)malloc(sizeof(struct __va_list_struct)), \
*(dest) = *(src))
#define va_end(ap) __builtin_free(ap)
#else
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)
#endif
/* fix a buggy dependency on GCC in libio.h */
typedef va_list __gnuc_va_list;
#define _VA_LIST_DEFINED
#endif /* _STDARG_H */

View File

@@ -7,15 +7,14 @@ typedef __WCHAR_TYPE__ wchar_t;
typedef __PTRDIFF_TYPE__ ptrdiff_t;
#define offsetof(type, field) ((size_t) &((type *)0)->field)
/* need to do that because of glibc 2.1 bug (should have a way to test
presence of 'long long' without __GNUC__, or TCC should define
__GNUC__ ? */
#if !defined(__int8_t_defined) && !defined(__dietlibc__)
#ifndef __int8_t_defined
#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
void *alloca(size_t size);
#endif

View File

@@ -18,6 +18,7 @@ void *realloc(void *ptr, size_t size);
int atoi(const char *nptr);
long int strtol(const char *nptr, char **endptr, int base);
unsigned long int strtoul(const char *nptr, char **endptr, int base);
void exit(int);
/* stdio.h */
typedef struct __FILE FILE;

45
lib/alloca86-bt.S Normal file
View 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
lib/alloca86.S Normal file
View 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
/* ---------------------------------------------- */

View File

@@ -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

View File

@@ -89,13 +89,13 @@ union double_long {
double d;
#if 1
struct {
unsigned long lower;
long upper;
unsigned int lower;
int upper;
} l;
#else
struct {
long upper;
unsigned long lower;
int upper;
unsigned int lower;
} l;
#endif
long long ll;
@@ -106,6 +106,9 @@ union float_long {
long l;
};
/* XXX: we don't support several builtin supports for now */
#ifndef __x86_64__
/* XXX: use gcc/tcc intrinsic ? */
#if defined(__i386__)
#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
@@ -399,7 +402,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;
@@ -419,7 +422,7 @@ unsigned long long __umoddi3(unsigned long long u, unsigned long long v)
}
/* XXX: fix tcc's code generator to do this instead */
long long __sardi3(long long a, int b)
long long __ashrdi3(long long a, int b)
{
#ifdef __TINYC__
DWunion u;
@@ -438,7 +441,7 @@ long long __sardi3(long long a, int b)
}
/* XXX: fix tcc's code generator to do this instead */
unsigned long long __shrdi3(unsigned long long a, int b)
unsigned long long __lshrdi3(unsigned long long a, int b)
{
#ifdef __TINYC__
DWunion u;
@@ -457,7 +460,7 @@ unsigned long long __shrdi3(unsigned long long a, int b)
}
/* XXX: fix tcc's code generator to do this instead */
long long __shldi3(long long a, int b)
long long __ashldi3(long long a, int b)
{
#ifdef __TINYC__
DWunion u;
@@ -466,7 +469,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;
@@ -482,8 +485,10 @@ unsigned short __tcc_fpu_control = 0x137f;
unsigned short __tcc_int_fpu_control = 0x137f | 0x0c00;
#endif
#endif /* !__x86_64__ */
/* XXX: fix tcc's code generator to do this instead */
float __ulltof(unsigned long long a)
float __floatundisf(unsigned long long a)
{
DWunion uu;
XFtype r;
@@ -498,7 +503,7 @@ float __ulltof(unsigned long long a)
}
}
double __ulltod(unsigned long long a)
double __floatundidf(unsigned long long a)
{
DWunion uu;
XFtype r;
@@ -513,7 +518,7 @@ double __ulltod(unsigned long long a)
}
}
long double __ulltold(unsigned long long a)
long double __floatundixf(unsigned long long a)
{
DWunion uu;
XFtype r;

2259
libtcc.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,12 @@
#ifndef LIBTCC_H
#define LIBTCC_H
#ifdef LIBTCC_AS_DLL
#define LIBTCCAPI __declspec(dllexport)
#else
#define LIBTCCAPI
#endif
#ifdef __cplusplus
extern "C" {
#endif
@@ -10,46 +16,46 @@ struct TCCState;
typedef struct TCCState TCCState;
/* create a new TCC compilation context */
TCCState *tcc_new(void);
LIBTCCAPI TCCState *tcc_new(void);
/* free a TCC compilation context */
void tcc_delete(TCCState *s);
LIBTCCAPI void tcc_delete(TCCState *s);
/* add debug information in the generated code */
void tcc_enable_debug(TCCState *s);
LIBTCCAPI void tcc_enable_debug(TCCState *s);
/* set error/warning display callback */
void tcc_set_error_func(TCCState *s, void *error_opaque,
LIBTCCAPI void tcc_set_error_func(TCCState *s, void *error_opaque,
void (*error_func)(void *opaque, const char *msg));
/* set/reset a warning */
int tcc_set_warning(TCCState *s, const char *warning_name, int value);
LIBTCCAPI int tcc_set_warning(TCCState *s, const char *warning_name, int value);
/*****************************/
/* preprocessor */
/* add include path */
int tcc_add_include_path(TCCState *s, const char *pathname);
LIBTCCAPI int tcc_add_include_path(TCCState *s, const char *pathname);
/* add in system include path */
int tcc_add_sysinclude_path(TCCState *s, const char *pathname);
LIBTCCAPI int tcc_add_sysinclude_path(TCCState *s, const char *pathname);
/* define preprocessor symbol 'sym'. Can put optional value */
void tcc_define_symbol(TCCState *s, const char *sym, const char *value);
LIBTCCAPI void tcc_define_symbol(TCCState *s, const char *sym, const char *value);
/* undefine preprocess symbol 'sym' */
void tcc_undefine_symbol(TCCState *s, const char *sym);
LIBTCCAPI void tcc_undefine_symbol(TCCState *s, const char *sym);
/*****************************/
/* compiling */
/* add a file (either a C file, dll, an object, a library or an ld
script). Return -1 if error. */
int tcc_add_file(TCCState *s, const char *filename);
LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename);
/* compile a string containing a C source. Return non zero if
error. */
int tcc_compile_string(TCCState *s, const char *buf);
LIBTCCAPI int tcc_compile_string(TCCState *s, const char *buf);
/*****************************/
/* linking commands */
@@ -60,35 +66,40 @@ 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 */
int tcc_set_output_type(TCCState *s, int output_type);
#define TCC_OUTPUT_PREPROCESS 4 /* preprocessed file (used internally) */
LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type);
#define TCC_OUTPUT_FORMAT_ELF 0 /* default output format: ELF */
#define TCC_OUTPUT_FORMAT_BINARY 1 /* binary image output */
#define TCC_OUTPUT_FORMAT_COFF 2 /* COFF */
/* equivalent to -Lpath option */
int tcc_add_library_path(TCCState *s, const char *pathname);
LIBTCCAPI int tcc_add_library_path(TCCState *s, const char *pathname);
/* the library name is the same as the argument of the '-l' option */
int tcc_add_library(TCCState *s, const char *libraryname);
LIBTCCAPI int tcc_add_library(TCCState *s, const char *libraryname);
/* add a symbol to the compiled program */
int tcc_add_symbol(TCCState *s, const char *name, unsigned long val);
LIBTCCAPI int tcc_add_symbol(TCCState *s, const char *name, void *val);
/* output an executable, library or object file. DO NOT call
tcc_relocate() before. */
int tcc_output_file(TCCState *s, const char *filename);
LIBTCCAPI int tcc_output_file(TCCState *s, const char *filename);
/* link and run main() function and return its value. DO NOT call
tcc_relocate() before. */
int tcc_run(TCCState *s, int argc, char **argv);
LIBTCCAPI int tcc_run(TCCState *s, int argc, char **argv);
/* do all relocations (needed before using tcc_get_symbol()). Return
non zero if link error. */
int tcc_relocate(TCCState *s);
/* copy code into memory passed in by the caller and do all relocations
(needed before using tcc_get_symbol()).
returns -1 on error and required size if ptr is NULL */
LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr);
/* return symbol value. return 0 if OK, -1 if symbol not found */
int tcc_get_symbol(TCCState *s, unsigned long *pval, const char *name);
/* return symbol value or NULL if not found */
LIBTCCAPI void *tcc_get_symbol(TCCState *s, const char *name);
/* set CONFIG_TCCDIR at runtime */
LIBTCCAPI void tcc_set_lib_path(TCCState *s, const char *path);
#ifdef __cplusplus
}

View File

@@ -1,15 +0,0 @@
#ifndef _STDARG_H
#define _STDARG_H
typedef char *va_list;
/* only correct for i386 */
#define va_start(ap,last) ap = ((char *)&(last)) + ((sizeof(last)+3)&~3)
#define va_arg(ap,type) (ap += (sizeof(type)+3)&~3, *(type *)(ap - ((sizeof(type)+3)&~3)))
#define va_end(ap)
/* fix a buggy dependency on GCC in libio.h */
typedef va_list __gnuc_va_list;
#define _VA_LIST_DEFINED
#endif

View File

@@ -16,11 +16,8 @@
@headings double
@end iftex
@c @ifhtml
@contents
@c @end ifhtml
@ifnothtml
@node Top, Introduction, (dir), (dir)
@top Tiny C Compiler Reference Documentation
@@ -29,10 +26,14 @@ This manual documents version @value{VERSION} of the Tiny C Compiler.
@menu
* Introduction:: Introduction to tcc.
* Invoke:: Invocation of tcc (command line, options).
* Clang:: ANSI C and extensions.
* asm:: Assembler syntax.
* linker:: Output file generation and supported targets.
* Bounds:: Automatic bounds-checking of C code.
* Libtcc:: The libtcc library.
* devel:: Guide for Developers.
@end menu
@end ifnothtml
@node Introduction
@chapter Introduction
@@ -42,7 +43,7 @@ compilers, it is meant to be self-relying: you do not need an
external assembler or linker because TCC does that for you.
TCC compiles so @emph{fast} that even for big projects @code{Makefile}s may
not be necessary.
not be necessary.
TCC not only supports ANSI C, but also most of the new ISO C99
standard and many GNUC extensions including inline assembly.
@@ -63,11 +64,11 @@ ports for the ARM (@code{arm-tcc}) and the TMS320C67xx targets
(@code{c67-tcc}). More information about the ARM port is available at
@url{http://lists.gnu.org/archive/html/tinycc-devel/2003-10/msg00044.html}.
For usage on Windows, see also tcc-win32.txt.
@node Invoke
@chapter Command line invocation
[This manual documents version @value{VERSION} of the Tiny C Compiler]
@section Quick start
@example
@@ -94,9 +95,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 +138,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 +154,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 +170,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
@@ -338,6 +347,7 @@ Fabrice Bellard
@end ignore
@node Clang
@chapter C language support
@section ANSI C
@@ -406,13 +416,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 +449,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 +482,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:
@@ -565,6 +579,7 @@ indicate that you use TCC.
@end itemize
@node asm
@chapter TinyCC Assembler
Since version 0.9.16, TinyCC integrates its own assembler. TinyCC
@@ -694,6 +709,7 @@ tries to guess it from the operand sizes.
Currently, MMX opcodes are supported but not SSE ones.
@node linker
@chapter TinyCC Linker
@cindex linker
@@ -721,14 +737,10 @@ libraries (.so).
@section PE-i386 file generation
@cindex PE-i386
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.
TCC for Windows supports the native Win32 executable file format (PE-i386). It
generates EXE files (console and gui) and DLL files.
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.
For usage on Windows, see also tcc-win32.txt.
@section GNU Linker Scripts
@cindex scripts, linker
@@ -839,6 +851,7 @@ The idea consists in giving a C string containing the program you want
to compile directly to @code{libtcc}. Then you can access to any global
symbol (function or variable) defined.
@node devel
@chapter Developer's guide
This chapter gives some hints to understand how TCC works. You can skip

10409
tcc.c

File diff suppressed because it is too large Load Diff

766
tcc.h Normal file
View File

@@ -0,0 +1,766 @@
/*
* TCC - Tiny C Compiler
*
* Copyright (c) 2001-2004 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#define _GNU_SOURCE
#include "config.h"
#ifdef CONFIG_TCCBOOT
#include "tccboot.h"
#define CONFIG_TCC_STATIC
#else
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <math.h>
#include <signal.h>
#include <fcntl.h>
#include <setjmp.h>
#include <time.h>
#ifdef _WIN32
#include <windows.h>
#include <sys/timeb.h>
#include <io.h> /* open, close etc. */
#include <direct.h> /* getcwd */
#define inline __inline
#define inp next_inp
#endif
#ifndef _WIN32
#include <unistd.h>
#include <sys/time.h>
#include <sys/ucontext.h>
#include <sys/mman.h>
#endif
#endif /* !CONFIG_TCCBOOT */
#ifndef PAGESIZE
#define PAGESIZE 4096
#endif
#include "elf.h"
#include "stab.h"
#ifndef O_BINARY
#define O_BINARY 0
#endif
#include "libtcc.h"
/* parser debug */
//#define PARSE_DEBUG
/* preprocessor debug */
//#define PP_DEBUG
/* include file debug */
//#define INC_DEBUG
//#define MEM_DEBUG
/* assembler debug */
//#define ASM_DEBUG
/* target selection */
//#define TCC_TARGET_I386 /* i386 code generator */
//#define TCC_TARGET_ARM /* ARMv4 code generator */
//#define TCC_TARGET_C67 /* TMS320C67xx code generator */
//#define TCC_TARGET_X86_64 /* x86-64 code generator */
/* default target is I386 */
#if !defined(TCC_TARGET_I386) && !defined(TCC_TARGET_ARM) && \
!defined(TCC_TARGET_C67) && !defined(TCC_TARGET_X86_64)
#define TCC_TARGET_I386
#endif
#if !defined(_WIN32) && !defined(TCC_UCLIBC) && !defined(TCC_TARGET_ARM) && \
!defined(TCC_TARGET_C67) && !defined(TCC_TARGET_X86_64)
#define CONFIG_TCC_BCHECK /* enable bound checking code */
#endif
#if defined(_WIN32) && !defined(TCC_TARGET_PE)
#define CONFIG_TCC_STATIC
#endif
/* define it to include assembler support */
#if !defined(TCC_TARGET_ARM) && !defined(TCC_TARGET_C67) && \
!defined(TCC_TARGET_X86_64)
#define CONFIG_TCC_ASM
#endif
/* object format selection */
#if defined(TCC_TARGET_C67)
#define TCC_TARGET_COFF
#endif
#if !defined(_WIN32) && !defined(CONFIG_TCCBOOT)
#define CONFIG_TCC_BACKTRACE
#endif
#define FALSE 0
#define false 0
#define TRUE 1
#define true 1
typedef int BOOL;
/* path to find crt1.o, crti.o and crtn.o. Only needed when generating
executables or dlls */
#define CONFIG_TCC_CRT_PREFIX CONFIG_SYSROOT "/usr/lib"
#define INCLUDE_STACK_SIZE 32
#define IFDEF_STACK_SIZE 64
#define VSTACK_SIZE 256
#define STRING_MAX_SIZE 1024
#define PACK_STACK_SIZE 8
#define TOK_HASH_SIZE 8192 /* must be a power of two */
#define TOK_ALLOC_INCR 512 /* must be a power of two */
#define TOK_MAX_SIZE 4 /* token max size in int unit when stored in string */
/* token symbol management */
typedef struct TokenSym {
struct TokenSym *hash_next;
struct Sym *sym_define; /* direct pointer to define */
struct Sym *sym_label; /* direct pointer to label */
struct Sym *sym_struct; /* direct pointer to structure */
struct Sym *sym_identifier; /* direct pointer to identifier */
int tok; /* token number */
int len;
char str[1];
} TokenSym;
#ifdef TCC_TARGET_PE
typedef unsigned short nwchar_t;
#else
typedef int nwchar_t;
#endif
typedef struct CString {
int size; /* size in bytes */
void *data; /* either 'char *' or 'nwchar_t *' */
int size_allocated;
void *data_allocated; /* if non NULL, data has been malloced */
} CString;
/* type definition */
typedef struct CType {
int t;
struct Sym *ref;
} CType;
/* constant value */
typedef union CValue {
long double ld;
double d;
float f;
int i;
unsigned int ui;
unsigned int ul; /* address (should be unsigned long on 64 bit cpu) */
long long ll;
unsigned long long ull;
struct CString *cstr;
void *ptr;
int tab[1];
} CValue;
/* value on stack */
typedef struct SValue {
CType type; /* type */
unsigned short r; /* register + flags */
unsigned short r2; /* second register, used for 'long long'
type. If not used, set to VT_CONST */
CValue c; /* constant, if VT_CONST */
struct Sym *sym; /* symbol, if (VT_SYM | VT_CONST) */
} SValue;
/* symbol management */
typedef struct Sym {
int v; /* symbol token */
long r; /* associated register */
long c; /* associated number */
CType type; /* associated type */
struct Sym *next; /* next related symbol */
struct Sym *prev; /* prev symbol in stack */
struct Sym *prev_tok; /* previous symbol for this token */
} Sym;
/* section definition */
/* XXX: use directly ELF structure for parameters ? */
/* special flag to indicate that the section should not be linked to
the other ones */
#define SHF_PRIVATE 0x80000000
/* special flag, too */
#define SECTION_ABS ((void *)1)
typedef struct Section {
unsigned long data_offset; /* current data offset */
unsigned char *data; /* section data */
unsigned long data_allocated; /* used for realloc() handling */
int sh_name; /* elf section name (only used during output) */
int sh_num; /* elf section number */
int sh_type; /* elf section type */
int sh_flags; /* elf section flags */
int sh_info; /* elf section info */
int sh_addralign; /* elf section alignment */
int sh_entsize; /* elf entry size */
unsigned long sh_size; /* section size (only used during output) */
unsigned long sh_addr; /* address at which the section is relocated */
unsigned long sh_offset; /* file offset */
int nb_hashed_syms; /* used to resize the hash table */
struct Section *link; /* link to another section */
struct Section *reloc; /* corresponding section for relocation, if any */
struct Section *hash; /* hash table for symbols */
struct Section *next;
char name[1]; /* section name */
} Section;
typedef struct DLLReference {
int level;
void *handle;
char name[1];
} DLLReference;
/* GNUC attribute definition */
typedef struct AttributeDef {
int aligned;
int packed;
Section *section;
int func_attr; /* calling convention, exports, ... */
} AttributeDef;
/* -------------------------------------------------- */
/* gr: wrappers for casting sym->r for other purposes */
typedef struct {
unsigned
func_call : 8,
func_args : 8,
func_export : 1;
} func_attr_t;
#define FUNC_CALL(r) (((func_attr_t*)&(r))->func_call)
#define FUNC_EXPORT(r) (((func_attr_t*)&(r))->func_export)
#define FUNC_ARGS(r) (((func_attr_t*)&(r))->func_args)
#define INLINE_DEF(r) (*(int **)&(r))
/* -------------------------------------------------- */
#define SYM_STRUCT 0x40000000 /* struct/union/enum symbol space */
#define SYM_FIELD 0x20000000 /* struct/union field symbol space */
#define SYM_FIRST_ANOM 0x10000000 /* first anonymous sym */
/* stored in 'Sym.c' field */
#define FUNC_NEW 1 /* ansi function prototype */
#define FUNC_OLD 2 /* old function prototype */
#define FUNC_ELLIPSIS 3 /* ansi function prototype with ... */
/* stored in 'Sym.r' field */
#define FUNC_CDECL 0 /* standard c call */
#define FUNC_STDCALL 1 /* pascal c call */
#define FUNC_FASTCALL1 2 /* first param in %eax */
#define FUNC_FASTCALL2 3 /* first parameters in %eax, %edx */
#define FUNC_FASTCALL3 4 /* first parameter in %eax, %edx, %ecx */
#define FUNC_FASTCALLW 5 /* first parameter in %ecx, %edx */
/* field 'Sym.t' for macros */
#define MACRO_OBJ 0 /* object like macro */
#define MACRO_FUNC 1 /* function like macro */
/* field 'Sym.r' for C labels */
#define LABEL_DEFINED 0 /* label is defined */
#define LABEL_FORWARD 1 /* label is forward defined */
#define LABEL_DECLARED 2 /* label is declared but never used */
/* type_decl() types */
#define TYPE_ABSTRACT 1 /* type without variable */
#define TYPE_DIRECT 2 /* type with variable */
#define IO_BUF_SIZE 8192
typedef struct BufferedFile {
uint8_t *buf_ptr;
uint8_t *buf_end;
int fd;
int line_num; /* current line number - here to simplify code */
int ifndef_macro; /* #ifndef macro / #endif search */
int ifndef_macro_saved; /* saved ifndef_macro */
int *ifdef_stack_ptr; /* ifdef_stack value at the start of the file */
char inc_type; /* type of include */
char inc_filename[512]; /* filename specified by the user */
char filename[1024]; /* current filename - here to simplify code */
unsigned char buffer[IO_BUF_SIZE + 1]; /* extra size for CH_EOB char */
} BufferedFile;
#define CH_EOB '\\' /* end of buffer or '\0' char in file */
#define CH_EOF (-1) /* end of file */
/* parsing state (used to save parser state to reparse part of the
source several times) */
typedef struct ParseState {
int *macro_ptr;
int line_num;
int tok;
CValue tokc;
} ParseState;
/* used to record tokens */
typedef struct TokenString {
int *str;
int len;
int allocated_len;
int last_line_num;
} TokenString;
/* include file cache, used to find files faster and also to eliminate
inclusion if the include file is protected by #ifndef ... #endif */
typedef struct CachedInclude {
int ifndef_macro;
int hash_next; /* -1 if none */
char type; /* '"' or '>' to give include type */
char filename[1]; /* path specified in #include */
} CachedInclude;
#define CACHED_INCLUDES_HASH_SIZE 512
#ifdef CONFIG_TCC_ASM
typedef struct ExprValue {
uint32_t v;
Sym *sym;
} ExprValue;
#define MAX_ASM_OPERANDS 30
typedef struct ASMOperand {
int id; /* GCC 3 optionnal identifier (0 if number only supported */
char *constraint;
char asm_str[16]; /* computed asm string for operand */
SValue *vt; /* C value of the expression */
int ref_index; /* if >= 0, gives reference to a output constraint */
int input_index; /* if >= 0, gives reference to an input constraint */
int priority; /* priority, used to assign registers */
int reg; /* if >= 0, register number used for this operand */
int is_llong; /* true if double register value */
int is_memory; /* true if memory operand */
int is_rw; /* for '+' modifier */
} ASMOperand;
#endif
struct TCCState {
int output_type;
BufferedFile **include_stack_ptr;
int *ifdef_stack_ptr;
/* include file handling */
char **include_paths;
int nb_include_paths;
char **sysinclude_paths;
int nb_sysinclude_paths;
CachedInclude **cached_includes;
int nb_cached_includes;
char **library_paths;
int nb_library_paths;
/* array of all loaded dlls (including those referenced by loaded
dlls) */
DLLReference **loaded_dlls;
int nb_loaded_dlls;
/* sections */
Section **sections;
int nb_sections; /* number of sections, including first dummy section */
Section **priv_sections;
int nb_priv_sections; /* number of private sections */
/* got handling */
Section *got;
Section *plt;
unsigned long *got_offsets;
int nb_got_offsets;
/* give the correspondance from symtab indexes to dynsym indexes */
int *symtab_to_dynsym;
/* temporary dynamic symbol sections (for dll loading) */
Section *dynsymtab_section;
/* exported dynamic symbol section */
Section *dynsym;
int nostdinc; /* if true, no standard headers are added */
int nostdlib; /* if true, no standard libraries are added */
int nocommon; /* if true, do not use common symbols for .bss data */
/* if true, static linking is performed */
int static_link;
/* soname as specified on the command line (-soname) */
const char *soname;
/* if true, all symbols are exported */
int rdynamic;
/* if true, only link in referenced objects from archive */
int alacarte_link;
/* address of text section */
unsigned long text_addr;
int has_text_addr;
/* output format, see TCC_OUTPUT_FORMAT_xxx */
int output_format;
/* C language options */
int char_is_unsigned;
int leading_underscore;
/* warning switches */
int warn_write_strings;
int warn_unsupported;
int warn_error;
int warn_none;
int warn_implicit_function_declaration;
/* display some information during compilation */
int verbose;
/* compile with debug symbol (and use them if error during execution) */
int do_debug;
/* compile with built-in memory and bounds checker */
int do_bounds_check;
/* give the path of the tcc libraries */
const char *tcc_lib_path;
/* error handling */
void *error_opaque;
void (*error_func)(void *opaque, const char *msg);
int error_set_jmp_enabled;
jmp_buf error_jmp_buf;
int nb_errors;
/* tiny assembler state */
Sym *asm_labels;
/* see include_stack_ptr */
BufferedFile *include_stack[INCLUDE_STACK_SIZE];
/* see ifdef_stack_ptr */
int ifdef_stack[IFDEF_STACK_SIZE];
/* see cached_includes */
int cached_includes_hash[CACHED_INCLUDES_HASH_SIZE];
/* pack stack */
int pack_stack[PACK_STACK_SIZE];
int *pack_stack_ptr;
/* output file for preprocessing */
FILE *outfile;
/* for tcc_relocate */
int runtime_added;
#ifdef TCC_TARGET_X86_64
/* write PLT and GOT here */
char *runtime_plt_and_got;
unsigned int runtime_plt_and_got_offset;
#endif
};
/* The current value can be: */
#define VT_VALMASK 0x00ff
#define VT_CONST 0x00f0 /* constant in vc
(must be first non register value) */
#define VT_LLOCAL 0x00f1 /* lvalue, offset on stack */
#define VT_LOCAL 0x00f2 /* offset on stack */
#define VT_CMP 0x00f3 /* the value is stored in processor flags (in vc) */
#define VT_JMP 0x00f4 /* value is the consequence of jmp true (even) */
#define VT_JMPI 0x00f5 /* value is the consequence of jmp false (odd) */
#define VT_LVAL 0x0100 /* var is an lvalue */
#define VT_SYM 0x0200 /* a symbol value is added */
#define VT_MUSTCAST 0x0400 /* value must be casted to be correct (used for
char/short stored in integer registers) */
#define VT_MUSTBOUND 0x0800 /* bound checking must be done before
dereferencing value */
#define VT_BOUNDED 0x8000 /* value is bounded. The address of the
bounding function call point is in vc */
#define VT_LVAL_BYTE 0x1000 /* lvalue is a byte */
#define VT_LVAL_SHORT 0x2000 /* lvalue is a short */
#define VT_LVAL_UNSIGNED 0x4000 /* lvalue is unsigned */
#define VT_LVAL_TYPE (VT_LVAL_BYTE | VT_LVAL_SHORT | VT_LVAL_UNSIGNED)
/* types */
#define VT_INT 0 /* integer type */
#define VT_BYTE 1 /* signed byte type */
#define VT_SHORT 2 /* short type */
#define VT_VOID 3 /* void type */
#define VT_PTR 4 /* pointer */
#define VT_ENUM 5 /* enum definition */
#define VT_FUNC 6 /* function type */
#define VT_STRUCT 7 /* struct/union definition */
#define VT_FLOAT 8 /* IEEE float */
#define VT_DOUBLE 9 /* IEEE double */
#define VT_LDOUBLE 10 /* IEEE long double */
#define VT_BOOL 11 /* ISOC99 boolean type */
#define VT_LLONG 12 /* 64 bit integer */
#define VT_LONG 13 /* long integer (NEVER USED as type, only
during parsing) */
#define VT_BTYPE 0x000f /* mask for basic type */
#define VT_UNSIGNED 0x0010 /* unsigned type */
#define VT_ARRAY 0x0020 /* array type (also has VT_PTR) */
#define VT_BITFIELD 0x0040 /* bitfield modifier */
#define VT_CONSTANT 0x0800 /* const modifier */
#define VT_VOLATILE 0x1000 /* volatile modifier */
#define VT_SIGNED 0x2000 /* signed type */
/* storage */
#define VT_EXTERN 0x00000080 /* extern definition */
#define VT_STATIC 0x00000100 /* static variable */
#define VT_TYPEDEF 0x00000200 /* typedef definition */
#define VT_INLINE 0x00000400 /* inline definition */
#define VT_STRUCT_SHIFT 16 /* shift for bitfield shift values */
/* type mask (except storage) */
#define VT_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE)
#define VT_TYPE (~(VT_STORAGE))
/* token values */
/* warning: the following compare tokens depend on i386 asm code */
#define TOK_ULT 0x92
#define TOK_UGE 0x93
#define TOK_EQ 0x94
#define TOK_NE 0x95
#define TOK_ULE 0x96
#define TOK_UGT 0x97
#define TOK_Nset 0x98
#define TOK_Nclear 0x99
#define TOK_LT 0x9c
#define TOK_GE 0x9d
#define TOK_LE 0x9e
#define TOK_GT 0x9f
#define TOK_LAND 0xa0
#define TOK_LOR 0xa1
#define TOK_DEC 0xa2
#define TOK_MID 0xa3 /* inc/dec, to void constant */
#define TOK_INC 0xa4
#define TOK_UDIV 0xb0 /* unsigned division */
#define TOK_UMOD 0xb1 /* unsigned modulo */
#define TOK_PDIV 0xb2 /* fast division with undefined rounding for pointers */
#define TOK_CINT 0xb3 /* number in tokc */
#define TOK_CCHAR 0xb4 /* char constant in tokc */
#define TOK_STR 0xb5 /* pointer to string in tokc */
#define TOK_TWOSHARPS 0xb6 /* ## preprocessing token */
#define TOK_LCHAR 0xb7
#define TOK_LSTR 0xb8
#define TOK_CFLOAT 0xb9 /* float constant */
#define TOK_LINENUM 0xba /* line number info */
#define TOK_CDOUBLE 0xc0 /* double constant */
#define TOK_CLDOUBLE 0xc1 /* long double constant */
#define TOK_UMULL 0xc2 /* unsigned 32x32 -> 64 mul */
#define TOK_ADDC1 0xc3 /* add with carry generation */
#define TOK_ADDC2 0xc4 /* add with carry use */
#define TOK_SUBC1 0xc5 /* add with carry generation */
#define TOK_SUBC2 0xc6 /* add with carry use */
#define TOK_CUINT 0xc8 /* unsigned int constant */
#define TOK_CLLONG 0xc9 /* long long constant */
#define TOK_CULLONG 0xca /* unsigned long long constant */
#define TOK_ARROW 0xcb
#define TOK_DOTS 0xcc /* three dots */
#define TOK_SHR 0xcd /* unsigned shift right */
#define TOK_PPNUM 0xce /* preprocessor number */
#define TOK_SHL 0x01 /* shift left */
#define TOK_SAR 0x02 /* signed shift right */
/* assignement operators : normal operator or 0x80 */
#define TOK_A_MOD 0xa5
#define TOK_A_AND 0xa6
#define TOK_A_MUL 0xaa
#define TOK_A_ADD 0xab
#define TOK_A_SUB 0xad
#define TOK_A_DIV 0xaf
#define TOK_A_XOR 0xde
#define TOK_A_OR 0xfc
#define TOK_A_SHL 0x81
#define TOK_A_SAR 0x82
#ifndef offsetof
#define offsetof(type, field) ((size_t) &((type *)0)->field)
#endif
#ifndef countof
#define countof(tab) (sizeof(tab) / sizeof((tab)[0]))
#endif
#define TOK_EOF (-1) /* end of file */
#define TOK_LINEFEED 10 /* line feed */
/* all identificators and strings have token above that */
#define TOK_IDENT 256
/* only used for i386 asm opcodes definitions */
#define DEF_ASM(x) DEF(TOK_ASM_ ## x, #x)
#define DEF_BWL(x) \
DEF(TOK_ASM_ ## x ## b, #x "b") \
DEF(TOK_ASM_ ## x ## w, #x "w") \
DEF(TOK_ASM_ ## x ## l, #x "l") \
DEF(TOK_ASM_ ## x, #x)
#define DEF_WL(x) \
DEF(TOK_ASM_ ## x ## w, #x "w") \
DEF(TOK_ASM_ ## x ## l, #x "l") \
DEF(TOK_ASM_ ## x, #x)
#define DEF_FP1(x) \
DEF(TOK_ASM_ ## f ## x ## s, "f" #x "s") \
DEF(TOK_ASM_ ## fi ## x ## l, "fi" #x "l") \
DEF(TOK_ASM_ ## f ## x ## l, "f" #x "l") \
DEF(TOK_ASM_ ## fi ## x ## s, "fi" #x "s")
#define DEF_FP(x) \
DEF(TOK_ASM_ ## f ## x, "f" #x ) \
DEF(TOK_ASM_ ## f ## x ## p, "f" #x "p") \
DEF_FP1(x)
#define DEF_ASMTEST(x) \
DEF_ASM(x ## o) \
DEF_ASM(x ## no) \
DEF_ASM(x ## b) \
DEF_ASM(x ## c) \
DEF_ASM(x ## nae) \
DEF_ASM(x ## nb) \
DEF_ASM(x ## nc) \
DEF_ASM(x ## ae) \
DEF_ASM(x ## e) \
DEF_ASM(x ## z) \
DEF_ASM(x ## ne) \
DEF_ASM(x ## nz) \
DEF_ASM(x ## be) \
DEF_ASM(x ## na) \
DEF_ASM(x ## nbe) \
DEF_ASM(x ## a) \
DEF_ASM(x ## s) \
DEF_ASM(x ## ns) \
DEF_ASM(x ## p) \
DEF_ASM(x ## pe) \
DEF_ASM(x ## np) \
DEF_ASM(x ## po) \
DEF_ASM(x ## l) \
DEF_ASM(x ## nge) \
DEF_ASM(x ## nl) \
DEF_ASM(x ## ge) \
DEF_ASM(x ## le) \
DEF_ASM(x ## ng) \
DEF_ASM(x ## nle) \
DEF_ASM(x ## g)
#define TOK_ASM_int TOK_INT
enum tcc_token {
TOK_LAST = TOK_IDENT - 1,
#define DEF(id, str) id,
#include "tcctok.h"
#undef DEF
};
#define TOK_UIDENT TOK_DEFINE
#ifdef _WIN32
#define snprintf _snprintf
#define vsnprintf _vsnprintf
#ifndef __GNUC__
#define strtold (long double)strtod
#define strtof (float)strtod
#define strtoll (long long)strtol
#endif
#elif defined(TCC_UCLIBC) || defined(__FreeBSD__) || defined(__DragonFly__) \
|| defined(__OpenBSD__)
/* currently incorrect */
long double strtold(const char *nptr, char **endptr)
{
return (long double)strtod(nptr, endptr);
}
float strtof(const char *nptr, char **endptr)
{
return (float)strtod(nptr, endptr);
}
#else
/* XXX: need to define this to use them in non ISOC99 context */
extern float strtof (const char *__nptr, char **__endptr);
extern long double strtold (const char *__nptr, char **__endptr);
#endif
#ifdef _WIN32
#define IS_PATHSEP(c) (c == '/' || c == '\\')
#define IS_ABSPATH(p) (IS_PATHSEP(p[0]) || (p[0] && p[1] == ':' && IS_PATHSEP(p[2])))
#define PATHCMP stricmp
#else
#define IS_PATHSEP(c) (c == '/')
#define IS_ABSPATH(p) IS_PATHSEP(p[0])
#define PATHCMP strcmp
#endif
void error(const char *fmt, ...);
void error_noabort(const char *fmt, ...);
void warning(const char *fmt, ...);
void tcc_set_lib_path_w32(TCCState *s);
int tcc_set_flag(TCCState *s, const char *flag_name, int value);
void tcc_print_stats(TCCState *s, int64_t total_time);
void tcc_free(void *ptr);
void *tcc_malloc(unsigned long size);
void *tcc_mallocz(unsigned long size);
void *tcc_realloc(void *ptr, unsigned long size);
char *tcc_strdup(const char *str);
char *tcc_basename(const char *name);
char *tcc_fileextension (const char *name);
char *pstrcpy(char *buf, int buf_size, const char *s);
char *pstrcat(char *buf, int buf_size, const char *s);
void dynarray_add(void ***ptab, int *nb_ptr, void *data);
void dynarray_reset(void *pp, int *n);
#ifdef CONFIG_TCC_BACKTRACE
extern int num_callers;
extern const char **rt_bound_error_msg;
#endif
/* true if float/double/long double type */
static inline int is_float(int t)
{
int bt;
bt = t & VT_BTYPE;
return bt == VT_LDOUBLE || bt == VT_DOUBLE || bt == VT_FLOAT;
}
/* space exlcuding newline */
static inline int is_space(int ch)
{
return ch == ' ' || ch == '\t' || ch == '\v' || ch == '\f' || ch == '\r';
}

View File

@@ -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;
}
}
}
}

View File

@@ -84,6 +84,8 @@ int tcc_output_coff(TCCState *s1, FILE *f)
Section *stext, *sdata, *sbss;
int i, NSectionsToOutput = 0;
Coff_str_table = pCoff_str_table = NULL;
stext = FindSection(s1, ".text");
sdata = FindSection(s1, ".data");
sbss = FindSection(s1, ".bss");
@@ -183,7 +185,7 @@ int tcc_output_coff(TCCState *s1, FILE *f)
coff_sec->s_nlnno = 0;
coff_sec->s_lnnoptr = 0;
if (do_debug && tcc_sect == stext) {
if (s1->do_debug && tcc_sect == stext) {
// count how many line nos data
// also find association between source file name and function
@@ -311,7 +313,7 @@ int tcc_output_coff(TCCState *s1, FILE *f)
file_hdr.f_symptr = file_pointer; /* file pointer to symtab */
if (do_debug)
if (s1->do_debug)
file_hdr.f_nsyms = coff_nb_syms; /* number of symtab entries */
else
file_hdr.f_nsyms = 0;
@@ -362,7 +364,7 @@ int tcc_output_coff(TCCState *s1, FILE *f)
// group the symbols in order of filename, func1, func2, etc
// finally global symbols
if (do_debug)
if (s1->do_debug)
SortSymbolTable();
// write line no data
@@ -371,7 +373,7 @@ int tcc_output_coff(TCCState *s1, FILE *f)
coff_sec = &section_header[i];
tcc_sect = s1->sections[i];
if (do_debug && tcc_sect == stext) {
if (s1->do_debug && tcc_sect == stext) {
// count how many line nos data
@@ -499,7 +501,7 @@ int tcc_output_coff(TCCState *s1, FILE *f)
}
// write symbol table
if (do_debug) {
if (s1->do_debug) {
int k;
struct syment csym;
AUXFUNC auxfunc;
@@ -670,7 +672,7 @@ int tcc_output_coff(TCCState *s1, FILE *f)
}
}
if (do_debug) {
if (s1->do_debug) {
// write string table
// first write the size
@@ -940,7 +942,7 @@ int tcc_load_coff(TCCState * s1, int fd)
if (name[0] == '_' && strcmp(name, "_main") != 0)
name++;
tcc_add_symbol(s1, name, csym.n_value);
tcc_add_symbol(s1, name, (void*)csym.n_value);
}
// skip any aux records

1006
tccelf.c

File diff suppressed because it is too large Load Diff

5122
tccgen.c Normal file

File diff suppressed because it is too large Load Diff

1989
tccpe.c

File diff suppressed because it is too large Load Diff

2935
tccpp.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -101,11 +101,21 @@
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__")
DEF(TOK_builtin_types_compatible_p, "__builtin_types_compatible_p")
DEF(TOK_builtin_constant_p, "__builtin_constant_p")
DEF(TOK_builtin_frame_address, "__builtin_frame_address")
#ifdef TCC_TARGET_X86_64
DEF(TOK_builtin_malloc, "__builtin_malloc")
DEF(TOK_builtin_free, "__builtin_free")
DEF(TOK_malloc, "malloc")
DEF(TOK_free, "free")
#endif
DEF(TOK_REGPARM1, "regparm")
DEF(TOK_REGPARM2, "__regparm__")
@@ -118,28 +128,48 @@
#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")
DEF(TOK___aeabi_ldivmod, "__aeabi_ldivmod")
DEF(TOK___aeabi_uldivmod, "__aeabi_uldivmod")
#else
DEF(TOK_memcpy, "memcpy")
DEF(TOK_memset, "memset")
DEF(TOK_alloca, "alloca")
DEF(TOK___divdi3, "__divdi3")
DEF(TOK___moddi3, "__moddi3")
DEF(TOK___udivdi3, "__udivdi3")
DEF(TOK___umoddi3, "__umoddi3")
#endif
#if defined(TCC_TARGET_ARM)
DEF(TOK___divsi3, "__divsi3")
#ifdef TCC_ARM_EABI
DEF(TOK___aeabi_idivmod, "__aeabi_idivmod")
DEF(TOK___aeabi_uidivmod, "__aeabi_uidivmod")
DEF(TOK___divsi3, "__aeabi_idiv")
DEF(TOK___udivsi3, "__aeabi_uidiv")
DEF(TOK___floatdisf, "__aeabi_l2f")
DEF(TOK___floatdidf, "__aeabi_l2d")
DEF(TOK___fixsfdi, "__aeabi_f2lz")
DEF(TOK___fixdfdi, "__aeabi_d2lz")
#else
DEF(TOK___modsi3, "__modsi3")
DEF(TOK___udivsi3, "__udivsi3")
DEF(TOK___umodsi3, "__umodsi3")
DEF(TOK___sardi3, "__ashrdi3")
DEF(TOK___shrdi3, "__lshrdi3")
DEF(TOK___shldi3, "__ashldi3")
DEF(TOK___slltold, "__slltold")
DEF(TOK___divsi3, "__divsi3")
DEF(TOK___udivsi3, "__udivsi3")
DEF(TOK___floatdisf, "__floatdisf")
DEF(TOK___floatdidf, "__floatdidf")
#ifndef TCC_ARM_VFP
DEF(TOK___floatdixf, "__floatdixf")
DEF(TOK___fixunssfsi, "__fixunssfsi")
DEF(TOK___fixunsdfsi, "__fixunsdfsi")
DEF(TOK___fixunsxfsi, "__fixunsxfsi")
DEF(TOK___fixxfdi, "__fixxfdi")
#endif
DEF(TOK___fixsfdi, "__fixsfdi")
DEF(TOK___fixdfdi, "__fixdfdi")
DEF(TOK___fixxfdi, "__fixxfdi")
#endif
#elif defined(TCC_TARGET_C67)
DEF(TOK__divi, "_divi")
DEF(TOK__divu, "_divu")
@@ -147,24 +177,35 @@
DEF(TOK__divd, "_divd")
DEF(TOK__remi, "_remi")
DEF(TOK__remu, "_remu")
DEF(TOK___sardi3, "__sardi3")
DEF(TOK___shrdi3, "__shrdi3")
DEF(TOK___shldi3, "__shldi3")
#else
/* XXX: same names on i386 ? */
DEF(TOK___sardi3, "__sardi3")
DEF(TOK___shrdi3, "__shrdi3")
DEF(TOK___shldi3, "__shldi3")
#endif
#ifdef TCC_TARGET_I386
DEF(TOK___tcc_int_fpu_control, "__tcc_int_fpu_control")
DEF(TOK___tcc_fpu_control, "__tcc_fpu_control")
DEF(TOK___ulltof, "__ulltof")
DEF(TOK___ulltod, "__ulltod")
DEF(TOK___ulltold, "__ulltold")
#endif
#ifdef TCC_ARM_EABI
DEF(TOK___ashrdi3, "__aeabi_lasr")
DEF(TOK___lshrdi3, "__aeabi_llsr")
DEF(TOK___ashldi3, "__aeabi_llsl")
DEF(TOK___floatundisf, "__aeabi_ul2f")
DEF(TOK___floatundidf, "__aeabi_ul2d")
DEF(TOK___fixunssfdi, "__aeabi_f2ulz")
DEF(TOK___fixunsdfdi, "__aeabi_d2ulz")
#else
DEF(TOK___ashrdi3, "__ashrdi3")
DEF(TOK___lshrdi3, "__lshrdi3")
DEF(TOK___ashldi3, "__ashldi3")
DEF(TOK___floatundisf, "__floatundisf")
DEF(TOK___floatundidf, "__floatundidf")
#ifndef TCC_ARM_VFP
DEF(TOK___floatundixf, "__floatundixf")
DEF(TOK___fixunsxfdi, "__fixunsxfdi")
#endif
DEF(TOK___fixunssfdi, "__fixunssfdi")
DEF(TOK___fixunsdfdi, "__fixunsdfdi")
DEF(TOK___fixunsxfdi, "__fixunsxfdi")
#endif
#ifdef TCC_TARGET_PE
DEF(TOK___chkstk, "__chkstk")
#endif
/* bound checking symbols */
#ifdef CONFIG_TCC_BCHECK
@@ -177,14 +218,17 @@
DEF(TOK___bound_ptr_indir16, "__bound_ptr_indir16")
DEF(TOK___bound_local_new, "__bound_local_new")
DEF(TOK___bound_local_delete, "__bound_local_delete")
#if 0
DEF(TOK_malloc, "malloc")
DEF(TOK_free, "free")
DEF(TOK_realloc, "realloc")
DEF(TOK_memalign, "memalign")
DEF(TOK_calloc, "calloc")
#endif
DEF(TOK_memmove, "memmove")
DEF(TOK_strlen, "strlen")
DEF(TOK_strcpy, "strcpy")
DEF(TOK_alloca, "alloca")
#endif
/* Tiny Assembler */

145
tests/Makefile Normal file
View File

@@ -0,0 +1,145 @@
#
# Tiny C Compiler Makefile - tests
#
# what tests to run
TESTS = libtest test3
# these should work too
# TESTS += test1 test2 speed
# these don't work as they should
# TESTS += test4 btest asmtest
TOP = ..
include $(TOP)/Makefile
# run local version of tcc with local libraries and includes
TCC = ../tcc -B..
RUN_TCC = $(NATIVE_TARGET) -run ../tcc.c -B..
DISAS=objdump -d
all test : $(TESTS)
# make sure that tcc exists
$(TESTS) : ../tcc
../tcc ../libtcc.a :
$(MAKE) -C ..
# libtcc test
libtest: libtcc_test$(EXESUF)
@echo ------------ $@ ------------
./libtcc_test lib_path=..
libtcc_test$(EXESUF): libtcc_test.c ../libtcc.a
$(CC) -o $@ $^ -I.. $(CFLAGS) $(LIBS)
# test.ref - generate using gcc
test.ref: tcctest.c
cp -u ../include/tcclib.h .
$(CC) -o tcctest.gcc $< -I. -w $(CFLAGS)
./tcctest.gcc > $@
# auto test
test1: test.ref
@echo ------------ $@ ------------
$(TCC) -run tcctest.c > test.out1
@if diff -u test.ref test.out1 ; then echo "Auto Test OK"; fi
# iterated test2 (compile tcc then compile tcctest.c !)
test2: test.ref
@echo ------------ $@ ------------
$(TCC) $(RUN_TCC) $(RUN_TCC) -run tcctest.c > test.out2
@if diff -u test.ref test.out2 ; then echo "Auto Test2 OK"; fi
# iterated test3 (compile tcc then compile tcc then compile tcctest.c !)
test3: test.ref
@echo ------------ $@ ------------
$(TCC) $(RUN_TCC) $(RUN_TCC) $(RUN_TCC) -run tcctest.c > test.out3
@if diff -u test.ref test.out3 ; then echo "Auto Test3 OK"; fi
# binary output test
test4: test.ref
@echo ------------ $@ ------------
# dynamic output
$(TCC) -o tcctest1 tcctest.c
./tcctest1 > test1.out
@if diff -u test.ref test1.out ; then echo "Dynamic Auto Test OK"; fi
# object + link output
$(TCC) -c -o tcctest3.o tcctest.c
$(TCC) -o tcctest3 tcctest3.o
./tcctest3 > test3.out
@if diff -u test.ref test3.out ; then echo "Object Auto Test OK"; fi
# static output
$(TCC) -static -o tcctest2 tcctest.c
./tcctest2 > test2.out
@if diff -u test.ref test2.out ; then echo "Static Auto Test OK"; fi
# dynamic output + bound check
$(TCC) -b -o tcctest4 tcctest.c
./tcctest4 > test4.out
@if diff -u test.ref test4.out ; then echo "BCheck Auto Test OK"; fi
# memory and bound check auto test
BOUNDS_OK = 1 4 8 10
BOUNDS_FAIL= 2 5 7 9 11 12 13
btest: boundtest.c
@echo ------------ $@ ------------
@for i in $(BOUNDS_OK); do \
if $(TCC) -b -run boundtest.c $$i ; then \
/bin/true ; \
else\
echo Failed positive test $$i ; exit 1 ; \
fi ;\
done ;\
for i in $(BOUNDS_FAIL); do \
if $(TCC) -b -run boundtest.c $$i ; then \
echo Failed negative test $$i ; exit 1 ;\
else\
/bin/true ; \
fi ;\
done ;\
echo Bound test OK
# speed test
speed: ex2 ex3
@echo ------------ $@ ------------
time ./ex2 1238 2 3 4 10 13 4
time $(TCC) -run ../examples/ex2.c 1238 2 3 4 10 13 4
time ./ex3 35
time $(TCC) -run ../examples/ex3.c 35
ex%: ../examples/ex%.c
$(CC) -o $@ $< $(CFLAGS)
# tiny assembler testing
asmtest.ref: asmtest.S
$(CC) -o asmtest.ref.o -c asmtest.S
objdump -D asmtest.ref.o > $@
asmtest: asmtest.ref
@echo ------------ $@ ------------
$(TCC) -c asmtest.S
objdump -D asmtest.o > $@
@if diff -u --ignore-matching-lines="file format" asmtest.ref asmtest.out ; then echo "ASM Auto Test OK"; fi
# targets for development
%.bin: %.c tcc
$(TCC) -g -o $@ $<
$(DISAS) $@
instr: instr.o
objdump -d instr.o
instr.o: instr.S
$(CC) -o $@ -c $< -O2 -Wall -g
cache: tcc_g
cachegrind ./tcc_g -o /tmp/linpack -lm bench/linpack.c
vg_annotate tcc.c > /tmp/linpack.cache.log
# clean
clean:
rm -vf *~ *.o *.a *.bin *.i *.ref *.out *.out? *.gcc \
tcctest[1234] ex? libtcc_test$(EXESUF) tcc_g tcclib.h

0
gcctestsuite.sh → tests/gcctestsuite.sh Executable file → Normal file
View File

View File

@@ -5,6 +5,7 @@
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "libtcc.h"
@@ -14,7 +15,7 @@ int add(int a, int b)
return a + b;
}
char my_program[] =
char my_program[] =
"int fib(int n)\n"
"{\n"
" if (n <= 2)\n"
@@ -35,31 +36,49 @@ int main(int argc, char **argv)
{
TCCState *s;
int (*func)(int);
unsigned long val;
void *mem;
int size;
s = tcc_new();
if (!s) {
fprintf(stderr, "Could not create tcc state\n");
exit(1);
}
/* MUST BE CALLED before any compilation or file loading */
/* if tcclib.h and libtcc1.a are not installed, where can we find them */
if (argc == 2 && !memcmp(argv[1], "lib_path=",9))
tcc_set_lib_path(s, argv[1]+9);
/* MUST BE CALLED before any compilation */
tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
tcc_compile_string(s, my_program);
if (tcc_compile_string(s, my_program) == -1)
return 1;
/* as a test, we add a symbol that the compiled program can be
linked with. You can have a similar result by opening a dll
with tcc_add_dll(() and using its symbols directly. */
tcc_add_symbol(s, "add", (unsigned long)&add);
tcc_relocate(s);
/* as a test, we add a symbol that the compiled program can use.
You may also open a dll with tcc_add_dll() and use symbols from that */
tcc_add_symbol(s, "add", add);
tcc_get_symbol(s, &val, "foo");
func = (void *)val;
/* get needed size of the code */
size = tcc_relocate(s, NULL);
if (size == -1)
return 1;
/* allocate memory and copy the code into it */
mem = malloc(size);
tcc_relocate(s, mem);
/* get entry symbol */
func = tcc_get_symbol(s, "foo");
if (!func)
return 1;
/* delete the state */
tcc_delete(s);
/* run the code */
func(32);
tcc_delete(s);
free(mem);
return 0;
}

View File

@@ -1,7 +1,7 @@
/*
* TCC auto test program
*/
#include "config.h"
#include "../config.h"
#if GCC_MAJOR >= 3
@@ -70,10 +70,12 @@ void bitfield_test(void);
void c99_bool_test(void);
void float_test(void);
void longlong_test(void);
void manyarg_test(void);
void stdarg_test(void);
void whitespace_test(void);
void relocation_test(void);
void old_style_function(void);
void alloca_test(void);
void sizeof_test(void);
void typeof_test(void);
void local_label_test(void);
@@ -223,7 +225,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
@@ -311,7 +313,7 @@ test\14\
void string_test()
{
int b;
unsigned int b;
printf("string:\n");
printf("\141\1423\143\n");/* dezdez test */
printf("\x41\x42\x43\x3a\n");
@@ -441,14 +443,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()
@@ -516,10 +525,12 @@ int main(int argc, char **argv)
c99_bool_test();
float_test();
longlong_test();
manyarg_test();
stdarg_test();
whitespace_test();
relocation_test();
old_style_function();
alloca_test();
sizeof_test();
typeof_test();
statement_expr_test();
@@ -688,6 +699,7 @@ int tab4[10];
void expr_ptr_test()
{
int *p, *q;
int i = -1;
printf("expr_ptr:\n");
p = tab4;
@@ -703,6 +715,37 @@ void expr_ptr_test()
printf("dec=%d\n", p - tab4);
printf("add=%d\n", p + 3 - tab4);
printf("add=%d\n", 3 + p - tab4);
/* check if 64bit support is ok */
q = p = 0;
q += i;
printf("%p %p %ld\n", q, p, p-q);
printf("%d %d %d %d %d %d\n",
p == q, p != q, p < q, p <= q, p >= q, p > q);
i = 0xf0000000;
p += i;
printf("%p %p %ld\n", q, p, p-q);
printf("%d %d %d %d %d %d\n",
p == q, p != q, p < q, p <= q, p >= q, p > q);
p = (int *)((char *)p + 0xf0000000);
printf("%p %p %ld\n", q, p, p-q);
printf("%d %d %d %d %d %d\n",
p == q, p != q, p < q, p <= q, p >= q, p > q);
p += 0xf0000000;
printf("%p %p %ld\n", q, p, p-q);
printf("%d %d %d %d %d %d\n",
p == q, p != q, p < q, p <= q, p >= q, p > q);
{
struct size12 {
int i, j, k;
};
struct size12 s[2], *sp = s;
int i, j;
sp->i = 42;
sp++;
j = -1;
printf("%d\n", sp[j].i);
}
}
void expr_cmp_test()
@@ -1066,6 +1109,10 @@ void cast_test()
int a;
char c;
char tab[10];
unsigned b,d;
short s;
char *p = NULL;
p -= 0x700000000042;
printf("cast_test:\n");
a = 0xfffff;
@@ -1088,7 +1135,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;
@@ -1099,6 +1154,16 @@ void cast_test()
printf("sizeof(+(char)'a') = %d\n", sizeof(+(char)'a'));
printf("sizeof(-(char)'a') = %d\n", sizeof(-(char)'a'));
printf("sizeof(~(char)'a') = %d\n", sizeof(-(char)'a'));
/* from pointer to integer types */
printf("%d %d %ld %ld %lld %lld\n",
(int)p, (unsigned int)p,
(long)p, (unsigned long)p,
(long long)p, (unsigned long long)p);
/* from integers to pointers */
printf("%p %p %p %p\n",
(void *)a, (void *)b, (void *)c, (void *)d);
}
/* initializers tests */
@@ -1324,8 +1389,35 @@ void bitfield_test(void)
printf("st1.f2 == -1\n");
else
printf("st1.f2 != -1\n");
/* bit sizes below must be bigger than 32 since GCC doesn't allow
long-long bitfields whose size is not bigger than int */
struct sbf2 {
long long f1 : 45;
long long : 2;
long long f2 : 35;
unsigned long long f3 : 38;
} st2;
st2.f1 = 0x123456789ULL;
a = 120;
st2.f2 = (long long)a << 25;
st2.f3 = a;
st2.f2++;
printf("%lld %lld %lld\n", st2.f1, st2.f2, st2.f3);
}
#ifdef __x86_64__
#define FLOAT_FMT "%f\n"
#else
/* x86's float isn't compatible with GCC */
#define FLOAT_FMT "%.5f\n"
#endif
/* declare strto* functions as they are C99 */
double strtod(const char *nptr, char **endptr);
float strtof(const char *nptr, char **endptr);
long double strtold(const char *nptr, char **endptr);
#define FTEST(prefix, type, fmt)\
void prefix ## cmp(type a, type b)\
{\
@@ -1347,6 +1439,8 @@ void prefix ## cmp(type a, type b)\
printf(fmt "\n", ++a);\
printf(fmt "\n", a++);\
printf(fmt "\n", a);\
b = 0;\
printf("%d %d\n", !a, !b);\
}\
void prefix ## fcast(type a)\
{\
@@ -1371,6 +1465,18 @@ void prefix ## fcast(type a)\
printf("utof: " fmt "\n", b);\
}\
\
float prefix ## retf(type a) { return a; }\
double prefix ## retd(type a) { return a; }\
long double prefix ## retld(type a) { return a; }\
\
void prefix ## call(void)\
{\
printf("float: " FLOAT_FMT, prefix ## retf(42.123456789));\
printf("double: %f\n", prefix ## retd(42.123456789));\
printf("long double: %Lf\n", prefix ## retld(42.123456789));\
printf("strto%s: %f\n", #prefix, (double)strto ## prefix("1.2", NULL));\
}\
\
void prefix ## test(void)\
{\
printf("testing '%s'\n", #type);\
@@ -1379,6 +1485,7 @@ void prefix ## test(void)\
prefix ## cmp(1, 1);\
prefix ## fcast(234.6);\
prefix ## fcast(-2334.6);\
prefix ## call();\
}
FTEST(f, float, "%f")
@@ -1498,6 +1605,8 @@ void lloptest(long long a, long long b)
printf("arith2: %Ld %Ld\n", a++, b++);
printf("arith2: %Ld %Ld\n", --a, --b);
printf("arith2: %Ld %Ld\n", a, b);
b = ub = 0;
printf("not: %d %d %d %d\n", !a, !ua, !b, !ub);
}
void llshift(long long a, int b)
@@ -1619,6 +1728,50 @@ void longlong_test(void)
p[0]++;
printf("%lld\n", *p);
}
a = 68719476720LL;
b = 4294967295LL;
printf("%d %d %d %d\n", a > b, a < b, a >= b, a <= b);
printf("%Ld\n", 0x123456789LLU);
}
void manyarg_test(void)
{
long double ld = 1234567891234LL;
printf("manyarg_test:\n");
printf("%d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f\n",
1, 2, 3, 4, 5, 6, 7, 8,
0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0);
printf("%d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f "
"%Ld %Ld %f %f\n",
1, 2, 3, 4, 5, 6, 7, 8,
0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0,
1234567891234LL, 987654321986LL,
42.0, 43.0);
printf("%Lf %d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f "
"%Ld %Ld %f %f\n",
ld, 1, 2, 3, 4, 5, 6, 7, 8,
0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0,
1234567891234LL, 987654321986LL,
42.0, 43.0);
/* XXX: known bug of x86-64 */
#ifndef __x86_64__
printf("%d %d %d %d %d %d %d %d %Lf\n",
1, 2, 3, 4, 5, 6, 7, 8, ld);
printf("%d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f "
"%Ld %Ld %f %f %Lf\n",
1, 2, 3, 4, 5, 6, 7, 8,
0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0,
1234567891234LL, 987654321986LL,
42.0, 43.0, ld);
printf("%d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f "
"%Lf %Ld %Ld %f %f %Lf\n",
1, 2, 3, 4, 5, 6, 7, 8,
0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0,
ld, 1234567891234LL, 987654321986LL,
42.0, 43.0, ld);
#endif
}
void vprintf1(const char *fmt, ...)
@@ -1628,6 +1781,7 @@ void vprintf1(const char *fmt, ...)
int c, i;
double d;
long long ll;
long double ld;
va_start(ap, fmt);
@@ -1654,6 +1808,10 @@ void vprintf1(const char *fmt, ...)
ll = va_arg(ap, long long);
printf("%Ld", ll);
break;
case 'F':
ld = va_arg(ap, long double);
printf("%Lf", ld);
break;
}
p++;
} else {
@@ -1667,9 +1825,48 @@ void vprintf1(const char *fmt, ...)
void stdarg_test(void)
{
long double ld = 1234567891234LL;
vprintf1("%d %d %d\n", 1, 2, 3);
vprintf1("%f %d %f\n", 1.0, 2, 3.0);
vprintf1("%l %l %d %f\n", 1234567891234LL, 987654321986LL, 3, 1234.0);
vprintf1("%F %F %F\n", 1.2L, 2.3L, 3.4L);
#ifdef __x86_64__
/* a bug of x86's TCC */
vprintf1("%d %f %l %F %d %f %l %F\n",
1, 1.2, 3L, 4.5L, 6, 7.8, 9L, 0.1L);
#endif
vprintf1("%d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f\n",
1, 2, 3, 4, 5, 6, 7, 8,
0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8);
vprintf1("%d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f\n",
1, 2, 3, 4, 5, 6, 7, 8,
0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0);
vprintf1("%d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f "
"%l %l %f %f\n",
1, 2, 3, 4, 5, 6, 7, 8,
0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0,
1234567891234LL, 987654321986LL,
42.0, 43.0);
vprintf1("%F %d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f "
"%l %l %f %f\n",
ld, 1, 2, 3, 4, 5, 6, 7, 8,
0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0,
1234567891234LL, 987654321986LL,
42.0, 43.0);
vprintf1("%d %d %d %d %d %d %d %d %F\n",
1, 2, 3, 4, 5, 6, 7, 8, ld);
vprintf1("%d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f "
"%l %l %f %f %F\n",
1, 2, 3, 4, 5, 6, 7, 8,
0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0,
1234567891234LL, 987654321986LL,
42.0, 43.0, ld);
vprintf1("%d %d %d %d %d %d %d %d %f %f %f %f %f %f %f %f %f %f "
"%F %l %l %f %f %F\n",
1, 2, 3, 4, 5, 6, 7, 8,
0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0,
ld, 1234567891234LL, 987654321986LL,
42.0, 43.0, ld);
}
void whitespace_test(void)
@@ -1740,6 +1937,18 @@ void old_style_function(void)
decl_func2(NULL);
}
void alloca_test()
{
#if defined __i386__ || defined __x86_64__
char *p = alloca(16);
strcpy(p,"123456789012345");
printf("alloca: p is %s\n", p);
char *demo = "This is only a test.\n";
/* Test alloca embedded in a larger expression */
printf("alloca: %s\n", strcpy(alloca(strlen(demo)+1),demo) );
#endif
}
void sizeof_test(void)
{
int a;
@@ -1747,6 +1956,8 @@ void sizeof_test(void)
printf("sizeof(int) = %d\n", sizeof(int));
printf("sizeof(unsigned int) = %d\n", sizeof(unsigned int));
printf("sizeof(long) = %d\n", sizeof(long));
printf("sizeof(unsigned long) = %d\n", sizeof(unsigned long));
printf("sizeof(short) = %d\n", sizeof(short));
printf("sizeof(unsigned short) = %d\n", sizeof(unsigned short));
printf("sizeof(char) = %d\n", sizeof(char));
@@ -1803,14 +2014,14 @@ void local_label_test(void)
goto l1;
l2:
a = 1 + ({
__label__ l1, l2, l3;
goto l4;
l5:
printf("aa1\n");
__label__ l1, l2, l3, l4;
goto l1;
l4:
printf("aa1\n");
goto l3;
l2:
printf("aa3\n");
goto l3;
goto l4;
l1:
printf("aa2\n");
goto l2;
@@ -1819,12 +2030,12 @@ void local_label_test(void)
});
printf("a=%d\n", a);
return;
l1:
l4:
printf("bb1\n");
goto l2;
l4:
l1:
printf("bb2\n");
goto l5;
goto l4;
}
/* inline assembler test */
@@ -1932,6 +2143,9 @@ void asm_test(void)
goto label1;
label2:
__asm__("btsl %1,%0" : "=m"(set) : "Ir"(20) : "cc");
#ifdef __GNUC__ // works strange with GCC 4.3
set=0x1080fd;
#endif
printf("set=0x%x\n", set);
val = 0x01020304;
printf("swab32(0x%08x) = 0x%0x\n", val, swab32(val));

View File

@@ -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;
}
/* -------------------------------------------------------------- */

28
win32/build-tcc.bat Normal file
View File

@@ -0,0 +1,28 @@
@rem ----------------------------------------------------
@rem batch file to build tcc using gcc and ar from mingw
@rem ----------------------------------------------------
:
@echo>..\config.h #define TCC_VERSION "0.9.25"
@echo>>..\config.h #define TCC_TARGET_PE 1
@echo>>..\config.h #define CONFIG_TCCDIR "."
@echo>>..\config.h #define CONFIG_SYSROOT ""
:
gcc -Os -fno-strict-aliasing ../tcc.c -o tcc.exe -s
gcc -Os -fno-strict-aliasing ../libtcc.c -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 ../lib/libtcc1.c
.\tcc -c ../lib/alloca86.S
.\tcc -c ../lib/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

View File

@@ -1,6 +0,0 @@
; Windows DLL example - export definition for the DLL
LIBRARY dll.dll
EXPORTS
HelloWorld

View File

@@ -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

View File

@@ -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 */

View File

@@ -12,10 +12,12 @@ 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
void *alloca(size_t);
#endif

View File

@@ -1,115 +0,0 @@
TinyCC-PE
---------
TinyCC (aka TCC) is a small but hyperfast C compiler,
written by Fabrice Bellard,
TinyCC-PE is the TinyCC compiler with an extension to
write PE executables for MS-Windows.
Features:
---------
TinyCC-PE can produce console applications, native windows
GUI programs and DLL's.
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.
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.
Examples:
---------
For the 'Fibonacci' console example type from the command line:
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
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
Header Files:
-------------
The system header files, except '_mingw.h', are from the
2.0 mingw distribution. See also: http://www.mingw.org/
Compile TCC:
------------
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

158
win32/tcc-win32.txt Normal file
View File

@@ -0,0 +1,158 @@
TinyCC
======
This file contains specific information for usage of TinyCC
under MS-Windows. See tcc-doc.html to have all the features.
Compilation from source:
------------------------
* You can use the MinGW and MSYS tools available at
http://www.mingw.org
Untar the TCC archive and type in the MSYS shell:
./configure
make
make install
The default install location is c:\Program Files\tcc
* Alternatively you can compile TCC with just GCC from MinGW using
win32\build-tcc.bat
To install, copy the entire contents of the win32 directory to
where you want.
Installation from the binary ZIP package:
-----------------------------------------
Unzip the package to a directory of your choice.
(Note that the binary package does not include libtcc. If you
want TCC as dynamic code generator, please use the source code
distribution.)
Set the system PATH:
--------------------
To be able to invoke the compiler from everywhere on your computer by
just typing "tcc", please add the directory containing tcc.exe to your
system PATH.
Examples:
---------
Open a console window (DOS box) and 'cd' to the examples directory.
For the 'Fibonacci' example type:
tcc fib.c
For the 'Hello Windows' GUI example type:
tcc hello_win.c
for the 'Hello DLL' example type
tcc -shared dll.c
tiny_impdef dll.dll (optional)
tcc hello_dll.c dll.def
Import Definition Files:
------------------------
To link with Windows system DLLs, TCC uses import definition
files (.def) instead of libraries.
The included 'tiny_impdef' program may be used to make additional
.def files for any DLL. For example:
tiny_impdef.exe opengl32.dll
Put opengl32.def into the tcc/lib directory. Specify -lopengl32 at
the TCC commandline to link a program that uses opengl32.dll.
Header Files:
-------------
The system header files (except _mingw.h) are from the MinGW
distribution:
http://www.mingw.org/
From the windows headers, only a minimal set is included. If you need
more, get MinGW's "w32api" package.
Resource Files:
---------------
TCC can link windows resources in coff format as generated by MinGW's
windres.exe. For example:
windres -O coff app.rc -o appres.o
tcc app.c appres.o -o app.exe
Tiny Libmaker:
--------------
The included tiny_libmaker tool by Timovj Lahde can be used as
'ar' replacement to make a library from several object files:
tiny_libmaker [rcs] library objectfiles ...
Limitations:
------------
- 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 tiny_libmaker
or MinGW's ar.
- No leading underscore is generated in the ELF symbols.
- With DLLs, only functions (not data) can be im-/exported.
- Bounds checking (option -b) is not supported currently.
- 64-bit systems are not (yet) supported.
Documentation and License:
--------------------------
TCC is distributed under the GNU Lesser General Public License. (See
COPYING file or http://www.gnu.org/licenses/lgpl-2.1.html)
TinyCC homepage is at:
http://fabrice.bellard.free.fr/tcc/
WinAPI Help and 3rd-party tools:
--------------------------------
The Windows API documentation (Win95) in a single .hlp file is
available on the lcc-win32 site as "win32hlp.exe" or from other
locations as "win32hlp_big.zip".
A nice RAD tool to create windows resources (dialog boxes etc.) is
"ResEd", available at the RadASM website.
--- grischka

393
win32/tools/tiny_impdef.c Normal file
View 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;
}
/* -------------------------------------------------------------- */

310
win32/tools/tiny_libmaker.c Normal file
View File

@@ -0,0 +1,310 @@
/*
* 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>
#ifdef _WIN32
#include <io.h> /* for mktemp */
#endif
/* #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;
}
}
}
strcpy(tfile, "./XXXXXX");
if (!mktemp(tfile) || (fo = fopen(tfile, "wb+")) == NULL)
{
fprintf(stderr, "Can't open temporary file %s\n", tfile);
return 2;
}
if ((fh = fopen(afile, "wb")) == NULL)
{
fprintf(stderr, "Can't open file %s \n", afile);
remove(tfile);
return 2;
}
funcmax = 250;
afpos = realloc(NULL, funcmax * sizeof *afpos); // 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) {
funcmax += 250;
afpos = realloc(afpos, funcmax * sizeof *afpos); // 250 func more
}
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;
}

1419
x86_64-gen.c Normal file

File diff suppressed because it is too large Load Diff