blob: f6aaabef3173beb6eac73a403c9e5232825c6e45 [file] [log] [blame]
/*
* relocate R_PPC_RELATIVE RELA entries. Normally this is done in
* assembly code to avoid the risk of using absolute addresses before
* they're relocated. We use C, but cautiously (no global references).
*
* Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
*
* This work is licensed under the terms of the GNU LGPL, version 2.
*/
#define DT_NULL 0
#define DT_RELA 7
#define DT_RELACOUNT 0x6ffffff9
#define R_PPC_RELATIVE 22
struct elf64_dyn {
signed long long tag;
unsigned long long val;
};
#define RELA_GET_TYPE(rela_ptr) ((rela_ptr)->info & 0xffffffff)
struct elf64_rela {
unsigned long long offset;
unsigned long long info;
signed long long addend;
};
void relocate(unsigned long load_addr, struct elf64_dyn *dyn_table);
void relocate(unsigned long load_addr, struct elf64_dyn *dyn_table)
{
unsigned long long rela_addr = 0, rela_count = 0, *addr;
struct elf64_dyn *d = dyn_table;
struct elf64_rela *r;
while (d && d->tag != DT_NULL) {
if (d->tag == DT_RELA)
rela_addr = d->val;
else if (d->tag == DT_RELACOUNT)
rela_count = d->val;
if (rela_addr && rela_count)
break;
++d;
}
if (!rela_addr || !rela_count)
return;
r = (void *)(rela_addr + load_addr);
while (rela_count--) {
if (RELA_GET_TYPE(r) == R_PPC_RELATIVE) {
addr = (void *)(r->offset + load_addr);
*addr = r->addend + load_addr;
}
++r;
}
}