Skip to content

Commit

Permalink
Share code for loading archive content
Browse files Browse the repository at this point in the history
  * Allocate content array
  • Loading branch information
tyfkda committed Aug 22, 2024
1 parent ee5c850 commit 657923e
Show file tree
Hide file tree
Showing 6 changed files with 204 additions and 197 deletions.
79 changes: 35 additions & 44 deletions src/ld/elfobj.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,58 +100,49 @@ static bool load_symtab(ElfObj *elfobj) {
return true;
}

bool read_elf(ElfObj *elfobj, FILE *fp, const char *fn) {
elfobj->fp = fp;
elfobj->start_offset = ftell(fp);
ssize_t size = fread(&elfobj->ehdr, sizeof(elfobj->ehdr), 1, fp);
if (size != 1 || elfobj->ehdr.e_ident[0] != ELFMAG0 || elfobj->ehdr.e_ident[1] != ELFMAG1 ||
elfobj->ehdr.e_ident[2] != ELFMAG2 || elfobj->ehdr.e_ident[3] != ELFMAG3) {
ElfObj *read_elf(FILE *fp, const char *fn) {
long start_offset = ftell(fp);
Elf64_Ehdr ehdr;
ssize_t size = fread(&ehdr, sizeof(ehdr), 1, fp);
if (size != 1 || ehdr.e_ident[0] != ELFMAG0 || ehdr.e_ident[1] != ELFMAG1 ||
ehdr.e_ident[2] != ELFMAG2 || ehdr.e_ident[3] != ELFMAG3) {
fprintf(stderr, "no elf file: %s\n", fn);
return false;
return NULL;
}
if (elfobj->ehdr.e_machine != MACHINE_TYPE || elfobj->ehdr.e_version != EV_CURRENT ||
elfobj->ehdr.e_ehsize != sizeof(Elf64_Ehdr) ||
elfobj->ehdr.e_shentsize != sizeof(Elf64_Shdr) ||
elfobj->ehdr.e_shnum < 1 || elfobj->ehdr.e_shstrndx >= elfobj->ehdr.e_shnum) {
if (ehdr.e_machine != MACHINE_TYPE || ehdr.e_version != EV_CURRENT ||
ehdr.e_ehsize != sizeof(Elf64_Ehdr) ||
ehdr.e_shentsize != sizeof(Elf64_Shdr) ||
ehdr.e_shnum < 1 || ehdr.e_shstrndx >= ehdr.e_shnum) {
fprintf(stderr, "illegal elf: %s\n", fn);
return false;
return NULL;
}
elfobj->shdrs = read_all_section_headers(fp, elfobj->start_offset, &elfobj->ehdr);
if (elfobj->shdrs != NULL) {
ElfSectionInfo *section_infos = calloc_or_die(elfobj->ehdr.e_shnum * sizeof(*elfobj->section_infos));
elfobj->section_infos = section_infos;
for (unsigned short i = 0; i < elfobj->ehdr.e_shnum; ++i) {
Elf64_Shdr *shdr = &elfobj->shdrs[i];
ElfSectionInfo *p = &section_infos[i];
p->elfobj = elfobj;
p->shdr = shdr;
}
Elf64_Shdr *shdrs = read_all_section_headers(fp, start_offset, &ehdr);
if (shdrs == NULL)
return NULL;

elfobj->shstrtab = read_strtab(fp, elfobj->start_offset,
&elfobj->shdrs[elfobj->ehdr.e_shstrndx]);
if (elfobj->shstrtab != NULL) {
if (!load_symtab(elfobj))
return false;
}
ElfObj *elfobj = calloc_or_die(sizeof(*elfobj));
elfobj->fp = fp;
elfobj->start_offset = start_offset;
elfobj->ehdr = ehdr;
elfobj->shdrs = shdrs;
elfobj->shstrtab = NULL;
elfobj->symbol_table = NULL;

ElfSectionInfo *section_infos = calloc_or_die(ehdr.e_shnum * sizeof(ElfSectionInfo));
elfobj->section_infos = section_infos;
for (unsigned short i = 0; i < ehdr.e_shnum; ++i) {
Elf64_Shdr *shdr = &shdrs[i];
ElfSectionInfo *p = &section_infos[i];
p->elfobj = elfobj;
p->shdr = shdr;
}
return true;
}

void elfobj_init(ElfObj *elfobj) {
memset(elfobj, 0, sizeof(*elfobj));
}

bool open_elf(const char *fn, ElfObj *elfobj) {
FILE *fp;
if (!is_file(fn) || (fp = fopen(fn, "rb")) == NULL) {
fprintf(stderr, "cannot open: %s\n", fn);
} else {
if (read_elf(elfobj, fp, fn))
return true;
fclose(fp);
elfobj->fp = NULL;
elfobj->shstrtab = read_strtab(fp, elfobj->start_offset, &shdrs[ehdr.e_shstrndx]);
if (elfobj->shstrtab != NULL) {
if (!load_symtab(elfobj))
return NULL;
}
return false;
return elfobj;
}

void close_elf(ElfObj *elfobj) {
Expand Down
4 changes: 1 addition & 3 deletions src/ld/elfobj.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,7 @@ typedef struct ElfObj {
ElfSectionInfo *section_infos;
} ElfObj;

void elfobj_init(ElfObj *elfobj);
bool open_elf(const char *fn, ElfObj *elfobj);
bool read_elf(ElfObj *elfobj, FILE *fp, const char *fn);
ElfObj *read_elf(FILE *fp, const char *fn);
void close_elf(ElfObj *elfobj);
Elf64_Sym *elfobj_find_symbol(ElfObj *elfobj, const Name *name);

Expand Down
87 changes: 19 additions & 68 deletions src/ld/ld.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,63 +27,6 @@ static const char kDefaultEntryName[] = "_start";

//

typedef struct {
ElfObj *elfobj;
size_t size;
char name[1]; // [sizeof(((struct ar_hdr*)0)->ar_name) + 1]
} ArContent;

#define FOREACH_FILE_ARCONTENT(ar, content, body) \
{Vector *contents = (ar)->contents; \
for (int _ic = 0; _ic < contents->len; _ic += 2) { \
ArContent *content = contents->data[_ic + 1]; \
body \
}}

ElfObj *load_archive_elfobj(Archive *ar, uint32_t offset) {
Vector *contents = ar->contents;
for (int i = 0; i < contents->len; i += 2) {
if (VOIDP2INT(contents->data[i]) == offset) {
// Already loaded.
return NULL;
}
}

fseek(ar->fp, offset, SEEK_SET);

struct ar_hdr hdr;
read_or_die(ar->fp, &hdr, sizeof(hdr), "hdr");
if (memcmp(hdr.ar_fmag, ARFMAG, sizeof(hdr.ar_fmag)) != 0)
error("Malformed archive");

ArContent *content = malloc_or_die(sizeof(*content) + sizeof(hdr.ar_name));

memcpy(content->name, hdr.ar_name, sizeof(hdr.ar_name));
char *p = memchr(content->name, '/', sizeof(hdr.ar_name));
if (p == NULL)
p = &content->name[sizeof(hdr.ar_name)];
*p = '\0';

char sizestr[sizeof(hdr.ar_size) + 1];
memcpy(sizestr, hdr.ar_size, sizeof(hdr.ar_size));
sizestr[sizeof(hdr.ar_size)] = '\0';
content->size = strtoul(sizestr, NULL, 10);

ElfObj *elfobj = malloc_or_die(sizeof(*elfobj));
content->elfobj = elfobj;
elfobj_init(elfobj);
if (!read_elf(elfobj, ar->fp, content->name)) {
error("Failed to extract .o: %s", content->name);
}

vec_push(contents, INT2VOIDP(offset));
vec_push(contents, content);

return elfobj;
}

//

typedef struct {
const char *filename;
enum {
Expand Down Expand Up @@ -122,13 +65,16 @@ void ld_load(LinkEditor *ld, int i, const char *filename) {
File *file = &ld->files[i];
file->filename = filename;
if (strcasecmp(ext, "o") == 0) {
ElfObj *elfobj = malloc_or_die(sizeof(*elfobj));
elfobj_init(elfobj);
if (!open_elf(filename, elfobj)) {
exit(1);
FILE *fp;
if (!is_file(filename) || (fp = fopen(filename, "rb")) == NULL) {
fprintf(stderr, "cannot open: %s\n", filename);
} else {
ElfObj *elfobj = read_elf(fp, filename);
if (elfobj == NULL)
exit(1);
file->kind = FK_ELFOBJ;
file->elfobj = elfobj;
}
file->kind = FK_ELFOBJ;
file->elfobj = elfobj;
} else if (strcasecmp(ext, "a") == 0) {
Archive *archive = load_archive(filename);
if (archive == NULL) {
Expand Down Expand Up @@ -161,7 +107,7 @@ static uintptr_t ld_symbol_address(LinkEditor *ld, const Name *name) {
{
Archive *ar = file->archive;
FOREACH_FILE_ARCONTENT(ar, content, {
elfobj = content->elfobj;
elfobj = content->obj;
sym = elfobj_find_symbol(elfobj, name);
if (sym != NULL) {
i = ld->nfiles; // Found.
Expand Down Expand Up @@ -493,6 +439,11 @@ static void link_elfobj(LinkEditor *ld, ElfObj *elfobj, Table *unresolved) {
}
}

static void *load_elfobj(FILE *fp, const char *fn, size_t size) {
UNUSED(size);
return read_elf(fp, fn);
}

static void link_archive(LinkEditor *ld, Archive *ar, Table *unresolved) {
Table *table = &ar->symbol_table;
for (;;) {
Expand All @@ -504,7 +455,7 @@ static void link_archive(LinkEditor *ld, Archive *ar, Table *unresolved) {
if (!table_try_get(table, name, (void**)&symbol))
continue;

ElfObj *elfobj = load_archive_elfobj(ar, symbol->offset);
ElfObj *elfobj = load_archive_content(ar, symbol, load_elfobj);
if (elfobj != NULL) {
link_elfobj(ld, elfobj, unresolved);
retry = true;
Expand All @@ -518,7 +469,7 @@ static void link_archive(LinkEditor *ld, Archive *ar, Table *unresolved) {

static void resolve_rela_archive(LinkEditor *ld, Archive *ar) {
FOREACH_FILE_ARCONTENT(ar, content, {
resolve_rela_elfobj(ld, content->elfobj);
resolve_rela_elfobj(ld, content->obj);
});
}

Expand Down Expand Up @@ -617,7 +568,7 @@ bool ld_link(LinkEditor *ld, Table *unresolved, uintptr_t start_address) {
{
Archive *ar = file->archive;
FOREACH_FILE_ARCONTENT(ar, content, {
add_elfobj_sections(content->elfobj);
add_elfobj_sections(content->obj);
});
}
break;
Expand Down Expand Up @@ -730,7 +681,7 @@ static void dump_map_file(LinkEditor *ld, FILE *fp) {
{
Archive *ar = file->archive;
FOREACH_FILE_ARCONTENT(ar, content, {
dump_map_elfobj(ld, content->elfobj, file, content, fp);
dump_map_elfobj(ld, content->obj, file, content, fp);
});
}
break;
Expand Down
Loading

0 comments on commit 657923e

Please sign in to comment.