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 relocate(unsigned long load_addr,struct elf64_dyn * dyn_table)29void relocate(unsigned long load_addr, struct elf64_dyn *dyn_table) 30 { 31 unsigned long long rela_addr = 0, rela_count = 0, *addr; 32 struct elf64_dyn *d = dyn_table; 33 struct elf64_rela *r; 34 35 while (d && d->tag != DT_NULL) { 36 if (d->tag == DT_RELA) 37 rela_addr = d->val; 38 else if (d->tag == DT_RELACOUNT) 39 rela_count = d->val; 40 if (rela_addr && rela_count) 41 break; 42 ++d; 43 } 44 45 if (!rela_addr || !rela_count) 46 return; 47 48 r = (void *)(rela_addr + load_addr); 49 50 while (rela_count--) { 51 if (RELA_GET_TYPE(r) == R_PPC_RELATIVE) { 52 addr = (void *)(r->offset + load_addr); 53 *addr = r->addend + load_addr; 54 } 55 ++r; 56 } 57 } 58