1 /* 2 * relocate R_PPC_RELATIVE RELA entries. Normally this is done in 3 * assembly code to avoid the risk of using absolute addresses before 4 * they're relocated. We use C, but cautiously (no global references). 5 * 6 * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com> 7 * 8 * This work is licensed under the terms of the GNU LGPL, version 2. 9 */ 10 #define DT_NULL 0 11 #define DT_RELA 7 12 #define DT_RELACOUNT 0x6ffffff9 13 #define R_PPC_RELATIVE 22 14 15 struct elf64_dyn { 16 signed long long tag; 17 unsigned long long val; 18 }; 19 20 #define RELA_GET_TYPE(rela_ptr) ((rela_ptr)->info & 0xffffffff) 21 struct elf64_rela { 22 unsigned long long offset; 23 unsigned long long info; 24 signed long long addend; 25 }; 26 27 void relocate(unsigned long load_addr, struct elf64_dyn *dyn_table) 28 { 29 unsigned long long rela_addr = 0, rela_count = 0, *addr; 30 struct elf64_dyn *d = dyn_table; 31 struct elf64_rela *r; 32 33 while (d && d->tag != DT_NULL) { 34 if (d->tag == DT_RELA) 35 rela_addr = d->val; 36 else if (d->tag == DT_RELACOUNT) 37 rela_count = d->val; 38 if (rela_addr && rela_count) 39 break; 40 ++d; 41 } 42 43 if (!rela_addr || !rela_count) 44 return; 45 46 r = (void *)(rela_addr + load_addr); 47 48 while (rela_count--) { 49 if (RELA_GET_TYPE(r) == R_PPC_RELATIVE) { 50 addr = (void *)(r->offset + load_addr); 51 *addr = r->addend + load_addr; 52 } 53 ++r; 54 } 55 } 56