62 lines
1.7 KiB
C
62 lines
1.7 KiB
C
// SPDX-License-Identifier: ISC
|
|
|
|
#include <bits/elf.h>
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include "efi.h"
|
|
|
|
efi_status efistub_relocate(uintptr_t base, const elf64_dyn_t* dynamic) {
|
|
uintptr_t rela = 0;
|
|
size_t rela_size = 0;
|
|
size_t rela_ent = sizeof(elf64_rela_t);
|
|
uintptr_t relr = 0;
|
|
size_t relr_size = 0;
|
|
|
|
for (const elf64_dyn_t* dyn = dynamic; dyn->d_tag != DT_NULL; dyn++) {
|
|
switch (dyn->d_tag) {
|
|
case DT_RELA:
|
|
rela = base + dyn->d_un.d_val;
|
|
break;
|
|
case DT_RELASZ:
|
|
rela_size = dyn->d_un.d_val;
|
|
break;
|
|
case DT_RELAENT:
|
|
rela_ent = dyn->d_un.d_val;
|
|
break;
|
|
case DT_RELR:
|
|
relr = base + dyn->d_un.d_val;
|
|
break;
|
|
case DT_RELRSZ:
|
|
relr_size = dyn->d_un.d_val;
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (size_t off = 0; rela && off + rela_ent <= rela_size; off += rela_ent) {
|
|
const elf64_rela_t* r = (const elf64_rela_t*)(rela + off);
|
|
const uint32_t type = ELF64_R_TYPE(r->r_info);
|
|
if (type == R_NONE)
|
|
continue;
|
|
if (type != R_RELATIVE)
|
|
return EFI_LOAD_ERROR;
|
|
*(uint64_t*)(base + r->r_offset) = base + r->r_addend;
|
|
}
|
|
|
|
uint64_t* where = nullptr;
|
|
for (size_t off = 0; relr && off + sizeof(uint64_t) <= relr_size; off += sizeof(uint64_t)) {
|
|
uint64_t entry = *(const uint64_t*)(relr + off);
|
|
if (!(entry & 1)) {
|
|
where = (uint64_t*)(base + entry);
|
|
*where++ += base;
|
|
continue;
|
|
}
|
|
for (size_t i = 0; (entry >>= 1) != 0; i++) {
|
|
if (entry & 1)
|
|
where[i] += base;
|
|
}
|
|
where += 63;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|