From 59e18aee0e509a3ca75dbe6f909e18c1d17893d1 Mon Sep 17 00:00:00 2001 From: mingodad Date: Fri, 11 Jan 2013 00:04:38 +0000 Subject: [PATCH] Added what I call virtual io to tinycc this way we can make a monolitic executable or library that contains all needed to compile programs, truly tinycc portable. Tested under linux exec the "mk-it" shell script and you'll end up with a portable tinycc executable that doesn't depend on anything else. --- Makefile | 16 +- bin2c.c | 615 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ libtcc.c | 105 ++++++++-- libtcc.h | 29 +++ mk-attachments.sh | 4 + mk-it | 8 + tcc.c | 97 +++++++++ tcc.h | 24 ++- tcccoff.c | 4 +- tccelf.c | 43 ++-- tccpe.c | 4 +- tccpp.c | 16 +- 12 files changed, 903 insertions(+), 62 deletions(-) create mode 100644 bin2c.c create mode 100755 mk-attachments.sh create mode 100755 mk-it diff --git a/Makefile b/Makefile index c8bca47d..8281d565 100644 --- a/Makefile +++ b/Makefile @@ -172,15 +172,20 @@ PROGS+=$(PROGS_CROSS) TCCLIBS+=$(LIBTCC1_CROSS) endif -all: $(PROGS) $(TCCLIBS) $(TCCDOCS) +ifdef CONFIG_USE_ATTACHMENTS +FILE_ATTACHMENTS= tcc_attachments.o +CFLAGS += -DWITH_ATTACHMENTS=1 +endif + +all: $(PROGS) $(TCCLIBS) $(FILE_ATTACHMENTS) $(TCCDOCS) # Host Tiny C Compiler tcc$(EXESUF): tcc.o $(LIBTCC) - $(CC) -o $@ $^ $(LIBS) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $(LINK_LIBTCC) + $(CC) -o $@ $^ $(LIBS) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $(FILE_ATTACHMENTS) $(LINK_LIBTCC) # Cross Tiny C Compilers %-tcc$(EXESUF): - $(CC) -o $@ tcc.c -DONE_SOURCE $(DEFINES) $(CPPFLAGS) $(CFLAGS) $(LIBS) $(LDFLAGS) + $(CC) -o $@ tcc.c -DONE_SOURCE $(DEFINES) $(CPPFLAGS) $(CFLAGS) $(FILE_ATTACHMENTS) $(LIBS) $(LDFLAGS) $(I386_CROSS): DEFINES = -DTCC_TARGET_I386 \ -DCONFIG_TCCDIR="\"$(tccdir)/i386\"" @@ -227,9 +232,12 @@ libtcc.so.1.0: $(LIBTCC_OBJ) libtcc.so.1.0: CFLAGS+=-fPIC +#tcc_attachments.o: libtcc.c +# mk-attachments.sh + # profiling version tcc_p$(EXESUF): $(NATIVE_FILES) - $(CC) -o $@ $< $(NATIVE_DEFINES) $(CPPFLAGS_P) $(CFLAGS_P) $(LIBS_P) $(LDFLAGS_P) + $(CC) -o $@ $< $(NATIVE_DEFINES) $(CPPFLAGS_P) $(CFLAGS_P) $(LIBS_P) $(FILE_ATTACHMENTS) $(LDFLAGS_P) # windows utilities tiny_impdef$(EXESUF): win32/tools/tiny_impdef.c diff --git a/bin2c.c b/bin2c.c new file mode 100644 index 00000000..e8d2795e --- /dev/null +++ b/bin2c.c @@ -0,0 +1,615 @@ + +#include +#include +#include +#include +#include +#include +#include + +/* Version information */ +const char *versionInfo = + "bin2c version 1.0 by Fatih Aygun\n" + "\n" + "Visit sourceforge.net/projects/bin2c to for new versions.\n" + "This program is public domain, do whatever you want with it.\n" +; + +/* Command line help */ +const char *commandLineHelp = + "Usage: bin2c [OPTION...] FILE [FILE...]\n" + "bin2c creates a C soures and headers from binary files.\n" + "\n" + "Examples:\n" + " bin2c -o foo.h bar.bin # Create 'foo.h' from the contents of\n" + " 'bar.bin'\n" + " bin2c -o foo.h file1 file2 # Create 'foo.h' from the contents of 'file1'\n" + " and 'file2'\n" + " bin2c -d foo.h -o foo.c bar.bin # Create 'foo.c' and 'foo.h' from the\n" + " contents of 'bar.bin'\n" + "\n" + "Options:\n" + " -d, --header Name a header file (A header file will not be\n" + " created unless explicitly named)\n" + " -h, --help Print this command line help and exit immediately\n" + " -o, --output Name an output file\n" + " -m, --macro Create the size definition as a macro instead of\n" + " a const\n" + " -n, --name Name the symbol to be defined\n" + " -v, --version Print version information and exit immediately\n" + "\n" + "Visit sourceforge.net/projects/bin2c to for new versions.\n" + "This program is public domain, do whatever you want with it.\n" + ; + +/* Output formatting macros */ +#define bytesPerLine 16 +#define indentString " " +#define outputFormatBase "0x%.2X" +#define outputFormat outputFormatBase", " +#define outputFormatEOL outputFormatBase",\n" +#define outputFormatEOF outputFormatBase"\n" +#define sizeDefinition "const long int bin2c_%s_size = %d;\n" +#define sizeMacroDefinition "#define bin2c_%s_size %d\n" +#define typeName "const unsigned char" + +/* Define bool */ +#define bool int +#define false 0 +#define true 1 + +/* Global variables */ +FILE *outputFile=0; /* Current output file stream */ +const char *outputFileName=0; /* Current output file name */ +FILE *headerFile=0; /* Current header file */ +const char *headerFileName=0; /* Current header file name */ +FILE *tmpFuncFile=0; /* File to write final function that search for files */ +const char *tmpFuncFileName=0; /* Current tmpFunc file name */ +char *symbolName=0; /* Current symbol name */ +char *headerSymbol=0; /* Symbol for multiple inclusion protection */ +bool createMacro = false; /* Should we create a define instead of a const? */ + +/* Error messages */ +const char* cantOpen = "Can't open file '%s'"; +const char* cantClose = "Can't close file '%s'"; +const char* cantRemove = "Can't remove file '%s'"; +const char* cantWrite = "Can't write to file '%s'"; +const char* noOutputFilesAreNamed = "No output files are named"; +const char* noHeaderFilesAreNamed = "No header files are named"; +const char* cantMalloc = "Can't allocate memory for '%s'"; +const char* cantSeek = "Can't seek in the file '%s'"; +const char* cantDetermine = "Can't determine the file size of '%s'"; +const char* cantRead = "Can't read from file %s"; +const char* unknownOption = "Unknown option '%s'"; +const char* tryHelp = "Try 'bin2c --help' for more information.\n"; +const char* noSymbolName = "No symbol name is given"; +const char* notValidId = "'%s' is not a valid identifier"; +const char* symbolNameGiven = "Symbol name is given twice"; + +/* Print a formatted error message */ +static void vprintfError(const char *format, va_list args) +{ + fprintf(stderr, "bin2c: "); + vfprintf(stderr, format, args); + if (errno) { + fprintf(stderr, ": "); + perror(""); + errno = 0; + } else { + fprintf(stderr, "\n"); + } +} + +static void printfError(const char *format, ...) +{ + va_list args; + + va_start(args, format); + vprintfError(format, args); + va_end(args); +} + +/* Panic */ +static void panic() +{ + /* Close and remove the output file if it's open */ + if (outputFile) { + if (fclose(outputFile)) { + printfError(cantClose, outputFileName); + } + + if (remove(outputFileName)) { + printfError(cantRemove, outputFileName); + } + } + + /* Close and remove the header file if it's open */ + if (headerFile) { + if (fclose(headerFile)) { + printfError(cantClose, headerFileName); + } + + if (remove(headerFileName)) { + printfError(cantRemove, headerFileName); + } + } + + /* Close and remove the header file if it's open */ + if (tmpFuncFile) { + if (fclose(tmpFuncFile)) { + printfError(cantClose, tmpFuncFileName); + } + + if (remove(tmpFuncFileName)) { + printfError(cantRemove, tmpFuncFileName); + } + } + + /* Exit with an error code */ + exit(EXIT_FAILURE); +} + +/* Check a contidion and panic if it's false */ +static void check(bool condition, const char *format, ...) +{ + va_list args; + + if (!condition) { + va_start(args, format); + vprintfError(format, args); + va_end(args); + panic(); + } +} + +/* Write a formatted string to the output file and check for errors */ +static void output(const char *format, ...) +{ + va_list args; + + /* Try to write to the file */ + va_start(args, format); + vfprintf(outputFile, format, args); + va_end(args); + + /* Check for errors */ + check(!ferror(outputFile), cantWrite, outputFileName); +} + +/* Write a formatted string to the header file and check for errors */ +static void header(const char *format, ...) +{ + va_list args; + + /* Try to write to the file */ + va_start(args, format); + vfprintf(headerFile, format, args); + va_end(args); + + /* Check for errors */ + check(!ferror(headerFile), cantWrite, headerFileName); +} + +/* Write a formatted string to the tmp file and check for errors */ +static void tmpFunc(const char *format, ...) +{ + va_list args; + + /* Try to write to the file */ + va_start(args, format); + vfprintf(tmpFuncFile, format, args); + va_end(args); + + /* Check for errors */ + check(!ferror(tmpFuncFile), cantWrite, tmpFuncFileName); +} + +/* Allocate a valid C identifier from a file name */ +static char *fileNameToSymbol(const char *fileName) +{ + char *name; + int i; + + name = malloc(strlen(fileName) + 1); + check(name != 0, cantMalloc, "the symbol name"); + + /* Copy the file name to symbolName */ + strcpy(name, fileName); + + /* Replace every non alphanumerical character with '_' */ + for (i = 0; name[i]; ++i) { + if (!((name[i] >= 'a' && name[i] <= 'z') || + (name[i] >= 'A' && name[i] <= 'Z') || + (name[i] >= '0' && name[i] <= '9'))) { + name[i] = '_'; + } + } + + /* Replace the first character with '_' if it's a digit */ + if (name[0] >= '0' && name[0] <= '9') { + name[0] = '_'; + } + + return name; +} + + int isdir(const char * path) +{ + int bOK = 0; + #ifndef _MSC_VER + struct stat buf; + if (path == NULL) return 0; + if (stat(path, &buf) == 0 && S_ISDIR(buf.st_mode)) bOK=1; + #else + wchar_t *wcpath = to_wide_string((char*)path); + if (wcpath == NULL) return FALSE; + bOK = isdirW(wcpath); + FREE(wcpath); + #endif + return bOK; + } + +/* Process an input file */ +static int processFile(const char *fileName, long int from, long int to) +{ + bool symbolNameAllocated = false; /* Did we allocate the symbolName? */ + long int i, j; /* Indexes for various purposes */ + FILE *inputFile; /* Input file stream */ + int byte; /* Byte read from the input */ + long int fsize=0; + + if(isdir(fileName)) return 0; + + /* Be sure that the output file is open */ + check(outputFile != 0, noOutputFilesAreNamed); + + /* Write the comment */ + output("\n/* Contents of file %s */\n", fileName); + if (headerFile) { + header("\n/* Contents of file %s */\n", fileName); + } + + /* Make up a suitable symbolName if we don't have one */ + if (!symbolName) { + symbolName = fileNameToSymbol(fileName); + symbolNameAllocated = true; + } + + /* Open the input file */ + inputFile = fopen(fileName, "rb"); + check(inputFile != 0, cantOpen, fileName); + + /* If to == -1, set it to the last byte of the file */ + if (to == -1) { + check(!fseek(inputFile, 0, SEEK_END), cantSeek, fileName); + to = ftell(inputFile); + check(to >= 0, cantDetermine, fileName); + --to; + } + + assert(from <= to - 1); + + /* Position the file to "from" */ + check(!fseek(inputFile, from, SEEK_SET), cantSeek, fileName); + + fsize = to - from + 1; + + /* Output the size definition */ + if (headerFile) { + if (createMacro) { + header(sizeMacroDefinition, symbolName, fsize); + } else { + header("extern "sizeDefinition, symbolName, fsize); + output(sizeDefinition, symbolName, fsize); + } + } else { + if (createMacro) { + output(sizeMacroDefinition, symbolName, fsize); + } else { + output(sizeDefinition, symbolName, fsize); + } + } + + if (tmpFuncFile) { + tmpFunc("\t{\"/_attach_/%s\", bin2c_%s, %d},\n", fileName, symbolName, fsize); + } + /* Output the definition */ + output("%s bin2c_%s[%d] = {\n", typeName, symbolName, fsize); + if (headerFile) { + header("extern %s *bin2c_%s;\n", typeName, symbolName, fsize); + } + + /* Output the contents */ + j = 1; + for (i = from; i <= to; ++i) { + /* Read a byte from the input file */ + byte = fgetc(inputFile); + check(byte != EOF, cantRead, fileName); + + /* Output the indentation if it's the first byte of a line */ + if (j == 1) { + output(indentString); + } + + /* Output the actual byte */ + if (i == to) { + /* Output the last byte */ + output(outputFormatEOF, byte); + } else if (j == bytesPerLine) { + /* Output the last byte of a line */ + output(outputFormatEOL, byte); + } else { + /* Output a normal byte */ + output(outputFormat, byte); + } + + /* Next byte */ + ++j; + if (j > bytesPerLine) { + j = 1; + } + } + + /* Output the end of definition */ + output("};\n"); + + /* Free the symbol name if it was allocated by us */ + if (symbolNameAllocated) { + free(symbolName); + } + + /* Clear the symbol name */ + symbolName = 0; + return 1; +} + +/* Unknown option error */ +static void handleUnknownOption(const char *s) +{ + printfError(unknownOption, s); + fprintf(stderr, tryHelp); + panic(); +} + +/* Open an output file */ +static void openOutputFile(const char *fileName) +{ + /* Be sure that a file name is given */ + if (!fileName) { + printfError(noOutputFilesAreNamed); + fprintf(stderr, tryHelp); + panic(); + } + + /* Close previous output file if any */ + if (outputFile) { + check(!fclose(outputFile), cantClose, outputFileName); + } + + /* Open the new output file */ + outputFile = fopen(fileName, "w"); + check(outputFile != 0, cantOpen, outputFileName); + outputFileName = fileName; + + output("/* Generated by bin2c, do not edit manually */\n"); +} + +/* Open a header file */ +static void openHeaderFile(const char *fileName) +{ + /* Be sure that a file name is given */ + if (!fileName) { + printfError(noHeaderFilesAreNamed); + fprintf(stderr, tryHelp); + panic(); + } + + /* Close previous header file if any */ + if (headerFile) { + header("\n#endif /* __%s_included */\n", headerSymbol); + free(headerSymbol); + headerSymbol = 0; + check(!fclose(headerFile), cantClose, headerFileName); + } + + /* Open the new header file */ + headerFile = fopen(fileName, "w"); + check(headerFile != 0, cantOpen, headerFileName); + headerFileName = fileName; + headerSymbol = fileNameToSymbol(fileName); + + header("/* Generated by bin2c, do not edit manually */\n"); + header("#ifndef __%s_included\n", headerSymbol); + header("#define __%s_included\n", headerSymbol); +} + + typedef void writeFileFunc(const char *format, ...); + + void writeAttchmentStruct(writeFileFunc *writeFunc){ + (*writeFunc)("\ntypedef struct {\n"); + (*writeFunc)("\tconst char *file_name;\n"); + (*writeFunc)("\tconst unsigned char *sym_name;\n"); + (*writeFunc)("\tlong size;\n"); + (*writeFunc)("} bin2c_filesAttached_st;\n"); +} + +/* Open a header file */ +static void openFuncFile(const char *fileName) +{ + static char fnBuf[1024]; + /* Be sure that a file name is given */ + if (!fileName) { + printfError(noHeaderFilesAreNamed); + fprintf(stderr, tryHelp); + panic(); + } + + /* Close previous header file if any */ + if (tmpFuncFile) { + tmpFunc("\n};\n"); + check(!fclose(tmpFuncFile), cantClose, tmpFuncFileName); + } + + snprintf(fnBuf, sizeof(fnBuf), "%s.tmp", fileName); + + /* Open the new header file */ + tmpFuncFile = fopen(fnBuf, "w"); + check(tmpFuncFile != 0, cantOpen, fnBuf); + tmpFuncFileName = fnBuf; + + tmpFunc("\n/* Generated by bin2c, do not edit manually */\n"); + writeAttchmentStruct(&tmpFunc); + tmpFunc("const bin2c_filesAttached_st bin2c_filesAttached[] = {\n"); +} + +/* Set the symbol name for next file */ +static void setSymbolName(char *name) +{ + int i; + + if (symbolName) { + printfError(symbolNameGiven); + fprintf(stderr, tryHelp); + panic(); + } + + /* Be sure that a symbol name is given */ + if (!name) { + printfError(noSymbolName); + fprintf(stderr, tryHelp); + panic(); + } + + /* Check if the symbol is a valid C identifier */ + check((name[0] >= 'a' && name[0] <='z') || + (name[0] >= 'A' && name[0] <='Z') || + (name[0] == '_'), notValidId, name); + + for (i = 1; name[i]; ++i) { + check((name[i] >= 'a' && name[i] <='z') || + (name[i] >= 'A' && name[i] <='Z') || + (name[i] >= '0' && name[i] <='9') || + (name[i] == '_'), notValidId, name); + } + + /* Set the symbol name */ + symbolName = name; + } + + void concatenate(const char *dest, const char *src){ + int i,ch; + FILE *fpdest=fopen(dest,"a"); + FILE *fpsrc=fopen(src,"r"); + while((ch=getc(fpsrc))!=EOF) putc(ch,fpdest); + } + +/* Main function */ +int main(int argc, char **argv) +{ + int i; /* Index to process commandline arguments */ + int ipf = 0; /*total files processed*/ + + /* Scan for a -h or --help option */ + for (i = 1; i < argc; ++i) { + if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) { + /* Print command line arguments help and exit immediately */ + printf("%s", commandLineHelp); + return EXIT_SUCCESS; + } + } + + /* Scan for a -v or --version option */ + for (i = 1; i < argc; ++i) { + if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) { + /* Print version information and exit immediately */ + printf("%s", versionInfo); + return EXIT_SUCCESS; + } + } + + /* Process command line arguments */ + for (i = 1; i < argc; ++i) { + /* Check if it's an option or file name */ + if (argv[i][0] == '-') { + /* Process the option */ + switch (argv[i][1]) { + case '-': + /* Long options */ + if (!strcmp(argv[i], "--output")) { + /* Name an output file */ + openOutputFile(argv[i+1]); + openFuncFile(argv[i+1]); + ++i; + } else if (!strcmp(argv[i], "--header")) { + /* Name a header file */ + openHeaderFile(argv[i+1]); + ++i; + } else if (!strcmp(argv[i], "--macro")) { + /* Create a macro for the size definition */ + createMacro = true; + } else if (!strcmp(argv[i], "--name")) { + /* Name the symbol */ + setSymbolName(argv[i+1]); + ++i; + } else { + /* Unknown option */ + handleUnknownOption(argv[i]); + } + break; + case 'o': + /* Name an output file */ + openOutputFile(argv[i+1]); + openFuncFile(argv[i+1]); + ++i; + break; + case 'd': + /* Name a header file */ + openHeaderFile(argv[i+1]); + ++i; + break; + case 'm': + /* Create a macro for the size definition */ + createMacro = true; + break; + case 'n': + /* Name the symbol */ + setSymbolName(argv[i+1]); + ++i; + break; + default: + /* Unknown option */ + handleUnknownOption(argv[i]); + } + } else { + /* Process the file */ + if(processFile(argv[i], 0, -1)) ipf++; + } + } + + /* Close any remaining output files */ + if (headerFile) { + writeAttchmentStruct(&header); + header("extern const bin2c_filesAttached_st bin2c_filesAttached[%d];\n", ipf); + + header("\n#endif /* __%s_included */\n", headerSymbol); + free(headerSymbol); + headerSymbol = 0; + check(!fclose(headerFile), cantClose, headerFileName); + } + + if (tmpFuncFile) { + tmpFunc("};\n"); + check(!fclose(tmpFuncFile), cantClose, tmpFuncFileName); + } + + if (outputFile) { + check(!fclose(outputFile), cantClose, outputFileName); + } + + if (tmpFuncFile && outputFile) { + concatenate(outputFileName, tmpFuncFileName); + remove(tmpFuncFileName); + } + + return EXIT_SUCCESS; +} diff --git a/libtcc.c b/libtcc.c index b0a9b1a4..f554f743 100644 --- a/libtcc.c +++ b/libtcc.c @@ -268,6 +268,62 @@ PUB_FUNC void tcc_memstats(void) #define realloc(p, s) use_tcc_realloc(p, s) /********************************************************/ +/* virtual io */ + +LIBTCCAPI void tcc_set_vio_module(TCCState *s, vio_module_t *vio_module){ + s->vio_module = vio_module; + vio_module->tcc_state = s; +} + +void vio_initialize(vio_fd *fd) { + fd->fd = -1; + fd->vio_udata = NULL; + fd->vio_module = NULL; +} + +int vio_open(struct TCCState *s, vio_fd *fd, const char *fn, int oflag) { + int rc; + vio_initialize(fd); + fd->vio_module = s->vio_module; + if(s->vio_module && (s->vio_module->call_vio_open_flags & CALL_VIO_OPEN_FIRST)) { + rc = s->vio_module->vio_open(fd, fn, oflag); + if(rc >= 0) return rc; + } + + fd->fd = open(fn, oflag); + + if(fd->fd < 0 && s->vio_module && (s->vio_module->call_vio_open_flags & CALL_VIO_OPEN_LAST)) { + rc = s->vio_module->vio_open(fd, fn, oflag); + if(rc >= 0) return rc; + } + //printf("vio_open = %d %s\n", fd->fd, fn); + return fd->fd; +} + +off_t vio_lseek(vio_fd fd, off_t offset, int whence) { + if(fd.vio_udata) { + return fd.vio_module->vio_lseek(fd, offset, whence); + } + return lseek(fd.fd, offset, whence); +} + +size_t vio_read(vio_fd fd, void *buf, size_t bytes) { + if(fd.vio_udata) { + return fd.vio_module->vio_read(fd, buf, bytes); + } + return read(fd.fd, buf, bytes); +} + +int vio_close(vio_fd *fd) { + int rc = 0; + if(fd->vio_udata){ + fd->vio_module->vio_close(fd); + } else rc = close(fd->fd); + vio_initialize(fd); + return rc; +} + +/********************************************************/ /* dynarrays */ PUB_FUNC void dynarray_add(void ***ptab, int *nb_ptr, void *data) @@ -666,7 +722,7 @@ ST_FUNC void tcc_open_bf(TCCState *s1, const char *filename, int initlen) bf->line_num = 1; bf->ifndef_macro = 0; bf->ifdef_stack_ptr = s1->ifdef_stack_ptr; - bf->fd = -1; + vio_initialize(&bf->fd); bf->prev = file; file = bf; } @@ -674,26 +730,28 @@ ST_FUNC void tcc_open_bf(TCCState *s1, const char *filename, int initlen) ST_FUNC void tcc_close(void) { BufferedFile *bf = file; - if (bf->fd > 0) { - close(bf->fd); + if (bf->fd.fd > 0) { + vio_close(&bf->fd); total_lines += bf->line_num; } file = bf->prev; tcc_free(bf); } -ST_FUNC int tcc_open(TCCState *s1, const char *filename) +ST_FUNC vio_fd tcc_open(TCCState *s1, const char *filename) { - int fd; - if (strcmp(filename, "-") == 0) - fd = 0, filename = "stdin"; + vio_fd fd; + if (strcmp(filename, "-") == 0) { + vio_initialize(&fd); + fd.fd = 0, filename = "stdin"; + } else - fd = open(filename, O_RDONLY | O_BINARY); - if ((s1->verbose == 2 && fd >= 0) || s1->verbose == 3) - printf("%s %*s%s\n", fd < 0 ? "nf":"->", + vio_open(s1, &fd, filename, O_RDONLY | O_BINARY); + if ((s1->verbose == 2 && fd.fd >= 0) || s1->verbose == 3) + printf("%s %*s%s\n", fd.fd < 0 ? "nf":"->", (int)(s1->include_stack_ptr - s1->include_stack), "", filename); - if (fd < 0) - return -1; + if (fd.fd < 0) + return fd; tcc_open_bf(s1, filename, 0); file->fd = fd; @@ -817,18 +875,23 @@ static int tcc_compile(TCCState *s1) return s1->nb_errors != 0 ? -1 : 0; } -LIBTCCAPI int tcc_compile_string(TCCState *s, const char *str) +LIBTCCAPI int tcc_compile_named_string(TCCState *s, const char *str, const char *strname) { int len, ret; len = strlen(str); - tcc_open_bf(s, "", len); + tcc_open_bf(s, strname ? strname : "", len); memcpy(file->buffer, str, len); ret = tcc_compile(s); tcc_close(); return ret; } +LIBTCCAPI int tcc_compile_string(TCCState *s, const char *str) +{ + return tcc_compile_named_string(s, str, NULL); +} + /* define a preprocessor symbol. A value can also be provided with the '=' operator */ LIBTCCAPI void tcc_define_symbol(TCCState *s1, const char *sym, const char *value) { @@ -1028,6 +1091,7 @@ LIBTCCAPI TCCState *tcc_new(void) #ifdef TCC_TARGET_I386 s->seg_size = 32; #endif + s->vio_module = NULL; return s; } @@ -1094,7 +1158,8 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags) { const char *ext; ElfW(Ehdr) ehdr; - int fd, ret, size; + int ret=0, size; + vio_fd fd; /* find source file type with extension */ ext = tcc_fileextension(filename); @@ -1108,11 +1173,11 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags) #endif /* open the file */ - ret = tcc_open(s1, filename); - if (ret < 0) { + fd = tcc_open(s1, filename); + if (fd.fd < 0) { if (flags & AFF_PRINT_ERROR) tcc_error_noabort("file '%s' not found", filename); - return ret; + return fd.fd; } /* update target deps */ @@ -1146,8 +1211,8 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags) fd = file->fd; /* assume executable format: auto guess file type */ - size = read(fd, &ehdr, sizeof(ehdr)); - lseek(fd, 0, SEEK_SET); + size = vio_read(fd, &ehdr, sizeof(ehdr)); + vio_lseek(fd, 0, SEEK_SET); if (size <= 0) { tcc_error_noabort("could not read header"); goto the_end; diff --git a/libtcc.h b/libtcc.h index 278dca30..791cd29d 100644 --- a/libtcc.h +++ b/libtcc.h @@ -13,6 +13,28 @@ struct TCCState; typedef struct TCCState TCCState; +struct vio_module_t; + +typedef struct vio_fd { + int fd; + void *vio_udata; + struct vio_module_t *vio_module; +} vio_fd; + +#define CALL_VIO_OPEN_FIRST 0x01 +#define CALL_VIO_OPEN_LAST 0x02 + +typedef struct vio_module_t { + void *user_data; + struct TCCState *tcc_state; + int call_vio_open_flags; /*CALL_VIO_OPEN_FIRST, CALL_VIO_OPEN_LAST, one or both */ + int (*vio_open)(vio_fd *fd, const char *fn, int oflag) ; + off_t (*vio_lseek)(vio_fd fd, off_t offset, int whence); + size_t (*vio_read)(vio_fd fd, void *buf, size_t bytes); + int (*vio_close)(vio_fd *fd); +} vio_module_t; + + /* create a new TCC compilation context */ LIBTCCAPI TCCState *tcc_new(void); @@ -32,6 +54,9 @@ LIBTCCAPI int tcc_set_warning(TCCState *s, const char *warning_name, int value); /* set linker option */ LIBTCCAPI const char * tcc_set_linker(TCCState *s, char *option, int multi); +/* set virtual io module */ +LIBTCCAPI void tcc_set_vio_module(TCCState *s, vio_module_t *vio_module); + /*****************************/ /* preprocessor */ @@ -58,6 +83,10 @@ LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename); error. */ LIBTCCAPI int tcc_compile_string(TCCState *s, const char *buf); +/* compile a string containing a C source. Return non zero if + error. Can associate a name with string for errors. */ +int tcc_compile_named_string(TCCState *s, const char *buf, const char *strname); + /*****************************/ /* linking commands */ diff --git a/mk-attachments.sh b/mk-attachments.sh new file mode 100755 index 00000000..18cc0b08 --- /dev/null +++ b/mk-attachments.sh @@ -0,0 +1,4 @@ +FNAME=tcc_attachments +gcc -o bin2c bin2c.c +./bin2c -m -d ${FNAME}.h -o ${FNAME}.c include/* libtcc.a libtcc1.a +gcc -c ${FNAME}.c diff --git a/mk-it b/mk-it new file mode 100755 index 00000000..f73d3e6c --- /dev/null +++ b/mk-it @@ -0,0 +1,8 @@ +rm *.a +rm *.o +make +./mk-attachments.sh +rm tcc.o +make CONFIG_USE_ATTACHMENTS=1 +strip tcc + diff --git a/tcc.c b/tcc.c index 5dd5725c..f4d94be7 100644 --- a/tcc.c +++ b/tcc.c @@ -479,6 +479,98 @@ static int parse_args(TCCState *s, int argc, char **argv) return optind; } +#ifdef WITH_ATTACHMENTS +#include "tcc_attachments.h" +#define ATTACH_PREFIX "/_attach_" + +static vio_module_t vio_module; + +typedef struct vio_memfile_t { + off_t size; + off_t pos; + const unsigned char *mem; +} vio_memfile_t; + +static int vio_mem_open(vio_fd *fd, const char *fn, int oflag) { + //printf("%d:%s\n", fd->fd, fn); + if(fd->vio_module && strncmp(ATTACH_PREFIX, fn, sizeof(ATTACH_PREFIX)-1) == 0){ + int i, count = sizeof(bin2c_filesAttached)/sizeof(bin2c_filesAttached_st); + for(i=0; i < count; ++i) { + //printf("%s:%s\n", fn, bin2c_filesAttached[i].file_name); + if(strcmp(fn, bin2c_filesAttached[i].file_name) == 0) { + vio_memfile_t *mf = (vio_memfile_t*)tcc_malloc(sizeof(vio_memfile_t)); + mf->mem = bin2c_filesAttached[i].sym_name; + mf->size = bin2c_filesAttached[i].size; + mf->pos = 0; + fd->fd = 1; + fd->vio_udata = mf; + //printf("%d:%s\n", fd->fd, fn); + return fd->fd; + } + } + } + return -1; +} + +static off_t vio_mem_lseek(vio_fd fd, off_t offset, int whence) { + if(fd.vio_udata) { + off_t loffset = 0; + vio_memfile_t *mf = (vio_memfile_t*)fd.vio_udata; + if (whence == SEEK_CUR) + loffset = mf->pos + offset; + else if (whence == SEEK_SET) + loffset = offset; + else if (whence == SEEK_END) + loffset = ((off_t)mf->size) + offset; + + if (loffset < 0 && loffset > mf->size) + return -1; + + mf->pos = loffset; + + return mf->pos; + } + return lseek(fd.fd, offset, whence); +} + +static size_t vio_mem_read(vio_fd fd, void *buf, size_t bytes) { + if(fd.vio_udata) { + vio_memfile_t *mf = (vio_memfile_t*)fd.vio_udata; + if( (mf->pos + bytes) > mf->size) { + long bc = mf->size - mf->pos; + if(bc > 0) { + memcpy(buf, mf->mem + mf->pos, bc); + mf->pos = mf->size; + return bc; + } + return 0; + } + memcpy(buf, mf->mem + mf->pos, bytes); + mf->pos += bytes; + return bytes; + } + return 0; +} + +static int vio_mem_close(vio_fd *fd) { + if(fd->vio_udata){ + tcc_free(fd->vio_udata); + } + return 0; +} + +void set_vio_module(TCCState *s){ + vio_module.user_data = NULL; + vio_module.call_vio_open_flags = CALL_VIO_OPEN_FIRST; + vio_module.vio_open = &vio_mem_open; + vio_module.vio_lseek = &vio_mem_lseek; + vio_module.vio_read = &vio_mem_read; + vio_module.vio_close = &vio_mem_close; + tcc_set_vio_module(s, &vio_module); +} + +#endif + int main(int argc, char **argv) { int i; @@ -500,6 +592,11 @@ int main(int argc, char **argv) m_option = NULL; ret = 0; +#ifdef WITH_ATTACHMENTS + tcc_set_lib_path(s, ATTACH_PREFIX); + tcc_add_include_path(s, ATTACH_PREFIX); + set_vio_module(s); +#endif optind = parse_args(s, argc - 1, argv + 1); #if defined TCC_TARGET_X86_64 || defined TCC_TARGET_I386 diff --git a/tcc.h b/tcc.h index 5489b497..b738bc12 100644 --- a/tcc.h +++ b/tcc.h @@ -81,6 +81,15 @@ #include "stab.h" #include "libtcc.h" +/* virtual io to allow in memory files*/ + +void vio_initialize(vio_fd *fd); +int vio_open(struct TCCState *s, vio_fd *fd, const char *fn, int oflag); +off_t vio_lseek(vio_fd fd, off_t offset, int whence); +size_t vio_read(vio_fd fd, void *buf, size_t bytes); +int vio_close(vio_fd *fd); + + /* parser debug */ //#define PARSE_DEBUG /* preprocessor debug */ @@ -416,7 +425,7 @@ typedef struct AttributeDef { typedef struct BufferedFile { uint8_t *buf_ptr; uint8_t *buf_end; - int fd; + vio_fd fd; struct BufferedFile *prev; int line_num; /* current line number - here to simplify code */ int ifndef_macro; /* #ifndef macro / #endif search */ @@ -661,6 +670,7 @@ struct TCCState { unsigned int runtime_plt_and_got_offset; #endif #endif + vio_module_t *vio_module; }; /* The current value can be: */ @@ -1031,7 +1041,7 @@ ST_INLN Sym *sym_find(int v); ST_FUNC Sym *global_identifier_push(int v, int t, int c); ST_FUNC void tcc_open_bf(TCCState *s1, const char *filename, int initlen); -ST_FUNC int tcc_open(TCCState *s1, const char *filename); +ST_FUNC vio_fd tcc_open(TCCState *s1, const char *filename); ST_FUNC void tcc_close(void); ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags); @@ -1212,8 +1222,8 @@ ST_FUNC void relocate_syms(TCCState *s1, int do_resolve); ST_FUNC void relocate_section(TCCState *s1, Section *s); ST_FUNC void tcc_add_linker_symbols(TCCState *s1); -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 int tcc_load_object_file(TCCState *s1, vio_fd fd, unsigned long file_offset); +ST_FUNC int tcc_load_archive(TCCState *s1, vio_fd fd); ST_FUNC void *tcc_get_symbol_err(TCCState *s, const char *name); ST_FUNC void tcc_add_bcheck(TCCState *s1); @@ -1221,7 +1231,7 @@ ST_FUNC void build_got_entries(TCCState *s1); ST_FUNC void tcc_add_runtime(TCCState *s1); #ifndef TCC_TARGET_PE -ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level); +ST_FUNC int tcc_load_dll(TCCState *s1, vio_fd fd, const char *filename, int level); ST_FUNC int tcc_load_ldscript(TCCState *s1); ST_FUNC uint8_t *parse_comment(uint8_t *p); ST_FUNC void minp(void); @@ -1305,7 +1315,7 @@ ST_FUNC void gen_cvt_itof1(int t); #ifdef TCC_TARGET_COFF ST_FUNC int tcc_output_coff(TCCState *s1, FILE *f); -ST_FUNC int tcc_load_coff(TCCState * s1, int fd); +ST_FUNC int tcc_load_coff(TCCState * s1, vio_fd fd); #endif /* ------------ tccasm.c ------------ */ @@ -1327,7 +1337,7 @@ ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str); #endif /* ------------ tccpe.c -------------- */ #ifdef TCC_TARGET_PE -ST_FUNC int pe_load_file(struct TCCState *s1, const char *filename, int fd); +ST_FUNC int pe_load_file(struct TCCState *s1, const char *filename, vio_fd fd); ST_FUNC int pe_output_file(TCCState * s1, const char *filename); ST_FUNC int pe_putimport(TCCState *s1, int dllindex, const char *name, const void *value); ST_FUNC SValue *pe_getimport(SValue *sv, SValue *v2); diff --git a/tcccoff.c b/tcccoff.c index 2f525625..76262a1d 100644 --- a/tcccoff.c +++ b/tcccoff.c @@ -858,7 +858,7 @@ Section *FindSection(TCCState * s1, const char *sname) return 0; } -ST_FUNC int tcc_load_coff(TCCState * s1, int fd) +ST_FUNC int tcc_load_coff(TCCState * s1, vio_fd fd) { // tktk TokenSym *ts; @@ -870,7 +870,7 @@ ST_FUNC int tcc_load_coff(TCCState * s1, int fd) char name2[9]; FILHDR file_hdr; /* FILE HEADER STRUCTURE */ - f = fdopen(fd, "rb"); + f = fdopen(fd.fd, "rb"); if (!f) { tcc_error("Unable to open .out file for input"); } diff --git a/tccelf.c b/tccelf.c index da81d035..18ea94dc 100644 --- a/tccelf.c +++ b/tccelf.c @@ -2326,13 +2326,13 @@ LIBTCCAPI int tcc_output_file(TCCState *s, const char *filename) return ret; } -static void *load_data(int fd, unsigned long file_offset, unsigned long size) +static void *load_data(vio_fd fd, unsigned long file_offset, unsigned long size) { void *data; data = tcc_malloc(size); - lseek(fd, file_offset, SEEK_SET); - read(fd, data, size); + vio_lseek(fd, file_offset, SEEK_SET); + vio_read(fd, data, size); return data; } @@ -2346,7 +2346,7 @@ typedef struct SectionMergeInfo { /* 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, - int fd, unsigned long file_offset) + vio_fd fd, unsigned long file_offset) { ElfW(Ehdr) ehdr; ElfW(Shdr) *shdr, *sh; @@ -2364,7 +2364,7 @@ ST_FUNC int tcc_load_object_file(TCCState *s1, stab_index = stabstr_index = 0; - if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr)) + if (vio_read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr)) goto fail1; if (ehdr.e_ident[0] != ELFMAG0 || ehdr.e_ident[1] != ELFMAG1 || @@ -2491,9 +2491,9 @@ ST_FUNC int tcc_load_object_file(TCCState *s1, size = sh->sh_size; if (sh->sh_type != SHT_NOBITS) { unsigned char *ptr; - lseek(fd, file_offset + sh->sh_offset, SEEK_SET); + vio_lseek(fd, file_offset + sh->sh_offset, SEEK_SET); ptr = section_ptr_add(s, size); - read(fd, ptr, size); + vio_read(fd, ptr, size); } else { s->data_offset += size; } @@ -2649,7 +2649,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, vio_fd fd, int size) { int i, bound, nsyms, sym_index, off, ret; uint8_t *data; @@ -2658,7 +2658,7 @@ static int tcc_load_alacarte(TCCState *s1, int fd, int size) ElfW(Sym) *sym; data = tcc_malloc(size); - if (read(fd, data, size) != size) + if (vio_read(fd, data, size) != size) goto fail; nsyms = get_be32(data); ar_index = data + 4; @@ -2676,7 +2676,7 @@ static int tcc_load_alacarte(TCCState *s1, int fd, int size) printf("%5d\t%s\t%08x\n", i, p, sym->st_shndx); #endif ++bound; - lseek(fd, off, SEEK_SET); + vio_lseek(fd, off, SEEK_SET); if(tcc_load_object_file(s1, fd, off) < 0) { fail: ret = -1; @@ -2693,7 +2693,7 @@ static int tcc_load_alacarte(TCCState *s1, int fd, int size) } /* load a '.a' file */ -ST_FUNC int tcc_load_archive(TCCState *s1, int fd) +ST_FUNC int tcc_load_archive(TCCState *s1, vio_fd fd) { ArchiveHeader hdr; char ar_size[11]; @@ -2703,10 +2703,10 @@ ST_FUNC int tcc_load_archive(TCCState *s1, int fd) unsigned long file_offset; /* skip magic which was already checked */ - read(fd, magic, sizeof(magic)); + vio_read(fd, magic, sizeof(magic)); for(;;) { - len = read(fd, &hdr, sizeof(hdr)); + len = vio_read(fd, &hdr, sizeof(hdr)); if (len == 0) break; if (len != sizeof(hdr)) { @@ -2723,7 +2723,7 @@ ST_FUNC int tcc_load_archive(TCCState *s1, int fd) } ar_name[i + 1] = '\0'; // printf("name='%s' size=%d %s\n", ar_name, size, ar_size); - file_offset = lseek(fd, 0, SEEK_CUR); + file_offset = vio_lseek(fd, 0, SEEK_CUR); /* align to even */ size = (size + 1) & ~1; if (!strcmp(ar_name, "/")) { @@ -2739,7 +2739,7 @@ ST_FUNC int tcc_load_archive(TCCState *s1, int fd) if (tcc_load_object_file(s1, fd, file_offset) < 0) return -1; } - lseek(fd, file_offset + size, SEEK_SET); + vio_lseek(fd, file_offset + size, SEEK_SET); } return 0; } @@ -2748,7 +2748,7 @@ ST_FUNC int tcc_load_archive(TCCState *s1, int fd) /* load a DLL and all referenced DLLs. 'level = 0' means that the DLL is referenced by the user (so it should be added as DT_NEEDED in the generated ELF file) */ -ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level) +ST_FUNC int tcc_load_dll(TCCState *s1, vio_fd fd, const char *filename, int level) { ElfW(Ehdr) ehdr; ElfW(Shdr) *shdr, *sh, *sh1; @@ -2759,7 +2759,7 @@ ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level) const char *name, *soname; DLLReference *dllref; - read(fd, &ehdr, sizeof(ehdr)); + vio_read(fd, &ehdr, sizeof(ehdr)); /* test CPU specific stuff */ if (ehdr.e_ident[5] != ELFDATA2LSB || @@ -2986,14 +2986,13 @@ static int ld_next(TCCState *s1, char *name, int name_size) /* * Extract the file name from the library name * - * /!\ No test on filename capacity, be careful */ -static void libname_to_filename(TCCState *s1, const char libname[], char filename[]) +static void libname_to_filename(TCCState *s1, const char libname[], char filename[], size_t size) { if (!s1->static_link) { - sprintf(filename, "lib%s.so", libname); + snprintf(filename, size, "lib%s.so", libname); } else { - sprintf(filename, "lib%s.a", libname); + snprintf(filename, size, "lib%s.a", libname); } } @@ -3044,7 +3043,7 @@ static int ld_add_file_list(TCCState *s1, const char *cmd, int as_needed) goto lib_parse_error; } strcpy(libname, &filename[1]); - libname_to_filename(s1, libname, filename); + libname_to_filename(s1, libname, filename, sizeof(libname)); } else if (t != LD_TOK_NAME) { tcc_error_noabort("filename expected"); ret = -1; diff --git a/tccpe.c b/tccpe.c index 187b7106..a956da46 100644 --- a/tccpe.c +++ b/tccpe.c @@ -1638,9 +1638,9 @@ static int pe_load_dll(TCCState *s1, const char *dllname, FILE *fp) } /* ------------------------------------------------------------- */ -ST_FUNC int pe_load_file(struct TCCState *s1, const char *filename, int fd) +ST_FUNC int pe_load_file(struct TCCState *s1, const char *filename, vio_fd fd) { - FILE *fp = fdopen(dup(fd), "rb"); + FILE *fp = fdopen(dup(fd.fd), "rb"); int ret = -1; char buf[10]; if (fp) { diff --git a/tccpp.c b/tccpp.c index c0c7aecc..cc54dee2 100644 --- a/tccpp.c +++ b/tccpp.c @@ -360,13 +360,13 @@ static int tcc_peekc_slow(BufferedFile *bf) int len; /* only tries to read if really end of buffer */ if (bf->buf_ptr >= bf->buf_end) { - if (bf->fd != -1) { + if (bf->fd.fd != -1) { #if defined(PARSE_DEBUG) len = 8; #else len = IO_BUF_SIZE; #endif - len = read(bf->fd, bf->buffer, len); + len = vio_read(bf->fd, bf->buffer, len); if (len < 0) len = 0; } else { @@ -1438,6 +1438,8 @@ ST_FUNC void preprocess(int is_bof) CachedInclude *e; BufferedFile **f; const char *path; + int size; + vio_fd fd; if (i == -2) { /* check absolute include path */ @@ -1450,8 +1452,9 @@ ST_FUNC void preprocess(int is_bof) /* search in current dir if "header.h" */ if (c != '\"') continue; - path = file->filename; - pstrncpy(buf1, path, tcc_basename(path) - path); + size = tcc_basename(file->filename) - file->filename; + memcpy(buf1, file->filename, size); + buf1[size] = '\0'; } else { /* search in all the include paths */ @@ -1481,10 +1484,13 @@ ST_FUNC void preprocess(int is_bof) #ifdef INC_DEBUG printf("%s: skipping cached %s\n", file->filename, buf1); #endif + vio_initialize(&fd); + fd.fd = 0; goto include_done; } - if (tcc_open(s1, buf1) < 0) + fd = tcc_open(s1, buf1); + if (fd.fd < 0) include_trynext: continue; -- 2.11.4.GIT