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