[ipc/ipcdev.git] / qnx / src / ipc3x_dev / ti / syslink / procMgr / hlos / knl / loaders / Elf / Qnx / DLOAD / TMS470_DLOAD_REL / arm_reloc.c
1 /*
2 * arm_reloc.c
3 *
4 * Process ARM-specific dynamic relocations for core dynamic loader.
5 *
6 * Copyright (C) 2009-2015 Texas Instruments Incorporated - http://www.ti.com/
7 *
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the
19 * distribution.
20 *
21 * Neither the name of Texas Instruments Incorporated nor the names of
22 * its contributors may be used to endorse or promote products derived
23 * from this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 */
39 #include <limits.h>
40 #include "relocate.h"
41 #include "dload_api.h"
42 #include "util.h"
43 #include "dload_endian.h"
44 #include "symtab.h"
45 #include "arm_elf32.h"
46 #include "dload.h"
47 #include "arm_reloc.h"
49 #define EXTRACT(field, lsb_offset, field_size) \
50 ( (field >> lsb_offset) & ((1U << field_size) - 1) )
51 #define OPND_S(symval) (symval & ~0x1)
52 #define OPND_T(symval) (symval & 0x1)
53 #define IS_BLX(field) ((EXTRACT(field, 24, 8) & ~0x1) == 0xFA)
54 #define SIGN_EXTEND(field, field_size) (field |= -(field & (1<<(field_size-1))))
56 /*****************************************************************************/
57 /* Enumeration to represent the relocation container size. */
58 /* */
59 /* ARM_RELOC - one 32 bit relocation field */
60 /* THUMB32_RELOC - two 16 bit relocation fields */
61 /* THUMB16_RELOC - one 16 bit relocation field */
62 /* ARM8_RELOC - one 8 bit relocation field */
63 /*****************************************************************************/
64 typedef enum
65 {
66 ARM_RELOC,
67 THUMB32_RELOC,
68 THUMB16_RELOC,
69 ARM8_RELOC
70 }ARM_RELOC_SIZE;
72 /*****************************************************************************/
73 /* OBJ_IS_BE8() - Returns TRUE if the object file contains BE8 code. */
74 /*****************************************************************************/
75 static inline int obj_is_be8(struct Elf32_Ehdr* fhdr)
76 {
77 return (fhdr->e_flags & EF_ARM_BE8);
78 }
80 /*****************************************************************************/
81 /* IS_DATA_RELOCATION() - Returns TRUE if the relocation pertains to data */
82 /*****************************************************************************/
83 static BOOL is_data_relocation(ARM_RELOC_TYPE r_type)
84 {
85 switch (r_type)
86 {
87 case R_ARM_ABS32:
88 case R_ARM_ABS16:
89 case R_ARM_ABS8:
90 case R_ARM_PREL31:
91 case R_ARM_REL32:
92 case R_ARM_ABS32_NOI:
93 case R_ARM_REL32_NOI:
94 return TRUE;
95 default:
96 return FALSE;
97 }
98 }
100 /*****************************************************************************/
101 /* REL_SWAP_ENDIAN() - Return TRUE if we should change the endianness of a */
102 /* relocation field. Due to BE-8 encoding, we cannot */
103 /* simply rely on the wrong_endian member of elf_addrs. */
104 /*****************************************************************************/
105 static BOOL rel_swap_endian(DLIMP_Dynamic_Module* dyn_module,
106 ARM_RELOC_TYPE r_type)
107 {
108 /*---------------------------------------------------------------*/
109 /* LE -> BE8 - swap data relocations only */
110 /*---------------------------------------------------------------*/
111 if (dyn_module->wrong_endian && obj_is_be8(&dyn_module->fhdr) &&
112 is_data_relocation(r_type))
113 return TRUE;
114 /*---------------------------------------------------------------*/
115 /* BE -> BE8 - swap instruction relocations */
116 /*---------------------------------------------------------------*/
117 else if (!dyn_module->wrong_endian &&
118 obj_is_be8(&dyn_module->fhdr) &&
119 !is_data_relocation(r_type))
120 return TRUE;
121 /*---------------------------------------------------------------*/
122 /* LE -> BE32, BE8-> LE, BE32 -> LE - swap all relocations */
123 /*---------------------------------------------------------------*/
124 else if (dyn_module->wrong_endian)
125 return TRUE;
127 /*---------------------------------------------------------------*/
128 /* BE32 -> BE32, LE -> LE, BE8 -> BE32 - swap nothing */
129 /*---------------------------------------------------------------*/
130 return FALSE;
131 }
133 /*****************************************************************************/
134 /* REL_CONCLUDES_GROUP() - Returns true if this relocation type concludes a */
135 /* group relocation sequence */
136 /*****************************************************************************/
137 static BOOL rel_concludes_group(ARM_RELOC_TYPE r_type)
138 {
139 switch (r_type)
140 {
141 case R_ARM_ALU_PC_G0:
142 case R_ARM_ALU_PC_G1:
143 case R_ARM_ALU_PC_G2:
144 case R_ARM_LDC_PC_G0:
145 case R_ARM_LDC_PC_G1:
146 case R_ARM_LDC_PC_G2:
147 case R_ARM_LDR_PC_G0:
148 case R_ARM_LDR_PC_G1:
149 case R_ARM_LDR_PC_G2:
150 case R_ARM_LDRS_PC_G0:
151 case R_ARM_LDRS_PC_G1:
152 case R_ARM_LDRS_PC_G2:
153 return TRUE;
154 default:
155 return FALSE;
156 }
157 }
159 /*****************************************************************************/
160 /* REL_GROUP_NUM() - Returns group number of this relocation type. */
161 /*****************************************************************************/
162 static int rel_group_num(ARM_RELOC_TYPE r_type)
163 {
164 switch (r_type)
165 {
166 case R_ARM_ALU_PC_G0:
167 case R_ARM_ALU_PC_G0_NC:
168 case R_ARM_LDC_PC_G0:
169 case R_ARM_LDR_PC_G0:
170 case R_ARM_LDRS_PC_G0:
171 return 0;
173 case R_ARM_ALU_PC_G1:
174 case R_ARM_ALU_PC_G1_NC:
175 case R_ARM_LDC_PC_G1:
176 case R_ARM_LDR_PC_G1:
177 case R_ARM_LDRS_PC_G1:
178 return 1;
180 case R_ARM_ALU_PC_G2:
181 case R_ARM_LDC_PC_G2:
182 case R_ARM_LDR_PC_G2:
183 case R_ARM_LDRS_PC_G2:
184 return 2;
186 default:
187 return 0;
188 }
189 }
191 /*****************************************************************************/
192 /* REL_ALU_MASK_OFFSET() - Calculate the offset of an 8-bit mask for an */
193 /* ALU immediate value. */
194 /*****************************************************************************/
195 static uint32_t rel_alu_mask_offset(int32_t residual, int bit_align)
196 {
197 uint32_t mask_offset;
199 for (mask_offset = 31; mask_offset > 7; mask_offset--)
200 if (residual & (0x1 << mask_offset)) break;
201 mask_offset -= 7;
203 if (bit_align == 0) bit_align = 1;
205 if (mask_offset % bit_align != 0)
206 mask_offset += (bit_align - (mask_offset % bit_align));
208 return mask_offset;
209 }
211 /*****************************************************************************/
212 /* REL_MASK_FOR_GROUP() - Mask off the appropriate bits from reloc_val, */
213 /* depending on the group relocation type. */
214 /* See Section 4.6.1.4 Group relocations in AAELF */
215 /* for more details. */
216 /*****************************************************************************/
217 static void rel_mask_for_group(ARM_RELOC_TYPE r_type, int32_t* reloc_val)
218 {
219 int32_t curr_residual = *reloc_val;
220 int num_alu_groups = rel_group_num(r_type) + 1;
221 int n;
222 if (rel_concludes_group(r_type)) num_alu_groups--;
224 for (n = 0; n < num_alu_groups; n++)
225 {
226 uint32_t mask_offset = rel_alu_mask_offset(curr_residual, 2);
227 uint32_t cres_mask = 0xFF << mask_offset;
229 *reloc_val = curr_residual & cres_mask;
231 curr_residual = curr_residual & ~cres_mask;
232 }
234 if (rel_concludes_group(r_type)) *reloc_val = curr_residual;
236 }
238 /*****************************************************************************/
239 /* GET_RELOC_SIZE() - Return the container size for this relocation type. */
240 /*****************************************************************************/
241 static ARM_RELOC_SIZE get_reloc_size(ARM_RELOC_TYPE r_type)
242 {
243 switch (r_type)
244 {
245 case R_ARM_THM_ABS5:
246 case R_ARM_THM_PC8:
247 case R_ARM_THM_JUMP6:
248 case R_ARM_THM_JUMP11:
249 case R_ARM_THM_JUMP8:
250 return THUMB16_RELOC;
252 case R_ARM_THM_CALL:
253 case R_ARM_THM_JUMP24:
254 case R_ARM_THM_MOVW_ABS_NC:
255 case R_ARM_THM_MOVT_ABS:
256 case R_ARM_THM_MOVW_PREL_NC:
257 case R_ARM_THM_MOVT_PREL:
258 case R_ARM_THM_JUMP19:
259 case R_ARM_THM_ALU_PREL_11_0:
260 case R_ARM_THM_PC12:
261 case R_ARM_THM_MOVW_BREL_NC:
262 case R_ARM_THM_MOVT_BREL:
263 case R_ARM_THM_MOVW_BREL:
264 return THUMB32_RELOC;
266 case R_ARM_ABS8:
267 return ARM8_RELOC;
269 default:
270 return ARM_RELOC;
271 }
272 }
274 /*****************************************************************************/
275 /* REL_CHANGE_ENDIAN() - Changes the endianess of the relocation field */
276 /* located at address. The size of the field depends */
277 /* on the relocation type. */
278 /*****************************************************************************/
279 static void rel_change_endian(ARM_RELOC_TYPE r_type, uint8_t* address)
280 {
281 ARM_RELOC_SIZE reloc_size = get_reloc_size(r_type);
283 switch (reloc_size)
284 {
285 case ARM_RELOC:
286 {
287 DLIMP_change_endian32((int32_t*)address);
288 break;
289 }
291 case THUMB32_RELOC:
292 {
293 int16_t* ins1_ptr = (int16_t*)address;
294 DLIMP_change_endian16(ins1_ptr);
295 DLIMP_change_endian16(ins1_ptr + 1);
296 break;
297 }
299 case THUMB16_RELOC:
300 {
301 DLIMP_change_endian16((int16_t*)address);
302 break;
303 }
305 default:
306 {
307 break;
308 }
309 }
310 }
312 /*****************************************************************************/
313 /* WRITE_RELOC_R() - Write a relocation value to address rel_field_ptr. */
314 /* It is assumed that all values have been properly packed */
315 /* and masked. */
316 /*****************************************************************************/
317 static void write_reloc_r(uint8_t* rel_field_ptr,
318 ARM_RELOC_TYPE r_type, int32_t reloc_val,
319 uint32_t symval)
320 {
321 #if LOADER_DEBUG
322 /*------------------------------------------------------------------------*/
323 /* Print some details about the relocation we are about to process. */
324 /*------------------------------------------------------------------------*/
325 if(debugging_on)
326 {
327 DLIF_trace("RWRT: rel_field_ptr: 0x%x\n", (uint32_t)rel_field_ptr);
328 DLIF_trace("RWRT: result: 0x%x\n", reloc_val);
329 }
330 #endif
333 /*------------------------------------------------------------------------*/
334 /* Given the relocation type, carry out relocation into a 4 byte packet */
335 /* within the buffered segment. */
336 /*------------------------------------------------------------------------*/
337 switch(r_type)
338 {
339 case R_ARM_ABS32:
340 case R_ARM_REL32:
341 case R_ARM_REL32_NOI:
342 case R_ARM_ABS32_NOI:
343 {
344 *((uint32_t*)rel_field_ptr) = reloc_val;
345 break;
346 }
348 case R_ARM_PREL31:
349 {
350 *((uint32_t*)rel_field_ptr) |= reloc_val;
351 break;
352 }
354 case R_ARM_PC24:
355 case R_ARM_CALL:
356 case R_ARM_PLT32:
357 {
358 /*----------------------------------------------------------------*/
359 /* ARM BL/BLX */
360 /* reloc_val has already been packed down to 25 bits. If the */
361 /* callee is a thumb function, we convert to a BLX. After */
362 /* conversion, the field is packed down to 24 bits. */
363 /*----------------------------------------------------------------*/
364 uint32_t rel_field = *((uint32_t*)rel_field_ptr);
366 /*----------------------------------------------------------------*/
367 /* Check to see if callee is a thumb function. If so convert to */
368 /* BLX */
369 /*----------------------------------------------------------------*/
370 if (OPND_T(symval))
371 rel_field |= 0xF0000000;
373 /*----------------------------------------------------------------*/
374 /* Clear imm24 bits. This must be done for both BL and BLX */
375 /*----------------------------------------------------------------*/
376 rel_field &= ~0xFFFFFF;
378 if (IS_BLX(rel_field))
379 {
380 uint8_t Hval = reloc_val & 0x1;
381 /*------------------------------------------------------------*/
382 /* For BLX clear bit 24 (the H bit) */
383 /*------------------------------------------------------------*/
384 rel_field &= ~0x01000000;
385 rel_field |= Hval << 24;
386 }
388 /*----------------------------------------------------------------*/
389 /* Pack reloc_val down to 24 bits. */
390 /*----------------------------------------------------------------*/
391 rel_field |= (reloc_val >> 1);
392 *((uint32_t*)rel_field_ptr) = rel_field;
393 break;
394 }
396 case R_ARM_JUMP24:
397 {
398 *((uint32_t*)rel_field_ptr) &= ~0xFFFFFF;
399 *((uint32_t*)rel_field_ptr) |= reloc_val;
400 break;
401 }
403 case R_ARM_THM_CALL:
404 case R_ARM_THM_JUMP24:
405 {
406 /*----------------------------------------------------------------*/
407 /* THUMB B.W/BL/BLX */
408 /*----------------------------------------------------------------*/
409 uint16_t* rel_field_16_ptr = (uint16_t*) rel_field_ptr;
411 uint8_t Sval;
412 uint8_t J1;
413 uint8_t J2;
414 uint16_t imm10;
415 uint16_t imm11;
417 /*----------------------------------------------------------------*/
418 /* If callee is a thumb function, convert BL to BLX */
419 /*----------------------------------------------------------------*/
420 if (!OPND_T(symval) && r_type == R_ARM_THM_CALL)
421 {
422 if (reloc_val & 0x1) reloc_val++;
423 *(rel_field_16_ptr + 1) &= 0xEFFF;
424 }
426 /*----------------------------------------------------------------*/
427 /* reloc_val = S:I1:I2:imm10:imm11 */
428 /*----------------------------------------------------------------*/
429 Sval = (reloc_val >> 23) & 0x1;
430 J1 = ((reloc_val >> 22) ^ (!Sval)) & 0x1;
431 J2 = ((reloc_val >> 21) ^ (!Sval)) & 0x1;
432 imm10 = (reloc_val >> 11) & 0x3FF;
433 imm11 = reloc_val & 0x7FF;
435 *rel_field_16_ptr &= 0xF800;
436 *rel_field_16_ptr |= (Sval << 10);
437 *rel_field_16_ptr |= imm10;
439 rel_field_16_ptr++;
440 *rel_field_16_ptr &= 0xD000;
442 *rel_field_16_ptr |= (J1 << 13);
443 *rel_field_16_ptr |= (J2 << 11);
444 *rel_field_16_ptr |= imm11;
446 break;
447 }
448 case R_ARM_THM_JUMP19:
449 {
450 /*----------------------------------------------------------------*/
451 /* THUMB B<c>.W */
452 /* reloc_val = S:J2:J1:imm6:imm11:'0' */
453 /*----------------------------------------------------------------*/
454 uint16_t* rel_field_16_ptr = (uint16_t*) rel_field_ptr;
455 uint8_t S;
456 uint8_t J2;
457 uint8_t J1;
458 uint8_t imm6;
459 uint16_t imm11;
461 S = (reloc_val >> 19) & 0x1;
462 J2 = (reloc_val >> 18) & 0x1;
463 J1 = (reloc_val >> 17) & 0x1;
464 imm6 = (reloc_val >> 11) & 0x3F;
465 imm11 = (reloc_val ) & 0x7FF;
467 /*----------------------------------------------------------------*/
468 /* Clear S and imm6 fields in first part of instruction */
469 /*----------------------------------------------------------------*/
470 *rel_field_16_ptr &= 0xFBC0;
471 *rel_field_16_ptr |= (S << 10);
472 *rel_field_16_ptr |= imm6;
474 rel_field_16_ptr++;
476 *rel_field_16_ptr &= 0xD800;
477 *rel_field_16_ptr |= (J2 << 13);
478 *rel_field_16_ptr |= (J1 << 11);
479 *rel_field_16_ptr |= imm11;
480 break;
481 }
482 case R_ARM_THM_JUMP11:
483 {
484 /*----------------------------------------------------------------*/
485 /* THUMB B (unconditional) */
486 /*----------------------------------------------------------------*/
487 *((uint16_t*)rel_field_ptr) &= ~0x7FF;
488 *((uint16_t*)rel_field_ptr) |= reloc_val;
489 break;
490 }
492 case R_ARM_THM_JUMP8:
493 {
494 /*----------------------------------------------------------------*/
495 /* THUMB B<c> */
496 /*----------------------------------------------------------------*/
497 *((uint16_t*)rel_field_ptr) &= ~0xFF;
498 *((uint16_t*)rel_field_ptr) |= reloc_val;
499 break;
500 }
502 case R_ARM_THM_ABS5:
503 {
504 /*----------------------------------------------------------------*/
505 /* THUMB LDR<c> <Rt>, [<Rn>(,#imm}] */
506 /*----------------------------------------------------------------*/
507 *((uint16_t*)rel_field_ptr) &= 0xF83F;
508 *((uint16_t*)rel_field_ptr) |= (reloc_val << 6);
509 break;
510 }
512 case R_ARM_THM_PC8:
513 {
514 /*----------------------------------------------------------------*/
515 /* THUMB LDR<c> <Rt>,[SP{,#imm}] */
516 /*----------------------------------------------------------------*/
517 *((uint16_t*)rel_field_ptr) &= 0xFF00;
518 *((uint16_t*)rel_field_ptr) |= reloc_val;
519 break;
520 }
522 case R_ARM_THM_JUMP6:
523 {
524 /*----------------------------------------------------------------*/
525 /* THUMB CBZ,CBNZ */
526 /* reloc_field = Ival:imm5 */
527 /*----------------------------------------------------------------*/
528 uint8_t Ival;
529 uint8_t imm5;
531 Ival = (reloc_val >> 5) & 0x1;
532 imm5 = (reloc_val & 0x1F);
533 *((uint16_t*)rel_field_ptr) &= 0xFD07;
534 *((uint16_t*)rel_field_ptr) |= (Ival << 9);
535 *((uint16_t*)rel_field_ptr) |= (imm5 << 3);
536 break;
537 }
539 case R_ARM_ABS16:
540 {
541 /*----------------------------------------------------------------*/
542 /* 16 bit data relocation */
543 /*----------------------------------------------------------------*/
544 *((uint16_t*)rel_field_ptr) = reloc_val;
545 break;
546 }
548 case R_ARM_ABS8:
549 {
550 /*----------------------------------------------------------------*/
551 /* 8 bit data relocation */
552 /*----------------------------------------------------------------*/
553 *((uint8_t*)rel_field_ptr) = reloc_val;
554 break;
555 }
557 case R_ARM_MOVW_ABS_NC:
558 case R_ARM_MOVT_ABS:
559 case R_ARM_MOVW_PREL_NC:
560 case R_ARM_MOVT_PREL:
561 {
562 /*----------------------------------------------------------------*/
563 /* MOVW/MOVT */
564 /*----------------------------------------------------------------*/
565 uint8_t imm4 = reloc_val >> 12;
566 uint16_t imm12 = reloc_val & 0xFFF;
567 *((uint32_t*)rel_field_ptr) &= 0xFFF0F000;
568 *((uint32_t*)rel_field_ptr) |= imm12;
569 *((uint32_t*)rel_field_ptr) |= (imm4 << 16);
570 break;
571 }
573 case R_ARM_THM_MOVW_ABS_NC:
574 case R_ARM_THM_MOVT_ABS:
575 case R_ARM_THM_MOVW_PREL_NC:
576 case R_ARM_THM_MOVT_PREL:
577 {
578 /*----------------------------------------------------------------*/
579 /* THUMB2 MOVW/MOVT */
580 /*----------------------------------------------------------------*/
581 uint16_t* rel_field_16_ptr = (uint16_t*) rel_field_ptr;
583 uint8_t imm4 = (reloc_val >> 12);
584 uint8_t i = (reloc_val >> 11) & 0x1;
585 uint8_t imm3 = (reloc_val >> 8 ) & 0x7;
586 uint8_t imm8 = (reloc_val ) & 0xFF;
588 *rel_field_16_ptr &= 0xFBF0;
589 *rel_field_16_ptr |= i << 10;
590 *rel_field_16_ptr |= imm4;
592 rel_field_16_ptr++;
594 *rel_field_16_ptr &= 0x8F00;
595 *rel_field_16_ptr |= imm3 << 12;
596 *rel_field_16_ptr |= imm8;
598 break;
599 }
601 case R_ARM_ABS12:
602 {
603 /*----------------------------------------------------------------*/
604 /* LDR immediate */
605 /* */
606 /* We need to know the sign of the relocated value, so we wait to */
607 /* to mask off any bits until now. */
608 /*----------------------------------------------------------------*/
609 uint8_t S = !((reloc_val >> 31) & 0x1);
610 reloc_val = abs(reloc_val) & 0xFFF;
612 *((uint32_t*)rel_field_ptr) &= 0xFF7FF000;
613 *((uint32_t*)rel_field_ptr) |= reloc_val;
614 *((uint32_t*)rel_field_ptr) |= (S << 23);
615 break;
616 }
618 case R_ARM_THM_PC12:
619 {
620 /*----------------------------------------------------------------*/
621 /* LDR<,B,SB,H,SH> Rd, [PC, #imm] (literal) */
622 /* */
623 /* We need to know the sign of the relocated value, so we wait to */
624 /* to mask off any bits until now. */
625 /*----------------------------------------------------------------*/
626 uint16_t* rel_field_16_ptr = (uint16_t*) rel_field_ptr;
627 uint8_t U = (reloc_val < 0) ? 0 : 1;
628 reloc_val = abs(reloc_val) & 0xFFF;
630 *rel_field_16_ptr &= 0xFF7F;
631 *rel_field_16_ptr |= U << 7;
633 rel_field_16_ptr++;
635 *rel_field_16_ptr &= 0xF000;
636 *rel_field_16_ptr |= reloc_val;
638 break;
639 }
641 /*--------------------------------------------------------------------*/
642 /* ARM GROUP RELOCATIONS. See Section 4.6.1.4 in AAELF for more info */
643 /* */
644 /* For these relocations, the reloc_val is calculated by */
645 /* rel_mask_for_group(). We cannot check for overflow until after */
646 /* this has been called, so overflow checking has been delayed until */
647 /* now. */
648 /*--------------------------------------------------------------------*/
650 case R_ARM_ALU_PC_G0_NC:
651 case R_ARM_ALU_PC_G0:
652 case R_ARM_ALU_PC_G1_NC:
653 case R_ARM_ALU_PC_G2:
654 {
655 /*----------------------------------------------------------------*/
656 /* ARM ALU (ADD/SUB) */
657 /*----------------------------------------------------------------*/
658 uint32_t *rel_field_32_ptr = (uint32_t*) rel_field_ptr;
659 uint32_t mask_offset;
660 uint8_t Rval = 0;
661 uint8_t Ival = 0;
663 *rel_field_32_ptr &= 0xFF3FF000;
665 /******************************************************************/
666 /* Change the instruction to ADD or SUB, depending on the sign */
667 /******************************************************************/
668 if ((int32_t)reloc_val >= 0)
669 *rel_field_32_ptr |= 0x1 << 23;
670 else
671 *rel_field_32_ptr |= 0x1 << 22;
673 reloc_val = abs(reloc_val);
674 rel_mask_for_group(r_type, &reloc_val);
676 mask_offset = rel_alu_mask_offset(reloc_val, 2);
678 Rval = 32 - mask_offset;
679 Ival = (reloc_val >> mask_offset) & 0xFF;
681 if (reloc_val & ~(0xFF << mask_offset))
682 DLIF_error(DLET_RELOC, "relocation overflow\n");
684 *rel_field_32_ptr |= ((Rval >> 1) & 0xF) << 8;
685 *rel_field_32_ptr |= (Ival & 0xFF);
686 }
687 break;
689 case R_ARM_LDR_PC_G0:
690 case R_ARM_LDR_PC_G1:
691 case R_ARM_LDR_PC_G2:
692 {
693 /*----------------------------------------------------------------*/
694 /* ARM LDR/STR/LDRB/STRB */
695 /*----------------------------------------------------------------*/
696 uint8_t Uval = (reloc_val < 0) ? 0 : 1;
697 uint32_t Lval = 0;
699 reloc_val = abs(reloc_val);
701 rel_mask_for_group(r_type, &reloc_val);
703 if (abs(reloc_val) >= 0x1000)
704 DLIF_error(DLET_RELOC, "relocation overflow!\n");
706 Lval = reloc_val & 0xFFF;
708 *((uint32_t*) rel_field_ptr) &= 0xFF7FF000;
709 *((uint32_t*) rel_field_ptr) |= Uval << 23;
710 *((uint32_t*) rel_field_ptr) |= Lval;
711 }
712 break;
714 case R_ARM_LDRS_PC_G0:
715 case R_ARM_LDRS_PC_G1:
716 case R_ARM_LDRS_PC_G2:
717 {
718 /*----------------------------------------------------------------*/
719 /* ARM LDRD/STRD/LDRH/STRH/LDRSH/LDRSB */
720 /*----------------------------------------------------------------*/
721 uint8_t Uval = (reloc_val < 0) ? 0 : 1;
722 uint8_t Hval;
723 uint8_t Lval;
725 reloc_val = abs(reloc_val);
727 rel_mask_for_group(r_type, &reloc_val);
729 if (abs(reloc_val) >= 0x100)
730 DLIF_error(DLET_RELOC, "relocation overflow!\n");
732 Hval = (reloc_val >> 4) & 0xF;
733 Lval = (reloc_val ) & 0xF;
735 *((uint32_t*) rel_field_ptr) &= 0xFF7FF0F0;
736 *((uint32_t*) rel_field_ptr) |= (Uval << 23);
737 *((uint32_t*) rel_field_ptr) |= (Hval << 8);
738 *((uint32_t*) rel_field_ptr) |= Lval;
739 }
740 break;
742 case R_ARM_LDC_PC_G0:
743 case R_ARM_LDC_PC_G1:
744 case R_ARM_LDC_PC_G2:
745 {
746 /*----------------------------------------------------------------*/
747 /* ARM LDC/STC */
748 /*----------------------------------------------------------------*/
749 uint8_t Uval = (reloc_val < 0) ? 0 : 1;
750 uint8_t Lval;
752 reloc_val = abs(reloc_val);
754 rel_mask_for_group(r_type, &reloc_val);
756 if (abs(reloc_val) >= 0x1000)
757 DLIF_error(DLET_RELOC, "relocation overflow!\n");
759 Lval = reloc_val & 0xFF;
761 *((uint32_t*) rel_field_ptr) &= 0xFF7FFF00;
762 *((uint32_t*) rel_field_ptr) |= (Uval << 23);
763 *((uint32_t*) rel_field_ptr) |= Lval;
764 }
765 break;
767 /*--------------------------------------------------------------------*/
768 /* THUMB2 ALU RELOCATION. This is a big block of code, most of which */
769 /* was taken from the linker. The problem is that there are a lot of */
770 /* special formats. */
771 /*--------------------------------------------------------------------*/
772 case R_ARM_THM_ALU_PREL_11_0:
773 {
774 /*----------------------------------------------------------------*/
775 /* THUMB2 ADR.W */
776 /* */
777 /* Encode the immediate value as specified in section 4.2 of the */
778 /* Thumb2 supplement: "Immediate constants in data-processing */
779 /* instructions" */
780 /*----------------------------------------------------------------*/
781 uint16_t* rel_field_16_ptr = (uint16_t*) rel_field_ptr;
782 uint16_t imm12;
783 uint8_t bits_7_0, bits_15_8, bits_23_16, bits_31_24, Ival,
784 imm3, imm8;
786 /*----------------------------------------------------------------*/
787 /* Convert to ADD/SUB depending on the sign. */
788 /* Clear out the 'i' bit while clearing the ADD/SUB bits */
789 /* If SUB, set bits 7 and 5 to 1, else should be 0 */
790 /*----------------------------------------------------------------*/
791 *rel_field_16_ptr &= 0xFB5F;
792 if (reloc_val < 0)
793 *rel_field_16_ptr |= 0x00A0;
795 reloc_val = abs(reloc_val);
797 /*----------------------------------------------------------------*/
798 /* Extract out bits after we take the absolute value. */
799 /*----------------------------------------------------------------*/
800 bits_7_0 = (reloc_val) & 0xFF;
801 bits_15_8 = (reloc_val >> 8) & 0xFF;
802 bits_23_16 = (reloc_val >> 16) & 0xFF;
803 bits_31_24 = (reloc_val >> 24) & 0xFF;
805 /*----------------------------------------------------------------*/
806 /* Does the value match the pattern 0x00XY00XY? */
807 /*----------------------------------------------------------------*/
808 if (bits_23_16 == bits_7_0 && bits_31_24 == 0 && bits_15_8 == 0)
809 imm12 = (0x1 << 8) | bits_7_0;
811 /*----------------------------------------------------------------*/
812 /* Does the value match the pattern 0xXY00XY00? */
813 /*----------------------------------------------------------------*/
814 else if (bits_31_24 == bits_15_8 && bits_23_16 == 0 && bits_7_0 == 0)
815 imm12 = (0x2 << 8) | bits_7_0;
817 /*-----------------------------------------------------------------*/
818 /* Does the value match the pattern 0xXYXYXYXY? */
819 /*-----------------------------------------------------------------*/
820 else if (bits_31_24 == bits_23_16 && bits_31_24 == bits_15_8 &&
821 bits_31_24 == bits_7_0)
822 imm12 = (0x3 << 8) | bits_7_0;
824 /*-----------------------------------------------------------------*/
825 /* Finally, check to see if we can encode this immediate as an */
826 /* 8-bit shifted value. */
827 /*-----------------------------------------------------------------*/
828 else if (reloc_val >= 0 && reloc_val <= 255)
829 imm12 = reloc_val;
830 else
831 {
832 /*-------------------------------------------------------------*/
833 /* Calculate the mask for this immediate, then find the */
834 /* appropriate rotate and 8-bit immediate value */
835 /* (Rval and Sval). */
836 /*-------------------------------------------------------------*/
837 uint32_t mask_offset = rel_alu_mask_offset(
838 (uint32_t)reloc_val, 1);
839 uint8_t Rval = 32 - mask_offset;
840 uint8_t Sval = (reloc_val >> mask_offset) & 0x7F;
842 imm12 = (Rval << 7) | Sval;
844 /*-------------------------------------------------------------*/
845 /* If overflow occurred, then finding an 8-bit shiftable value */
846 /* failed. */
847 /*-------------------------------------------------------------*/
848 if (reloc_val & ~(0xFF << mask_offset))
849 DLIF_error(DLET_RELOC, "relocation overflow!\n");
850 }
852 Ival = (imm12 >> 11) & 0x1;
853 imm3 = (imm12 >> 8) & 0x7;
854 imm8 = (imm12) & 0xFF;
856 *rel_field_16_ptr |= Ival << 10;
857 rel_field_16_ptr++;
858 *rel_field_16_ptr |= imm3 << 12;
859 *rel_field_16_ptr |= imm8;
860 break;
861 }
863 default:
864 DLIF_error(DLET_RELOC,
865 "write_reloc_r called with invalid relocation type\n");
866 }
868 }
870 /*****************************************************************************/
871 /* PACK_RESULT() - Pack the result of a relocation calculation for storage */
872 /* in the relocation field. */
873 /*****************************************************************************/
874 static int32_t pack_result(int32_t unpacked_result, int r_type)
875 {
876 switch (r_type)
877 {
878 case R_ARM_ABS32:
879 case R_ARM_REL32:
880 case R_ARM_ABS16:
881 case R_ARM_ABS8:
882 case R_ARM_PREL31:
883 case R_ARM_MOVW_ABS_NC:
884 case R_ARM_MOVW_PREL_NC:
885 case R_ARM_THM_MOVW_ABS_NC:
886 case R_ARM_THM_MOVW_PREL_NC:
887 case R_ARM_ABS32_NOI:
888 case R_ARM_REL32_NOI:
889 case R_ARM_ABS12:
890 case R_ARM_ALU_PC_G0_NC:
891 case R_ARM_ALU_PC_G0:
892 case R_ARM_ALU_PC_G1_NC:
893 case R_ARM_ALU_PC_G1:
894 case R_ARM_ALU_PC_G2:
895 case R_ARM_LDR_PC_G0:
896 case R_ARM_LDR_PC_G1:
897 case R_ARM_LDR_PC_G2:
898 case R_ARM_LDRS_PC_G0:
899 case R_ARM_LDRS_PC_G1:
900 case R_ARM_LDRS_PC_G2:
901 case R_ARM_LDC_PC_G0:
902 case R_ARM_LDC_PC_G1:
903 case R_ARM_LDC_PC_G2:
904 case R_ARM_THM_PC12:
905 case R_ARM_THM_ALU_PREL_11_0:
906 return unpacked_result;
908 case R_ARM_PC24:
909 case R_ARM_CALL:
910 case R_ARM_PLT32:
911 case R_ARM_THM_CALL:
912 case R_ARM_THM_JUMP24:
913 case R_ARM_THM_JUMP11:
914 case R_ARM_THM_JUMP8:
915 case R_ARM_THM_JUMP6:
916 case R_ARM_THM_JUMP19:
917 return unpacked_result >> 1;
919 case R_ARM_JUMP24:
920 case R_ARM_THM_ABS5:
921 case R_ARM_THM_PC8:
922 return unpacked_result >> 2;
924 case R_ARM_MOVT_ABS:
925 case R_ARM_MOVT_PREL:
926 case R_ARM_THM_MOVT_ABS:
927 case R_ARM_THM_MOVT_PREL:
928 return unpacked_result >> 16;
930 default:
931 DLIF_error(DLET_RELOC,
932 "pack_result called with invalid relocation type!\n");
933 return 0;
934 }
936 }
938 /*****************************************************************************/
939 /* MASK_RESULT() - Mask the result of a relocation calculation so that it */
940 /* fits the size of the relocation type's field. */
941 /*****************************************************************************/
942 static int32_t mask_result(int32_t unmasked_result, int r_type)
943 {
944 switch (r_type)
945 {
946 case R_ARM_ABS8:
947 case R_ARM_THM_JUMP8:
948 case R_ARM_THM_PC8:
949 return unmasked_result & 0xFF;
951 case R_ARM_ABS16:
952 case R_ARM_MOVW_ABS_NC:
953 case R_ARM_MOVT_ABS:
954 case R_ARM_MOVW_PREL_NC:
955 case R_ARM_MOVT_PREL:
956 case R_ARM_THM_MOVW_ABS_NC:
957 case R_ARM_THM_MOVT_ABS:
958 case R_ARM_THM_MOVW_PREL_NC:
959 case R_ARM_THM_MOVT_PREL:
960 return unmasked_result & 0xFFFF;
962 case R_ARM_ABS32:
963 case R_ARM_REL32:
964 case R_ARM_ABS32_NOI:
965 case R_ARM_REL32_NOI:
966 case R_ARM_ABS12:
967 case R_ARM_ALU_PC_G0_NC:
968 case R_ARM_ALU_PC_G0:
969 case R_ARM_ALU_PC_G1_NC:
970 case R_ARM_ALU_PC_G1:
971 case R_ARM_ALU_PC_G2:
972 case R_ARM_LDR_PC_G0:
973 case R_ARM_LDR_PC_G1:
974 case R_ARM_LDR_PC_G2:
975 case R_ARM_LDRS_PC_G0:
976 case R_ARM_LDRS_PC_G1:
977 case R_ARM_LDRS_PC_G2:
978 case R_ARM_LDC_PC_G0:
979 case R_ARM_LDC_PC_G1:
980 case R_ARM_LDC_PC_G2:
981 case R_ARM_THM_PC12:
982 case R_ARM_THM_ALU_PREL_11_0:
983 return unmasked_result;
985 case R_ARM_PREL31:
986 return unmasked_result & 0x7FFFFFFF;
988 case R_ARM_CALL:
989 case R_ARM_PC24:
990 case R_ARM_THM_CALL:
991 case R_ARM_THM_JUMP24:
992 return unmasked_result & 0x01FFFFFF;
994 case R_ARM_JUMP24:
995 return unmasked_result & 0x00FFFFFF;
997 case R_ARM_THM_JUMP11:
998 return unmasked_result & 0x7FF;
1000 case R_ARM_THM_ABS5:
1001 return unmasked_result & 0x1F;
1003 case R_ARM_THM_JUMP6:
1004 return unmasked_result & 0x3F;
1006 case R_ARM_THM_JUMP19:
1007 return unmasked_result & 0xFFFFF;
1009 default:
1010 DLIF_error(DLET_RELOC,
1011 "mask_result invalid relocation type!\n");
1012 return 0;
1013 }
1015 }
1018 /*****************************************************************************/
1019 /* OVERFLOW() - Check relocation value against the range associated with a */
1020 /* given relocation type field size and signedness. */
1021 /*****************************************************************************/
1022 static BOOL rel_overflow(ARM_RELOC_TYPE r_type, int32_t reloc_value)
1023 {
1024 switch(r_type)
1025 {
1026 uint32_t sbits;
1027 case R_ARM_JUMP24:
1028 case R_ARM_CALL:
1029 case R_ARM_PC24:
1030 {
1031 sbits = reloc_value >> 25;
1032 return (sbits != 0 && sbits != -1UL);
1033 }
1034 case R_ARM_THM_CALL:
1035 case R_ARM_THM_JUMP24:
1036 {
1037 sbits = reloc_value >> 24;
1038 return (sbits != 0 && sbits != -1UL);
1039 }
1040 case R_ARM_THM_JUMP19:
1041 {
1042 sbits = reloc_value >> 20;
1043 return (sbits != 0 && sbits != -1UL);
1044 }
1045 case R_ARM_ABS12:
1046 case R_ARM_THM_PC12:
1047 {
1048 return abs(reloc_value) >= 0x1000;
1049 }
1050 case R_ARM_PREL31:
1051 {
1052 sbits = reloc_value >> 30;
1053 return (sbits != 0 && sbits != -1UL);
1054 }
1056 case R_ARM_ABS16:
1057 {
1058 return ((reloc_value > 65535) ||
1059 (reloc_value < -32768));
1060 }
1061 case R_ARM_ABS8:
1062 {
1063 return ((reloc_value > 255) ||
1064 (reloc_value < -128));
1065 }
1067 default:
1068 return FALSE;
1069 }
1070 }
1072 #if LOADER_DEBUG && LOADER_PROFILE
1073 extern int DLREL_relocations;
1074 extern time_t DLREL_total_reloc_time;
1075 #endif
1077 /*****************************************************************************/
1078 /* RELOC_DO() - Process a single relocation entry. */
1079 /*****************************************************************************/
1080 static void reloc_do(ARM_RELOC_TYPE r_type, uint8_t* address,
1081 uint32_t addend, uint32_t symval, uint32_t pc,
1082 uint32_t base_pointer)
1083 {
1084 int32_t reloc_value = 0;
1086 #if LOADER_DEBUG && LOADER_PROFILE
1087 /*------------------------------------------------------------------------*/
1088 /* In debug mode, keep a count of the number of relocations processed. */
1089 /* In profile mode, start the clock on a given relocation. */
1090 /*------------------------------------------------------------------------*/
1091 int start_time = 0;
1092 if (debugging_on || profiling_on)
1093 {
1094 DLREL_relocations++;
1095 if (profiling_on) start_time = clock();
1096 }
1097 #endif
1099 /*------------------------------------------------------------------------*/
1100 /* Calculate the relocation value according to the rules associated with */
1101 /* the given relocation type. */
1102 /*------------------------------------------------------------------------*/
1103 switch(r_type)
1104 {
1105 case R_ARM_NONE:
1106 reloc_value = addend;
1107 break;
1109 /*--------------------------------------------------------------------*/
1110 /* S + A */
1111 /*--------------------------------------------------------------------*/
1112 case R_ARM_ABS16:
1113 case R_ARM_ABS12:
1114 case R_ARM_THM_ABS5:
1115 case R_ARM_ABS8:
1116 case R_ARM_MOVT_ABS:
1117 case R_ARM_THM_MOVT_ABS:
1118 case R_ARM_ABS32_NOI:
1119 case R_ARM_PLT32_ABS:
1120 reloc_value = OPND_S(symval) + addend;
1121 break;
1123 /*--------------------------------------------------------------------*/
1124 /* (S + A) | T */
1125 /*--------------------------------------------------------------------*/
1126 case R_ARM_ABS32:
1127 case R_ARM_MOVW_ABS_NC:
1128 case R_ARM_THM_MOVW_ABS_NC:
1129 reloc_value = (OPND_S(symval) + addend) | OPND_T(symval);
1130 break;
1132 /*--------------------------------------------------------------------*/
1133 /* (S + A) - P */
1134 /*--------------------------------------------------------------------*/
1135 case R_ARM_LDR_PC_G0:
1136 case R_ARM_LDR_PC_G1:
1137 case R_ARM_LDR_PC_G2:
1138 case R_ARM_MOVT_PREL:
1139 case R_ARM_THM_MOVT_PREL:
1140 case R_ARM_REL32_NOI:
1141 case R_ARM_THM_JUMP6:
1142 case R_ARM_THM_JUMP11:
1143 case R_ARM_THM_JUMP8:
1144 case R_ARM_LDRS_PC_G0:
1145 case R_ARM_LDRS_PC_G1:
1146 case R_ARM_LDRS_PC_G2:
1147 case R_ARM_LDC_PC_G0:
1148 case R_ARM_LDC_PC_G1:
1149 case R_ARM_LDC_PC_G2:
1150 reloc_value = (OPND_S(symval) + addend) - pc;
1151 break;
1153 /*--------------------------------------------------------------------*/
1154 /* (S + A) - Pa */
1155 /*--------------------------------------------------------------------*/
1156 case R_ARM_THM_PC8:
1157 case R_ARM_THM_PC12:
1158 reloc_value = (OPND_S(symval) + addend) - (pc & 0xFFFFFFFC);
1159 break;
1161 /*--------------------------------------------------------------------*/
1162 /* ((S + A) | T) - P */
1163 /*--------------------------------------------------------------------*/
1164 case R_ARM_REL32:
1165 case R_ARM_PC24:
1166 case R_ARM_THM_CALL:
1167 case R_ARM_PLT32:
1168 case R_ARM_CALL:
1169 case R_ARM_JUMP24:
1170 case R_ARM_THM_JUMP24:
1171 case R_ARM_PREL31:
1172 case R_ARM_MOVW_PREL_NC:
1173 case R_ARM_THM_MOVW_PREL_NC:
1174 case R_ARM_THM_JUMP19:
1175 case R_ARM_THM_ALU_PREL_11_0:
1176 case R_ARM_ALU_PC_G0_NC:
1177 case R_ARM_ALU_PC_G0:
1178 case R_ARM_ALU_PC_G1_NC:
1179 case R_ARM_ALU_PC_G1:
1180 case R_ARM_ALU_PC_G2:
1181 reloc_value = ((OPND_S(symval) + addend) | OPND_T(symval)) - pc;
1182 break;
1184 /*---------------------------------------------------------------------*/
1185 /* Unrecognized relocation type. */
1186 /*---------------------------------------------------------------------*/
1187 default:
1188 DLIF_error(DLET_RELOC,"invalid relocation type!\n");
1189 break;
1191 }
1193 if (rel_overflow(r_type, reloc_value))
1194 DLIF_error(DLET_RELOC, "relocation overflow!\n");
1196 /*------------------------------------------------------------------------*/
1197 /* Move relocation value to appropriate offset for relocation field's */
1198 /* location. */
1199 /*------------------------------------------------------------------------*/
1200 reloc_value = pack_result(reloc_value, r_type);
1202 /*------------------------------------------------------------------------*/
1203 /* Mask packed result to the size of the relocation field. */
1204 /*------------------------------------------------------------------------*/
1205 reloc_value = mask_result(reloc_value, r_type);
1207 /*------------------------------------------------------------------------*/
1208 /* Write the relocated 4-byte packet back to the segment buffer. */
1209 /*------------------------------------------------------------------------*/
1210 write_reloc_r(address, r_type, reloc_value, symval);
1212 #if LOADER_DEBUG && LOADER_PROFILE
1213 /*------------------------------------------------------------------------*/
1214 /* In profile mode, add elapsed time for this relocation to total time */
1215 /* spent doing relocations. */
1216 /*------------------------------------------------------------------------*/
1217 if (profiling_on)
1218 DLREL_total_reloc_time += (clock() - start_time);
1219 if (debugging_on)
1220 DLIF_trace("reloc_value = 0x%x\n", reloc_value);
1221 #endif
1222 }
1224 /*****************************************************************************/
1225 /* REL_UNPACK_ADDEND() - Unpacks the addend from the relocation field */
1226 /*****************************************************************************/
1227 static void rel_unpack_addend(ARM_RELOC_TYPE r_type,
1228 uint8_t* address,
1229 uint32_t* addend)
1230 {
1231 switch (r_type)
1232 {
1233 case R_ARM_ABS32:
1234 case R_ARM_REL32:
1235 case R_ARM_ABS32_NOI:
1236 case R_ARM_REL32_NOI:
1237 {
1238 *addend = *((uint32_t*)address);
1239 }
1240 break;
1242 case R_ARM_ABS16:
1243 {
1244 *addend = *((uint16_t*)address);
1245 *addend = SIGN_EXTEND(*addend, 16);
1246 }
1247 break;
1249 case R_ARM_ABS8:
1250 {
1251 *addend = *address;
1252 *addend = SIGN_EXTEND(*addend, 8);
1253 }
1254 break;
1256 case R_ARM_CALL:
1257 case R_ARM_PC24:
1258 case R_ARM_PLT32:
1259 case R_ARM_JUMP24:
1260 {
1261 uint32_t rel_field = *((uint32_t*)address);
1262 uint32_t imm24;
1263 uint8_t Hval;
1264 if (IS_BLX(rel_field))
1265 Hval = EXTRACT(rel_field, 24, 1);
1266 else
1267 Hval = 0x0;
1269 imm24 = EXTRACT(rel_field, 0, 24);
1270 *addend = (((imm24 << 1) + Hval) << 1);
1271 SIGN_EXTEND(*addend, 26);
1272 }
1273 break;
1275 case R_ARM_THM_JUMP11:
1276 {
1277 *addend = EXTRACT(*((uint16_t*)address), 0, 11);
1278 *addend = *addend << 1;
1279 SIGN_EXTEND(*addend, 12);
1280 break;
1281 }
1283 case R_ARM_THM_JUMP8:
1284 {
1285 *addend = EXTRACT(*((uint16_t*)address), 0, 8);
1286 *addend = *addend << 1;
1287 SIGN_EXTEND(*addend, 9);
1288 break;
1289 }
1291 case R_ARM_THM_CALL:
1292 case R_ARM_THM_JUMP24:
1293 {
1294 uint16_t* rel_field_ptr = (uint16_t *) address;
1296 uint8_t Sval;
1297 uint16_t imm10;
1298 uint8_t I1;
1299 uint8_t I2;
1300 uint16_t imm11;
1302 Sval = EXTRACT(*rel_field_ptr, 10, 1);
1303 imm10 = EXTRACT(*rel_field_ptr, 0, 10);
1304 rel_field_ptr++;
1305 I1 = !(EXTRACT(*rel_field_ptr, 13, 1) ^ Sval);
1306 I2 = !(EXTRACT(*rel_field_ptr, 11, 1) ^ Sval);
1307 imm11 = EXTRACT(*rel_field_ptr, 0, 11);
1309 *addend = (Sval << 23) | (I1 << 22) | (I2 << 21) |
1310 (imm10 << 11) | imm11;
1311 *addend = *addend << 1;
1312 SIGN_EXTEND(*addend, 25);
1313 break;
1314 }
1316 case R_ARM_THM_JUMP19:
1317 {
1318 uint16_t* rel_field_ptr = (uint16_t *) address;
1320 uint8_t Sval;
1321 uint8_t imm6;
1322 uint8_t J1;
1323 uint8_t J2;
1324 uint16_t imm11;
1326 Sval = EXTRACT(*rel_field_ptr, 10, 1);
1327 imm6 = EXTRACT(*rel_field_ptr, 0, 6);
1328 rel_field_ptr++;
1329 J1 = EXTRACT(*rel_field_ptr, 13, 1);
1330 J2 = EXTRACT(*rel_field_ptr, 11, 1);
1331 imm11 = EXTRACT(*rel_field_ptr, 0, 11);
1333 *addend = (Sval << 19) | (J2 << 18) | (J1 << 17) |
1334 (imm6 << 11) | imm11;
1335 *addend = *addend << 1;
1336 SIGN_EXTEND(*addend, 21);
1337 }
1338 break;
1340 case R_ARM_LDR_PC_G0:
1341 case R_ARM_LDR_PC_G1:
1342 case R_ARM_LDR_PC_G2:
1343 case R_ARM_ABS12:
1344 {
1345 uint8_t Uval;
1346 uint16_t imm12;
1348 uint32_t* rel_field_ptr = (uint32_t*) address;
1350 Uval = EXTRACT(*rel_field_ptr, 23, 1);
1351 imm12 = EXTRACT(*rel_field_ptr, 0, 12);
1353 *addend = (Uval == 1) ? imm12 : -((int32_t)(imm12));
1354 }
1355 break;
1357 case R_ARM_THM_PC12:
1358 {
1359 uint8_t Uval;
1360 uint16_t imm12;
1361 uint16_t* rel_field_ptr = (uint16_t*) address;
1363 Uval = EXTRACT(*rel_field_ptr, 7, 1);
1364 rel_field_ptr++;
1365 imm12 = EXTRACT(*rel_field_ptr, 0, 12);
1367 *addend = (Uval == 1) ? imm12 : -((int32_t)imm12);
1368 break;
1369 }
1371 case R_ARM_LDRS_PC_G0:
1372 case R_ARM_LDRS_PC_G1:
1373 case R_ARM_LDRS_PC_G2:
1374 {
1375 uint8_t Uval;
1376 uint8_t imm4H;
1377 uint8_t imm4L;
1378 uint32_t* rel_field_ptr = (uint32_t*) address;
1380 Uval = EXTRACT(*rel_field_ptr, 23, 1);
1381 imm4H = EXTRACT(*rel_field_ptr, 8, 4);
1382 imm4L = EXTRACT(*rel_field_ptr, 0, 4);
1384 *addend = (imm4H << 4) | imm4L;
1385 if (Uval == 0) *addend = -(*addend);
1386 }
1387 break;
1389 case R_ARM_LDC_PC_G0:
1390 case R_ARM_LDC_PC_G1:
1391 case R_ARM_LDC_PC_G2:
1392 {
1393 uint8_t Uval;
1394 uint16_t imm8;
1395 uint32_t* rel_field_ptr = (uint32_t*) address;
1397 Uval = EXTRACT(*rel_field_ptr, 23, 1);
1398 imm8 = EXTRACT(*rel_field_ptr, 0, 8);
1400 *addend = (Uval == 1) ? imm8 : -((int32_t)imm8);
1401 }
1402 break;
1404 case R_ARM_ALU_PC_G0_NC:
1405 case R_ARM_ALU_PC_G0:
1406 case R_ARM_ALU_PC_G1_NC:
1407 case R_ARM_ALU_PC_G1:
1408 case R_ARM_ALU_PC_G2:
1409 {
1410 uint8_t Rval;
1411 uint8_t Ival;
1412 uint32_t rel_field = *((uint32_t*)address);
1414 Rval = EXTRACT(rel_field, 8, 4);
1415 Ival = EXTRACT(rel_field, 0, 8);
1417 *addend = (Ival >> Rval) | (Ival << (32 - Rval));
1419 if (EXTRACT(rel_field, 22, 2) == 1)
1420 *addend = -(*addend);
1421 }
1422 break;
1424 case R_ARM_MOVW_ABS_NC:
1425 case R_ARM_MOVT_ABS:
1426 case R_ARM_MOVW_PREL_NC:
1427 case R_ARM_MOVT_PREL:
1428 {
1429 uint8_t Ival;
1430 uint16_t Jval;
1431 uint32_t rel_field = *((uint32_t*)address);
1432 Ival = EXTRACT(rel_field, 16, 4);
1433 Jval = EXTRACT(rel_field, 0, 12);
1435 *addend = (Ival << 12) | Jval;
1436 SIGN_EXTEND(*addend, 16);
1437 }
1438 break;
1440 case R_ARM_THM_MOVW_ABS_NC:
1441 case R_ARM_THM_MOVT_ABS:
1442 case R_ARM_THM_MOVW_PREL_NC:
1443 case R_ARM_THM_MOVT_PREL:
1444 {
1445 uint8_t Ival;
1446 uint8_t Jval;
1447 uint8_t Kval;
1448 uint8_t Lval;
1450 uint16_t* rel_field_ptr = (uint16_t*)address;
1451 uint16_t rel_field = *rel_field_ptr;
1453 Ival = EXTRACT(rel_field, 0, 4);
1454 Jval = EXTRACT(rel_field, 10, 1);
1456 rel_field = *(rel_field_ptr + 1);
1457 Kval = EXTRACT(rel_field, 12, 3);
1458 Lval = EXTRACT(rel_field, 0, 8);
1460 *addend = (Ival << 12) | (Jval << 11) | (Kval << 8) | Lval;
1461 SIGN_EXTEND(*addend, 16);
1462 }
1463 break;
1465 case R_ARM_THM_ALU_PREL_11_0:
1466 {
1467 uint8_t Ival;
1468 uint8_t Jval;
1469 uint8_t Kval;
1470 uint16_t imm12;
1471 uint16_t* rel_field_ptr = (uint16_t*)address;
1472 uint16_t rel_field = *rel_field_ptr;
1473 uint8_t bits_11_10;
1475 Ival = EXTRACT(rel_field, 12, 3);
1477 rel_field = *(rel_field_ptr + 1);
1478 Jval = EXTRACT(rel_field, 12, 3);
1479 Kval = EXTRACT(rel_field, 0 , 8);
1481 imm12 = (Ival << 11) | (Jval << 8) | Kval;
1483 /*---------------------------------------------------------------*/
1484 /* Now that we've unpacked the immediate value, we need to */
1485 /* decode it according to section 4.2 in the Thumb2 supplement: */
1486 /* "Immediate constants in data-processing instructions" */
1487 /*---------------------------------------------------------------*/
1488 bits_11_10 = (imm12 >> 10) & 0x3;
1490 if (bits_11_10 == 0x0)
1491 {
1492 uint8_t bits_9_8 = (imm12 >> 8) & 0x3;
1493 uint8_t bits_7_0 = (imm12) & 0xFF;
1495 switch (bits_9_8)
1496 {
1497 case 0x0: *addend = bits_7_0;
1498 break;
1499 case 0x1: *addend = (bits_7_0 << 16) | (bits_7_0);
1500 break;
1501 case 0x2: *addend = (bits_7_0 << 24) | (bits_7_0 << 8);
1502 break;
1503 case 0x3: *addend= (bits_7_0 << 24) | (bits_7_0 << 16) |
1504 (bits_7_0 << 8) | (bits_7_0);
1505 break;
1506 }
1507 }
1508 else
1509 {
1510 uint8_t bits_6_0 = (imm12) & 0x7F;
1511 uint8_t bits_11_7 = (imm12 >> 7) & 0x1F;
1513 uint8_t byte = 0x80 | bits_6_0;
1514 *addend = (byte >> bits_11_7) | (byte << (32 - bits_11_7));
1515 }
1517 rel_field = *rel_field_ptr;
1519 if (EXTRACT(rel_field, 7, 1) == 1 &&
1520 EXTRACT(rel_field, 5, 1) == 1)
1521 *addend = -(*addend);
1522 }
1523 break;
1525 case R_ARM_THM_JUMP6:
1526 {
1527 uint8_t Ival;
1528 uint8_t Jval;
1530 uint16_t rel_field = *((uint16_t*)address);
1532 Ival = EXTRACT(rel_field, 9, 1);
1533 Jval = EXTRACT(rel_field, 3, 5);
1535 *addend = ((Ival << 5) | Jval) << 1;
1536 *addend = ((*addend + 4) & 0x7F) - 4;
1538 }
1539 break;
1541 case R_ARM_THM_ABS5:
1542 {
1543 uint16_t rel_field = *((uint16_t*)address);
1544 *addend = EXTRACT(rel_field, 6, 5);
1545 *addend = *addend << 2;
1546 break;
1547 }
1549 case R_ARM_THM_PC8:
1550 {
1551 uint16_t rel_field = *((uint16_t*)address);
1552 *addend = EXTRACT(rel_field, 0, 8);
1553 *addend = *addend << 2;
1554 *addend = ((*addend + 4) & 0x3FF) - 4;
1556 break;
1557 }
1559 case R_ARM_PREL31:
1560 {
1561 uint32_t rel_field = *((uint32_t*)address);
1562 *addend = EXTRACT(rel_field, 0, 31);
1563 SIGN_EXTEND(*addend, 31);
1564 break;
1565 }
1567 default:
1568 DLIF_error(DLET_RELOC,
1569 "ERROR: Cannot unpack addend for relocation type %d\n",
1570 r_type);
1571 }
1572 }
1574 /*****************************************************************************/
1575 /* PROCESS_REL_TABLE() - Process REL type relocation table. */
1576 /*****************************************************************************/
1577 static BOOL process_rel_table(DLOAD_HANDLE handle,
1578 DLIMP_Loaded_Segment* seg,
1579 struct Elf32_Rel* rel_table,
1580 uint32_t relnum,
1581 int32_t *start_rid,
1582 DLIMP_Dynamic_Module* dyn_module)
1583 {
1584 Elf32_Addr seg_start_addr = seg->input_vaddr;
1585 Elf32_Addr seg_end_addr = seg_start_addr + seg->phdr.p_memsz;
1586 BOOL found = FALSE;
1587 int32_t rid = *start_rid;
1589 if (rid >= relnum) rid = 0;
1591 for ( ; rid < relnum; rid++)
1592 {
1593 int32_t r_symid = ELF32_R_SYM(rel_table[rid].r_info);
1595 /*---------------------------------------------------------------*/
1596 /* If the relocation offset falls within the segment, process it */
1597 /*---------------------------------------------------------------*/
1598 if (rel_table[rid].r_offset >= seg_start_addr &&
1599 rel_table[rid].r_offset < seg_end_addr)
1600 {
1601 Elf32_Addr r_symval;
1602 ARM_RELOC_TYPE r_type =
1603 (ARM_RELOC_TYPE) ELF32_R_TYPE(rel_table[rid].r_info);
1604 int32_t r_symid = ELF32_R_SYM(rel_table[rid].r_info);
1605 uint8_t* reloc_address;
1606 uint32_t offset;
1607 uint32_t pc;
1608 uint32_t addend = 0;
1609 BOOL change_endian;
1611 found = TRUE;
1613 /*---------------------------------------------------------*/
1614 /* If symbol definition is not found don't do the */
1615 /* relocation. An error is generated by the lookup */
1616 /* function. */
1617 /*---------------------------------------------------------*/
1618 if (!DLSYM_canonical_lookup(handle, r_symid, dyn_module, &r_symval))
1619 continue;
1621 offset = rel_table[rid].r_offset - seg->input_vaddr;
1622 pc = seg->phdr.p_vaddr + offset;
1623 reloc_address = (uint8_t*)seg->host_address + offset;
1625 change_endian = rel_swap_endian(dyn_module, r_type);
1626 if (change_endian)
1627 rel_change_endian(r_type, reloc_address);
1629 rel_unpack_addend(r_type, reloc_address, &addend);
1631 #if LOADER_DEBUG && LOADER_PROFILE
1632 if (debugging_on)
1633 {
1634 char *r_symname = (char*) dyn_module->symtab[r_symid].st_name;
1635 DLIF_trace("r_type=%d, "
1636 "pc=0x%x, "
1637 "addend=0x%x, "
1638 "symnm=%s, "
1639 "symval=0x%x\n",
1640 r_type,
1641 pc,
1642 addend,
1643 r_symname,
1644 r_symval);
1645 }
1646 #endif
1647 /*----------------------------------------------------------*/
1648 /* Perform actual relocation. This is a really wide */
1649 /* function interface and could do with some encapsulation. */
1650 /*----------------------------------------------------------*/
1651 reloc_do(r_type,
1652 reloc_address,
1653 addend,
1654 r_symval,
1655 pc,
1656 0 /* static base, not yet supported */);
1659 if (change_endian)
1660 rel_change_endian(r_type, reloc_address);
1662 }
1663 else if (found)
1664 break;
1665 }
1667 *start_rid = rid;
1668 return found;
1669 }
1671 /*****************************************************************************/
1672 /* PROCESS_RELA_TABLE() */
1673 /* */
1674 /* Process a table of Elf32_Rela type relocations. */
1675 /* */
1676 /*****************************************************************************/
1677 static BOOL process_rela_table(DLOAD_HANDLE handle,
1678 DLIMP_Loaded_Segment* seg,
1679 struct Elf32_Rela* rela_table,
1680 uint32_t relanum,
1681 int32_t* start_rid,
1682 DLIMP_Dynamic_Module* dyn_module)
1683 {
1684 Elf32_Addr seg_start_addr = seg->input_vaddr;
1685 Elf32_Addr seg_end_addr = seg_start_addr + seg->phdr.p_memsz;
1686 BOOL found = FALSE;
1687 int32_t rid = *start_rid;
1689 if (rid >= relanum) rid = 0;
1691 for ( ; rid < relanum; rid++)
1692 {
1693 /*---------------------------------------------------------------*/
1694 /* If the relocation offset falls within the segment, process it */
1695 /*---------------------------------------------------------------*/
1696 if (rela_table[rid].r_offset >= seg_start_addr &&
1697 rela_table[rid].r_offset < seg_end_addr)
1698 {
1699 Elf32_Addr r_symval;
1700 ARM_RELOC_TYPE r_type =
1701 (ARM_RELOC_TYPE)ELF32_R_TYPE(rela_table[rid].r_info);
1702 int32_t r_symid = ELF32_R_SYM(rela_table[rid].r_info);
1703 uint8_t* reloc_address;
1704 uint32_t offset;
1705 uint32_t pc;
1706 uint32_t addend;
1707 BOOL change_endian;
1709 found = TRUE;
1711 /*---------------------------------------------------------*/
1712 /* If symbol definition is not found don't do the */
1713 /* relocation. An error is generated by the lookup */
1714 /* function. */
1715 /*---------------------------------------------------------*/
1716 if (!DLSYM_canonical_lookup(handle, r_symid, dyn_module, &r_symval))
1717 continue;
1719 offset = rela_table[rid].r_offset - seg->input_vaddr;
1720 pc = seg->phdr.p_vaddr + offset;
1721 reloc_address = (uint8_t*)seg->host_address + offset;
1722 addend = rela_table[rid].r_addend;
1724 change_endian = rel_swap_endian(dyn_module, r_type);
1725 if (change_endian)
1726 rel_change_endian(r_type, reloc_address);
1728 #if LOADER_DEBUG && LOADER_PROFILE
1729 if (debugging_on)
1730 {
1731 char *r_symname = (char*) dyn_module->symtab[r_symid].st_name;
1732 DLIF_trace("r_type=%d, "
1733 "pc=0x%x, "
1734 "addend=0x%x, "
1735 "symnm=%s, "
1736 "symval=0x%x\n",
1737 r_type,
1738 pc,
1739 addend,
1740 r_symname,
1741 r_symval);
1742 }
1743 #endif
1745 /*----------------------------------------------------------*/
1746 /* Perform actual relocation. This is a really wide */
1747 /* function interface and could do with some encapsulation. */
1748 /*----------------------------------------------------------*/
1750 reloc_do((ARM_RELOC_TYPE)ELF32_R_TYPE(rela_table[rid].r_info),
1751 reloc_address,
1752 addend,
1753 r_symval,
1754 pc,
1755 0);
1758 if (change_endian)
1759 rel_change_endian(r_type, reloc_address);
1760 }
1761 else if (found)
1762 break;
1763 }
1765 *start_rid = rid;
1766 return found;
1767 }
1769 /*****************************************************************************/
1770 /* READ_REL_TABLE() - */
1771 /* */
1772 /* Read in a REL type relocation table. This function allocates host */
1773 /* memory for the table. */
1774 /*****************************************************************************/
1775 static void read_rel_table(struct Elf32_Rel** rel_table,
1776 int32_t table_offset,
1777 uint32_t relnum, uint32_t relent,
1778 LOADER_FILE_DESC* elf_file,
1779 BOOL wrong_endian)
1780 {
1781 int i;
1783 if (relnum == 0) { *rel_table = NULL; return; }
1785 *rel_table = (struct Elf32_Rel*) DLIF_malloc(relnum*relent);
1786 if (NULL == *rel_table) {
1787 DLIF_error(DLET_MEMORY,"Failed to Allocate read_rel_table\n");
1788 return;
1789 }
1790 DLIF_fseek(elf_file, table_offset, LOADER_SEEK_SET);
1791 DLIF_fread(*rel_table, relnum, relent, elf_file);
1793 if (wrong_endian)
1794 for (i=0; i<relnum; i++)
1795 DLIMP_change_rel_endian(*rel_table + i);
1796 }
1798 /*****************************************************************************/
1799 /* READ_RELA_TABLE() - */
1800 /* */
1801 /* Read in a RELA type relocation table. This function allocates host */
1802 /* memory for the table. */
1803 /*****************************************************************************/
1804 static void read_rela_table(struct Elf32_Rela** rela_table,
1805 int32_t table_offset,
1806 uint32_t relanum, uint32_t relaent,
1807 LOADER_FILE_DESC* elf_file,
1808 BOOL wrong_endian)
1809 {
1810 int i;
1812 if (relanum == 0) { *rela_table = NULL; return; }
1814 *rela_table = DLIF_malloc(relanum*relaent);
1815 if (NULL == *rela_table) {
1816 DLIF_error(DLET_MEMORY,"Failed to Allocate read_rela_table\n");
1817 return;
1818 }
1819 DLIF_fseek(elf_file, table_offset, LOADER_SEEK_SET);
1820 DLIF_fread(*rela_table, relanum, relaent, elf_file);
1822 if (wrong_endian)
1823 for (i=0; i<relanum; i++)
1824 DLIMP_change_rela_endian(*rela_table + i);
1825 }
1827 /*****************************************************************************/
1828 /* PROCESS_GOT_RELOCS() - */
1829 /* */
1830 /* Process all GOT relocations. It is possible to have both REL and RELA */
1831 /* relocations in the same file, so we handle them both. */
1832 /*****************************************************************************/
1833 static void process_got_relocs(DLOAD_HANDLE handle,
1834 struct Elf32_Rel* rel_table, uint32_t relnum,
1835 struct Elf32_Rela* rela_table, uint32_t relanum,
1836 DLIMP_Dynamic_Module* dyn_module)
1837 {
1838 DLIMP_Loaded_Segment* seg =
1839 (DLIMP_Loaded_Segment*)(dyn_module->loaded_module->loaded_segments.buf);
1840 int seg_size = dyn_module->loaded_module->loaded_segments.size;
1841 int32_t rel_rid = 0;
1842 int32_t rela_rid = 0;
1843 int s;
1845 for (s=0; s<seg_size; s++)
1846 {
1847 /*---------------------------------------------------------------------*/
1848 /* Relocations into the BSS should not occur. */
1849 /*---------------------------------------------------------------------*/
1850 if(!seg[s].phdr.p_filesz) continue;
1852 #if LOADER_DEBUG && LOADER_PROFILE
1853 /*---------------------------------------------------------------------*/
1854 /* More details about the progress on this relocation entry. */
1855 /*---------------------------------------------------------------------*/
1856 if (debugging_on)
1857 {
1858 DLIF_trace("Reloc segment %d:\n", s);
1859 DLIF_trace("addr=0x%x, old_addr=0x%x, host=0x%x\n",
1860 seg[s].phdr.p_vaddr, seg[s].input_vaddr, seg[s].host_address);
1861 }
1862 #endif
1864 if (rela_table)
1865 process_rela_table(handle, (seg + s), rela_table, relanum, &rela_rid,
1866 dyn_module);
1868 if (rel_table)
1869 process_rel_table(handle, (seg + s), rel_table, relnum, &rel_rid,
1870 dyn_module);
1871 }
1872 }
1874 /*****************************************************************************/
1875 /* PROCESS_PLTGOT_RELOCS */
1876 /* */
1877 /* Proceses all PLTGOT relocation entries. The PLTGOT relocation table can */
1878 /* be either REL or RELA type. All PLTGOT relocations are guaranteed to */
1879 /* belong to the same segment. */
1880 /*****************************************************************************/
1881 static void process_pltgot_relocs(DLOAD_HANDLE handle,
1882 void* plt_reloc_table, int reltype,
1883 uint32_t pltnum,
1884 DLIMP_Dynamic_Module* dyn_module)
1885 {
1886 Elf32_Addr r_offset = (reltype == DT_REL) ?
1887 ((struct Elf32_Rel*) plt_reloc_table)->r_offset :
1888 ((struct Elf32_Rela*) plt_reloc_table)->r_offset;
1889 DLIMP_Loaded_Segment* seg =
1890 (DLIMP_Loaded_Segment*)(dyn_module->loaded_module->loaded_segments.buf);
1891 int seg_size = dyn_module->loaded_module->loaded_segments.size;
1892 int32_t plt_rid = 0;
1893 int s;
1895 /*------------------------------------------------------------------------*/
1896 /* For each segment s, check if the relocation falls within s. If so, */
1897 /* then all other relocations are guaranteed to fall with s. Process */
1898 /* all relocations and then return. */
1899 /*------------------------------------------------------------------------*/
1901 for (s=0; s<seg_size; s++)
1902 {
1903 Elf32_Addr seg_start_addr = seg[s].input_vaddr;
1904 Elf32_Addr seg_end_addr = seg_start_addr + seg[s].phdr.p_memsz;
1906 /*---------------------------------------------------------------------*/
1907 /* Relocations into the BSS should not occur. */
1908 /*------------------------------------------------------------------- */
1909 if(!seg[s].phdr.p_filesz) continue;
1911 if (r_offset >= seg_start_addr &&
1912 r_offset < seg_end_addr)
1913 {
1914 if (reltype == DT_REL)
1915 process_rel_table(handle, (seg + s),
1916 (struct Elf32_Rel*) plt_reloc_table,
1917 pltnum, &plt_rid,
1918 dyn_module);
1919 else
1920 process_rela_table(handle, (seg + s),
1921 (struct Elf32_Rela*) plt_reloc_table,
1922 pltnum, &plt_rid,
1923 dyn_module);
1925 break;
1926 }
1927 }
1928 }
1930 /*****************************************************************************/
1931 /* RELOCATE() - Perform RELA and REL type relocations for given ELF object */
1932 /* file that we are in the process of loading and relocating. */
1933 /*****************************************************************************/
1934 void DLREL_arm_relocate(DLOAD_HANDLE handle,
1935 LOADER_FILE_DESC* elf_file,
1936 DLIMP_Dynamic_Module* dyn_module)
1938 {
1939 struct Elf32_Dyn* dyn_nugget = dyn_module->dyntab;
1940 struct Elf32_Rela* rela_table = NULL;
1941 struct Elf32_Rel* rel_table = NULL;
1942 struct Elf32_Rela* rela_plt_table = NULL;
1943 struct Elf32_Rel* rel_plt_table = NULL;
1945 /*------------------------------------------------------------------------*/
1946 /* Read the size of the relocation table (DT_RELASZ) and the size per */
1947 /* relocation (DT_RELAENT) from the dynamic segment. */
1948 /*------------------------------------------------------------------------*/
1949 uint32_t relasz = DLIMP_get_first_dyntag(DT_RELASZ, dyn_nugget);
1950 uint32_t relaent = DLIMP_get_first_dyntag(DT_RELAENT, dyn_nugget);
1951 uint32_t relanum = 0;
1953 /*------------------------------------------------------------------------*/
1954 /* Read the size of the relocation table (DT_RELSZ) and the size per */
1955 /* relocation (DT_RELENT) from the dynamic segment. */
1956 /*------------------------------------------------------------------------*/
1957 uint32_t relsz = DLIMP_get_first_dyntag(DT_RELSZ, dyn_nugget);
1958 uint32_t relent = DLIMP_get_first_dyntag(DT_RELENT, dyn_nugget);
1959 uint32_t relnum = 0;
1961 /*------------------------------------------------------------------------*/
1962 /* Read the size of the relocation table (DT_PLTRELSZ) and the type of */
1963 /* of the PLTGOT relocation table (DT_PLTREL): one of DT_REL or DT_RELA */
1964 /*------------------------------------------------------------------------*/
1965 uint32_t pltrelsz = DLIMP_get_first_dyntag(DT_PLTRELSZ, dyn_nugget);
1966 int pltreltype = DLIMP_get_first_dyntag(DT_PLTREL, dyn_nugget);
1967 uint32_t pltnum = 0;
1969 /*------------------------------------------------------------------------*/
1970 /* Read the PLTGOT relocation table from the file */
1971 /* The PLTGOT table is a subsection at the end of either the DT_REL or */
1972 /* DT_RELA table. The size of the table it belongs to DT_REL(A)SZ */
1973 /* includes the size of the PLTGOT table. So it must be adjusted so that */
1974 /* the GOT relocation tables only contain actual GOT relocations. */
1975 /*------------------------------------------------------------------------*/
1976 if (pltrelsz != INT_MAX && pltrelsz != 0)
1977 {
1978 if (pltreltype == DT_REL)
1979 {
1980 pltnum = pltrelsz/relent;
1981 relsz -= pltrelsz;
1982 read_rel_table(&rel_plt_table,
1983 DLIMP_get_first_dyntag(DT_JMPREL, dyn_nugget),
1984 pltnum, relent, elf_file,
1985 dyn_module->wrong_endian);
1986 }
1987 else if (pltreltype == DT_RELA)
1988 {
1989 pltnum = pltrelsz/relaent;
1990 relasz -= pltrelsz;
1991 read_rela_table(&rela_plt_table,
1992 DLIMP_get_first_dyntag(DT_JMPREL, dyn_nugget),
1993 pltnum, relaent, elf_file,
1994 dyn_module->wrong_endian);
1995 }
1996 else
1997 {
1998 DLIF_error(DLET_RELOC,
1999 "DT_PLTREL is invalid: must be either %d or %d\n",
2000 DT_REL, DT_RELA);
2001 }
2002 }
2004 /*------------------------------------------------------------------------*/
2005 /* Read the DT_RELA GOT relocation table from the file */
2006 /*------------------------------------------------------------------------*/
2007 if (relasz != INT_MAX && relasz != 0)
2008 {
2009 relanum = relasz/relaent;
2010 read_rela_table(&rela_table, DLIMP_get_first_dyntag(DT_RELA, dyn_nugget),
2011 relanum, relaent, elf_file, dyn_module->wrong_endian);
2012 }
2014 /*------------------------------------------------------------------------*/
2015 /* Read the DT_REL GOT relocation table from the file */
2016 /*------------------------------------------------------------------------*/
2017 if (relsz != INT_MAX && relsz != 0)
2018 {
2019 relnum = relsz/relent;
2020 read_rel_table(&rel_table, DLIMP_get_first_dyntag(DT_REL, dyn_nugget),
2021 relnum, relent, elf_file, dyn_module->wrong_endian);
2022 }
2024 /*------------------------------------------------------------------------*/
2025 /* Process the PLTGOT relocations */
2026 /*------------------------------------------------------------------------*/
2027 if (rela_plt_table)
2028 process_pltgot_relocs(handle, rela_plt_table, pltreltype, pltnum,
2029 dyn_module);
2031 if (rel_plt_table)
2032 process_pltgot_relocs(handle, rel_plt_table, pltreltype, pltnum,
2033 dyn_module);
2035 /*------------------------------------------------------------------------*/
2036 /* Process the GOT relocations */
2037 /*------------------------------------------------------------------------*/
2038 if (rel_table || rela_table)
2039 process_got_relocs(handle, rel_table, relnum, rela_table, relanum,
2040 dyn_module);
2042 /*-------------------------------------------------------------------------*/
2043 /* Free memory used for ELF relocation table copies. */
2044 /*-------------------------------------------------------------------------*/
2045 if (rela_table) DLIF_free(rela_table);
2046 if (rel_table) DLIF_free(rel_table);
2047 if (rel_plt_table) DLIF_free(rel_plt_table);
2048 if (rela_plt_table) DLIF_free(rela_plt_table);
2049 }
2051 /*****************************************************************************/
2052 /* UNIT TESTING INTERFACE. */
2053 /*****************************************************************************/
2054 #ifdef UNIT_TEST
2055 void unit_arm_reloc_do(ARM_RELOC_TYPE r_type,
2056 uint8_t* address_space,
2057 uint32_t addend, uint32_t symval, uint32_t pc,
2058 uint32_t static_base, int wrong_endian)
2059 {
2060 reloc_do(r_type, address_space, addend, symval, pc, static_base);
2061 }
2063 void unit_arm_rel_unpack_addend(ARM_RELOC_TYPE r_type,
2064 uint8_t* address,
2065 uint32_t* addend)
2066 {
2067 rel_unpack_addend(r_type, address, addend);
2068 }
2070 BOOL unit_arm_rel_overflow(ARM_RELOC_TYPE r_type, int32_t reloc_value)
2071 {
2072 return rel_overflow(r_type, reloc_value);
2073 }
2075 void unit_arm_rel_mask_for_group(ARM_RELOC_TYPE r_type, int32_t* reloc_val)
2076 {
2077 rel_mask_for_group(r_type, reloc_val);
2078 }
2079 #endif