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