source: mainline/uspace/lib/c/arch/ppc32/src/rtld/reloc.c@ 7aebcdaf

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 7aebcdaf was 7aebcdaf, checked in by Jiri Svoboda <jiri@…>, 6 years ago

JMP_SLOT relocation should not care/warn about symbol size

  • Property mode set to 100644
File size: 10.7 KB
Line 
1/*
2 * Copyright (c) 2019 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libcppc32
30 * @brief
31 * @{
32 */
33/**
34 * @file
35 */
36
37#include <bitops.h>
38#include <smc.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <inttypes.h>
42#include <str.h>
43
44#include <libarch/rtld/elf_dyn.h>
45#include <rtld/symbol.h>
46#include <rtld/rtld.h>
47#include <rtld/rtld_debug.h>
48#include <rtld/rtld_arch.h>
49
50static void plt_farcall_init(uint32_t *plt, uint32_t *);
51static void plt_entry_init(uint32_t *, uint32_t *, uint32_t *, uintptr_t);
52static uint32_t *plt_entry_ptr(uint32_t *, size_t);
53static size_t plt_entry_index(size_t);
54static uint16_t addr_ha(uint32_t);
55static uint16_t addr_l(uint32_t);
56
57void module_process_pre_arch(module_t *m)
58{
59 /* Unused */
60}
61
62/**
63 * Process (fixup) all relocations in a relocation table.
64 */
65void rel_table_process(module_t *m, elf_rel_t *rt, size_t rt_size)
66{
67 /* Unused */
68 (void)m;
69 (void)rt;
70 (void)rt_size;
71}
72
73/**
74 * Process (fixup) all relocations in a relocation table with explicit addends.
75 */
76void rela_table_process(module_t *m, elf_rela_t *rt, size_t rt_size)
77{
78 unsigned i;
79
80 size_t rt_entries;
81 size_t r_offset;
82 size_t r_addend;
83 elf_xword r_info;
84 unsigned rel_type;
85 elf_word sym_idx;
86 uintptr_t sym_addr;
87
88 elf_symbol_t *sym_table;
89 elf_symbol_t *sym;
90 uintptr_t *r_ptr;
91 uintptr_t sym_size;
92 char *str_tab;
93
94 elf_symbol_t *sym_def;
95 module_t *dest;
96 uint32_t *plt;
97 uint32_t *plt_datawords;
98 size_t jmp_slots;
99
100 DPRINTF("Count jump slots.\n");
101
102 rt_entries = rt_size / sizeof(elf_rela_t);
103
104 jmp_slots = 0;
105 for (i = 0; i < rt_entries; ++i) {
106 r_info = rt[i].r_info;
107 rel_type = ELF32_R_TYPE(r_info);
108
109 if (rel_type == R_PPC_JMP_SLOT)
110 ++jmp_slots;
111 }
112
113 DPRINTF("Init farcall section\n");
114
115 plt = (uint32_t *)m->dyn.plt_got;
116
117 /* Table with addresses starts just after last PLT entry */
118 plt_datawords = plt_entry_ptr(plt, jmp_slots);
119
120 /* Init farcall section with reference to datawords table */
121 plt_farcall_init(plt, plt_datawords);
122
123 DPRINTF("parse relocation table\n");
124
125 sym_table = m->dyn.sym_tab;
126 str_tab = m->dyn.str_tab;
127
128 DPRINTF("rel table address: 0x%zx, entries: %zd\n", (uintptr_t)rt, rt_entries);
129
130 for (i = 0; i < rt_entries; ++i) {
131#if 0
132 DPRINTF("symbol %d: ", i);
133#endif
134 r_offset = rt[i].r_offset;
135 r_info = rt[i].r_info;
136 r_addend = rt[i].r_addend;
137
138 sym_idx = ELF32_R_SYM(r_info);
139 sym = &sym_table[sym_idx];
140
141#if 0
142 DPRINTF("name '%s', value 0x%x, size 0x%x\n",
143 str_tab + sym->st_name,
144 sym->st_value,
145 sym->st_size);
146#endif
147 rel_type = ELF32_R_TYPE(r_info);
148 r_ptr = (uintptr_t *)(r_offset + m->bias);
149
150 if (sym->st_name != 0) {
151 DPRINTF("rel_type: %x, rel_offset: 0x%zx\n", rel_type, r_offset);
152 sym_def = symbol_def_find(str_tab + sym->st_name,
153 m, ssf_none, &dest);
154 DPRINTF("dest name: '%s'\n", dest->dyn.soname);
155 DPRINTF("dest bias: 0x%zx\n", dest->bias);
156 if (sym_def) {
157 sym_addr = (uintptr_t)
158 symbol_get_addr(sym_def, dest, NULL);
159 DPRINTF("symbol definition found, value=0x%zx addr=0x%zx\n", sym_def->st_value, sym_addr);
160 } else {
161 printf("Definition of '%s' not found.\n",
162 str_tab + sym->st_name);
163 continue;
164 }
165 } else {
166 sym_addr = 0;
167 sym_def = NULL;
168
169 /*
170 * DTPMOD with null st_name should return the index
171 * of the current module.
172 */
173 dest = m;
174 }
175
176 switch (rel_type) {
177 case R_PPC_ADDR32:
178 DPRINTF("fixup R_PPC_ADDR32 (S+A)\n");
179 DPRINTF("*0x%zx = 0x%zx\n", (uintptr_t)r_ptr, sym_addr);
180 *r_ptr = sym_addr + r_addend;
181 DPRINTF("OK\n");
182 break;
183 case R_PPC_REL24:
184 DPRINTF("fixup R_PPC_REL24 ((S+A-P) >> 2)\n");
185 DPRINTF("*0x%zx = 0x%zx\n", (uintptr_t)r_ptr,
186 (sym_addr + r_addend - (uintptr_t)r_ptr) >> 2);
187 *r_ptr = (sym_addr + r_addend - (uintptr_t)r_ptr) >> 2;
188 DPRINTF("OK\n");
189 break;
190 case R_PPC_COPY:
191 /*
192 * Copy symbol data from shared object to specified
193 * location. Need to find the 'source', i.e. the
194 * other instance of the object than the one in the
195 * executable program.
196 */
197 DPRINTF("fixup R_PPC_COPY (s)\n");
198
199 sym_def = symbol_def_find(str_tab + sym->st_name,
200 m, ssf_noexec, &dest);
201
202 if (sym_def) {
203 sym_addr = (uintptr_t)
204 symbol_get_addr(sym_def, dest, NULL);
205 } else {
206 printf("Source definition of '%s' not found.\n",
207 str_tab + sym->st_name);
208 continue;
209 }
210
211 sym_size = sym->st_size;
212 if (sym_size != sym_def->st_size) {
213#if 0
214 printf("Warning: Mismatched symbol sizes.\n");
215#endif
216 /* Take the lower value. */
217 if (sym_size > sym_def->st_size)
218 sym_size = sym_def->st_size;
219 }
220
221 memcpy(r_ptr, (const void *)sym_addr, sym_size);
222 DPRINTF("OK\n");
223 break;
224
225 case R_PPC_JMP_SLOT:
226 DPRINTF("fixup R_PPC_JMP_SLOT (S)\n");
227 DPRINTF("r_offset=0x%zx r_addend=0x%zx\n",
228 r_offset, r_addend);
229
230 sym_def = symbol_def_find(str_tab + sym->st_name,
231 m, ssf_noexec, &dest);
232
233 if (sym_def) {
234 sym_addr = (uintptr_t)
235 symbol_get_addr(sym_def, dest, NULL);
236 } else {
237 printf("Source definition of '%s' not found.\n",
238 str_tab + sym->st_name);
239 continue;
240 }
241
242 DPRINTF("sym_addr = 0x%zx\n", sym_addr);
243 DPRINTF("r_offset=0x%zx\n", r_offset);
244
245 /*
246 * Fill PLT entry with jump to symbol address.
247 */
248 plt_entry_init(plt, (uint32_t *)r_ptr, plt_datawords,
249 sym_addr);
250
251 DPRINTF("OK\n");
252 break;
253
254 case R_PPC_RELATIVE:
255 DPRINTF("fixup R_PPC_RELATIVE (B+A)\n");
256 DPRINTF("*0x%zx = 0x%zx\n", (uintptr_t)r_ptr, m->bias + r_addend);
257 *r_ptr = m->bias + r_addend;
258 DPRINTF("OK\n");
259 break;
260
261 case R_PPC_DTPMOD32:
262 DPRINTF("fixup R_PPC_DTPMOD32\n");
263 DPRINTF("*0x%zx = 0x%zx\n", (uintptr_t)r_ptr, (size_t)dest->id);
264 *r_ptr = dest->id;
265 DPRINTF("OK\n");
266 break;
267
268 case R_PPC_DTPREL32:
269 DPRINTF("fixup R_PPC_DTPREL32\n"); /* XXXXX */
270 DPRINTF("*0x%zx = 0x%zx\n", (uintptr_t)r_ptr, sym_def->st_value);
271 *r_ptr = sym_def->st_value + r_addend;
272 DPRINTF("OK\n");
273 break;
274
275 default:
276 printf("Error: Unknown relocation type %d\n",
277 rel_type);
278 exit(1);
279 }
280
281 }
282}
283
284/** Init PLT farcall section. */
285static void plt_farcall_init(uint32_t *plt, uint32_t *plt_datawords)
286{
287 uint16_t hi;
288 uint16_t lo;
289 int i;
290
291 hi = addr_ha((uintptr_t)plt_datawords);
292 lo = addr_l((uintptr_t)plt_datawords);
293
294 plt[0] = 0x3d6b0000 | hi; /* addis %r11,% r11,. plt_datawords@ha */
295 plt[1] = 0x816b0000 | lo; /* lwz %r11, .plt_datawords@l(%r11) */
296 plt[2] = 0x7d6903a6; /* mtctr %r11 */
297 plt[3] = 0x4e800420; /* bctr */
298 plt[4] = 0x60000000; /* nop */
299 plt[5] = 0x60000000; /* nop */
300
301 smc_coherence(plt, 4 * 6);
302
303 for (i = 0; i < 6; i++)
304 DPRINTF("%p: farcall[%d] = %08zx\n", &plt[i], i, plt[i]);
305}
306
307/** Fill in PLT entry.
308 *
309 * Fill a PLT entry with PowerPC instructions to set table index and
310 * jump to the farcall section. Fill table entry with target address.
311 *
312 * @param plt Pointer to PLT
313 * @param plte Pointer to PLT entry to fill in
314 * @param datawords Address table
315 * @param ta Target address of the jump
316 */
317static void plt_entry_init(uint32_t *plt, uint32_t *plte, uint32_t *datawords,
318 uintptr_t ta)
319{
320 size_t index;
321 size_t woffset;
322 uint16_t i4index;
323 uint32_t btgt;
324
325 DPRINTF("plt_entry_init(plt=%p, plte=%p, datawords=%p, ta=0z%zx\n",
326 plt, plte, datawords, ta);
327
328 /* Entry offset in words */
329 woffset = plte - plt;
330
331 /* Entry index */
332 index = plt_entry_index(woffset);
333
334 /* This only works for the first 2048 entries */
335 assert(index * 4 < 0x8000);
336 i4index = 4 * index;
337
338 /* Relative branch offset */
339 btgt = ((uint8_t *)plt - (uint8_t *)&plte[1]) & 0x03ffffff;
340
341 /* Write target address to table */
342 datawords[index] = ta;
343 DPRINTF("%p: datawords[%zu] = %08x\n", &datawords[index], index, ta);
344
345 plte[0] = 0x39600000 | i4index; /* li %r11, 4 * index */
346 plte[1] = 0x48000000 | btgt; /* b .plt_farcall */
347
348 DPRINTF("%p: plte[0] = %08zx\n", &plte[0], plte[0]);
349 DPRINTF("%p: plte[1] = %08zx\n", &plte[1], plte[1]);
350
351 smc_coherence(plte, 4 * 2);
352}
353
354/** Determine PLT entry address.
355 *
356 * @param plt Start of PLT
357 * @param index PLT entry index
358 * @return Pointer to PLT entry
359 */
360static uint32_t *plt_entry_ptr(uint32_t *plt, size_t index)
361{
362 if (index < 8192)
363 return plt + 18 + 2 * index;
364 else
365 return plt + 18 + 2 * 8192 + 4 * (index - 8192);
366}
367
368/** Determine index of PLT entry from its word offset.
369 *
370 * @param woffset Offset of PLT entry in words
371 * @return PLT entry index
372 */
373static size_t plt_entry_index(size_t woffset)
374{
375 assert(woffset >= 18);
376 woffset -= 18;
377
378 if (woffset < 2 * 8192) {
379 assert((woffset & 0x1) == 0);
380 return woffset / 2;
381 } else {
382 assert((woffset & 0x3) == 0);
383 return (woffset - 2 * 8192) / 4;
384 }
385}
386
387/** Determine high bits of address.
388 *
389 * The lower bits are determined by @c addr_l function. The lower bits
390 * are considered to be a 16-bit signed integer.
391 *
392 * @param addr Address
393 * @return Higher bits of address
394 */
395static uint16_t addr_ha(uint32_t addr)
396{
397 int32_t la;
398
399 /* The lower part of the address is a signed 16-bit integer */
400 la = (int16_t)(addr & 0xffff);
401
402 /* Compute higher bits while compensating for the sign extension */
403 return (addr - la) >> 16;
404}
405
406/** Determine lower bits of address.
407 *
408 * The lower bits are considered to be 16-bit signed integer/immediate
409 * operand by the ISA, but we return them here as unsigned unmber so
410 * it can be easily incorporated into an instruction opcode.
411 *
412 * @param addr Address
413 * @return Lower bits of address cast as unsigned 16-bit integer
414 */
415static uint16_t addr_l(uint32_t addr)
416{
417 return (uint16_t) (addr & 0x0000ffff);
418}
419
420/** @}
421 */
Note: See TracBrowser for help on using the repository browser.