xref: /openbmc/linux/arch/powerpc/kernel/reloc_64.S (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
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