| Suzuki Poulose | 9c5f7d3 | 2011-12-14 22:58:12 +0000 | [diff] [blame] | 1 | /* | 
|  | 2 | * Code to process dynamic relocations for PPC32. | 
|  | 3 | * | 
|  | 4 | * Copyrights (C) IBM Corporation, 2011. | 
|  | 5 | *	Author: Suzuki Poulose <suzuki@in.ibm.com> | 
|  | 6 | * | 
|  | 7 | *  - Based on ppc64 code - reloc_64.S | 
|  | 8 | * | 
|  | 9 | *  This program is free software; you can redistribute it and/or | 
|  | 10 | *  modify it under the terms of the GNU General Public License | 
|  | 11 | *  as published by the Free Software Foundation; either version | 
|  | 12 | *  2 of the License, or (at your option) any later version. | 
|  | 13 | */ | 
|  | 14 |  | 
|  | 15 | #include <asm/ppc_asm.h> | 
|  | 16 |  | 
|  | 17 | /* Dynamic section table entry tags */ | 
|  | 18 | DT_RELA = 7			/* Tag for Elf32_Rela section */ | 
|  | 19 | DT_RELASZ = 8			/* Size of the Rela relocs */ | 
|  | 20 | DT_RELAENT = 9			/* Size of one Rela reloc entry */ | 
|  | 21 |  | 
|  | 22 | STN_UNDEF = 0			/* Undefined symbol index */ | 
|  | 23 | STB_LOCAL = 0			/* Local binding for the symbol */ | 
|  | 24 |  | 
|  | 25 | R_PPC_ADDR16_LO = 4		/* Lower half of (S+A) */ | 
|  | 26 | R_PPC_ADDR16_HI = 5		/* Upper half of (S+A) */ | 
|  | 27 | R_PPC_ADDR16_HA = 6		/* High Adjusted (S+A) */ | 
|  | 28 | R_PPC_RELATIVE = 22 | 
|  | 29 |  | 
|  | 30 | /* | 
|  | 31 | * r3 = desired final address | 
|  | 32 | */ | 
|  | 33 |  | 
|  | 34 | _GLOBAL(relocate) | 
|  | 35 |  | 
|  | 36 | mflr	r0		/* Save our LR */ | 
|  | 37 | bl	0f		/* Find our current runtime address */ | 
|  | 38 | 0:	mflr	r12		/* Make it accessible */ | 
|  | 39 | mtlr	r0 | 
|  | 40 |  | 
|  | 41 | lwz	r11, (p_dyn - 0b)(r12) | 
|  | 42 | add	r11, r11, r12	/* runtime address of .dynamic section */ | 
|  | 43 | lwz	r9, (p_rela - 0b)(r12) | 
|  | 44 | add	r9, r9, r12	/* runtime address of .rela.dyn section */ | 
|  | 45 | lwz	r10, (p_st - 0b)(r12) | 
|  | 46 | add	r10, r10, r12	/* runtime address of _stext section */ | 
|  | 47 | lwz	r13, (p_sym - 0b)(r12) | 
|  | 48 | add	r13, r13, r12	/* runtime address of .dynsym section */ | 
|  | 49 |  | 
|  | 50 | /* | 
|  | 51 | * Scan the dynamic section for RELA, RELASZ entries | 
|  | 52 | */ | 
|  | 53 | li	r6, 0 | 
|  | 54 | li	r7, 0 | 
|  | 55 | li	r8, 0 | 
|  | 56 | 1:	lwz	r5, 0(r11)	/* ELF_Dyn.d_tag */ | 
|  | 57 | cmpwi	r5, 0		/* End of ELF_Dyn[] */ | 
|  | 58 | beq	eodyn | 
|  | 59 | cmpwi	r5, DT_RELA | 
|  | 60 | bne	relasz | 
|  | 61 | lwz	r7, 4(r11)	/* r7 = rela.link */ | 
|  | 62 | b	skip | 
|  | 63 | relasz: | 
|  | 64 | cmpwi	r5, DT_RELASZ | 
|  | 65 | bne	relaent | 
|  | 66 | lwz	r8, 4(r11)	/* r8 = Total Rela relocs size */ | 
|  | 67 | b	skip | 
|  | 68 | relaent: | 
|  | 69 | cmpwi	r5, DT_RELAENT | 
|  | 70 | bne	skip | 
|  | 71 | lwz	r6, 4(r11)	/* r6 = Size of one Rela reloc */ | 
|  | 72 | skip: | 
|  | 73 | addi	r11, r11, 8 | 
|  | 74 | b	1b | 
|  | 75 | eodyn:				/* End of Dyn Table scan */ | 
|  | 76 |  | 
|  | 77 | /* Check if we have found all the entries */ | 
|  | 78 | cmpwi	r7, 0 | 
|  | 79 | beq	done | 
|  | 80 | cmpwi	r8, 0 | 
|  | 81 | beq	done | 
|  | 82 | cmpwi	r6, 0 | 
|  | 83 | beq	done | 
|  | 84 |  | 
|  | 85 |  | 
|  | 86 | /* | 
|  | 87 | * Work out the current offset from the link time address of .rela | 
|  | 88 | * section. | 
|  | 89 | *  cur_offset[r7] = rela.run[r9] - rela.link [r7] | 
|  | 90 | *  _stext.link[r12] = _stext.run[r10] - cur_offset[r7] | 
|  | 91 | *  final_offset[r3] = _stext.final[r3] - _stext.link[r12] | 
|  | 92 | */ | 
|  | 93 | subf	r7, r7, r9	/* cur_offset */ | 
|  | 94 | subf	r12, r7, r10 | 
|  | 95 | subf	r3, r12, r3	/* final_offset */ | 
|  | 96 |  | 
|  | 97 | subf	r8, r6, r8	/* relaz -= relaent */ | 
|  | 98 | /* | 
|  | 99 | * Scan through the .rela table and process each entry | 
|  | 100 | * r9	- points to the current .rela table entry | 
|  | 101 | * r13	- points to the symbol table | 
|  | 102 | */ | 
|  | 103 |  | 
|  | 104 | /* | 
|  | 105 | * Check if we have a relocation based on symbol | 
|  | 106 | * r5 will hold the value of the symbol. | 
|  | 107 | */ | 
|  | 108 | applyrela: | 
|  | 109 | lwz	r4, 4(r9)		/* r4 = rela.r_info */ | 
|  | 110 | srwi	r5, r4, 8		/* ELF32_R_SYM(r_info) */ | 
|  | 111 | cmpwi	r5, STN_UNDEF	/* sym == STN_UNDEF ? */ | 
|  | 112 | beq	get_type	/* value = 0 */ | 
|  | 113 | /* Find the value of the symbol at index(r5) */ | 
|  | 114 | slwi	r5, r5, 4		/* r5 = r5 * sizeof(Elf32_Sym) */ | 
|  | 115 | add	r12, r13, r5	/* r12 = &__dyn_sym[Index] */ | 
|  | 116 |  | 
|  | 117 | /* | 
|  | 118 | * GNU ld has a bug, where dynamic relocs based on | 
|  | 119 | * STB_LOCAL symbols, the value should be assumed | 
|  | 120 | * to be zero. - Alan Modra | 
|  | 121 | */ | 
|  | 122 | /* XXX: Do we need to check if we are using GNU ld ? */ | 
|  | 123 | lbz	r5, 12(r12)	/* r5 = dyn_sym[Index].st_info */ | 
|  | 124 | extrwi	r5, r5, 4, 24	/* r5 = ELF32_ST_BIND(r5) */ | 
|  | 125 | cmpwi	r5, STB_LOCAL	/* st_value = 0, ld bug */ | 
|  | 126 | beq	get_type	/* We have r5 = 0 */ | 
|  | 127 | lwz	r5, 4(r12)	/* r5 = __dyn_sym[Index].st_value */ | 
|  | 128 |  | 
|  | 129 | get_type: | 
|  | 130 | /* Load the relocation type to r4 */ | 
|  | 131 | extrwi	r4, r4, 8, 24	/* r4 = ELF32_R_TYPE(r_info) = ((char*)r4)[3] */ | 
|  | 132 |  | 
|  | 133 | /* R_PPC_RELATIVE */ | 
|  | 134 | cmpwi	r4, R_PPC_RELATIVE | 
|  | 135 | bne	hi16 | 
|  | 136 | lwz	r4, 0(r9)	/* r_offset */ | 
|  | 137 | lwz	r0, 8(r9)	/* r_addend */ | 
|  | 138 | add	r0, r0, r3	/* final addend */ | 
|  | 139 | stwx	r0, r4, r7	/* memory[r4+r7]) = (u32)r0 */ | 
|  | 140 | b	nxtrela		/* continue */ | 
|  | 141 |  | 
|  | 142 | /* R_PPC_ADDR16_HI */ | 
|  | 143 | hi16: | 
|  | 144 | cmpwi	r4, R_PPC_ADDR16_HI | 
|  | 145 | bne	ha16 | 
|  | 146 | lwz	r4, 0(r9)	/* r_offset */ | 
|  | 147 | lwz	r0, 8(r9)	/* r_addend */ | 
|  | 148 | add	r0, r0, r3 | 
|  | 149 | add	r0, r0, r5	/* r0 = (S+A+Offset) */ | 
|  | 150 | extrwi	r0, r0, 16, 0	/* r0 = (r0 >> 16) */ | 
|  | 151 | b	store_half | 
|  | 152 |  | 
|  | 153 | /* R_PPC_ADDR16_HA */ | 
|  | 154 | ha16: | 
|  | 155 | cmpwi	r4, R_PPC_ADDR16_HA | 
|  | 156 | bne	lo16 | 
|  | 157 | lwz	r4, 0(r9)	/* r_offset */ | 
|  | 158 | lwz	r0, 8(r9)	/* r_addend */ | 
|  | 159 | add	r0, r0, r3 | 
|  | 160 | add	r0, r0, r5	/* r0 = (S+A+Offset) */ | 
|  | 161 | extrwi	r5, r0, 1, 16	/* Extract bit 16 */ | 
|  | 162 | extrwi	r0, r0, 16, 0	/* r0 = (r0 >> 16) */ | 
|  | 163 | add	r0, r0, r5	/* Add it to r0 */ | 
|  | 164 | b	store_half | 
|  | 165 |  | 
|  | 166 | /* R_PPC_ADDR16_LO */ | 
|  | 167 | lo16: | 
|  | 168 | cmpwi	r4, R_PPC_ADDR16_LO | 
|  | 169 | bne	nxtrela | 
|  | 170 | lwz	r4, 0(r9)	/* r_offset */ | 
|  | 171 | lwz	r0, 8(r9)	/* r_addend */ | 
|  | 172 | add	r0, r0, r3 | 
|  | 173 | add	r0, r0, r5	/* r0 = (S+A+Offset) */ | 
|  | 174 | extrwi	r0, r0, 16, 16	/* r0 &= 0xffff */ | 
|  | 175 | /* Fall through to */ | 
|  | 176 |  | 
|  | 177 | /* Store half word */ | 
|  | 178 | store_half: | 
|  | 179 | sthx	r0, r4, r7	/* memory[r4+r7] = (u16)r0 */ | 
|  | 180 |  | 
|  | 181 | nxtrela: | 
|  | 182 | /* | 
|  | 183 | * We have to flush the modified instructions to the | 
|  | 184 | * main storage from the d-cache. And also, invalidate the | 
|  | 185 | * cached instructions in i-cache which has been modified. | 
|  | 186 | * | 
|  | 187 | * We delay the sync / isync operation till the end, since | 
|  | 188 | * we won't be executing the modified instructions until | 
|  | 189 | * we return from here. | 
|  | 190 | */ | 
|  | 191 | dcbst	r4,r7 | 
|  | 192 | sync			/* Ensure the data is flushed before icbi */ | 
|  | 193 | icbi	r4,r7 | 
|  | 194 | cmpwi	r8, 0		/* relasz = 0 ? */ | 
|  | 195 | ble	done | 
|  | 196 | add	r9, r9, r6	/* move to next entry in the .rela table */ | 
|  | 197 | subf	r8, r6, r8	/* relasz -= relaent */ | 
|  | 198 | b	applyrela | 
|  | 199 |  | 
|  | 200 | done: | 
|  | 201 | sync			/* Wait for the flush to finish */ | 
|  | 202 | isync			/* Discard prefetched instructions */ | 
|  | 203 | blr | 
|  | 204 |  | 
|  | 205 | p_dyn:		.long	__dynamic_start - 0b | 
|  | 206 | p_rela:		.long	__rela_dyn_start - 0b | 
|  | 207 | p_sym:		.long	__dynamic_symtab - 0b | 
|  | 208 | p_st:		.long	_stext - 0b |