[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)
- [Tinycc-devel] [PATCH] Add support for reading thin archive files.,
Reimar . Doeffinger <=