tinycc-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Tinycc-devel] [PATCH] Add support for reading thin archive files.


From: Reimar . Doeffinger
Subject: [Tinycc-devel] [PATCH] Add support for reading thin archive files.
Date: Sun, 29 Oct 2023 23:00:36 +0100

From: Reimar Döffinger <Reimar.Doeffinger@gmx.de>

---
 libtcc.c |   2 +-
 tcc.h    |   2 +-
 tccelf.c | 110 +++++++++++++++++++++++++++++++++++++++++++++++++------
 3 files changed, 101 insertions(+), 13 deletions(-)

diff --git a/libtcc.c b/libtcc.c
index 164f1402..52410396 100644
--- a/libtcc.c
+++ b/libtcc.c
@@ -1114,7 +1114,7 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const 
char *filename, int flags)
             break;
 
         case AFF_BINTYPE_AR:
-            ret = tcc_load_archive(s1, fd, !(flags & AFF_WHOLE_ARCHIVE));
+            ret = tcc_load_archive(s1, fd, filename, !(flags & 
AFF_WHOLE_ARCHIVE));
             break;
 
 #ifdef TCC_TARGET_PE
diff --git a/tcc.h b/tcc.h
index e4173863..d27c69d9 100644
--- a/tcc.h
+++ b/tcc.h
@@ -1557,7 +1557,7 @@ ST_FUNC ssize_t full_read(int fd, void *buf, size_t 
count);
 ST_FUNC void *load_data(int fd, unsigned long file_offset, unsigned long size);
 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, int alacarte);
+ST_FUNC int tcc_load_archive(TCCState *s1, int fd, const char *filename, int 
alacarte);
 ST_FUNC void add_array(TCCState *s1, const char *sec, int c);
 
 ST_FUNC struct sym_attr *get_sym_attr(TCCState *s1, int index, int alloc);
diff --git a/tccelf.c b/tccelf.c
index 0110152d..b571c6fb 100644
--- a/tccelf.c
+++ b/tccelf.c
@@ -3000,6 +3000,8 @@ ST_FUNC int tcc_object_type(int fd, ElfW(Ehdr) *h)
     } else if (size >= 8) {
         if (0 == memcmp(h, ARMAG, 8))
             return AFF_BINTYPE_AR;
+        if (0 == memcmp(h, "!<thin>\n", 8))
+            return AFF_BINTYPE_AR;
 #ifdef TCC_TARGET_COFF
         if (((struct filehdr*)h)->f_magic == COFF_C67_MAGIC)
             return AFF_BINTYPE_C67;
@@ -3335,8 +3337,59 @@ static int read_ar_header(int fd, int offset, 
ArchiveHeader *hdr)
     return len;
 }
 
+/* loads the "//" entry containing the long file names of the archive */
+static int tcc_load_ar_names(TCCState *s1, int fd, const char *size_str, char 
**ret, int *ret_size)
+{
+    char *names = NULL;
+    int size = 0;
+    *ret = NULL;
+    *ret_size = 0;
+
+    size = strtol(size_str, NULL, 0);
+    names = tcc_malloc(size);
+    if (size < 1 || full_read(fd, names, size) != size) {
+        tcc_free(names);
+        return 1;
+    }
+    for (int i = 0; i < size - 1; i++) {
+        if (names[i] == '/' && names[i + 1] == '\n')
+            names[i] = 0;
+    }
+    names[size-1] = 0;
+    *ret = names;
+    *ret_size = size;
+    return 0;
+}
+
+static int tcc_add_ar_thin_file(TCCState *s1, const char *arname, const char 
*n, const char *fnames, int fnames_size)
+{
+    int pathlen = tcc_basename(arname) - arname;
+    int fname_ofs = strtol(n+1, NULL, 0);
+    int ret;
+    const char *basename;
+    int l;
+    char *combined_name;
+    if (n[0] != '/' || !fnames || fname_ofs < 0 || fname_ofs >= fnames_size) {
+        tcc_error_noabort("invalid thin archive");
+        return 1;
+    }
+    basename = fnames + fname_ofs;
+    l = strlen(basename) + 1;
+    // arbitrary path length limit...
+    if (pathlen > 4096 || l > 4096)
+        return 1;
+    if (s1->verbose == 2)
+        printf("   -> %s\n", basename);
+    combined_name = tcc_malloc(pathlen + l);
+    memcpy(combined_name, arname, pathlen);
+    memcpy(combined_name + pathlen, basename, l);
+    ret = tcc_add_file_internal(s1, combined_name, AFF_TYPE_BIN | 
AFF_PRINT_ERROR);
+    tcc_free(combined_name);
+    return ret;
+}
+
 /* load only the objects which resolve undefined symbols */
-static int tcc_load_alacarte(TCCState *s1, int fd, int size, int entrysize)
+static int tcc_load_alacarte(TCCState *s1, int fd, const char *filename, int 
size, int entrysize, unsigned long file_offset, int is_thin)
 {
     int i, bound, nsyms, sym_index, len, ret = -1;
     unsigned long long off;
@@ -3345,6 +3398,9 @@ static int tcc_load_alacarte(TCCState *s1, int fd, int 
size, int entrysize)
     const uint8_t *ar_index;
     ElfW(Sym) *sym;
     ArchiveHeader hdr;
+    ArchiveHeader fnamehdr;
+    char *fnames = NULL;
+    int fnames_size = 0;
 
     data = tcc_malloc(size);
     if (full_read(fd, data, size) != size)
@@ -3353,6 +3409,21 @@ static int tcc_load_alacarte(TCCState *s1, int fd, int 
size, int entrysize)
     ar_index = data + entrysize;
     ar_names = (char *) ar_index + nsyms * entrysize;
 
+    if (is_thin) {
+        file_offset += size;
+        len = read_ar_header(fd, file_offset, &fnamehdr);
+        if (len <= 0 || memcmp(fnamehdr.ar_fmag, ARFMAG, 2)) {
+            tcc_error_noabort("invalid archive");
+            goto the_end;
+        }
+        if (strcmp(fnamehdr.ar_name, "//")) {
+            tcc_error_noabort("file name directory not found");
+            goto the_end;
+        }
+        if (tcc_load_ar_names(s1, fd, fnamehdr.ar_size, &fnames, &fnames_size) 
!= 0)
+            goto the_end;
+    }
+
     do {
         bound = 0;
         for (p = ar_names, i = 0; i < nsyms; i++, p += strlen(p)+1) {
@@ -3372,7 +3443,10 @@ static int tcc_load_alacarte(TCCState *s1, int fd, int 
size, int entrysize)
             off += len;
             if (s1->verbose == 2)
                 printf("   -> %s\n", hdr.ar_name);
-            if (tcc_load_object_file(s1, fd, off) < 0)
+            if (is_thin) {
+                if (tcc_add_ar_thin_file(s1, filename, hdr.ar_name, fnames, 
fnames_size) != 0)
+                    goto the_end;
+            } else if (tcc_load_object_file(s1, fd, off) < 0)
                 goto the_end;
             ++bound;
         }
@@ -3380,20 +3454,23 @@ static int tcc_load_alacarte(TCCState *s1, int fd, int 
size, int entrysize)
     ret = 0;
  the_end:
     tcc_free(data);
+    tcc_free(fnames);
     return ret;
 }
 
 /* load a '.a' file */
-ST_FUNC int tcc_load_archive(TCCState *s1, int fd, int alacarte)
+ST_FUNC int tcc_load_archive(TCCState *s1, int fd, const char *filename, int 
alacarte)
 {
     ArchiveHeader hdr;
-    /* char magic[8]; */
-    int size, len;
+    char *fnames = NULL;
+    int fnames_size;
+    char magic[8];
+    int size, len, is_thin;
     unsigned long file_offset;
     ElfW(Ehdr) ehdr;
 
-    /* skip magic which was already checked */
-    /* full_read(fd, magic, sizeof(magic)); */
+    full_read(fd, magic, sizeof(magic));
+    is_thin = memcmp(magic, "!<thin>\n", 8) == 0;
     file_offset = sizeof ARMAG - 1;
 
     for(;;) {
@@ -3409,17 +3486,28 @@ ST_FUNC int tcc_load_archive(TCCState *s1, int fd, int 
alacarte)
         if (alacarte) {
             /* coff symbol table : we handle it */
             if (!strcmp(hdr.ar_name, "/"))
-                return tcc_load_alacarte(s1, fd, size, 4);
+                return tcc_load_alacarte(s1, fd, filename, size, 4, 
file_offset, is_thin);
             if (!strcmp(hdr.ar_name, "/SYM64/"))
-                return tcc_load_alacarte(s1, fd, size, 8);
+                return tcc_load_alacarte(s1, fd, filename, size, 8, 
file_offset, is_thin);
+        } else if (is_thin && !fnames && !strcmp(hdr.ar_name, "//")) {
+            if (tcc_load_ar_names(s1, fd, hdr.ar_size, &fnames, &fnames_size) 
!= 0)
+                return -1;
         } else if (tcc_object_type(fd, &ehdr) == AFF_BINTYPE_REL) {
             if (s1->verbose == 2)
                 printf("   -> %s\n", hdr.ar_name);
-            if (tcc_load_object_file(s1, fd, file_offset) < 0)
+            if (is_thin) size = 0;
+            if (is_thin && tcc_add_ar_thin_file(s1, filename, hdr.ar_name, 
fnames, fnames_size) != 0) {
+                tcc_free(fnames);
                 return -1;
-        }
+            }
+            if (!is_thin && tcc_load_object_file(s1, fd, file_offset) < 0)
+                return -1;
+        } else if (is_thin && fnames)
+            // the files after the file name directory have no actual size 
anymore
+            size = 0;
         file_offset += size;
     }
+    tcc_free(fnames);
 }
 
 #ifndef ELF_OBJ_ONLY
-- 
2.39.3 (Apple Git-145)




reply via email to

[Prev in Thread] Current Thread [Next in Thread]