From 47abdbd3d52a0bf92e907c3e059b5136c140fec2 Mon Sep 17 00:00:00 2001 From: Thomas Preud'homme Date: Tue, 30 Mar 2010 09:45:31 +0200 Subject: [PATCH] Better handle ld scripts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * search file from INPUT and GROUP commands in the library path in addition to the current directory * handle libraries specified by -lfoo options * Search lib in GROUP command repeatedly --- tcc.h | 2 + tccelf.c | 116 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- tccpp.c | 21 ++++++++++ 3 files changed, 136 insertions(+), 3 deletions(-) diff --git a/tcc.h b/tcc.h index a7b6aa6..b59f61a 100644 --- a/tcc.h +++ b/tcc.h @@ -225,6 +225,8 @@ typedef struct Sym { struct Sym *prev_tok; /* previous symbol for this token */ } Sym; +static int new_undef_sym = 0; /* Is there a new undefined sym since last new_undef_sym() */ + /* section definition */ /* XXX: use directly ELF structure for parameters ? */ /* special flag to indicate that the section should not be linked to diff --git a/tccelf.c b/tccelf.c index 4f16ecf..6f69013 100644 --- a/tccelf.c +++ b/tccelf.c @@ -259,6 +259,7 @@ ST_FUNC int add_elf_sym(Section *s, uplong value, unsigned long size, do_patch: esym->st_info = ELFW(ST_INFO)(sym_bind, sym_type); esym->st_shndx = sh_num; + new_undef_sym = 1; esym->st_value = value; esym->st_size = size; esym->st_other = other; @@ -2808,9 +2809,77 @@ static int ld_next(TCCState *s1, char *name, int name_size) return c; } +/* + * Extract the library name from the file name + * Return 0 if the file isn't a library + * + * /!\ No test on filename capacity, be careful + */ +static int filename_to_libname(TCCState *s1, char filename[], char libname[]) +{ + char *ext, *base; + int libprefix; + + /* already converted to library name */ + if (filename[0] == '\0') + return 1; + base = tcc_basename(filename); + if (base != filename) + return 0; + ext = strrchr(base, '.'); + if (ext == NULL) + return 0; + ext++; + libprefix = !strncmp(filename, "lib", 3); + if (!s1->static_link) { +#ifdef TCC_TARGET_PE + if (!strncmp(ext, "def", 3)) { + *(--ext) = '\0'; + strcpy(libname, filename); + *ext = '.'; + return 1; + } +#else + if (libprefix && (!strncmp(ext, "so", 2))) { + *(--ext) = '\0'; + strcpy(libname, filename + 3); + *ext = '.'; + return 1; + } +#endif + } else { + if (libprefix && (!strncmp(ext, "a", 1))) { + *(--ext) = '\0'; + strcpy(libname, filename + 3); + *ext = '.'; + return 1; + } + } + return 0; +} + +/* + * Extract the file name from the library name + * + * /!\ No test on filename capacity, be careful + */ +static void libname_to_filename(TCCState *s1, char libname[], char filename[]) +{ + if (!s1->static_link) { +#ifdef TCC_TARGET_PE + snprintf(filename, strlen(libname) + 5, "%s.def", libname); +#else + snprintf(filename, strlen(libname) + 7, "lib%s.so", libname); +#endif + } else { + snprintf(filename, strlen(libname) + 6, "lib%s.a", libname); + } +} + static int ld_add_file_list(TCCState *s1, int as_needed) { char filename[1024]; + char libname[1024]; int t, ret; t = ld_next(s1, filename, sizeof(filename)); @@ -2818,11 +2887,20 @@ static int ld_add_file_list(TCCState *s1, int as_needed) expect("("); t = ld_next(s1, filename, sizeof(filename)); for(;;) { + libname[0] = '\0'; if (t == LD_TOK_EOF) { error_noabort("unexpected end of file"); return -1; } else if (t == ')') { break; + } else if (t == '-') { + t = ld_next(s1, filename, sizeof(filename)); + if ((t != LD_TOK_NAME) || (filename[0] != 'l')) { + error_noabort("library name expected"); + return -1; + } + strcpy(libname, &filename[1]); + libname_to_filename(s1, libname, filename); } else if (t != LD_TOK_NAME) { error_noabort("filename expected"); return -1; @@ -2833,8 +2911,15 @@ static int ld_add_file_list(TCCState *s1, int as_needed) return ret; } else { /* TODO: Implement AS_NEEDED support. Ignore it for now */ - if (!as_needed) - tcc_add_file(s1, filename); + if (!as_needed) { + ret = tcc_add_file_internal(s1, filename, 0); + if (ret) { + if (filename_to_libname(s1, filename, libname)) + ret = tcc_add_library(s1, libname); + if (ret) + return ret; + } + } } t = ld_next(s1, filename, sizeof(filename)); if (t == ',') { @@ -2844,6 +2929,14 @@ static int ld_add_file_list(TCCState *s1, int as_needed) return 0; } +static int new_undef_syms(void) +{ + int ret = 0; + ret = new_undef_sym; + new_undef_sym = 0; + return ret; +} + /* interpret a subset of GNU ldscripts to handle the dummy libc.so files */ ST_FUNC int tcc_load_ldscript(TCCState *s1) @@ -2862,7 +2955,24 @@ ST_FUNC int tcc_load_ldscript(TCCState *s1) return -1; if (!strcmp(cmd, "INPUT") || !strcmp(cmd, "GROUP")) { - ret = ld_add_file_list(s1, 0); + if (!strcmp(cmd, "GROUP")) { + BufferedFile *buf_state; + int off; + + buf_state = tcc_save_buffer_state(&off); + new_undef_syms(); + ret = ld_add_file_list(s1, 0); + if (ret) + goto free_bufstate; + while (!ret && new_undef_syms()) { + tcc_load_buffer_state(buf_state, off); + ret = ld_add_file_list(s1, 0); + } + free_bufstate: + tcc_free_buffer_state(buf_state); + } else { + ret = ld_add_file_list(s1, 0); + } if (ret) return ret; } else if (!strcmp(cmd, "OUTPUT_FORMAT") || diff --git a/tccpp.c b/tccpp.c index 51348cf..f974242 100644 --- a/tccpp.c +++ b/tccpp.c @@ -378,6 +378,27 @@ static int tcc_peekc_slow(BufferedFile *bf) } } +BufferedFile *tcc_save_buffer_state(int *offset) +{ + BufferedFile *state; + + state = tcc_malloc(sizeof(BufferedFile)); + memcpy(state, file, sizeof(BufferedFile)); + *offset = lseek(file->fd, 0, SEEK_CUR); + return state; +} + +void tcc_load_buffer_state(BufferedFile *buf_state, int offset) +{ + memcpy(file, buf_state, sizeof(BufferedFile)); + lseek(file->fd, offset, SEEK_SET); +} + +void tcc_free_buffer_state(BufferedFile *buf_state) +{ + tcc_free(buf_state); +} + /* return the current character, handling end of block if necessary (but not stray) */ ST_FUNC int handle_eob(void)