17 Commits

Author SHA1 Message Date
bellard
44cea6aee9 update 2003-10-05 10:21:28 +00:00
bellard
77a19bf50e update 2003-10-05 09:48:53 +00:00
bellard
b7f12dfbdf update 2003-10-04 21:29:04 +00:00
bellard
9890ea1233 added examples 2003-10-04 21:25:32 +00:00
bellard
feed3262c9 fixed libc linking when running in memory 2003-10-04 21:24:46 +00:00
bellard
bef8703f77 added arguments to -run - fixed libc linking when running in memory - output a warning instead of an error if invalid escaped sequence in character 2003-10-04 21:23:51 +00:00
bellard
46169b92d9 .gnu.linkonce section support (useful to link with recent glibc) 2003-10-04 14:45:23 +00:00
bellard
d369a77647 unbounded section name (might be useful when section name contains function name for g++ linkonce sections) 2003-10-04 14:41:18 +00:00
bellard
c5ce5eaeda fixed -w option - doc update (thanx to Romain Francoise) 2003-10-04 13:04:47 +00:00
bellard
9c1106d854 added -w option 2003-09-19 20:35:50 +00:00
bellard
f8d0241764 changed tcc_get_symbol() prototype 2003-07-20 19:19:58 +00:00
bellard
c5959b77b4 fixed typdefed type parsing (Mauro Persano) 2003-07-20 18:44:29 +00:00
bellard
7b940fcb1b reject abstract declarators in function definition (Mauro Persano) 2003-07-20 12:40:53 +00:00
bellard
21d2d99bdc suppressed warning for const function parameters 2003-06-02 20:32:30 +00:00
bellard
277e01cd64 const warning test 2003-06-02 20:31:46 +00:00
bellard
9d95be78c8 added init_array defines for new ld compatibility 2003-05-29 22:52:53 +00:00
bellard
370f5e571c added missing texi2pod.pl 2003-05-24 18:31:27 +00:00
18 changed files with 470 additions and 84 deletions

View File

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

View File

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

View File

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

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

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

View File

@@ -1 +1 @@
0.9.19
0.9.20

8
ex1.c Executable file
View 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
View 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
View 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
View 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
View File

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

33
gcctestsuite.sh Executable file
View 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."

View File

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

View File

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

View File

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

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

View File

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

View File

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