dont require phdr to link

This commit is contained in:
Freya Murphy 2024-10-01 18:20:10 -04:00
parent 853a1ba612
commit fb07130990
Signed by: freya
GPG key ID: 744AB800E383AE52
5 changed files with 154 additions and 63 deletions

View file

@ -12,8 +12,6 @@
#include "link.h"
#include "mips.h"
#define SEC_ALIGN 0x1000
static int load_objects(struct linker *linker)
{
int max_entries = linker->args->in_count + 1;
@ -168,7 +166,7 @@ static int relocate_symbol(struct linker *linker, struct object *obj,
struct symbol_table *symtab, const Elf32_Sym *sym)
{
size_t shndx = B16(sym->st_shndx);
if (shndx == 0)
if (shndx == 0 || shndx == SHN_ABS)
return M_SUCCESS; // ignore this symbol
// find the given section
@ -184,11 +182,9 @@ static int relocate_symbol(struct linker *linker, struct object *obj,
return M_ERROR;
}
Elf32_Shdr const *shdr = &obj->shdr[shndx];
struct segment *sec = NULL;
for (size_t i = 0; i < obj->phdr_len; i++) {
Elf32_Phdr *temp = &obj->phdr[i];
if (PHDR_SHDR_MATCH(temp, shdr)) {
if (obj->phdr_to_shdr_mapping[i] == shndx) {
sec = &obj->segments[i];
break;
}
@ -219,6 +215,20 @@ static int relocate_symbol(struct linker *linker, struct object *obj,
new.st_shndx = B16(new_shndx);
new.st_size = 0;
// rename symbol if its name is empty to perm placeholder
//if (B32(sym->st_name) == 0) {
// #define __MAX 512
// char name[__MAX];
// memset(name, 0, __MAX);
// strcat(name, "__sym");
// snprintf(name + strlen(name), __MAX - strlen(name), "%d",
// B32(sym->st_value));
// if (strtab_push(linker->symtab.strtab, name, &str_off))
// return M_ERROR;
// new.st_name = B32(str_off);
// #undef __MAX
//}
if (symtab_get(&linker->symtab, NULL, name, obj->index) == M_SUCCESS) {
ERROR("cannot link doubly defiend symbol '%s'", name);
return M_ERROR;
@ -447,33 +457,38 @@ static int relocate_instruction_rela(struct linker *linker,
// 16bit absolute
if (vaddr_abs > UINT16_MAX)
warn = true;
ins.immd = (uint16_t)vaddr_abs;
ins.immd += (uint16_t)vaddr_abs;
break;
case R_MIPS_PC16:
// 16bit relative shifted
if (vaddr_rel > INT16_MAX || vaddr_rel < INT16_MIN)
warn = true;
ins.offset = vaddr_rel;
ins.offset += vaddr_rel;
break;
case R_MIPS_26:
case R_MIPS_JALR:
// 26bit absolute shifted
if (vaddr_abs >= (1 << 25))
warn = true;
ins.target = (vaddr_abs & 0x0FFFFFFF) >> 2;
ins.target += (vaddr_abs & 0x0FFFFFFF) >> 2;
break;
case R_MIPS_PC26_S2:
// 26bit relative shifted
if (vaddr_rel >= (1 << 24) || -vaddr_rel > (1 << 24))
warn = true;
ins.offs26 = vaddr_rel;
ins.offs26 += vaddr_rel;
break;
case R_MIPS_LO16:
// lo 16bit absolute
ins.immd = (uint16_t)(vaddr_abs & 0xFFFF);
ins.immd += (uint16_t)(vaddr_abs & 0xFFFF);
break;
case R_MIPS_HI16:
// hi 16bit absolute
ins.immd = (uint16_t)(vaddr_abs >> 16);
ins.immd += (uint16_t)(vaddr_abs >> 16);
break;
case R_MIPS_32:
// 32bit absolute
ins.raw = vaddr_abs;
break;
default:
ERROR("do not know how do handle relocation type [%d]", typ);
@ -596,9 +611,6 @@ static void update_offsets(struct linker *linker)
static int write_file(struct linker *linker)
{
extern char *current_file;
current_file = linker->args->out_file;
int fd = open(linker->args->out_file, O_RDWR | O_CREAT, 0711);
if (fd < 0) {
PERROR("cannot write");
@ -739,12 +751,16 @@ static void linker_free(struct linker *linker)
int link_files(struct linker_arguments args) {
struct linker linker;
extern char *current_file;
int res = M_SUCCESS;
if (res == M_SUCCESS)
res = linker_init(&linker, &args);
if (res == M_SUCCESS)
res = load_objects(&linker);
current_file = args.out_file;
if (res == M_SUCCESS)
res = relocate_segments(&linker);
if (res == M_SUCCESS)

View file

@ -35,6 +35,9 @@
#define TEXT_VADDR_MIN 0x00400000
#define DATA_VADDR_MIN 0x10000000
// alignment of a section
#define SEC_ALIGN 0x1000
// pre define
struct linker;
struct object;
@ -42,6 +45,7 @@ struct segment;
struct string_table;
struct symbol_table;
struct symbol_table_mapping;
struct glboff_table;
///
/// relocation table
@ -220,6 +224,10 @@ struct object {
// program table
Elf32_Phdr *phdr;
size_t phdr_len;
bool phdr_local; // if phdr was created though malloc
// phdr <=> shdr mappings
uint32_t *phdr_to_shdr_mapping;
// object meta
const char *name;

105
mld/obj.c
View file

@ -49,10 +49,10 @@ static int load_ehdr(struct object *object)
EHDR_ASSERT(type, sizeof(Elf32_Half));
EHDR_ASSERT(machine, sizeof(Elf32_Half));
EHDR_ASSERT(version, sizeof(Elf32_Word));
EHDR_ASSERT(flags, sizeof(Elf32_Word));
// EHDR_ASSERT(flags, sizeof(Elf32_Word));
EHDR_ASSERT(ehsize, sizeof(Elf32_Half));
EHDR_ASSERT(phentsize, sizeof(Elf32_Half));
EHDR_ASSERT(shentsize, sizeof(Elf32_Half));
// EHDR_ASSERT(phentsize, sizeof(Elf32_Half));
// EHDR_ASSERT(shentsize, sizeof(Elf32_Half));
#undef EHDR_ASSERT
@ -81,23 +81,94 @@ static int load_shdr(struct object *object)
return M_SUCCESS;
}
/**
* Create the phdr
*/
static int create_phdr(struct object *object)
{
uint32_t entries = 0;
for (uint32_t i = 0; i < object->shdr_len; i++) {
Elf32_Shdr *hdr = &object->shdr[i];
uint32_t type = B32(hdr->sh_type);
if (type != SHT_PROGBITS && type != SHT_NOBITS)
continue;
entries += 1;
}
Elf32_Phdr *phdr = malloc(entries * sizeof(Elf32_Phdr));
if (phdr == NULL) {
PERROR("cannot alloc");
return M_ERROR;
}
object->phdr = phdr;
object->phdr_len = entries;
object->phdr_local = true;
uint32_t *mapping = malloc(entries * sizeof(uint32_t));
if (mapping == NULL) {
PERROR("cannot alloc");
return M_ERROR;
}
object->phdr_to_shdr_mapping = mapping;
uint32_t index = 0;
for (uint32_t i = 0; i < object->shdr_len; i++) {
Elf32_Shdr *hdr = &object->shdr[i];
uint32_t type = B32(hdr->sh_type);
if (type != SHT_PROGBITS && type != SHT_NOBITS)
continue;
mapping[index] = i;
phdr[index++] = (Elf32_Phdr) {
.p_type = B32(PT_LOAD),
.p_flags = B32(
// execute
((B32(hdr->sh_flags) & SHF_EXECINSTR)
? PF_X : 0) |
// write
((B32(hdr->sh_flags) & SHF_WRITE)
? PF_W : 0) |
// read
((B32(hdr->sh_flags) & SHF_ALLOC)
? PF_R : 0)
),
.p_offset = hdr->sh_offset,
.p_vaddr = hdr->sh_addr,
.p_paddr = hdr->sh_addr,
.p_filesz = hdr->sh_size,
.p_memsz = hdr->sh_size,
.p_align = B32(SEC_ALIGN),
};
}
return M_SUCCESS;
}
/**
* Map the phdr
*/
static int load_phdr(struct object *object)
{
size_t phdr_len = B16(object->ehdr->e_phentsize) *
B16(object->ehdr->e_phnum);
size_t phdr_off = B32(object->ehdr->e_phoff);
object->phdr = (Elf32_Phdr *) (object->mapped + phdr_off);
object->phdr_len = B16(object->ehdr->e_phnum);
//size_t phdr_len = B16(object->ehdr->e_phentsize) *
// B16(object->ehdr->e_phnum);
if (BOUND_CHK(object, phdr_len, phdr_off)) {
ERROR("cannot read phdr");
return M_ERROR;
}
//if (phdr_len < 1)
return create_phdr(object);
return M_SUCCESS;
//size_t phdr_off = B32(object->ehdr->e_phoff);
//object->phdr = (Elf32_Phdr *) (object->mapped + phdr_off);
//object->phdr_len = B16(object->ehdr->e_phnum);
//if (BOUND_CHK(object, phdr_len, phdr_off)) {
// ERROR("cannot read phdr");
// return M_ERROR;
//}
//return M_SUCCESS;
}
/**
@ -231,7 +302,7 @@ static int load_shstrtab(struct object *object)
*/
static int load_segments(struct object *object)
{
object->segment_len = B16(object->ehdr->e_phnum);
object->segment_len = object->phdr_len;
object->segments = malloc(sizeof(struct segment) *
object->segment_len);
@ -287,6 +358,8 @@ int object_load(struct object *object, char *path, uint32_t index)
object->mapped = NULL;
object->name = path;
object->index = index;
object->phdr_local = false;
object->phdr_to_shdr_mapping = NULL;
/** load the file */
if (map_file(object, path))
@ -331,6 +404,10 @@ void object_free(struct object *obj)
free(obj->strtabs);
if (obj->segments != NULL)
free(obj->segments);
if (obj->phdr_local)
free(obj->phdr);
if (obj->phdr_to_shdr_mapping)
free(obj->phdr_to_shdr_mapping);
if (obj->fd > 0)
close(obj->fd);
if (obj->mapped != NULL && obj->mapped != MAP_FAILED)

View file

@ -25,14 +25,8 @@ static int load_phdr(struct object *obj, struct segment *seg, size_t index)
*/
static int load_shdr(struct object *obj, struct segment *seg, size_t index)
{
bool found = false;
for (size_t i = 0; i < obj->shdr_len; i++) {
Elf32_Shdr *hdr = &obj->shdr[i];
// find shdr that matches the offset in phdr
if (!PHDR_SHDR_MATCH(seg->phdr, hdr))
continue;
uint32_t shndx = obj->phdr_to_shdr_mapping[index];
Elf32_Shdr *hdr = &obj->shdr[shndx];
// get name
uint32_t name = B32(hdr->sh_name);
@ -52,16 +46,8 @@ static int load_shdr(struct object *obj, struct segment *seg, size_t index)
return M_ERROR;
}
found = true;
seg->shdr = hdr;
seg->shdr_idx = i;
break;
}
if (!found) {
ERROR("cannot find shdr for segment [%d]", index);
return M_ERROR;
}
seg->shdr_idx = shndx;
return M_SUCCESS;
}

View file

@ -56,6 +56,10 @@ int symtab_get(struct symbol_table *symtab, Elf32_Sym **res, const char *name,
if (strcmp(name, symname) != 0)
continue;
// ignore absolute symbols
if (B16(sym->st_shndx) == SHN_ABS)
continue;
// only allow retrevial of local variables from the
// same object
if (sym->st_info >> 4 != STB_GLOBAL && symtab->map != NULL &&