mirror of
https://github.com/mirror/tinycc.git
synced 2026-08-24 11:33:28 +08:00
Compare commits
17 Commits
release_0_
...
release_0_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
44cea6aee9 | ||
|
|
77a19bf50e | ||
|
|
b7f12dfbdf | ||
|
|
9890ea1233 | ||
|
|
feed3262c9 | ||
|
|
bef8703f77 | ||
|
|
46169b92d9 | ||
|
|
d369a77647 | ||
|
|
c5ce5eaeda | ||
|
|
9c1106d854 | ||
|
|
f8d0241764 | ||
|
|
c5959b77b4 | ||
|
|
7b940fcb1b | ||
|
|
21d2d99bdc | ||
|
|
277e01cd64 | ||
|
|
9d95be78c8 | ||
|
|
370f5e571c |
@@ -2,8 +2,6 @@ tcc_g
|
||||
tcc
|
||||
tc2.c
|
||||
ex3
|
||||
ex1.c
|
||||
ex2.c
|
||||
otcc1.c
|
||||
doc
|
||||
tc3s.c
|
||||
@@ -11,14 +9,11 @@ p3.c
|
||||
tc1.c
|
||||
error.c
|
||||
i386-gen1.c
|
||||
ex4.c
|
||||
test.out2
|
||||
test.out3
|
||||
web.sh
|
||||
ex3.c
|
||||
memdebug.c
|
||||
bench
|
||||
ex5.c
|
||||
tcc-newparse.c
|
||||
p1.c
|
||||
Makefile.uClibc
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
version 0.9.20:
|
||||
|
||||
- added '-w' option
|
||||
- added '.gnu.linkonce' ELF sections support
|
||||
- fixed libc linking when running in memory (avoid 'stat' function
|
||||
errors).
|
||||
- extended '-run' option to be able to give several arguments to a C
|
||||
script.
|
||||
|
||||
version 0.9.19:
|
||||
|
||||
- "alacarte" linking (Dave Long)
|
||||
|
||||
2
Makefile
2
Makefile
@@ -222,7 +222,7 @@ FILES= Makefile Makefile.uClibc configure VERSION \
|
||||
stddef.h stdarg.h stdbool.h float.h varargs.h \
|
||||
tcclib.h libtcc.h libtcc_test.c \
|
||||
ex1.c ex2.c ex3.c ex4.c ex5.c \
|
||||
tcctest.c boundtest.c gcctestsuite.sh
|
||||
tcctest.c boundtest.c gcctestsuite.sh texi2pod.pl
|
||||
|
||||
FILE=tcc-$(VERSION)
|
||||
|
||||
|
||||
2
README
2
README
@@ -50,7 +50,7 @@ The include file <tcclib.h> can be used if you want a small basic libc
|
||||
include support (especially useful for floppy disks). Of course, you
|
||||
can also use standard headers, although they are slower to compile.
|
||||
|
||||
You can begin your C script with '#!/usr/local/bin/tcc' on the first
|
||||
You can begin your C script with '#!/usr/local/bin/tcc -run' on the first
|
||||
line and set its execute bits (chmod a+x your_script). Then, you can
|
||||
launch the C code as a shell or perl script :-) The command line
|
||||
arguments are put in 'argc' and 'argv' of the main functions, as in
|
||||
|
||||
4
TODO
4
TODO
@@ -1,5 +1,7 @@
|
||||
TODO list:
|
||||
|
||||
- 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
|
||||
@@ -26,14 +28,12 @@ TODO list:
|
||||
- check section alignment in C
|
||||
- fix invalid cast in comparison 'if (v == (int8_t)v)'
|
||||
- packed attribute
|
||||
- support link once trick (gcc 3.2 / glibc compilation issue)
|
||||
- finish varargs.h support (gcc 3.2 testsuite issue)
|
||||
- fix static functions declared inside block
|
||||
- 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
|
||||
- look at GCC 3.2 compatibility problems.
|
||||
- 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
|
||||
|
||||
8
ex1.c
Executable file
8
ex1.c
Executable file
@@ -0,0 +1,8 @@
|
||||
#! /usr/local/bin/tcc -run
|
||||
#include <tcclib.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
printf("Hello World\n");
|
||||
return 0;
|
||||
}
|
||||
97
ex2.c
Normal file
97
ex2.c
Normal file
@@ -0,0 +1,97 @@
|
||||
#include "tcclib.h"
|
||||
|
||||
#define N 20
|
||||
|
||||
int nb_num;
|
||||
int tab[N];
|
||||
int stack_ptr;
|
||||
int stack_op[N];
|
||||
int stack_res[60];
|
||||
int result;
|
||||
|
||||
int find(int n, int i1, int a, int b, int op)
|
||||
{
|
||||
int i, j;
|
||||
int c;
|
||||
|
||||
if (stack_ptr >= 0) {
|
||||
stack_res[3*stack_ptr] = a;
|
||||
stack_op[stack_ptr] = op;
|
||||
stack_res[3*stack_ptr+1] = b;
|
||||
stack_res[3*stack_ptr+2] = n;
|
||||
if (n == result)
|
||||
return 1;
|
||||
tab[i1] = n;
|
||||
}
|
||||
|
||||
for(i=0;i<nb_num;i++) {
|
||||
for(j=i+1;j<nb_num;j++) {
|
||||
a = tab[i];
|
||||
b = tab[j];
|
||||
if (a != 0 && b != 0) {
|
||||
|
||||
tab[j] = 0;
|
||||
stack_ptr++;
|
||||
|
||||
if (find(a + b, i, a, b, '+'))
|
||||
return 1;
|
||||
if (find(a - b, i, a, b, '-'))
|
||||
return 1;
|
||||
if (find(b - a, i, b, a, '-'))
|
||||
return 1;
|
||||
if (find(a * b, i, a, b, '*'))
|
||||
return 1;
|
||||
if (b != 0) {
|
||||
c = a / b;
|
||||
if (find(c, i, a, b, '/'))
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (a != 0) {
|
||||
c = b / a;
|
||||
if (find(c, i, b, a, '/'))
|
||||
return 1;
|
||||
}
|
||||
|
||||
stack_ptr--;
|
||||
tab[i] = a;
|
||||
tab[j] = b;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
p = 1;
|
||||
result = atoi(argv[p]);
|
||||
printf("result=%d\n", result);
|
||||
nb_num = 0;
|
||||
for(i=p+1;i<argc;i++) {
|
||||
tab[nb_num++] = atoi(argv[i]);
|
||||
}
|
||||
|
||||
stack_ptr = -1;
|
||||
res = find(0, 0, 0, 0, ' ');
|
||||
if (res) {
|
||||
for(i=0;i<=stack_ptr;i++) {
|
||||
printf("%d %c %d = %d\n",
|
||||
stack_res[3*i], stack_op[i],
|
||||
stack_res[3*i+1], stack_res[3*i+2]);
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
printf("Impossible\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
23
ex3.c
Normal file
23
ex3.c
Normal file
@@ -0,0 +1,23 @@
|
||||
#include <tcclib.h>
|
||||
|
||||
int fib(n)
|
||||
{
|
||||
if (n <= 2)
|
||||
return 1;
|
||||
else
|
||||
return fib(n-1) + fib(n-2);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int n;
|
||||
if (argc < 2) {
|
||||
printf("usage: fib n\n"
|
||||
"Compute nth Fibonacci number\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
n = atoi(argv[1]);
|
||||
printf("fib(%d) = %d\n", n, fib(n, 2));
|
||||
return 0;
|
||||
}
|
||||
25
ex4.c
Executable file
25
ex4.c
Executable file
@@ -0,0 +1,25 @@
|
||||
#!./tcc -run -L/usr/X11R6/lib -lX11
|
||||
#include <stdlib.h>
|
||||
/* Yes, TCC can use X11 too ! */
|
||||
#include <stdio.h>
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
Display *display;
|
||||
Screen *screen;
|
||||
|
||||
display = XOpenDisplay("");
|
||||
if (!display) {
|
||||
fprintf(stderr, "Could not open X11 display\n");
|
||||
exit(1);
|
||||
}
|
||||
printf("X11 display opened.\n");
|
||||
screen = XScreenOfDisplay(display, 0);
|
||||
printf("width = %d\nheight = %d\ndepth = %d\n",
|
||||
screen->width,
|
||||
screen->height,
|
||||
screen->root_depth);
|
||||
XCloseDisplay(display);
|
||||
return 0;
|
||||
}
|
||||
8
ex5.c
Normal file
8
ex5.c
Normal file
@@ -0,0 +1,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
printf("Hello World\n");
|
||||
return 0;
|
||||
}
|
||||
33
gcctestsuite.sh
Executable file
33
gcctestsuite.sh
Executable file
@@ -0,0 +1,33 @@
|
||||
#!/bin/sh
|
||||
|
||||
TESTSUITE_PATH=$HOME/gcc/gcc-3.2/gcc/testsuite/gcc.c-torture
|
||||
TCC="./tcc -B. -I. -DNO_TRAMPOLINES"
|
||||
rm -f tcc.sum tcc.log
|
||||
nb_failed="0"
|
||||
|
||||
for src in $TESTSUITE_PATH/compile/*.c ; do
|
||||
echo $TCC -o /tmp/test.o -c $src
|
||||
$TCC -o /tmp/test.o -c $src >> tcc.log 2>&1
|
||||
if [ "$?" == "0" ] ; then
|
||||
result="PASS"
|
||||
else
|
||||
result="FAIL"
|
||||
nb_failed=$[ $nb_failed + 1 ]
|
||||
fi
|
||||
echo "$result: $src" >> tcc.sum
|
||||
done
|
||||
|
||||
for src in $TESTSUITE_PATH/execute/*.c ; do
|
||||
echo $TCC $src
|
||||
$TCC $src >> tcc.log 2>&1
|
||||
if [ "$?" == "0" ] ; then
|
||||
result="PASS"
|
||||
else
|
||||
result="FAIL"
|
||||
nb_failed=$[ $nb_failed + 1 ]
|
||||
fi
|
||||
echo "$result: $src" >> tcc.sum
|
||||
done
|
||||
|
||||
echo "$nb_failed test(s) failed." >> tcc.sum
|
||||
echo "$nb_failed test(s) failed."
|
||||
4
libtcc.h
4
libtcc.h
@@ -83,8 +83,8 @@ int tcc_run(TCCState *s, int argc, char **argv);
|
||||
non zero if link error. */
|
||||
int tcc_relocate(TCCState *s);
|
||||
|
||||
/* return symbol value or error */
|
||||
void *tcc_get_symbol(TCCState *s, const char *name);
|
||||
/* return symbol value. return 0 if OK, -1 if symbol not found */
|
||||
int tcc_get_symbol(TCCState *s, unsigned long *pval, const char *name);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -35,7 +35,8 @@ int main(int argc, char **argv)
|
||||
{
|
||||
TCCState *s;
|
||||
int (*func)(int);
|
||||
|
||||
unsigned long val;
|
||||
|
||||
s = tcc_new();
|
||||
if (!s) {
|
||||
fprintf(stderr, "Could not create tcc state\n");
|
||||
@@ -54,8 +55,9 @@ int main(int argc, char **argv)
|
||||
|
||||
tcc_relocate(s);
|
||||
|
||||
func = tcc_get_symbol(s, "foo");
|
||||
|
||||
tcc_get_symbol(s, &val, "foo");
|
||||
func = (void *)val;
|
||||
|
||||
func(32);
|
||||
|
||||
tcc_delete(s);
|
||||
|
||||
35
tcc-doc.texi
35
tcc-doc.texi
@@ -154,8 +154,28 @@ Set the path where the tcc internal libraries can be found (default is
|
||||
@item -bench
|
||||
Output compilation statistics.
|
||||
|
||||
@item -run
|
||||
Run compiled source.
|
||||
@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
|
||||
@option{-run} option, separated by spaces. Example:
|
||||
|
||||
@example
|
||||
tcc "-run -L/usr/X11R6/lib -lX11" ex4.c
|
||||
@end example
|
||||
|
||||
In a script, it gives the following header:
|
||||
|
||||
@example
|
||||
#!/usr/local/bin/tcc -run -L/usr/X11R6/lib -lX11
|
||||
#include <stdlib.h>
|
||||
int main(int argc, char **argv)
|
||||
@{
|
||||
...
|
||||
@}
|
||||
@end example
|
||||
|
||||
@end table
|
||||
|
||||
Preprocessor options:
|
||||
@@ -181,7 +201,14 @@ Undefine preprocessor symbol @samp{sym}.
|
||||
|
||||
Warning options:
|
||||
|
||||
Note: each warning option has a negative form beginning with @option{-Wno-}.
|
||||
@table @option
|
||||
@item -w
|
||||
Disable all warnings.
|
||||
|
||||
@end table
|
||||
|
||||
Note: each of the following warning options has a negative form beginning with
|
||||
@option{-Wno-}.
|
||||
|
||||
@table @option
|
||||
@item -Wunsupported
|
||||
@@ -604,7 +631,7 @@ executable ELF files and dynamic ELF libraries without relying on an
|
||||
external linker.
|
||||
|
||||
Dynamic ELF libraries can be output but the C compiler does not generate
|
||||
position independent code (PIC). It means that the dynamic librairy
|
||||
position independent code (PIC). It means that the dynamic library
|
||||
code generated by TCC cannot be factorized among processes yet.
|
||||
|
||||
TCC linker eliminates unreferenced object code in libraries. A single pass is
|
||||
|
||||
191
tcc.c
191
tcc.c
@@ -175,7 +175,7 @@ typedef struct Section {
|
||||
struct Section *reloc; /* corresponding section for relocation, if any */
|
||||
struct Section *hash; /* hash table for symbols */
|
||||
struct Section *next;
|
||||
char name[64]; /* section name */
|
||||
char name[1]; /* section name */
|
||||
} Section;
|
||||
|
||||
typedef struct DLLReference {
|
||||
@@ -408,7 +408,8 @@ struct TCCState {
|
||||
int warn_write_strings;
|
||||
int warn_unsupported;
|
||||
int warn_error;
|
||||
|
||||
int warn_none;
|
||||
|
||||
/* error handling */
|
||||
void *error_opaque;
|
||||
void (*error_func)(void *opaque, const char *msg);
|
||||
@@ -963,8 +964,8 @@ Section *new_section(TCCState *s1, const char *name, int sh_type, int sh_flags)
|
||||
{
|
||||
Section *sec;
|
||||
|
||||
sec = tcc_mallocz(sizeof(Section));
|
||||
pstrcpy(sec->name, sizeof(sec->name), name);
|
||||
sec = tcc_mallocz(sizeof(Section) + strlen(name));
|
||||
strcpy(sec->name, name);
|
||||
sec->sh_type = sh_type;
|
||||
sec->sh_flags = sh_flags;
|
||||
switch(sh_type) {
|
||||
@@ -1238,6 +1239,9 @@ void warning(const char *fmt, ...)
|
||||
TCCState *s1 = tcc_state;
|
||||
va_list ap;
|
||||
|
||||
if (s1->warn_none)
|
||||
return;
|
||||
|
||||
va_start(ap, fmt);
|
||||
error1(s1, 1, fmt, ap);
|
||||
va_end(ap);
|
||||
@@ -2806,7 +2810,7 @@ static void preprocess(int is_bof)
|
||||
static void parse_escape_string(CString *outstr, const uint8_t *buf, int is_long)
|
||||
{
|
||||
int c, n;
|
||||
const char *p;
|
||||
const uint8_t *p;
|
||||
|
||||
p = buf;
|
||||
for(;;) {
|
||||
@@ -2886,7 +2890,11 @@ static void parse_escape_string(CString *outstr, const uint8_t *buf, int is_long
|
||||
break;
|
||||
default:
|
||||
invalid_escape:
|
||||
error("invalid escaped char");
|
||||
if (c >= '!' && c <= '~')
|
||||
warning("unknown escape sequence: \'\\%c\'", c);
|
||||
else
|
||||
warning("unknown escape sequence: \'\\x%x\'", c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
p++;
|
||||
@@ -6204,12 +6212,13 @@ static void struct_decl(CType *type, int u)
|
||||
*/
|
||||
static int parse_btype(CType *type, AttributeDef *ad)
|
||||
{
|
||||
int t, u, type_found;
|
||||
int t, u, type_found, typespec_found;
|
||||
Sym *s;
|
||||
CType type1;
|
||||
|
||||
memset(ad, 0, sizeof(AttributeDef));
|
||||
type_found = 0;
|
||||
typespec_found = 0;
|
||||
t = 0;
|
||||
while(1) {
|
||||
switch(tok) {
|
||||
@@ -6227,6 +6236,7 @@ static int parse_btype(CType *type, AttributeDef *ad)
|
||||
if ((t & VT_BTYPE) != 0)
|
||||
error("too many basic types");
|
||||
t |= u;
|
||||
typespec_found = 1;
|
||||
break;
|
||||
case TOK_VOID:
|
||||
u = VT_VOID;
|
||||
@@ -6236,6 +6246,7 @@ static int parse_btype(CType *type, AttributeDef *ad)
|
||||
goto basic_type;
|
||||
case TOK_INT:
|
||||
next();
|
||||
typespec_found = 1;
|
||||
break;
|
||||
case TOK_LONG:
|
||||
next();
|
||||
@@ -6287,10 +6298,11 @@ static int parse_btype(CType *type, AttributeDef *ad)
|
||||
t |= VT_VOLATILE;
|
||||
next();
|
||||
break;
|
||||
case TOK_REGISTER:
|
||||
case TOK_SIGNED1:
|
||||
case TOK_SIGNED2:
|
||||
case TOK_SIGNED3:
|
||||
typespec_found = 1;
|
||||
case TOK_REGISTER:
|
||||
case TOK_AUTO:
|
||||
case TOK_RESTRICT1:
|
||||
case TOK_RESTRICT2:
|
||||
@@ -6300,6 +6312,7 @@ static int parse_btype(CType *type, AttributeDef *ad)
|
||||
case TOK_UNSIGNED:
|
||||
t |= VT_UNSIGNED;
|
||||
next();
|
||||
typespec_found = 1;
|
||||
break;
|
||||
|
||||
/* storage */
|
||||
@@ -6335,6 +6348,8 @@ static int parse_btype(CType *type, AttributeDef *ad)
|
||||
parse_expr_type(&type1);
|
||||
goto basic_type2;
|
||||
default:
|
||||
if (typespec_found)
|
||||
goto the_end;
|
||||
s = sym_find(tok);
|
||||
if (!s || !(s->type.t & VT_TYPEDEF))
|
||||
goto the_end;
|
||||
@@ -6581,7 +6596,9 @@ static void gfunc_param_typed(Sym *func, Sym *arg)
|
||||
} else if (arg == NULL) {
|
||||
error("too many arguments to function");
|
||||
} else {
|
||||
gen_assign_cast(&arg->type);
|
||||
type = arg->type;
|
||||
type.t &= ~VT_CONSTANT; /* need to do that to avoid false warning */
|
||||
gen_assign_cast(&type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8505,6 +8522,13 @@ static void decl(int l)
|
||||
error("cannot use local functions");
|
||||
if (!(type.t & VT_FUNC))
|
||||
expect("function definition");
|
||||
|
||||
/* reject abstract declarators in function definition */
|
||||
sym = type.ref;
|
||||
while ((sym = sym->next) != NULL)
|
||||
if (!(sym->v & ~SYM_FIELD))
|
||||
expect("identifier");
|
||||
|
||||
/* XXX: cannot do better now: convert extern line to static inline */
|
||||
if ((type.t & (VT_EXTERN | VT_INLINE)) == (VT_EXTERN | VT_INLINE))
|
||||
type.t = (type.t & ~VT_EXTERN) | VT_STATIC;
|
||||
@@ -9064,6 +9088,8 @@ int tcc_relocate(TCCState *s1)
|
||||
|
||||
tcc_add_runtime(s1);
|
||||
|
||||
build_got_entries(s1);
|
||||
|
||||
relocate_common_syms();
|
||||
|
||||
/* compute relocation address : section are relocated in place. We
|
||||
@@ -9099,7 +9125,7 @@ int tcc_run(TCCState *s1, int argc, char **argv)
|
||||
if (tcc_relocate(s1) < 0)
|
||||
return -1;
|
||||
|
||||
prog_main = tcc_get_symbol(s1, "main");
|
||||
prog_main = tcc_get_symbol_err(s1, "main");
|
||||
|
||||
if (do_debug) {
|
||||
#ifdef WIN32
|
||||
@@ -9124,10 +9150,11 @@ int tcc_run(TCCState *s1, int argc, char **argv)
|
||||
void (*bound_init)(void);
|
||||
|
||||
/* set error function */
|
||||
rt_bound_error_msg = (void *)tcc_get_symbol(s1, "__bound_error_msg");
|
||||
rt_bound_error_msg = (void *)tcc_get_symbol_err(s1,
|
||||
"__bound_error_msg");
|
||||
|
||||
/* XXX: use .init section so that it also work in binary ? */
|
||||
bound_init = (void *)tcc_get_symbol(s1, "__bound_init");
|
||||
bound_init = (void *)tcc_get_symbol_err(s1, "__bound_init");
|
||||
bound_init();
|
||||
}
|
||||
#endif
|
||||
@@ -9294,7 +9321,7 @@ static int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
|
||||
Elf32_Ehdr ehdr;
|
||||
int fd, ret;
|
||||
BufferedFile *saved_file;
|
||||
|
||||
|
||||
/* find source file type with extension */
|
||||
filename1 = strrchr(filename, '/');
|
||||
if (filename1)
|
||||
@@ -9346,8 +9373,17 @@ static int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
|
||||
if (ehdr.e_type == ET_REL) {
|
||||
ret = tcc_load_object_file(s1, fd, 0);
|
||||
} else if (ehdr.e_type == ET_DYN) {
|
||||
ret = tcc_load_dll(s1, fd, filename,
|
||||
(flags & AFF_REFERENCED_DLL) != 0);
|
||||
if (s1->output_type == TCC_OUTPUT_MEMORY) {
|
||||
void *h;
|
||||
h = dlopen(filename, RTLD_GLOBAL | RTLD_LAZY);
|
||||
if (h)
|
||||
ret = 0;
|
||||
else
|
||||
ret = -1;
|
||||
} else {
|
||||
ret = tcc_load_dll(s1, fd, filename,
|
||||
(flags & AFF_REFERENCED_DLL) != 0);
|
||||
}
|
||||
} else {
|
||||
error_noabort("unrecognized ELF file");
|
||||
goto fail;
|
||||
@@ -9409,23 +9445,12 @@ int tcc_add_library(TCCState *s, const char *libraryname)
|
||||
{
|
||||
char buf[1024];
|
||||
int i;
|
||||
void *h;
|
||||
|
||||
/* first we look for the dynamic library if not static linking */
|
||||
if (!s->static_link) {
|
||||
snprintf(buf, sizeof(buf), "lib%s.so", libraryname);
|
||||
/* if we output to memory, then we simply we dlopen(). */
|
||||
if (s->output_type == TCC_OUTPUT_MEMORY) {
|
||||
/* Since the libc is already loaded, we don't need to load it again */
|
||||
if (!strcmp(libraryname, "c"))
|
||||
return 0;
|
||||
h = dlopen(buf, RTLD_GLOBAL | RTLD_LAZY);
|
||||
if (h)
|
||||
return 0;
|
||||
} else {
|
||||
if (tcc_add_dll(s, buf, 0) == 0)
|
||||
return 0;
|
||||
}
|
||||
if (tcc_add_dll(s, buf, 0) == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* then we look for the static library */
|
||||
@@ -9532,7 +9557,6 @@ int tcc_set_warning(TCCState *s, const char *warning_name, int value)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#if !defined(LIBTCC)
|
||||
|
||||
/* extract the basename of a file */
|
||||
@@ -9579,6 +9603,7 @@ void help(void)
|
||||
" -bench output compilation statistics\n"
|
||||
" -run run compiled source\n"
|
||||
" -Wwarning set or reset (with 'no-' prefix) 'warning'\n"
|
||||
" -w disable all warnings\n"
|
||||
"Preprocessor options:\n"
|
||||
" -Idir add include path 'dir'\n"
|
||||
" -Dsym[=val] define 'sym' with value 'val'\n"
|
||||
@@ -9635,6 +9660,7 @@ enum {
|
||||
TCC_OPTION_rdynamic,
|
||||
TCC_OPTION_run,
|
||||
TCC_OPTION_v,
|
||||
TCC_OPTION_w,
|
||||
};
|
||||
|
||||
static const TCCOption tcc_options[] = {
|
||||
@@ -9656,7 +9682,7 @@ static const TCCOption tcc_options[] = {
|
||||
{ "static", TCC_OPTION_static, 0 },
|
||||
{ "shared", TCC_OPTION_shared, 0 },
|
||||
{ "o", TCC_OPTION_o, TCC_OPTION_HAS_ARG },
|
||||
{ "run", TCC_OPTION_run, 0 },
|
||||
{ "run", TCC_OPTION_run, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
|
||||
{ "rdynamic", TCC_OPTION_rdynamic, 0 },
|
||||
{ "r", TCC_OPTION_r, 0 },
|
||||
{ "W", TCC_OPTION_W, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
|
||||
@@ -9667,34 +9693,53 @@ static const TCCOption tcc_options[] = {
|
||||
{ "nostdlib", TCC_OPTION_nostdlib, 0 },
|
||||
{ "print-search-dirs", TCC_OPTION_print_search_dirs, 0 },
|
||||
{ "v", TCC_OPTION_v, 0 },
|
||||
{ "w", TCC_OPTION_w, 0 },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
int main(int argc, char **argv)
|
||||
/* convert 'str' into an array of space separated strings */
|
||||
static int expand_args(char ***pargv, const char *str)
|
||||
{
|
||||
char *r;
|
||||
int optind, output_type, multiple_files, i, reloc_output;
|
||||
TCCState *s;
|
||||
char **files;
|
||||
int nb_files, nb_libraries, nb_objfiles, dminus, ret;
|
||||
char objfilename[1024];
|
||||
int64_t start_time = 0;
|
||||
const char *s1;
|
||||
char **argv, *arg;
|
||||
int argc, len;
|
||||
|
||||
argc = 0;
|
||||
argv = NULL;
|
||||
for(;;) {
|
||||
while (is_space(*str))
|
||||
str++;
|
||||
if (*str == '\0')
|
||||
break;
|
||||
s1 = str;
|
||||
while (*str != '\0' && !is_space(*str))
|
||||
str++;
|
||||
len = str - s1;
|
||||
arg = tcc_malloc(len + 1);
|
||||
memcpy(arg, s1, len);
|
||||
arg[len] = '\0';
|
||||
dynarray_add((void ***)&argv, &argc, arg);
|
||||
}
|
||||
*pargv = argv;
|
||||
return argc;
|
||||
}
|
||||
|
||||
static char **files;
|
||||
static int nb_files, nb_libraries;
|
||||
static int multiple_files;
|
||||
static int print_search_dirs;
|
||||
static int output_type;
|
||||
static int reloc_output;
|
||||
static const char *outfile;
|
||||
|
||||
int parse_args(TCCState *s, int argc, char **argv)
|
||||
{
|
||||
int optind;
|
||||
const TCCOption *popt;
|
||||
const char *optarg, *p1, *r1, *outfile;
|
||||
int print_search_dirs;
|
||||
const char *optarg, *p1, *r1;
|
||||
char *r;
|
||||
|
||||
s = tcc_new();
|
||||
output_type = TCC_OUTPUT_EXE;
|
||||
|
||||
optind = 1;
|
||||
outfile = NULL;
|
||||
multiple_files = 1;
|
||||
dminus = 0;
|
||||
files = NULL;
|
||||
nb_files = 0;
|
||||
nb_libraries = 0;
|
||||
reloc_output = 0;
|
||||
print_search_dirs = 0;
|
||||
optind = 0;
|
||||
while (1) {
|
||||
if (optind >= argc) {
|
||||
if (nb_files == 0 && !print_search_dirs)
|
||||
@@ -9748,7 +9793,7 @@ int main(int argc, char **argv)
|
||||
case TCC_OPTION_HELP:
|
||||
show_help:
|
||||
help();
|
||||
return 1;
|
||||
exit(1);
|
||||
case TCC_OPTION_I:
|
||||
if (tcc_add_include_path(s, optarg) < 0)
|
||||
error("too many include paths");
|
||||
@@ -9823,12 +9868,20 @@ int main(int argc, char **argv)
|
||||
print_search_dirs = 1;
|
||||
break;
|
||||
case TCC_OPTION_run:
|
||||
multiple_files = 0;
|
||||
output_type = TCC_OUTPUT_MEMORY;
|
||||
{
|
||||
int argc1;
|
||||
char **argv1;
|
||||
argc1 = expand_args(&argv1, optarg);
|
||||
if (argc1 > 0) {
|
||||
parse_args(s, argc1, argv1);
|
||||
}
|
||||
multiple_files = 0;
|
||||
output_type = TCC_OUTPUT_MEMORY;
|
||||
}
|
||||
break;
|
||||
case TCC_OPTION_v:
|
||||
printf("tcc version %s\n", TCC_VERSION);
|
||||
return 0;
|
||||
exit(0);
|
||||
case TCC_OPTION_W:
|
||||
{
|
||||
const char *p = optarg;
|
||||
@@ -9842,6 +9895,9 @@ int main(int argc, char **argv)
|
||||
goto unsupported_option;
|
||||
}
|
||||
break;
|
||||
case TCC_OPTION_w:
|
||||
s->warn_none = 1;
|
||||
break;
|
||||
case TCC_OPTION_rdynamic:
|
||||
s->rdynamic = 1;
|
||||
break;
|
||||
@@ -9854,6 +9910,29 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
}
|
||||
return optind;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
TCCState *s;
|
||||
int nb_objfiles, ret, optind;
|
||||
char objfilename[1024];
|
||||
int64_t start_time = 0;
|
||||
|
||||
s = tcc_new();
|
||||
output_type = TCC_OUTPUT_EXE;
|
||||
outfile = NULL;
|
||||
multiple_files = 1;
|
||||
files = NULL;
|
||||
nb_files = 0;
|
||||
nb_libraries = 0;
|
||||
reloc_output = 0;
|
||||
print_search_dirs = 0;
|
||||
|
||||
optind = parse_args(s, argc - 1, argv + 1) + 1;
|
||||
|
||||
if (print_search_dirs) {
|
||||
/* enough for Linux kernel */
|
||||
printf("install: %s/\n", tcc_lib_path);
|
||||
|
||||
88
tccelf.c
88
tccelf.c
@@ -154,16 +154,25 @@ static int find_elf_sym(Section *s, const char *name)
|
||||
}
|
||||
|
||||
/* return elf symbol value or error */
|
||||
void *tcc_get_symbol(TCCState *s, const char *name)
|
||||
int tcc_get_symbol(TCCState *s, unsigned long *pval, const char *name)
|
||||
{
|
||||
int sym_index;
|
||||
Elf32_Sym *sym;
|
||||
|
||||
sym_index = find_elf_sym(symtab_section, name);
|
||||
if (!sym_index)
|
||||
error("%s not defined", name);
|
||||
return -1;
|
||||
sym = &((Elf32_Sym *)symtab_section->data)[sym_index];
|
||||
return (void *)sym->st_value;
|
||||
*pval = sym->st_value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *tcc_get_symbol_err(TCCState *s, const char *name)
|
||||
{
|
||||
unsigned long val;
|
||||
if (tcc_get_symbol(s, &val, name) < 0)
|
||||
error("%s not defined", name);
|
||||
return (void *)val;
|
||||
}
|
||||
|
||||
/* add an elf symbol : check if it is already defined and patch
|
||||
@@ -771,6 +780,34 @@ static void put_dt(Section *dynamic, int dt, unsigned long val)
|
||||
dyn->d_un.d_val = val;
|
||||
}
|
||||
|
||||
static void add_init_array_defines(TCCState *s1, const char *section_name)
|
||||
{
|
||||
Section *s;
|
||||
long end_offset;
|
||||
char sym_start[1024];
|
||||
char sym_end[1024];
|
||||
|
||||
snprintf(sym_start, sizeof(sym_start), "__%s_start", section_name + 1);
|
||||
snprintf(sym_end, sizeof(sym_end), "__%s_end", section_name + 1);
|
||||
|
||||
s = find_section(s1, section_name);
|
||||
if (!s) {
|
||||
end_offset = 0;
|
||||
s = data_section;
|
||||
} else {
|
||||
end_offset = s->data_offset;
|
||||
}
|
||||
|
||||
add_elf_sym(symtab_section,
|
||||
0, 0,
|
||||
ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE),
|
||||
s->sh_num, sym_start);
|
||||
add_elf_sym(symtab_section,
|
||||
end_offset, 0,
|
||||
ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE),
|
||||
s->sh_num, sym_end);
|
||||
}
|
||||
|
||||
/* add tcc runtime libraries */
|
||||
static void tcc_add_runtime(TCCState *s1)
|
||||
{
|
||||
@@ -812,9 +849,12 @@ static void tcc_add_runtime(TCCState *s1)
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
/* add libc if not memory output */
|
||||
if (s1->output_type != TCC_OUTPUT_MEMORY && !s1->nostdlib) {
|
||||
/* add libc */
|
||||
if (!s1->nostdlib) {
|
||||
tcc_add_library(s1, "c");
|
||||
}
|
||||
/* add crt end if not memory output */
|
||||
if (s1->output_type != TCC_OUTPUT_MEMORY && !s1->nostdlib) {
|
||||
tcc_add_file(s1, CONFIG_TCC_CRT_PREFIX "/crtn.o");
|
||||
}
|
||||
/* add various standard linker symbols */
|
||||
@@ -830,6 +870,11 @@ static void tcc_add_runtime(TCCState *s1)
|
||||
bss_section->data_offset, 0,
|
||||
ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE),
|
||||
bss_section->sh_num, "_end");
|
||||
/* horrible new standard ldscript defines */
|
||||
add_init_array_defines(s1, ".preinit_array");
|
||||
add_init_array_defines(s1, ".init_array");
|
||||
add_init_array_defines(s1, ".fini_array");
|
||||
|
||||
/* add start and stop symbols for sections whose name can be
|
||||
expressed in C */
|
||||
for(i = 1; i < s1->nb_sections; i++) {
|
||||
@@ -1350,7 +1395,7 @@ int tcc_output_file(TCCState *s1, const char *filename)
|
||||
|
||||
/* get entry point address */
|
||||
if (file_type == TCC_OUTPUT_EXE)
|
||||
ehdr.e_entry = (unsigned long)tcc_get_symbol(s1, "_start");
|
||||
ehdr.e_entry = (unsigned long)tcc_get_symbol_err(s1, "_start");
|
||||
else
|
||||
ehdr.e_entry = text_section->sh_addr; /* XXX: is it correct ? */
|
||||
}
|
||||
@@ -1466,7 +1511,8 @@ static void *load_data(int fd, unsigned long file_offset, unsigned long size)
|
||||
typedef struct SectionMergeInfo {
|
||||
Section *s; /* corresponding existing section */
|
||||
unsigned long offset; /* offset of the new section in the existing section */
|
||||
int new_section; /* true if section 's' was added */
|
||||
uint8_t new_section; /* true if section 's' was added */
|
||||
uint8_t link_once; /* true if link once section */
|
||||
} SectionMergeInfo;
|
||||
|
||||
/* load an object file and merge it with current files */
|
||||
@@ -1553,8 +1599,19 @@ static int tcc_load_object_file(TCCState *s1,
|
||||
/* find corresponding section, if any */
|
||||
for(j = 1; j < s1->nb_sections;j++) {
|
||||
s = s1->sections[j];
|
||||
if (!strcmp(s->name, sh_name))
|
||||
goto found;
|
||||
if (!strcmp(s->name, sh_name)) {
|
||||
if (!strncmp(sh_name, ".gnu.linkonce",
|
||||
sizeof(".gnu.linkonce") - 1)) {
|
||||
/* if a 'linkonce' section is already present, we
|
||||
do not add it again. It is a little tricky as
|
||||
symbols can still be defined in
|
||||
it. */
|
||||
sm_table[i].link_once = 1;
|
||||
goto next;
|
||||
} else {
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* not found: create new section */
|
||||
s = new_section(s1, sh_name, sh->sh_type, sh->sh_flags);
|
||||
@@ -1588,6 +1645,7 @@ static int tcc_load_object_file(TCCState *s1,
|
||||
} else {
|
||||
s->data_offset += size;
|
||||
}
|
||||
next: ;
|
||||
}
|
||||
|
||||
/* second short pass to update sh_link and sh_info fields of new
|
||||
@@ -1615,6 +1673,18 @@ static int tcc_load_object_file(TCCState *s1,
|
||||
if (sym->st_shndx != SHN_UNDEF &&
|
||||
sym->st_shndx < SHN_LORESERVE) {
|
||||
sm = &sm_table[sym->st_shndx];
|
||||
if (sm->link_once) {
|
||||
/* if a symbol is in a link once section, we use the
|
||||
already defined symbol. It is very important to get
|
||||
correct relocations */
|
||||
if (ELF32_ST_BIND(sym->st_info) != STB_LOCAL) {
|
||||
name = strtab + sym->st_name;
|
||||
sym_index = find_elf_sym(symtab_section, name);
|
||||
if (sym_index)
|
||||
old_to_new_syms[i] = sym_index;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
/* if no corresponding section added, no need to add symbol */
|
||||
if (!sm->s)
|
||||
continue;
|
||||
|
||||
10
tcctest.c
10
tcctest.c
@@ -1943,3 +1943,13 @@ void builtin_test(void)
|
||||
printf("res = %d\n", __builtin_constant_p(1));
|
||||
printf("res = %d\n", __builtin_constant_p(1 + 2));
|
||||
printf("res = %d\n", __builtin_constant_p(&constant_p_var));
|
||||
printf("res = %d\n", __builtin_constant_p(constant_p_var));
|
||||
}
|
||||
|
||||
|
||||
void const_func(const int a)
|
||||
{
|
||||
}
|
||||
|
||||
void const_warn_test(void)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user