commit 6eefe55e4b7993a1d573e7d4db6def85f418f824 Author: Bernhard Reutner-Fischer Date: Wed Sep 2 15:55:48 2009 +0200 Handle --whole-archive Support and document -Wl,--{no-,}whole-archive. Also move the bounds-checking code to a bcheck.a to avoid undefined references to __bound_new_region() (when using a libtcc1_s.so instead of libtcc1.a) on i386. Signed-off-by: aldot diff --git a/Makefile b/Makefile index 01c3e27..6387246 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,7 @@ include $(TOP)/config.mak CFLAGS+=-g -Wall CFLAGS_P=$(CFLAGS) -pg -static -DCONFIG_TCC_STATIC LIBS_P= +CFLAGS_PIC ?= -fPIC ifneq ($(GCC_MAJOR),2) CFLAGS+=-fno-strict-aliasing @@ -32,19 +33,22 @@ LIBS+=-ldl endif endif +BCHECK= +BCHECK_O= +ALLOCA_O= + ifeq ($(ARCH),i386) NATIVE_TARGET=-DTCC_TARGET_I386 LIBTCC1=libtcc1.a -BCHECK_O=bcheck.o -ALLOCA_O=alloca86.o alloca86-bt.o -else +ALLOCA_O=alloca86.o +BCHECK_O=bcheck.o alloca86-bt.o +BCHECK=bcheck.a +endif ifeq ($(ARCH),x86-64) NATIVE_TARGET=-DTCC_TARGET_X86_64 LIBTCC1=libtcc1.a -BCHECK_O= ALLOCA_O=alloca86_64.o endif -endif ifeq ($(ARCH),arm) NATIVE_TARGET=-DTCC_TARGET_ARM @@ -54,12 +58,10 @@ endif ifdef CONFIG_WIN32 NATIVE_TARGET+=-DTCC_TARGET_PE -BCHECK_O= endif ifneq ($(wildcard /lib/ld-uClibc.so.0),) NATIVE_TARGET+=-DTCC_UCLIBC -BCHECK_O= endif ifdef CONFIG_USE_LIBGCC @@ -111,7 +113,7 @@ ifdef CONFIG_CROSS PROGS+=$(PROGS_CROSS) endif -all: $(PROGS) $(LIBTCC1) $(BCHECK_O) libtcc.a tcc-doc.html tcc.1 libtcc_test$(EXESUF) +all: $(PROGS) $(LIBTCC1) $(BCHECK) libtcc.a tcc-doc.html tcc.1 libtcc_test$(EXESUF) # Host Tiny C Compiler tcc$(EXESUF): $(NATIVE_FILES) @@ -191,12 +193,15 @@ libtcc1.a: $(LIBTCC1_OBJS) bcheck.o: bcheck.c $(CC) -o $@ -c $< -O2 -Wall +bcheck.a: $(BCHECK_O) + $(AR) rcs $@ $^ + # install TCC_INCLUDES = stdarg.h stddef.h stdbool.h float.h varargs.h tcclib.h INSTALL=install ifndef CONFIG_WIN32 -install: $(PROGS) $(LIBTCC1) $(BCHECK_O) libtcc.a tcc.1 tcc-doc.html +install: $(PROGS) $(LIBTCC1) $(BCHECK) libtcc.a tcc.1 tcc-doc.html mkdir -p "$(bindir)" $(INSTALL) -s -m755 $(PROGS) "$(bindir)" mkdir -p "$(mandir)/man1" @@ -206,8 +211,8 @@ install: $(PROGS) $(LIBTCC1) $(BCHECK_O) libtcc.a tcc.1 tcc-doc.html ifneq ($(LIBTCC1),) $(INSTALL) -m644 $(LIBTCC1) "$(tccdir)" endif -ifneq ($(BCHECK_O),) - $(INSTALL) -m644 $(BCHECK_O) "$(tccdir)" +ifneq ($(BCHECK),) + $(INSTALL) -m644 $(BCHECK) "$(tccdir)" endif $(INSTALL) -m644 $(addprefix include/,$(TCC_INCLUDES)) "$(tccdir)/include" mkdir -p "$(docdir)" @@ -219,7 +224,7 @@ endif uninstall: rm -fv $(foreach P,$(PROGS),"$(bindir)/$P") - rm -fv $(foreach P,$(LIBTCC1) $(BCHECK_O),"$(tccdir)/$P") + rm -fv $(foreach P,$(LIBTCC1) $(BCHECK),"$(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" diff --git a/libtcc.c b/libtcc.c index c25fb2c..e04db5e 100644 --- a/libtcc.c +++ b/libtcc.c @@ -206,6 +206,7 @@ static int tcc_add_dll(TCCState *s, const char *filename, int flags); #define AFF_PRINT_ERROR 0x0001 /* print error if file not found */ #define AFF_REFERENCED_DLL 0x0002 /* load a referenced dll from another dll */ #define AFF_PREPROCESS 0x0004 /* preprocess file */ +#define AFF_WHOLE_ARCHIVE 0x0008 /* add whole archive not just undef symbol */ static int tcc_add_file_internal(TCCState *s, const char *filename, int flags); /* tcccoff.c */ @@ -2082,7 +2083,7 @@ static int tcc_add_file_internal(TCCState *s1, const char *filename, int flags) if (memcmp((char *)&ehdr, ARMAG, 8) == 0) { file->line_num = 0; /* do not display line number if error */ - ret = tcc_load_archive(s1, fd); + ret = tcc_load_archive(s1, fd, flags & AFF_WHOLE_ARCHIVE); goto the_end; } @@ -2099,9 +2100,11 @@ static int tcc_add_file_internal(TCCState *s1, const char *filename, int flags) /* as GNU ld, consider it is an ld script if not recognized */ ret = tcc_load_ldscript(s1); #endif +/* TODO: the_end label should be here !! */ if (ret < 0) - error_noabort("unrecognized file type"); - + error_noabort("%s: unrecognized file type", filename); + else if (s1->verbose) + printf("+> %s\n", filename); the_end: if (file) tcc_close(file); diff --git a/tcc-doc.texi b/tcc-doc.texi index 7cc61bb..3bb640c 100644 --- a/tcc-doc.texi +++ b/tcc-doc.texi @@ -295,6 +295,14 @@ also be given). @item -Wl,-Ttext,address Set the start of the .text section to @var{address}. address@hidden -Wl,--whole-archive +Add a whole archive, not just the symbols of the archive that would +satisfy undefined symbols in the program. + address@hidden -Wl,--no-whole-archive +Turn off the effect of the --whole-archive option for subsequent archive +files. + @item -Wl,--oformat,fmt Use @var{fmt} as output format. The supported output formats are: @table @code diff --git a/tcc.c b/tcc.c index 501dc01..d8138a0 100644 --- a/tcc.c +++ b/tcc.c @@ -54,6 +54,8 @@ void help(void) " -static static linking\n" " -rdynamic export all global symbols to dynamic linker\n" " -r generate (relocatable) object file\n" + " --whole-archive include all object files in the archives\n" + " --no-whole-archive turn the effect of --whole-archives off\n" "Debugger options:\n" " -g generate runtime debug info\n" #ifdef CONFIG_TCC_BCHECK @@ -66,13 +68,15 @@ void help(void) } static char **files; -static int nb_files, nb_libraries; +static char **whole_archives; +static int nb_files, nb_libraries, nb_whole_archive; static int multiple_files; static int print_search_dirs; static int output_type; static int reloc_output; static const char *outfile; static int do_bench = 0; +static unsigned do_whole_archive = 0; #define TCC_OPTION_HAS_ARG 0x0001 #define TCC_OPTION_NOSEP 0x0002 /* cannot have space before option and arg */ @@ -227,6 +231,7 @@ int parse_args(TCCState *s, int argc, char **argv) if (r[0] != '-' || r[1] == '\0') { /* add a new file */ dynarray_add((void ***)&files, &nb_files, r); + dynarray_add((void ***)&whole_archives, &nb_whole_archive, (void*)do_whole_archive); if (!multiple_files) { optind--; /* argv[0] will be this file */ @@ -297,6 +302,7 @@ int parse_args(TCCState *s, int argc, char **argv) break; case TCC_OPTION_l: dynarray_add((void ***)&files, &nb_files, r); + dynarray_add((void ***)&whole_archives, &nb_whole_archive, (void*)do_whole_archive); nb_libraries++; break; case TCC_OPTION_bench: @@ -400,6 +406,10 @@ int parse_args(TCCState *s, int argc, char **argv) { error("target %s not found", p); } + } else if (strstart(optarg, "--whole-archive", &p)) { + do_whole_archive = 1; + } else if (strstart(optarg, "--no-whole-archive", &p)) { + do_whole_archive = 0; } else { error("unsupported linker option '%s'", optarg); } @@ -436,8 +446,10 @@ int main(int argc, char **argv) outfile = NULL; multiple_files = 1; files = NULL; + whole_archives = NULL; nb_files = 0; nb_libraries = 0; + nb_whole_archive = 0; reloc_output = 0; print_search_dirs = 0; ret = 0; @@ -521,9 +533,10 @@ int main(int argc, char **argv) ret = 1; } } else { + int whole = ((int)whole_archives[i]) << 3; /* AFF_WHOLE_ARCHIVE */ if (1 == s->verbose) - printf("-> %s\n", filename); - if (tcc_add_file(s, filename) < 0) + printf("-%c %s\n", whole?'[':'>', filename); + if (tcc_add_file_internal(s, filename, whole) < 0) ret = 1; } } diff --git a/tccelf.c b/tccelf.c index b55d55a..45ade9e 100644 --- a/tccelf.c +++ b/tccelf.c @@ -1188,8 +1188,8 @@ static void tcc_add_runtime(TCCState *s1) ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, bounds_section->sh_num, "__bounds_start"); /* add bound check code */ - snprintf(buf, sizeof(buf), "%s/%s", s1->tcc_lib_path, "bcheck.o"); - tcc_add_file(s1, buf); + snprintf(buf, sizeof(buf), "%s/%s", s1->tcc_lib_path, "bcheck.a"); + tcc_add_file_internal(s1, buf, AFF_WHOLE_ARCHIVE | AFF_PRINT_ERROR); #ifdef TCC_TARGET_I386 if (s1->output_type != TCC_OUTPUT_MEMORY) { /* add 'call __bound_init()' in .init section */ @@ -2329,7 +2329,7 @@ static int get_be32(const uint8_t *b) } /* load only the objects which resolve undefined symbols */ -static int tcc_load_alacarte(TCCState *s1, int fd, int size) +static int tcc_load_alacarte(TCCState *s1, int fd, int size, int whole_archive) { int i, bound, nsyms, sym_index, off, ret; uint8_t *data; @@ -2351,6 +2351,7 @@ static int tcc_load_alacarte(TCCState *s1, int fd, int size) if(sym_index) { sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; if(sym->st_shndx == SHN_UNDEF) { + load_obj: off = get_be32(ar_index + i * 4) + sizeof(ArchiveHeader); #if 0 printf("%5d\t%s\t%08x\n", i, p, sym->st_shndx); @@ -2363,6 +2364,8 @@ static int tcc_load_alacarte(TCCState *s1, int fd, int size) goto the_end; } } + } else if (whole_archive) { + goto load_obj; } } } while(bound); @@ -2373,7 +2376,7 @@ static int tcc_load_alacarte(TCCState *s1, int fd, int size) } /* load a '.a' file */ -static int tcc_load_archive(TCCState *s1, int fd) +static int tcc_load_archive(TCCState *s1, int fd, int whole_archive) { ArchiveHeader hdr; char ar_size[11]; @@ -2409,7 +2412,7 @@ static int tcc_load_archive(TCCState *s1, int fd) if (!strcmp(ar_name, "/")) { /* coff symbol table : we handle it */ if(s1->alacarte_link) - return tcc_load_alacarte(s1, fd, size); + return tcc_load_alacarte(s1, fd, size, whole_archive); } else if (!strcmp(ar_name, "//") || !strcmp(ar_name, "__.SYMDEF") || !strcmp(ar_name, "__.SYMDEF/") ||