12874c5fdSThomas Gleixner/* SPDX-License-Identifier: GPL-2.0-or-later */ 29c5f7d39SSuzuki Poulose/* 39c5f7d39SSuzuki Poulose * Code to process dynamic relocations for PPC32. 49c5f7d39SSuzuki Poulose * 59c5f7d39SSuzuki Poulose * Copyrights (C) IBM Corporation, 2011. 69c5f7d39SSuzuki Poulose * Author: Suzuki Poulose <suzuki@in.ibm.com> 79c5f7d39SSuzuki Poulose * 89c5f7d39SSuzuki Poulose * - Based on ppc64 code - reloc_64.S 99c5f7d39SSuzuki Poulose */ 109c5f7d39SSuzuki Poulose 119c5f7d39SSuzuki Poulose#include <asm/ppc_asm.h> 129c5f7d39SSuzuki Poulose 139c5f7d39SSuzuki Poulose/* Dynamic section table entry tags */ 149c5f7d39SSuzuki PouloseDT_RELA = 7 /* Tag for Elf32_Rela section */ 159c5f7d39SSuzuki PouloseDT_RELASZ = 8 /* Size of the Rela relocs */ 169c5f7d39SSuzuki PouloseDT_RELAENT = 9 /* Size of one Rela reloc entry */ 179c5f7d39SSuzuki Poulose 189c5f7d39SSuzuki PouloseSTN_UNDEF = 0 /* Undefined symbol index */ 199c5f7d39SSuzuki PouloseSTB_LOCAL = 0 /* Local binding for the symbol */ 209c5f7d39SSuzuki Poulose 219c5f7d39SSuzuki PouloseR_PPC_ADDR16_LO = 4 /* Lower half of (S+A) */ 229c5f7d39SSuzuki PouloseR_PPC_ADDR16_HI = 5 /* Upper half of (S+A) */ 239c5f7d39SSuzuki PouloseR_PPC_ADDR16_HA = 6 /* High Adjusted (S+A) */ 249c5f7d39SSuzuki PouloseR_PPC_RELATIVE = 22 259c5f7d39SSuzuki Poulose 269c5f7d39SSuzuki Poulose/* 279c5f7d39SSuzuki Poulose * r3 = desired final address 289c5f7d39SSuzuki Poulose */ 299c5f7d39SSuzuki Poulose 309c5f7d39SSuzuki Poulose_GLOBAL(relocate) 319c5f7d39SSuzuki Poulose 329c5f7d39SSuzuki Poulose mflr r0 /* Save our LR */ 33*33e14024SChristophe Leroy bcl 20,31,$+4 /* Find our current runtime address */ 349c5f7d39SSuzuki Poulose0: mflr r12 /* Make it accessible */ 359c5f7d39SSuzuki Poulose mtlr r0 369c5f7d39SSuzuki Poulose 379c5f7d39SSuzuki Poulose lwz r11, (p_dyn - 0b)(r12) 389c5f7d39SSuzuki Poulose add r11, r11, r12 /* runtime address of .dynamic section */ 399c5f7d39SSuzuki Poulose lwz r9, (p_rela - 0b)(r12) 409c5f7d39SSuzuki Poulose add r9, r9, r12 /* runtime address of .rela.dyn section */ 419c5f7d39SSuzuki Poulose lwz r10, (p_st - 0b)(r12) 429c5f7d39SSuzuki Poulose add r10, r10, r12 /* runtime address of _stext section */ 439c5f7d39SSuzuki Poulose lwz r13, (p_sym - 0b)(r12) 449c5f7d39SSuzuki Poulose add r13, r13, r12 /* runtime address of .dynsym section */ 459c5f7d39SSuzuki Poulose 469c5f7d39SSuzuki Poulose /* 479c5f7d39SSuzuki Poulose * Scan the dynamic section for RELA, RELASZ entries 489c5f7d39SSuzuki Poulose */ 499c5f7d39SSuzuki Poulose li r6, 0 509c5f7d39SSuzuki Poulose li r7, 0 519c5f7d39SSuzuki Poulose li r8, 0 529c5f7d39SSuzuki Poulose1: lwz r5, 0(r11) /* ELF_Dyn.d_tag */ 539c5f7d39SSuzuki Poulose cmpwi r5, 0 /* End of ELF_Dyn[] */ 549c5f7d39SSuzuki Poulose beq eodyn 559c5f7d39SSuzuki Poulose cmpwi r5, DT_RELA 569c5f7d39SSuzuki Poulose bne relasz 579c5f7d39SSuzuki Poulose lwz r7, 4(r11) /* r7 = rela.link */ 589c5f7d39SSuzuki Poulose b skip 599c5f7d39SSuzuki Pouloserelasz: 609c5f7d39SSuzuki Poulose cmpwi r5, DT_RELASZ 619c5f7d39SSuzuki Poulose bne relaent 629c5f7d39SSuzuki Poulose lwz r8, 4(r11) /* r8 = Total Rela relocs size */ 639c5f7d39SSuzuki Poulose b skip 649c5f7d39SSuzuki Pouloserelaent: 659c5f7d39SSuzuki Poulose cmpwi r5, DT_RELAENT 669c5f7d39SSuzuki Poulose bne skip 679c5f7d39SSuzuki Poulose lwz r6, 4(r11) /* r6 = Size of one Rela reloc */ 689c5f7d39SSuzuki Pouloseskip: 699c5f7d39SSuzuki Poulose addi r11, r11, 8 709c5f7d39SSuzuki Poulose b 1b 719c5f7d39SSuzuki Pouloseeodyn: /* End of Dyn Table scan */ 729c5f7d39SSuzuki Poulose 739c5f7d39SSuzuki Poulose /* Check if we have found all the entries */ 749c5f7d39SSuzuki Poulose cmpwi r7, 0 759c5f7d39SSuzuki Poulose beq done 769c5f7d39SSuzuki Poulose cmpwi r8, 0 779c5f7d39SSuzuki Poulose beq done 789c5f7d39SSuzuki Poulose cmpwi r6, 0 799c5f7d39SSuzuki Poulose beq done 809c5f7d39SSuzuki Poulose 819c5f7d39SSuzuki Poulose 829c5f7d39SSuzuki Poulose /* 839c5f7d39SSuzuki Poulose * Work out the current offset from the link time address of .rela 849c5f7d39SSuzuki Poulose * section. 859c5f7d39SSuzuki Poulose * cur_offset[r7] = rela.run[r9] - rela.link [r7] 869c5f7d39SSuzuki Poulose * _stext.link[r12] = _stext.run[r10] - cur_offset[r7] 879c5f7d39SSuzuki Poulose * final_offset[r3] = _stext.final[r3] - _stext.link[r12] 889c5f7d39SSuzuki Poulose */ 899c5f7d39SSuzuki Poulose subf r7, r7, r9 /* cur_offset */ 909c5f7d39SSuzuki Poulose subf r12, r7, r10 919c5f7d39SSuzuki Poulose subf r3, r12, r3 /* final_offset */ 929c5f7d39SSuzuki Poulose 939c5f7d39SSuzuki Poulose subf r8, r6, r8 /* relaz -= relaent */ 949c5f7d39SSuzuki Poulose /* 959c5f7d39SSuzuki Poulose * Scan through the .rela table and process each entry 969c5f7d39SSuzuki Poulose * r9 - points to the current .rela table entry 979c5f7d39SSuzuki Poulose * r13 - points to the symbol table 989c5f7d39SSuzuki Poulose */ 999c5f7d39SSuzuki Poulose 1009c5f7d39SSuzuki Poulose /* 1019c5f7d39SSuzuki Poulose * Check if we have a relocation based on symbol 1029c5f7d39SSuzuki Poulose * r5 will hold the value of the symbol. 1039c5f7d39SSuzuki Poulose */ 1049c5f7d39SSuzuki Pouloseapplyrela: 1059c5f7d39SSuzuki Poulose lwz r4, 4(r9) /* r4 = rela.r_info */ 1069c5f7d39SSuzuki Poulose srwi r5, r4, 8 /* ELF32_R_SYM(r_info) */ 1079c5f7d39SSuzuki Poulose cmpwi r5, STN_UNDEF /* sym == STN_UNDEF ? */ 1089c5f7d39SSuzuki Poulose beq get_type /* value = 0 */ 1099c5f7d39SSuzuki Poulose /* Find the value of the symbol at index(r5) */ 1109c5f7d39SSuzuki Poulose slwi r5, r5, 4 /* r5 = r5 * sizeof(Elf32_Sym) */ 1119c5f7d39SSuzuki Poulose add r12, r13, r5 /* r12 = &__dyn_sym[Index] */ 1129c5f7d39SSuzuki Poulose 1139c5f7d39SSuzuki Poulose /* 1149c5f7d39SSuzuki Poulose * GNU ld has a bug, where dynamic relocs based on 1159c5f7d39SSuzuki Poulose * STB_LOCAL symbols, the value should be assumed 1169c5f7d39SSuzuki Poulose * to be zero. - Alan Modra 1179c5f7d39SSuzuki Poulose */ 1189c5f7d39SSuzuki Poulose /* XXX: Do we need to check if we are using GNU ld ? */ 1199c5f7d39SSuzuki Poulose lbz r5, 12(r12) /* r5 = dyn_sym[Index].st_info */ 1209c5f7d39SSuzuki Poulose extrwi r5, r5, 4, 24 /* r5 = ELF32_ST_BIND(r5) */ 1219c5f7d39SSuzuki Poulose cmpwi r5, STB_LOCAL /* st_value = 0, ld bug */ 1229c5f7d39SSuzuki Poulose beq get_type /* We have r5 = 0 */ 1239c5f7d39SSuzuki Poulose lwz r5, 4(r12) /* r5 = __dyn_sym[Index].st_value */ 1249c5f7d39SSuzuki Poulose 1259c5f7d39SSuzuki Pouloseget_type: 1269c5f7d39SSuzuki Poulose /* Load the relocation type to r4 */ 1279c5f7d39SSuzuki Poulose extrwi r4, r4, 8, 24 /* r4 = ELF32_R_TYPE(r_info) = ((char*)r4)[3] */ 1289c5f7d39SSuzuki Poulose 1299c5f7d39SSuzuki Poulose /* R_PPC_RELATIVE */ 1309c5f7d39SSuzuki Poulose cmpwi r4, R_PPC_RELATIVE 1319c5f7d39SSuzuki Poulose bne hi16 1329c5f7d39SSuzuki Poulose lwz r4, 0(r9) /* r_offset */ 1339c5f7d39SSuzuki Poulose lwz r0, 8(r9) /* r_addend */ 1349c5f7d39SSuzuki Poulose add r0, r0, r3 /* final addend */ 1359c5f7d39SSuzuki Poulose stwx r0, r4, r7 /* memory[r4+r7]) = (u32)r0 */ 1369c5f7d39SSuzuki Poulose b nxtrela /* continue */ 1379c5f7d39SSuzuki Poulose 1389c5f7d39SSuzuki Poulose /* R_PPC_ADDR16_HI */ 1399c5f7d39SSuzuki Poulosehi16: 1409c5f7d39SSuzuki Poulose cmpwi r4, R_PPC_ADDR16_HI 1419c5f7d39SSuzuki Poulose bne ha16 1429c5f7d39SSuzuki Poulose lwz r4, 0(r9) /* r_offset */ 1439c5f7d39SSuzuki Poulose lwz r0, 8(r9) /* r_addend */ 1449c5f7d39SSuzuki Poulose add r0, r0, r3 1459c5f7d39SSuzuki Poulose add r0, r0, r5 /* r0 = (S+A+Offset) */ 1469c5f7d39SSuzuki Poulose extrwi r0, r0, 16, 0 /* r0 = (r0 >> 16) */ 1479c5f7d39SSuzuki Poulose b store_half 1489c5f7d39SSuzuki Poulose 1499c5f7d39SSuzuki Poulose /* R_PPC_ADDR16_HA */ 1509c5f7d39SSuzuki Pouloseha16: 1519c5f7d39SSuzuki Poulose cmpwi r4, R_PPC_ADDR16_HA 1529c5f7d39SSuzuki Poulose bne lo16 1539c5f7d39SSuzuki Poulose lwz r4, 0(r9) /* r_offset */ 1549c5f7d39SSuzuki Poulose lwz r0, 8(r9) /* r_addend */ 1559c5f7d39SSuzuki Poulose add r0, r0, r3 1569c5f7d39SSuzuki Poulose add r0, r0, r5 /* r0 = (S+A+Offset) */ 1579c5f7d39SSuzuki Poulose extrwi r5, r0, 1, 16 /* Extract bit 16 */ 1589c5f7d39SSuzuki Poulose extrwi r0, r0, 16, 0 /* r0 = (r0 >> 16) */ 1599c5f7d39SSuzuki Poulose add r0, r0, r5 /* Add it to r0 */ 1609c5f7d39SSuzuki Poulose b store_half 1619c5f7d39SSuzuki Poulose 1629c5f7d39SSuzuki Poulose /* R_PPC_ADDR16_LO */ 1639c5f7d39SSuzuki Pouloselo16: 1649c5f7d39SSuzuki Poulose cmpwi r4, R_PPC_ADDR16_LO 165348c2298SKevin Hao bne unknown_type 1669c5f7d39SSuzuki Poulose lwz r4, 0(r9) /* r_offset */ 1679c5f7d39SSuzuki Poulose lwz r0, 8(r9) /* r_addend */ 1689c5f7d39SSuzuki Poulose add r0, r0, r3 1699c5f7d39SSuzuki Poulose add r0, r0, r5 /* r0 = (S+A+Offset) */ 1709c5f7d39SSuzuki Poulose extrwi r0, r0, 16, 16 /* r0 &= 0xffff */ 1719c5f7d39SSuzuki Poulose /* Fall through to */ 1729c5f7d39SSuzuki Poulose 1739c5f7d39SSuzuki Poulose /* Store half word */ 1749c5f7d39SSuzuki Poulosestore_half: 1759c5f7d39SSuzuki Poulose sthx r0, r4, r7 /* memory[r4+r7] = (u16)r0 */ 1769c5f7d39SSuzuki Poulose 1779c5f7d39SSuzuki Poulosenxtrela: 1789c5f7d39SSuzuki Poulose /* 1799c5f7d39SSuzuki Poulose * We have to flush the modified instructions to the 1809c5f7d39SSuzuki Poulose * main storage from the d-cache. And also, invalidate the 1819c5f7d39SSuzuki Poulose * cached instructions in i-cache which has been modified. 1829c5f7d39SSuzuki Poulose * 1839c5f7d39SSuzuki Poulose * We delay the sync / isync operation till the end, since 1849c5f7d39SSuzuki Poulose * we won't be executing the modified instructions until 1859c5f7d39SSuzuki Poulose * we return from here. 1869c5f7d39SSuzuki Poulose */ 1879c5f7d39SSuzuki Poulose dcbst r4,r7 1889c5f7d39SSuzuki Poulose sync /* Ensure the data is flushed before icbi */ 1899c5f7d39SSuzuki Poulose icbi r4,r7 190348c2298SKevin Haounknown_type: 1919c5f7d39SSuzuki Poulose cmpwi r8, 0 /* relasz = 0 ? */ 1929c5f7d39SSuzuki Poulose ble done 1939c5f7d39SSuzuki Poulose add r9, r9, r6 /* move to next entry in the .rela table */ 1949c5f7d39SSuzuki Poulose subf r8, r6, r8 /* relasz -= relaent */ 1959c5f7d39SSuzuki Poulose b applyrela 1969c5f7d39SSuzuki Poulose 1979c5f7d39SSuzuki Poulosedone: 1989c5f7d39SSuzuki Poulose sync /* Wait for the flush to finish */ 1999c5f7d39SSuzuki Poulose isync /* Discard prefetched instructions */ 2009c5f7d39SSuzuki Poulose blr 2019c5f7d39SSuzuki Poulose 2029c5f7d39SSuzuki Poulosep_dyn: .long __dynamic_start - 0b 2039c5f7d39SSuzuki Poulosep_rela: .long __rela_dyn_start - 0b 2049c5f7d39SSuzuki Poulosep_sym: .long __dynamic_symtab - 0b 2059c5f7d39SSuzuki Poulosep_st: .long _stext - 0b 206