diff --git a/libtcc.c b/libtcc.c index 64a40ff..29dc964 100644 --- a/libtcc.c +++ b/libtcc.c @@ -1298,10 +1298,9 @@ LIBTCCAPI int tcc_add_sysinclude_path(TCCState *s, const char *pathname) ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags) { - ElfW(Ehdr) ehdr; - int fd, ret, size; - int filetype = flags & 0x0F; + int ret, filetype; + filetype = flags & 0x0F; if (filetype == 0) { /* use a file extension to detect a filetype */ const char *ext = tcc_fileextension(filename); @@ -1320,16 +1319,6 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags) } } - parse_flags = 0; -#ifdef CONFIG_TCC_ASM - /* if .S file, define __ASSEMBLER__ like gcc does */ - if (filetype == AFF_TYPE_ASM - || filetype == AFF_TYPE_ASMPP) { - tcc_define_symbol(s1, "__ASSEMBLER__", NULL); - parse_flags = PARSE_FLAG_ASM_FILE; - } -#endif - /* open the file */ ret = tcc_open(s1, filename); if (ret < 0) { @@ -1342,96 +1331,76 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags) dynarray_add((void ***)&s1->target_deps, &s1->nb_target_deps, tcc_strdup(filename)); - if (flags & AFF_PREPROCESS) { - ret = tcc_preprocess(s1); - goto the_end; - } - - if (filetype == AFF_TYPE_C) { - /* C file assumed */ - ret = tcc_compile(s1); - goto the_end; - } - + parse_flags = 0; #ifdef CONFIG_TCC_ASM - if (filetype == AFF_TYPE_ASMPP) { - /* non preprocessed assembler */ - ret = tcc_assemble(s1, 1); - goto the_end; - } - - if (filetype == AFF_TYPE_ASM) { - /* preprocessed assembler */ - ret = tcc_assemble(s1, 0); - goto the_end; + /* if .S file, define __ASSEMBLER__ like gcc does */ + if (filetype == AFF_TYPE_ASM || filetype == AFF_TYPE_ASMPP) { + tcc_define_symbol(s1, "__ASSEMBLER__", NULL); + parse_flags = PARSE_FLAG_ASM_FILE; } #endif - fd = file->fd; - /* assume executable format: auto guess file type */ - size = read(fd, &ehdr, sizeof(ehdr)); - lseek(fd, 0, SEEK_SET); - if (size <= 0) { - tcc_error_noabort("could not read header"); - goto the_end; - } + if (flags & AFF_PREPROCESS) { + ret = tcc_preprocess(s1); + } else if (filetype == AFF_TYPE_C) { + ret = tcc_compile(s1); +#ifdef CONFIG_TCC_ASM + } else if (filetype == AFF_TYPE_ASMPP) { + /* non preprocessed assembler */ + ret = tcc_assemble(s1, 1); + } else if (filetype == AFF_TYPE_ASM) { + /* preprocessed assembler */ + ret = tcc_assemble(s1, 0); +#endif + } else { + ElfW(Ehdr) ehdr; + int fd, obj_type; - if (size == sizeof(ehdr) && - ehdr.e_ident[0] == ELFMAG0 && - ehdr.e_ident[1] == ELFMAG1 && - ehdr.e_ident[2] == ELFMAG2 && - ehdr.e_ident[3] == ELFMAG3) { + fd = file->fd; + obj_type = tcc_object_type(fd, &ehdr); + lseek(fd, 0, SEEK_SET); /* do not display line number if error */ file->line_num = 0; - if (ehdr.e_type == ET_REL) { - ret = tcc_load_object_file(s1, fd, 0); - goto the_end; - } + switch (obj_type) { + case AFF_BINTYPE_REL: + ret = tcc_load_object_file(s1, fd, 0); + break; #ifndef TCC_TARGET_PE - if (ehdr.e_type == ET_DYN) { + case AFF_BINTYPE_DYN: if (s1->output_type == TCC_OUTPUT_MEMORY) { + ret = 0; #ifdef TCC_IS_NATIVE - void *h; - h = dlopen(filename, RTLD_GLOBAL | RTLD_LAZY); - if (h) + if (NULL == dlopen(filename, RTLD_GLOBAL | RTLD_LAZY)) + ret = -1; #endif - ret = 0; } else { ret = tcc_load_dll(s1, fd, filename, (flags & AFF_REFERENCED_DLL) != 0); } - goto the_end; - } + break; #endif - tcc_error_noabort("unrecognized ELF file"); - goto the_end; - } - - if (memcmp((char *)&ehdr, ARMAG, 8) == 0) { - file->line_num = 0; /* do not display line number if error */ - ret = tcc_load_archive(s1, fd); - goto the_end; - } - + case AFF_BINTYPE_AR: + ret = tcc_load_archive(s1, fd); + break; #ifdef TCC_TARGET_COFF - if (*(uint16_t *)(&ehdr) == COFF_C67_MAGIC) { - ret = tcc_load_coff(s1, fd); - goto the_end; - } + case AFF_BINTYPE_C67: + ret = tcc_load_coff(s1, fd); + break; #endif - + default: #ifdef TCC_TARGET_PE - ret = pe_load_file(s1, filename, fd); + ret = pe_load_file(s1, filename, fd); #else - /* as GNU ld, consider it is an ld script if not recognized */ - ret = tcc_load_ldscript(s1); + /* as GNU ld, consider it is an ld script if not recognized */ + ret = tcc_load_ldscript(s1); #endif - if (ret < 0) - tcc_error_noabort("unrecognized file type"); - -the_end: + if (ret < 0) + tcc_error_noabort("unrecognized file type"); + break; + } + } tcc_close(); return ret; } @@ -1702,6 +1671,15 @@ static const FlagDef warning_defs[] = { "implicit-function-declaration" }, }; +static int no_flag(const char **pp) +{ + const char *p = *pp; + if (*p != 'n' || *++p != 'o' || *++p != '-') + return 0; + *pp = p + 1; + return 1; +} + ST_FUNC int set_flag(TCCState *s, const FlagDef *flags, int nb_flags, const char *name, int value) { @@ -1710,10 +1688,9 @@ ST_FUNC int set_flag(TCCState *s, const FlagDef *flags, int nb_flags, const char *r; r = name; - if (r[0] == 'n' && r[1] == 'o' && r[2] == '-') { - r += 3; + if (no_flag(&r)) value = !value; - } + for(i = 0, p = flags; i < nb_flags; i++, p++) { if (!strcmp(r, p->name)) goto found; @@ -1789,6 +1766,7 @@ static int strstart(const char *val, const char **str) static int link_option(const char *str, const char *val, const char **ptr) { const char *p, *q; + int ret; /* there should be 1 or 2 dashes */ if (*str++ != '-') @@ -1800,6 +1778,13 @@ static int link_option(const char *str, const char *val, const char **ptr) p = str; q = val; + ret = 1; + if (q[0] == '?') { + ++q; + if (no_flag(&p)) + ret = -1; + } + while (*q != '\0' && *q != '=') { if (*p != *q) return 0; @@ -1816,7 +1801,7 @@ static int link_option(const char *str, const char *val, const char **ptr) p++; } *ptr = p; - return 1; + return ret; } static const char *skip_linker_arg(const char **str) @@ -1842,6 +1827,7 @@ static int tcc_set_linker(TCCState *s, const char *option) const char *p = NULL; char *end = NULL; int ignoring = 0; + int ret; if (link_option(option, "Bsymbolic", &p)) { s->symbolic = 1; @@ -1915,6 +1901,8 @@ static int tcc_set_linker(TCCState *s, const char *option) } else goto err; #endif + } else if (ret = link_option(option, "?whole-archive", &p), ret) { + s->alacarte_link = ret < 0; } else if (p) { return 0; } else { @@ -2152,7 +2140,7 @@ PUB_FUNC int tcc_parse_args(TCCState *s, int argc, char **argv) tcc_set_lib_path(s, optarg); break; case TCC_OPTION_l: - args_parser_add_file(s, optarg, AFF_TYPE_LIB); + args_parser_add_file(s, optarg, AFF_TYPE_LIBWH - s->alacarte_link); s->nb_libraries++; break; case TCC_OPTION_pthread: @@ -2295,8 +2283,6 @@ PUB_FUNC int tcc_parse_args(TCCState *s, int argc, char **argv) printf ("%s\n", TCC_VERSION); exit(0); break; - case TCC_OPTION_traditional: - break; case TCC_OPTION_x: if (*optarg == 'c') s->filetype = AFF_TYPE_C; @@ -2312,6 +2298,7 @@ PUB_FUNC int tcc_parse_args(TCCState *s, int argc, char **argv) if (x > 0) tcc_define_symbol(s, "__OPTIMIZE__", NULL); break; + case TCC_OPTION_traditional: case TCC_OPTION_pedantic: case TCC_OPTION_pipe: case TCC_OPTION_s: diff --git a/tcc.c b/tcc.c index 2bfc672..35680ec 100644 --- a/tcc.c +++ b/tcc.c @@ -314,7 +314,8 @@ int main(int argc, char **argv) /* compile or add each files or library */ for(i = ret = 0; i < s->nb_files && ret == 0; i++) { struct filespec *f = s->files[i]; - if (f->type == AFF_TYPE_LIB) { + if (f->type >= AFF_TYPE_LIB) { + s->alacarte_link = f->type == AFF_TYPE_LIB; if (tcc_add_library_err(s, f->name) < 0) ret = 1; } else { @@ -323,10 +324,11 @@ int main(int argc, char **argv) s->filetype = f->type; if (tcc_add_file(s, f->name) < 0) ret = 1; - s->filetype = AFF_TYPE_NONE; if (!first_file) first_file = f->name; } + s->filetype = AFF_TYPE_NONE; + s->alacarte_link = 1; } if (0 == ret) { diff --git a/tcc.h b/tcc.h index 2c38fa5..a5380b5 100644 --- a/tcc.h +++ b/tcc.h @@ -1143,12 +1143,19 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags) #define AFF_REFERENCED_DLL 0x20 /* load a referenced dll from another dll */ #define AFF_PREPROCESS 0x40 /* preprocess file */ /* combined with: */ -#define AFF_TYPE_NONE 0 -#define AFF_TYPE_C 1 -#define AFF_TYPE_ASM 2 -#define AFF_TYPE_ASMPP 3 -#define AFF_TYPE_BIN 4 -#define AFF_TYPE_LIB 5 +#define AFF_TYPE_NONE 0 +#define AFF_TYPE_C 1 +#define AFF_TYPE_ASM 2 +#define AFF_TYPE_ASMPP 3 +#define AFF_TYPE_BIN 4 +#define AFF_TYPE_LIB 5 +#define AFF_TYPE_LIBWH 6 +/* values from tcc_object_type(...) */ +#define AFF_BINTYPE_REL 1 +#define AFF_BINTYPE_DYN 2 +#define AFF_BINTYPE_AR 3 +#define AFF_BINTYPE_C67 4 + ST_FUNC int tcc_add_crt(TCCState *s, const char *filename); @@ -1348,6 +1355,7 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s); ST_FUNC void relocate_plt(TCCState *s1); ST_FUNC void tcc_add_linker_symbols(TCCState *s1); +ST_FUNC int tcc_object_type(int fd, ElfW(Ehdr) *h); ST_FUNC int tcc_load_object_file(TCCState *s1, int fd, unsigned long file_offset); ST_FUNC int tcc_load_archive(TCCState *s1, int fd); ST_FUNC void tcc_add_bcheck(TCCState *s1); diff --git a/tccelf.c b/tccelf.c index 33336c6..33ee076 100644 --- a/tccelf.c +++ b/tccelf.c @@ -2725,6 +2725,25 @@ typedef struct SectionMergeInfo { uint8_t link_once; /* true if link once section */ } SectionMergeInfo; +ST_FUNC int tcc_object_type(int fd, ElfW(Ehdr) *h) +{ + int size = read(fd, h, sizeof *h); + if (size == sizeof *h && 0 == memcmp(h, ELFMAG, 4)) { + if (h->e_type == ET_REL) + return AFF_BINTYPE_REL; + if (h->e_type == ET_DYN) + return AFF_BINTYPE_DYN; + } else if (size >= 8) { + if (0 == memcmp(h, ARMAG, 8)) + return AFF_BINTYPE_AR; +#ifdef TCC_TARGET_COFF + if (((struct filehdr*)h)->f_magic == COFF_C67_MAGIC) + return AFF_BINTYPE_C67; +#endif + } + return 0; +} + /* load an object file and merge it with current files */ /* XXX: handle correctly stab (debug) info */ ST_FUNC int tcc_load_object_file(TCCState *s1, @@ -2746,15 +2765,8 @@ ST_FUNC int tcc_load_object_file(TCCState *s1, stab_index = stabstr_index = 0; - if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr)) - goto fail1; - if (ehdr.e_ident[0] != ELFMAG0 || - ehdr.e_ident[1] != ELFMAG1 || - ehdr.e_ident[2] != ELFMAG2 || - ehdr.e_ident[3] != ELFMAG3) - goto fail1; - /* test if object file */ - if (ehdr.e_type != ET_REL) + lseek(fd, file_offset, SEEK_SET); + if (tcc_object_type(fd, &ehdr) != AFF_BINTYPE_REL) goto fail1; /* test CPU specific stuff */ if (ehdr.e_ident[5] != ELFDATA2LSB || @@ -3052,7 +3064,6 @@ static int tcc_load_alacarte(TCCState *s1, int fd, int size) if(sym->st_shndx == SHN_UNDEF) { off = get_be32(ar_index + i * 4) + sizeof(ArchiveHeader); ++bound; - lseek(fd, off, SEEK_SET); if(tcc_load_object_file(s1, fd, off) < 0) { fail: ret = -1; @@ -3105,14 +3116,12 @@ ST_FUNC int tcc_load_archive(TCCState *s1, int fd) /* coff symbol table : we handle it */ if(s1->alacarte_link) return tcc_load_alacarte(s1, fd, size); - } else if (!strcmp(ar_name, "//") || - !strcmp(ar_name, "__.SYMDEF") || - !strcmp(ar_name, "__.SYMDEF/") || - !strcmp(ar_name, "ARFILENAMES/")) { - /* skip symbol table or archive names */ } else { - if (tcc_load_object_file(s1, fd, file_offset) < 0) - return -1; + ElfW(Ehdr) ehdr; + if (tcc_object_type(fd, &ehdr) == AFF_BINTYPE_REL) { + if (tcc_load_object_file(s1, fd, file_offset) < 0) + return -1; + } } lseek(fd, file_offset + size, SEEK_SET); } diff --git a/tccpe.c b/tccpe.c index 3e15d91..0e88fa9 100644 --- a/tccpe.c +++ b/tccpe.c @@ -1664,7 +1664,7 @@ ST_FUNC int pe_load_file(struct TCCState *s1, const char *filename, int fd) ret = pe_load_def(s1, fd); else if (pe_load_res(s1, fd) == 0) ret = 0; - else if (read_mem(fd, 0, buf, sizeof buf) && 0 == strncmp(buf, "MZ", 2)) + else if (read_mem(fd, 0, buf, 4) && 0 == memcmp(buf, "MZ\220", 4)) ret = pe_load_dll(s1, tcc_basename(filename), fd); return ret; }