1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ |
2 | /* |
3 | * Code to process dynamic relocations in the kernel. |
4 | * |
5 | * Copyright 2008 Paul Mackerras, IBM Corp. |
6 | */ |
7 | |
8 | #include <asm/ppc_asm.h> |
9 | |
10 | RELA = 7 |
11 | RELASZ = 8 |
12 | RELAENT = 9 |
13 | R_PPC64_RELATIVE = 22 |
14 | R_PPC64_UADDR64 = 43 |
15 | |
16 | /* |
17 | * r3 = desired final address of kernel |
18 | */ |
19 | _GLOBAL(relocate) |
20 | mflr r0 |
21 | bcl 20,31,$+4 |
22 | 0: mflr r12 /* r12 has runtime addr of label 0 */ |
23 | mtlr r0 |
24 | ld r11,(p_dyn - 0b)(r12) |
25 | add r11,r11,r12 /* r11 has runtime addr of .dynamic section */ |
26 | ld r9,(p_rela - 0b)(r12) |
27 | add r9,r9,r12 /* r9 has runtime addr of .rela.dyn section */ |
28 | ld r10,(p_st - 0b)(r12) |
29 | add r10,r10,r12 /* r10 has runtime addr of _stext */ |
30 | ld r4,(p_sym - 0b)(r12) |
31 | add r4,r4,r12 /* r4 has runtime addr of .dynsym */ |
32 | |
33 | /* |
34 | * Scan the dynamic section for the RELA, RELASZ and RELAENT entries. |
35 | */ |
36 | li r7,0 |
37 | li r8,0 |
38 | .Ltags: |
39 | ld r6,0(r11) /* get tag */ |
40 | cmpdi r6,0 |
41 | beq .Lend_of_list /* end of list */ |
42 | cmpdi r6,RELA |
43 | bne 2f |
44 | ld r7,8(r11) /* get RELA pointer in r7 */ |
45 | b 4f |
46 | 2: cmpdi r6,RELASZ |
47 | bne 3f |
48 | ld r8,8(r11) /* get RELASZ value in r8 */ |
49 | b 4f |
50 | 3: cmpdi r6,RELAENT |
51 | bne 4f |
52 | ld r12,8(r11) /* get RELAENT value in r12 */ |
53 | 4: addi r11,r11,16 |
54 | b .Ltags |
55 | .Lend_of_list: |
56 | cmpdi r7,0 /* check we have RELA, RELASZ, RELAENT */ |
57 | cmpdi cr1,r8,0 |
58 | beq .Lout |
59 | beq cr1,.Lout |
60 | cmpdi r12,0 |
61 | beq .Lout |
62 | |
63 | /* |
64 | * Work out linktime address of _stext and hence the |
65 | * relocation offset to be applied. |
66 | * cur_offset [r7] = rela.run [r9] - rela.link [r7] |
67 | * _stext.link [r10] = _stext.run [r10] - cur_offset [r7] |
68 | * final_offset [r3] = _stext.final [r3] - _stext.link [r10] |
69 | */ |
70 | subf r7,r7,r9 /* cur_offset */ |
71 | subf r10,r7,r10 |
72 | subf r3,r10,r3 /* final_offset */ |
73 | |
74 | /* |
75 | * Run through the list of relocations and process the |
76 | * R_PPC64_RELATIVE and R_PPC64_UADDR64 ones. |
77 | */ |
78 | divd r8,r8,r12 /* RELASZ / RELAENT */ |
79 | mtctr r8 |
80 | .Lrels: ld r0,8(r9) /* ELF64_R_TYPE(reloc->r_info) */ |
81 | cmpdi r0,R_PPC64_RELATIVE |
82 | bne .Luaddr64 |
83 | ld r6,0(r9) /* reloc->r_offset */ |
84 | ld r0,16(r9) /* reloc->r_addend */ |
85 | b .Lstore |
86 | .Luaddr64: |
87 | srdi r5,r0,32 /* ELF64_R_SYM(reloc->r_info) */ |
88 | clrldi r0,r0,32 |
89 | cmpdi r0,R_PPC64_UADDR64 |
90 | bne .Lnext |
91 | ld r6,0(r9) |
92 | ld r0,16(r9) |
93 | mulli r5,r5,24 /* 24 == sizeof(elf64_sym) */ |
94 | add r5,r5,r4 /* elf64_sym[ELF64_R_SYM] */ |
95 | ld r5,8(r5) |
96 | add r0,r0,r5 |
97 | .Lstore: |
98 | add r0,r0,r3 |
99 | stdx r0,r7,r6 |
100 | .Lnext: |
101 | add r9,r9,r12 |
102 | bdnz .Lrels |
103 | .Lout: |
104 | blr |
105 | |
106 | .balign 8 |
107 | p_dyn: .8byte __dynamic_start - 0b |
108 | p_rela: .8byte __rela_dyn_start - 0b |
109 | p_sym: .8byte __dynamic_symtab - 0b |
110 | p_st: .8byte _stext - 0b |
111 | |
112 | |