]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - ipc/ipcdev.git/blob - qnx/src/ipc3x_dev/ti/syslink/procMgr/hlos/knl/loaders/Elf/Qnx/DLOAD/TMS470_DLOAD_REL/arm_reloc.c
Merge remote-tracking branch 'vincent/3.00.00.11_eng' into tmp
[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 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 #if defined (__KERNEL__)
40 #include <linux/limits.h>
41 #else
42 #include <limits.h>
43 #endif
44 #include "relocate.h"
45 #include "dload_api.h"
46 #include "util.h"
47 #include "dload_endian.h"
48 #include "symtab.h"
49 #include "arm_elf32.h"
51 #define EXTRACT(field, lsb_offset, field_size) \
52    ( (field >> lsb_offset) & ((1U << field_size) - 1) )
53 #define OPND_S(symval) (symval & ~0x1)
54 #define OPND_T(symval) (symval & 0x1)
55 #define IS_BLX(field) ((EXTRACT(field, 24, 8) & ~0x1) == 0xFA)
56 #define SIGN_EXTEND(field, field_size) (field |= -(field & (1<<(field_size-1))))
58 /*****************************************************************************/
59 /* Enumeration to represent the relocation container size.                   */
60 /*                                                                           */
61 /* ARM_RELOC      - one 32 bit relocation field                              */
62 /* THUMB32_RELOC  - two 16 bit relocation fields                             */
63 /* THUMB16_RELOC  - one 16 bit relocation field                              */
64 /* ARM8_RELOC     - one 8 bit relocation field                               */
65 /*****************************************************************************/
66 typedef enum
67 {
68     ARM_RELOC,
69     THUMB32_RELOC,
70     THUMB16_RELOC,
71     ARM8_RELOC
72 }ARM_RELOC_SIZE;
74 /*****************************************************************************/
75 /* OBJ_IS_BE8() - Returns TRUE if the object file contains BE8 code.         */
76 /*****************************************************************************/
77 static inline int obj_is_be8(struct Elf32_Ehdr* fhdr)
78 {
79     return (fhdr->e_flags & EF_ARM_BE8);
80 }
82 /*****************************************************************************/
83 /* IS_DATA_RELOCATION() - Returns TRUE if the relocation pertains to data    */
84 /*****************************************************************************/
85 static BOOL is_data_relocation(ARM_RELOC_TYPE r_type)
86 {
87     switch (r_type)
88     {
89         case R_ARM_ABS32:
90         case R_ARM_ABS16:
91         case R_ARM_ABS8:
92         case R_ARM_PREL31:
93         case R_ARM_REL32:
94         case R_ARM_ABS32_NOI:
95         case R_ARM_REL32_NOI:
96             return TRUE;
97         default:
98             return FALSE;
99     }
101     return FALSE;
104 /*****************************************************************************/
105 /* REL_SWAP_ENDIAN() - Return TRUE if we should change the endianness of a   */
106 /*                     relocation field.  Due to BE-8 encoding, we cannot    */
107 /*                     simply rely on the wrong_endian member of elf_addrs.  */
108 /*****************************************************************************/
109 static BOOL rel_swap_endian(DLIMP_Dynamic_Module* dyn_module,
110                             ARM_RELOC_TYPE r_type)
112     /*---------------------------------------------------------------*/
113     /* LE -> BE8 - swap data relocations only                        */
114     /*---------------------------------------------------------------*/
115     if (dyn_module->wrong_endian && obj_is_be8(&dyn_module->fhdr) &&
116         is_data_relocation(r_type))
117         return TRUE;
118     /*---------------------------------------------------------------*/
119     /* BE -> BE8 - swap instruction relocations                      */
120     /*---------------------------------------------------------------*/
121     else if (!dyn_module->wrong_endian &&
122              obj_is_be8(&dyn_module->fhdr) &&
123              !is_data_relocation(r_type))
124         return TRUE;
125     /*---------------------------------------------------------------*/
126     /* LE -> BE32, BE8-> LE, BE32 -> LE - swap all relocations       */
127     /*---------------------------------------------------------------*/
128     else if (dyn_module->wrong_endian)
129         return TRUE;
131     /*---------------------------------------------------------------*/
132     /* BE32 -> BE32, LE -> LE, BE8 -> BE32 - swap nothing            */
133     /*---------------------------------------------------------------*/
134     return FALSE;
137 /*****************************************************************************/
138 /* REL_CONCLUDES_GROUP() - Returns true if this relocation type concludes a  */
139 /*                         group relocation sequence                         */
140 /*****************************************************************************/
141 static BOOL rel_concludes_group(ARM_RELOC_TYPE r_type)
143     switch (r_type)
144     {
145         case R_ARM_ALU_PC_G0:
146         case R_ARM_ALU_PC_G1:
147         case R_ARM_ALU_PC_G2:
148         case R_ARM_LDC_PC_G0:
149         case R_ARM_LDC_PC_G1:
150         case R_ARM_LDC_PC_G2:
151         case R_ARM_LDR_PC_G0:
152         case R_ARM_LDR_PC_G1:
153         case R_ARM_LDR_PC_G2:
154         case R_ARM_LDRS_PC_G0:
155         case R_ARM_LDRS_PC_G1:
156         case R_ARM_LDRS_PC_G2:
157             return TRUE;
158         default:
159             return FALSE;
160     }
161     return FALSE;
164 /*****************************************************************************/
165 /* REL_GROUP_NUM() - Returns group number of this relocation type.           */
166 /*****************************************************************************/
167 static int rel_group_num(ARM_RELOC_TYPE r_type)
169     switch (r_type)
170     {
171       case R_ARM_ALU_PC_G0:
172       case R_ARM_ALU_PC_G0_NC:
173       case R_ARM_LDC_PC_G0:
174       case R_ARM_LDR_PC_G0:
175       case R_ARM_LDRS_PC_G0:
176          return 0;
178       case R_ARM_ALU_PC_G1:
179       case R_ARM_ALU_PC_G1_NC:
180       case R_ARM_LDC_PC_G1:
181       case R_ARM_LDR_PC_G1:
182       case R_ARM_LDRS_PC_G1:
183          return 1;
185       case R_ARM_ALU_PC_G2:
186       case R_ARM_LDC_PC_G2:
187       case R_ARM_LDR_PC_G2:
188       case R_ARM_LDRS_PC_G2:
189          return 2;
191       default:
192          return 0;
193     }
195     return 0;
198 /*****************************************************************************/
199 /* REL_ALU_MASK_OFFSET() - Calculate the offset of an 8-bit mask for an      */
200 /*                         ALU immediate value.                              */
201 /*****************************************************************************/
202 static uint32_t rel_alu_mask_offset(int32_t residual, int bit_align)
204     uint32_t mask_offset;
206     for (mask_offset = 31; mask_offset > 7; mask_offset--)
207         if (residual & (0x1 << mask_offset)) break;
208     mask_offset -= 7;
210     if (bit_align == 0) bit_align = 1;
212     if ((mask_offset & bit_align) !=0)
213         mask_offset += (bit_align - (mask_offset % bit_align));
215     return mask_offset;
218 /*****************************************************************************/
219 /* REL_MASK_FOR_GROUP() - Mask off the appropriate bits from reloc_val,      */
220 /*                        depending on the group relocation type.            */
221 /*                        See Section 4.6.1.4 Group relocations in AAELF     */
222 /*                        for more details.                                  */
223 /*****************************************************************************/
224 static void rel_mask_for_group(ARM_RELOC_TYPE r_type, int32_t* reloc_val)
226     int32_t curr_residual = *reloc_val;
227     int num_alu_groups = rel_group_num(r_type) + 1;
228     int n;
229     if (rel_concludes_group(r_type)) num_alu_groups--;
231     for (n = 0; n < num_alu_groups; n++)
232     {
233         uint32_t mask_offset = rel_alu_mask_offset(curr_residual, 2);
234         uint32_t cres_mask   = 0xFF << mask_offset;
236         *reloc_val = curr_residual & cres_mask;
238         curr_residual = curr_residual & ~cres_mask;
239     }
241     if (rel_concludes_group(r_type)) *reloc_val = curr_residual;
245 /*****************************************************************************/
246 /* GET_RELOC_SIZE() - Return the container size for this relocation type.    */
247 /*****************************************************************************/
248 static ARM_RELOC_SIZE get_reloc_size(ARM_RELOC_TYPE r_type)
250     switch (r_type)
251     {
252         case R_ARM_THM_ABS5:
253         case R_ARM_THM_PC8:
254         case R_ARM_THM_JUMP6:
255         case R_ARM_THM_JUMP11:
256         case R_ARM_THM_JUMP8:
257            return THUMB16_RELOC;
259         case R_ARM_THM_CALL:
260         case R_ARM_THM_JUMP24:
261         case R_ARM_THM_MOVW_ABS_NC:
262         case R_ARM_THM_MOVT_ABS:
263         case R_ARM_THM_MOVW_PREL_NC:
264         case R_ARM_THM_MOVT_PREL:
265         case R_ARM_THM_JUMP19:
266         case R_ARM_THM_ALU_PREL_11_0:
267         case R_ARM_THM_PC12:
268         case R_ARM_THM_MOVW_BREL_NC:
269         case R_ARM_THM_MOVT_BREL:
270         case R_ARM_THM_MOVW_BREL:
271            return THUMB32_RELOC;
273         case R_ARM_ABS8:
274            return ARM8_RELOC;
276         default:
277            return ARM_RELOC;
278     }
281 /*****************************************************************************/
282 /* REL_CHANGE_ENDIAN() - Changes the endianess of the relocation field       */
283 /*                       located at address.  The size of the field depends  */
284 /*                       on the relocation type.                             */
285 /*****************************************************************************/
286 static void rel_change_endian(ARM_RELOC_TYPE r_type, uint8_t* address)
288     ARM_RELOC_SIZE reloc_size = get_reloc_size(r_type);
290     switch (reloc_size)
291     {
292         case ARM_RELOC:
293         {
294             DLIMP_change_endian32((int32_t*)address);
295             break;
296         }
298         case THUMB32_RELOC:
299         {
300             int16_t* ins1_ptr = (int16_t*)address;
301             DLIMP_change_endian16(ins1_ptr);
302             DLIMP_change_endian16(ins1_ptr + 1);
303             break;
304         }
306         case THUMB16_RELOC:
307         {
308             DLIMP_change_endian16((int16_t*)address);
309             break;
310         }
312         default:
313         {
314             break;
315         }
316     }
319 /*****************************************************************************/
320 /* WRITE_RELOC_R() - Write a relocation value to address rel_field_ptr.      */
321 /*                   It is assumed that all values have been properly packed */
322 /*                   and masked.                                             */
323 /*****************************************************************************/
324 static void write_reloc_r(uint8_t* rel_field_ptr,
325                           ARM_RELOC_TYPE r_type, int32_t reloc_val,
326                           uint32_t symval)
328 #if LOADER_DEBUG
329    /*------------------------------------------------------------------------*/
330    /* Print some details about the relocation we are about to process.       */
331    /*------------------------------------------------------------------------*/
332    if(debugging_on)
333    {
334           DLIF_trace("RWRT: rel_field_ptr: 0x%x\n", (uint32_t)rel_field_ptr);
335           DLIF_trace("RWRT: result: 0x%x\n", reloc_val);
336    }
337 #endif
340    /*------------------------------------------------------------------------*/
341    /* Given the relocation type, carry out relocation into a 4 byte packet   */
342    /* within the buffered segment.                                           */
343    /*------------------------------------------------------------------------*/
344    switch(r_type)
345    {
346        case R_ARM_ABS32:
347        case R_ARM_REL32:
348        case R_ARM_REL32_NOI:
349        case R_ARM_ABS32_NOI:
350        {
351           *((uint32_t*)rel_field_ptr) = reloc_val;
352           break;
353        }
355        case R_ARM_PREL31:
356        {
357            *((uint32_t*)rel_field_ptr) |= reloc_val;
358            break;
359        }
361        case R_ARM_PC24:
362        case R_ARM_CALL:
363        case R_ARM_PLT32:
364        {
365            /*----------------------------------------------------------------*/
366            /* ARM BL/BLX                                                     */
367            /* reloc_val has already been packed down to 25 bits. If the      */
368            /* callee is a thumb function, we convert to a BLX. After         */
369            /* conversion, the field is packed down to 24 bits.               */
370            /*----------------------------------------------------------------*/
371            uint32_t rel_field = *((uint32_t*)rel_field_ptr);
373            /*----------------------------------------------------------------*/
374            /* Check to see if callee is a thumb function.  If so convert to  */
375            /* BLX                                                            */
376            /*----------------------------------------------------------------*/
377            if (OPND_T(symval))
378                rel_field |= 0xF0000000;
380            /*----------------------------------------------------------------*/
381            /* Clear imm24 bits.  This must be done for both BL and BLX       */
382            /*----------------------------------------------------------------*/
383            rel_field &= ~0xFFFFFF;
385            if (IS_BLX(rel_field))
386            {
387                uint8_t Hval = reloc_val & 0x1;
388                /*------------------------------------------------------------*/
389                /* For BLX clear bit 24 (the H bit)                           */
390                /*------------------------------------------------------------*/
391                rel_field &= ~0x01000000;
392                rel_field |= Hval << 24;
393            }
395            /*----------------------------------------------------------------*/
396            /* Pack reloc_val down to 24 bits.                                */
397            /*----------------------------------------------------------------*/
398            rel_field |= (reloc_val >> 1);
399            *((uint32_t*)rel_field_ptr) = rel_field;
400            break;
401        }
403        case R_ARM_JUMP24:
404        {
405            *((uint32_t*)rel_field_ptr) &= ~0xFFFFFF;
406            *((uint32_t*)rel_field_ptr) |= reloc_val;
407            break;
408        }
410        case R_ARM_THM_CALL:
411        case R_ARM_THM_JUMP24:
412        {
413            /*----------------------------------------------------------------*/
414            /* THUMB B.W/BL/BLX                                               */
415            /*----------------------------------------------------------------*/
416            uint16_t* rel_field_16_ptr = (uint16_t*) rel_field_ptr;
418            uint8_t Sval;
419            uint8_t J1;
420            uint8_t J2;
421            uint16_t imm10;
422            uint16_t imm11;
424            /*----------------------------------------------------------------*/
425            /* If callee is a thumb function, convert BL to BLX               */
426            /*----------------------------------------------------------------*/
427            if (!OPND_T(symval) && r_type == R_ARM_THM_CALL)
428            {
429                if (reloc_val & 0x1) reloc_val++;
430                *(rel_field_16_ptr + 1) &= 0xEFFF;
431            }
433            /*----------------------------------------------------------------*/
434            /* reloc_val = S:I1:I2:imm10:imm11                                */
435            /*----------------------------------------------------------------*/
436            Sval  = (reloc_val >> 23)    & 0x1;
437            J1    = ((reloc_val >> 22) ^ (!Sval)) & 0x1;
438            J2    = ((reloc_val >> 21) ^ (!Sval)) & 0x1;
439            imm10 = (reloc_val >> 11)  & 0x3FF;
440            imm11 = reloc_val & 0x7FF;
442            *rel_field_16_ptr &= 0xF800;
443            *rel_field_16_ptr |= (Sval << 10);
444            *rel_field_16_ptr |= imm10;
446            rel_field_16_ptr++;
447            *rel_field_16_ptr &= 0xD000;
449            *rel_field_16_ptr |= (J1 << 13);
450            *rel_field_16_ptr |= (J2 << 11);
451            *rel_field_16_ptr |= imm11;
453            break;
454        }
455        case R_ARM_THM_JUMP19:
456        {
457            /*----------------------------------------------------------------*/
458            /* THUMB B<c>.W                                                   */
459            /* reloc_val = S:J2:J1:imm6:imm11:'0'                             */
460            /*----------------------------------------------------------------*/
461            uint16_t* rel_field_16_ptr = (uint16_t*) rel_field_ptr;
462            uint8_t S;
463            uint8_t J2;
464            uint8_t J1;
465            uint8_t imm6;
466            uint16_t imm11;
468            S =     (reloc_val >> 19) & 0x1;
469            J2 =    (reloc_val >> 18) & 0x1;
470            J1 =    (reloc_val >> 17) & 0x1;
471            imm6 =  (reloc_val >> 11) & 0x3F;
472            imm11 = (reloc_val      ) & 0x7FF;
474            /*----------------------------------------------------------------*/
475            /* Clear S and imm6 fields in first part of instruction           */
476            /*----------------------------------------------------------------*/
477            *rel_field_16_ptr &= 0xFBC0;
478            *rel_field_16_ptr |= (S << 10);
479            *rel_field_16_ptr |= imm6;
481            rel_field_16_ptr++;
483            *rel_field_16_ptr &= 0xD800;
484            *rel_field_16_ptr |= (J2 << 13);
485            *rel_field_16_ptr |= (J1 << 11);
486            *rel_field_16_ptr |= imm11;
487            break;
488        }
489        case R_ARM_THM_JUMP11:
490        {
491            /*----------------------------------------------------------------*/
492            /* THUMB B (unconditional)                                        */
493            /*----------------------------------------------------------------*/
494            *((uint16_t*)rel_field_ptr) &= ~0x7FF;
495            *((uint16_t*)rel_field_ptr) |= reloc_val;
496            break;
497        }
499        case R_ARM_THM_JUMP8:
500        {
501            /*----------------------------------------------------------------*/
502            /* THUMB B<c>                                                     */
503            /*----------------------------------------------------------------*/
504            *((uint16_t*)rel_field_ptr) &= ~0xFF;
505            *((uint16_t*)rel_field_ptr) |= reloc_val;
506            break;
507        }
509        case R_ARM_THM_ABS5:
510        {
511            /*----------------------------------------------------------------*/
512            /* THUMB LDR<c> <Rt>, [<Rn>(,#imm}]                               */
513            /*----------------------------------------------------------------*/
514            *((uint16_t*)rel_field_ptr) &= 0xF83F;
515            *((uint16_t*)rel_field_ptr) |= (reloc_val << 6);
516            break;
517        }
519        case R_ARM_THM_PC8:
520        {
521            /*----------------------------------------------------------------*/
522            /* THUMB LDR<c> <Rt>,[SP{,#imm}]                                  */
523            /*----------------------------------------------------------------*/
524            *((uint16_t*)rel_field_ptr) &= 0xFF00;
525            *((uint16_t*)rel_field_ptr) |= reloc_val;
526            break;
527        }
529        case R_ARM_THM_JUMP6:
530        {
531            /*----------------------------------------------------------------*/
532            /* THUMB CBZ,CBNZ                                                 */
533            /* reloc_field = Ival:imm5                                        */
534            /*----------------------------------------------------------------*/
535            uint8_t Ival;
536            uint8_t imm5;
538            Ival = (reloc_val >> 5) & 0x1;
539            imm5 = (reloc_val & 0x1F);
540            *((uint16_t*)rel_field_ptr) &= 0xFD07;
541            *((uint16_t*)rel_field_ptr) |= (Ival << 9);
542            *((uint16_t*)rel_field_ptr) |= (imm5 << 3);
543            break;
544        }
546        case R_ARM_ABS16:
547        {
548            /*----------------------------------------------------------------*/
549            /* 16 bit data relocation                                         */
550            /*----------------------------------------------------------------*/
551            *((uint16_t*)rel_field_ptr) = reloc_val;
552            break;
553        }
555        case R_ARM_ABS8:
556        {
557            /*----------------------------------------------------------------*/
558            /* 8 bit data relocation                                          */
559            /*----------------------------------------------------------------*/
560            *((uint8_t*)rel_field_ptr) = reloc_val;
561            break;
562        }
564        case R_ARM_MOVW_ABS_NC:
565        case R_ARM_MOVT_ABS:
566        case R_ARM_MOVW_PREL_NC:
567        case R_ARM_MOVT_PREL:
568        {
569            /*----------------------------------------------------------------*/
570            /* MOVW/MOVT                                                      */
571            /*----------------------------------------------------------------*/
572            uint8_t imm4 = reloc_val >> 12;
573            uint16_t imm12 = reloc_val & 0xFFF;
574            *((uint32_t*)rel_field_ptr) &= 0xFFF0F000;
575            *((uint32_t*)rel_field_ptr) |= imm12;
576            *((uint32_t*)rel_field_ptr) |= (imm4 << 16);
577            break;
578        }
580        case R_ARM_THM_MOVW_ABS_NC:
581        case R_ARM_THM_MOVT_ABS:
582        case R_ARM_THM_MOVW_PREL_NC:
583        case R_ARM_THM_MOVT_PREL:
584        {
585            /*----------------------------------------------------------------*/
586            /* THUMB2 MOVW/MOVT                                               */
587            /*----------------------------------------------------------------*/
588            uint16_t* rel_field_16_ptr = (uint16_t*) rel_field_ptr;
590            uint8_t imm4   = (reloc_val >> 12);
591            uint8_t i      = (reloc_val >> 11) & 0x1;
592            uint8_t imm3   = (reloc_val >> 8 ) & 0x7;
593            uint8_t imm8   = (reloc_val      ) & 0xFF;
595            *rel_field_16_ptr &= 0xFBF0;
596            *rel_field_16_ptr |= i << 10;
597            *rel_field_16_ptr |= imm4;
599            rel_field_16_ptr++;
601            *rel_field_16_ptr &= 0x8F00;
602            *rel_field_16_ptr |= imm3 << 12;
603            *rel_field_16_ptr |= imm8;
605            break;
606        }
608        case R_ARM_ABS12:
609        {
610            /*----------------------------------------------------------------*/
611            /* LDR immediate                                                  */
612            /*                                                                */
613            /* We need to know the sign of the relocated value, so we wait to */
614            /* to mask off any bits until now.                                */
615            /*----------------------------------------------------------------*/
616            uint8_t S = !((reloc_val >> 31) & 0x1);
617            reloc_val = abs(reloc_val) & 0xFFF;
619            *((uint32_t*)rel_field_ptr) &= 0xFF7FF000;
620            *((uint32_t*)rel_field_ptr) |= reloc_val;
621            *((uint32_t*)rel_field_ptr) |= (S << 23);
622            break;
623        }
625        case R_ARM_THM_PC12:
626        {
627            /*----------------------------------------------------------------*/
628            /* LDR<,B,SB,H,SH> Rd, [PC, #imm] (literal)                       */
629            /*                                                                */
630            /* We need to know the sign of the relocated value, so we wait to */
631            /* to mask off any bits until now.                                */
632            /*----------------------------------------------------------------*/
633            uint16_t* rel_field_16_ptr = (uint16_t*) rel_field_ptr;
634            uint8_t U = (reloc_val < 0) ? 0 : 1;
635            reloc_val = abs(reloc_val) & 0xFFF;
637            *rel_field_16_ptr &= 0xFF7F;
638            *rel_field_16_ptr |= U << 7;
640            rel_field_16_ptr++;
642            *rel_field_16_ptr &= 0xF000;
643            *rel_field_16_ptr |= reloc_val;
645            break;
646        }
648        /*--------------------------------------------------------------------*/
649        /* ARM GROUP RELOCATIONS.  See Section 4.6.1.4 in AAELF for more info */
650        /*                                                                    */
651        /* For these relocations, the reloc_val is calculated by              */
652        /* rel_mask_for_group().  We cannot check for overflow until after    */
653        /* this has been called, so overflow checking has been delayed until  */
654        /* now.                                                               */
655        /*--------------------------------------------------------------------*/
657        case R_ARM_ALU_PC_G0_NC:
658        case R_ARM_ALU_PC_G0:
659        case R_ARM_ALU_PC_G1_NC:
660        case R_ARM_ALU_PC_G2:
661        {
662            /*----------------------------------------------------------------*/
663            /* ARM ALU (ADD/SUB)                                              */
664            /*----------------------------------------------------------------*/
665            uint32_t *rel_field_32_ptr = (uint32_t*) rel_field_ptr;
666            uint32_t mask_offset;
667            uint8_t Rval = 0;
668            uint8_t Ival = 0;
670            *rel_field_32_ptr &= 0xFF3FF000;
672            /******************************************************************/
673            /* Change the instruction to ADD or SUB, depending on the sign    */
674            /******************************************************************/
675            if ((int32_t)reloc_val >= 0)
676                *rel_field_32_ptr |= 0x1 << 23;
677            else
678                *rel_field_32_ptr |= 0x1 << 22;
680            reloc_val = abs(reloc_val);
681            rel_mask_for_group(r_type, &reloc_val);
683            mask_offset = rel_alu_mask_offset(reloc_val, 2);
685            Rval = 32 - mask_offset;
686            Ival = (reloc_val >> mask_offset) & 0xFF;
688            if (reloc_val & ~(0xFF << mask_offset))
689                DLIF_error(DLET_RELOC, "relocation overflow\n");
691            *rel_field_32_ptr |= ((Rval >> 1) & 0xF) << 8;
692            *rel_field_32_ptr |= (Ival & 0xFF);
693        }
694        break;
696        case R_ARM_LDR_PC_G0:
697        case R_ARM_LDR_PC_G1:
698        case R_ARM_LDR_PC_G2:
699        {
700            /*----------------------------------------------------------------*/
701            /* ARM LDR/STR/LDRB/STRB                                          */
702            /*----------------------------------------------------------------*/
703            uint8_t Uval = (reloc_val < 0) ? 0 : 1;
704            uint32_t Lval = 0;
706            reloc_val = abs(reloc_val);
708            rel_mask_for_group(r_type, &reloc_val);
710            if (abs(reloc_val) >= 0x1000)
711                DLIF_error(DLET_RELOC, "relocation overflow!\n");
713            Lval = reloc_val & 0xFFF;
715            *((uint32_t*) rel_field_ptr) &= 0xFF7FF000;
716            *((uint32_t*) rel_field_ptr) |= Uval << 23;
717            *((uint32_t*) rel_field_ptr) |= Lval;
718        }
719        break;
721        case R_ARM_LDRS_PC_G0:
722        case R_ARM_LDRS_PC_G1:
723        case R_ARM_LDRS_PC_G2:
724        {
725            /*----------------------------------------------------------------*/
726            /* ARM LDRD/STRD/LDRH/STRH/LDRSH/LDRSB                            */
727            /*----------------------------------------------------------------*/
728            uint8_t Uval = (reloc_val < 0) ? 0 : 1;
729            uint8_t Hval;
730            uint8_t Lval;
732            reloc_val = abs(reloc_val);
734            rel_mask_for_group(r_type, &reloc_val);
736            if (abs(reloc_val) >= 0x100)
737                DLIF_error(DLET_RELOC, "relocation overflow!\n");
739            Hval = (reloc_val >> 4) & 0xF;
740            Lval = (reloc_val     ) & 0xF;
742            *((uint32_t*) rel_field_ptr) &= 0xFF7FF0F0;
743            *((uint32_t*) rel_field_ptr) |= (Uval << 23);
744            *((uint32_t*) rel_field_ptr) |= (Hval << 8);
745            *((uint32_t*) rel_field_ptr) |= Lval;
746        }
747        break;
749        case R_ARM_LDC_PC_G0:
750        case R_ARM_LDC_PC_G1:
751        case R_ARM_LDC_PC_G2:
752        {
753            /*----------------------------------------------------------------*/
754            /* ARM LDC/STC                                                    */
755            /*----------------------------------------------------------------*/
756            uint8_t Uval = (reloc_val < 0) ? 0 : 1;
757            uint8_t Lval;
759            reloc_val = abs(reloc_val);
761            rel_mask_for_group(r_type, &reloc_val);
763            if (abs(reloc_val) >= 0x1000)
764                DLIF_error(DLET_RELOC, "relocation overflow!\n");
766            Lval = reloc_val & 0xFF;
768            *((uint32_t*) rel_field_ptr) &= 0xFF7FFF00;
769            *((uint32_t*) rel_field_ptr) |= (Uval << 23);
770            *((uint32_t*) rel_field_ptr) |= Lval;
771        }
772        break;
774        /*--------------------------------------------------------------------*/
775        /* THUMB2 ALU RELOCATION.  This is a big block of code, most of which */
776        /* was taken from the linker.  The problem is that there are a lot of */
777        /* special formats.                                                   */
778        /*--------------------------------------------------------------------*/
779        case R_ARM_THM_ALU_PREL_11_0:
780        {
781            /*----------------------------------------------------------------*/
782            /* THUMB2 ADR.W                                                   */
783            /*                                                                */
784            /* Encode the immediate value as specified in section 4.2 of the  */
785            /* Thumb2 supplement:  "Immediate constants in data-processing    */
786            /* instructions"                                                  */
787            /*----------------------------------------------------------------*/
788            uint16_t* rel_field_16_ptr = (uint16_t*) rel_field_ptr;
789            uint16_t imm12;
790            uint8_t  bits_7_0, bits_15_8, bits_23_16, bits_31_24, Ival,
791                     imm3, imm8;
793            /*----------------------------------------------------------------*/
794            /* Convert to ADD/SUB depending on the sign.                      */
795            /* Clear out the 'i' bit while clearing the ADD/SUB bits          */
796            /* If SUB, set bits 7 and 5 to 1, else should be 0                */
797            /*----------------------------------------------------------------*/
798            *rel_field_16_ptr &= 0xFB5F;
799            if (reloc_val < 0)
800                *rel_field_16_ptr |= 0x00A0;
802            reloc_val = abs(reloc_val);
804            /*----------------------------------------------------------------*/
805            /* Extract out bits after we take the absolute value.             */
806            /*----------------------------------------------------------------*/
807            bits_7_0   = (reloc_val)       & 0xFF;
808            bits_15_8  = (reloc_val >> 8)  & 0xFF;
809            bits_23_16 = (reloc_val >> 16) & 0xFF;
810            bits_31_24 = (reloc_val >> 24) & 0xFF;
812            /*----------------------------------------------------------------*/
813            /* Does the value match the pattern 0x00XY00XY?                   */
814            /*----------------------------------------------------------------*/
815            if (bits_23_16 == bits_7_0 && bits_31_24 == 0 && bits_15_8 == 0)
816                imm12 = (0x1 << 8) | bits_7_0;
818            /*----------------------------------------------------------------*/
819            /* Does the value match the pattern 0xXY00XY00?                   */
820            /*----------------------------------------------------------------*/
821            else if (bits_31_24 == bits_15_8 && bits_23_16 == 0 && bits_7_0 == 0)
822                imm12 = (0x2 << 8) | bits_7_0;
824            /*-----------------------------------------------------------------*/
825            /* Does the value match the pattern 0xXYXYXYXY?                    */
826            /*-----------------------------------------------------------------*/
827            else if (bits_31_24 == bits_23_16 && bits_31_24 == bits_15_8 &&
828                     bits_31_24 == bits_7_0)
829                imm12 = (0x3 << 8) | bits_7_0;
831            /*-----------------------------------------------------------------*/
832            /* Finally, check to see if we can encode this immediate as an     */
833            /* 8-bit shifted value.                                            */
834            /*-----------------------------------------------------------------*/
835            else if (reloc_val >= 0 && reloc_val <= 255)
836                imm12 = reloc_val;
837            else
838            {
839                /*-------------------------------------------------------------*/
840                /* Calculate the mask for this immediate, then find the        */
841                /* appropriate rotate and 8-bit immediate value                */
842                /* (Rval and Sval).                                            */
843                /*-------------------------------------------------------------*/
844                uint32_t mask_offset = rel_alu_mask_offset(
845                    (uint32_t)reloc_val, 1);
846                uint8_t Rval         = 32 - mask_offset;
847                uint8_t Sval         = (reloc_val >> mask_offset) & 0x7F;
849                imm12 = (Rval << 7) | Sval;
851                /*-------------------------------------------------------------*/
852                /* If overflow occurred, then finding an 8-bit shiftable value */
853                /* failed.                                                     */
854                /*-------------------------------------------------------------*/
855                if (reloc_val & ~(0xFF << mask_offset))
856                    DLIF_error(DLET_RELOC, "relocation overflow!\n");
857            }
859            Ival = (imm12 >> 11) & 0x1;
860            imm3 = (imm12 >> 8)  & 0x7;
861            imm8 = (imm12)       & 0xFF;
863            *rel_field_16_ptr |= Ival << 10;
864            rel_field_16_ptr++;
865            *rel_field_16_ptr |= imm3 << 12;
866            *rel_field_16_ptr |= imm8;
867            break;
868        }
870        default:
871           DLIF_error(DLET_RELOC,
872                      "write_reloc_r called with invalid relocation type\n");
873    }
877 /*****************************************************************************/
878 /* PACK_RESULT() - Pack the result of a relocation calculation for storage   */
879 /*      in the relocation field.                                             */
880 /*****************************************************************************/
881 static int32_t pack_result(int32_t unpacked_result, int r_type)
883     switch (r_type)
884     {
885         case R_ARM_ABS32:
886         case R_ARM_REL32:
887         case R_ARM_ABS16:
888         case R_ARM_ABS8:
889         case R_ARM_PREL31:
890         case R_ARM_MOVW_ABS_NC:
891         case R_ARM_MOVW_PREL_NC:
892         case R_ARM_THM_MOVW_ABS_NC:
893         case R_ARM_THM_MOVW_PREL_NC:
894         case R_ARM_ABS32_NOI:
895         case R_ARM_REL32_NOI:
896         case R_ARM_ABS12:
897         case R_ARM_ALU_PC_G0_NC:
898         case R_ARM_ALU_PC_G0:
899         case R_ARM_ALU_PC_G1_NC:
900         case R_ARM_ALU_PC_G1:
901         case R_ARM_ALU_PC_G2:
902         case R_ARM_LDR_PC_G0:
903         case R_ARM_LDR_PC_G1:
904         case R_ARM_LDR_PC_G2:
905         case R_ARM_LDRS_PC_G0:
906         case R_ARM_LDRS_PC_G1:
907         case R_ARM_LDRS_PC_G2:
908         case R_ARM_LDC_PC_G0:
909         case R_ARM_LDC_PC_G1:
910         case R_ARM_LDC_PC_G2:
911         case R_ARM_THM_PC12:
912         case R_ARM_THM_ALU_PREL_11_0:
913            return unpacked_result;
915         case R_ARM_PC24:
916         case R_ARM_CALL:
917         case R_ARM_PLT32:
918         case R_ARM_THM_CALL:
919         case R_ARM_THM_JUMP24:
920         case R_ARM_THM_JUMP11:
921         case R_ARM_THM_JUMP8:
922         case R_ARM_THM_JUMP6:
923         case R_ARM_THM_JUMP19:
924            return unpacked_result >> 1;
926         case R_ARM_JUMP24:
927         case R_ARM_THM_ABS5:
928         case R_ARM_THM_PC8:
929            return unpacked_result >> 2;
931         case R_ARM_MOVT_ABS:
932         case R_ARM_MOVT_PREL:
933         case R_ARM_THM_MOVT_ABS:
934         case R_ARM_THM_MOVT_PREL:
935            return unpacked_result >> 16;
937         default:
938            DLIF_error(DLET_RELOC,
939                       "pack_result called with invalid relocation type!\n");
940            return 0;
941     }
945 /*****************************************************************************/
946 /* MASK_RESULT() - Mask the result of a relocation calculation so that it    */
947 /*      fits the size of the relocation type's field.                        */
948 /*****************************************************************************/
949 static int32_t mask_result(int32_t unmasked_result, int r_type)
951     switch (r_type)
952     {
953         case R_ARM_ABS8:
954         case R_ARM_THM_JUMP8:
955         case R_ARM_THM_PC8:
956            return unmasked_result & 0xFF;
958         case R_ARM_ABS16:
959         case R_ARM_MOVW_ABS_NC:
960         case R_ARM_MOVT_ABS:
961         case R_ARM_MOVW_PREL_NC:
962         case R_ARM_MOVT_PREL:
963         case R_ARM_THM_MOVW_ABS_NC:
964         case R_ARM_THM_MOVT_ABS:
965         case R_ARM_THM_MOVW_PREL_NC:
966         case R_ARM_THM_MOVT_PREL:
967            return unmasked_result & 0xFFFF;
969         case R_ARM_ABS32:
970         case R_ARM_REL32:
971         case R_ARM_ABS32_NOI:
972         case R_ARM_REL32_NOI:
973         case R_ARM_ABS12:
974         case R_ARM_ALU_PC_G0_NC:
975         case R_ARM_ALU_PC_G0:
976         case R_ARM_ALU_PC_G1_NC:
977         case R_ARM_ALU_PC_G1:
978         case R_ARM_ALU_PC_G2:
979         case R_ARM_LDR_PC_G0:
980         case R_ARM_LDR_PC_G1:
981         case R_ARM_LDR_PC_G2:
982         case R_ARM_LDRS_PC_G0:
983         case R_ARM_LDRS_PC_G1:
984         case R_ARM_LDRS_PC_G2:
985         case R_ARM_LDC_PC_G0:
986         case R_ARM_LDC_PC_G1:
987         case R_ARM_LDC_PC_G2:
988         case R_ARM_THM_PC12:
989         case R_ARM_THM_ALU_PREL_11_0:
990            return unmasked_result;
992         case R_ARM_PREL31:
993            return unmasked_result & 0x7FFFFFFF;
995         case R_ARM_CALL:
996         case R_ARM_PC24:
997         case R_ARM_THM_CALL:
998         case R_ARM_THM_JUMP24:
999            return unmasked_result & 0x01FFFFFF;
1001         case R_ARM_JUMP24:
1002            return unmasked_result & 0x00FFFFFF;
1004         case R_ARM_THM_JUMP11:
1005            return unmasked_result & 0x7FF;
1007         case R_ARM_THM_ABS5:
1008            return unmasked_result & 0x1F;
1010         case R_ARM_THM_JUMP6:
1011            return unmasked_result & 0x3F;
1013         case R_ARM_THM_JUMP19:
1014            return unmasked_result & 0xFFFFF;
1016         default:
1017            DLIF_error(DLET_RELOC,
1018                       "mask_result invalid relocation type!\n");
1019            return 0;
1020     }
1025 /*****************************************************************************/
1026 /* OVERFLOW() - Check relocation value against the range associated with a   */
1027 /*      given relocation type field size and signedness.                     */
1028 /*****************************************************************************/
1029 static BOOL rel_overflow(ARM_RELOC_TYPE r_type, int32_t reloc_value)
1031     switch(r_type)
1032     {
1033         uint32_t sbits;
1034         case R_ARM_JUMP24:
1035         case R_ARM_CALL:
1036         case R_ARM_PC24:
1037         {
1038             sbits = reloc_value >> 25;
1039             return (sbits != 0 && sbits != -1UL);
1040         }
1041         case R_ARM_THM_CALL:
1042         case R_ARM_THM_JUMP24:
1043         {
1044             sbits = reloc_value >> 24;
1045             return (sbits != 0 && sbits != -1UL);
1046         }
1047         case R_ARM_THM_JUMP19:
1048         {
1049             sbits = reloc_value >> 20;
1050             return (sbits != 0 && sbits != -1UL);
1051         }
1052         case R_ARM_ABS12:
1053         case R_ARM_THM_PC12:
1054         {
1055             return abs(reloc_value) >= 0x1000;
1056         }
1057         case R_ARM_PREL31:
1058         {
1059             sbits = reloc_value >> 30;
1060             return (sbits != 0 && sbits != -1UL);
1061         }
1063         case R_ARM_ABS16:
1064         {
1065             return ((reloc_value > 65535) ||
1066                         (reloc_value < -32768));
1067         }
1068         case R_ARM_ABS8:
1069         {
1070             return ((reloc_value > 255) ||
1071                          (reloc_value < -128));
1072         }
1074         default:
1075             return FALSE;
1076     }
1077     return FALSE;
1080 /*****************************************************************************/
1081 /* RELOC_DO() - Process a single relocation entry.                           */
1082 /*****************************************************************************/
1083 static void reloc_do(ARM_RELOC_TYPE r_type, uint8_t* address,
1084               uint32_t addend, uint32_t symval, uint32_t pc,
1085               uint32_t base_pointer)
1087     int32_t reloc_value = 0;
1089 #if LOADER_DEBUG && LOADER_PROFILE
1090    /*------------------------------------------------------------------------*/
1091    /* In debug mode, keep a count of the number of relocations processed.    */
1092    /* In profile mode, start the clock on a given relocation.                */
1093    /*------------------------------------------------------------------------*/
1094    int start_time;
1095    if (debugging_on || profiling_on)
1096    {
1097       DLREL_relocations++;
1098       if (profiling_on) start_time = clock();
1099    }
1100 #endif
1102    /*------------------------------------------------------------------------*/
1103    /* Calculate the relocation value according to the rules associated with  */
1104    /* the given relocation type.                                             */
1105    /*------------------------------------------------------------------------*/
1106    switch(r_type)
1107    {
1108        case R_ARM_NONE:
1109           reloc_value = addend;
1110           break;
1112        /*--------------------------------------------------------------------*/
1113        /* S + A                                                              */
1114        /*--------------------------------------------------------------------*/
1115        case R_ARM_ABS16:
1116        case R_ARM_ABS12:
1117        case R_ARM_THM_ABS5:
1118        case R_ARM_ABS8:
1119        case R_ARM_MOVT_ABS:
1120        case R_ARM_THM_MOVT_ABS:
1121        case R_ARM_ABS32_NOI:
1122        case R_ARM_PLT32_ABS:
1123           reloc_value = OPND_S(symval) + addend;
1124           break;
1126        /*--------------------------------------------------------------------*/
1127        /* (S + A) | T                                                        */
1128        /*--------------------------------------------------------------------*/
1129        case R_ARM_ABS32:
1130        case R_ARM_MOVW_ABS_NC:
1131        case R_ARM_THM_MOVW_ABS_NC:
1132           reloc_value = (OPND_S(symval) + addend) | OPND_T(symval);
1133           break;
1135        /*--------------------------------------------------------------------*/
1136        /* (S + A) - P                                                        */
1137        /*--------------------------------------------------------------------*/
1138        case R_ARM_LDR_PC_G0:
1139        case R_ARM_LDR_PC_G1:
1140        case R_ARM_LDR_PC_G2:
1141        case R_ARM_MOVT_PREL:
1142        case R_ARM_THM_MOVT_PREL:
1143        case R_ARM_REL32_NOI:
1144        case R_ARM_THM_JUMP6:
1145        case R_ARM_THM_JUMP11:
1146        case R_ARM_THM_JUMP8:
1147        case R_ARM_LDRS_PC_G0:
1148        case R_ARM_LDRS_PC_G1:
1149        case R_ARM_LDRS_PC_G2:
1150        case R_ARM_LDC_PC_G0:
1151        case R_ARM_LDC_PC_G1:
1152        case R_ARM_LDC_PC_G2:
1153           reloc_value = (OPND_S(symval) + addend) - pc;
1154           break;
1156        /*--------------------------------------------------------------------*/
1157        /* (S + A) - Pa                                                       */
1158        /*--------------------------------------------------------------------*/
1159        case R_ARM_THM_PC8:
1160        case R_ARM_THM_PC12:
1161           reloc_value = (OPND_S(symval) + addend) - (pc & 0xFFFFFFFC);
1162           break;
1164        /*--------------------------------------------------------------------*/
1165        /* ((S + A) | T) - P                                                  */
1166        /*--------------------------------------------------------------------*/
1167        case R_ARM_REL32:
1168        case R_ARM_PC24:
1169        case R_ARM_THM_CALL:
1170        case R_ARM_PLT32:
1171        case R_ARM_CALL:
1172        case R_ARM_JUMP24:
1173        case R_ARM_THM_JUMP24:
1174        case R_ARM_PREL31:
1175        case R_ARM_MOVW_PREL_NC:
1176        case R_ARM_THM_MOVW_PREL_NC:
1177        case R_ARM_THM_JUMP19:
1178        case R_ARM_THM_ALU_PREL_11_0:
1179        case R_ARM_ALU_PC_G0_NC:
1180        case R_ARM_ALU_PC_G0:
1181        case R_ARM_ALU_PC_G1_NC:
1182        case R_ARM_ALU_PC_G1:
1183        case R_ARM_ALU_PC_G2:
1184           reloc_value = ((OPND_S(symval) + addend) | OPND_T(symval)) - pc;
1185           break;
1187       /*---------------------------------------------------------------------*/
1188       /* Unrecognized relocation type.                                       */
1189       /*---------------------------------------------------------------------*/
1190       default:
1191          DLIF_error(DLET_RELOC,"invalid relocation type!\n");
1192          break;
1194    }
1196    if (rel_overflow(r_type, reloc_value))
1197        DLIF_error(DLET_RELOC, "relocation overflow!\n");
1199    /*------------------------------------------------------------------------*/
1200    /* Move relocation value to appropriate offset for relocation field's     */
1201    /* location.                                                              */
1202    /*------------------------------------------------------------------------*/
1203    reloc_value = pack_result(reloc_value, r_type);
1205    /*------------------------------------------------------------------------*/
1206    /* Mask packed result to the size of the relocation field.                */
1207    /*------------------------------------------------------------------------*/
1208    reloc_value = mask_result(reloc_value, r_type);
1210    /*------------------------------------------------------------------------*/
1211    /* Write the relocated 4-byte packet back to the segment buffer.          */
1212    /*------------------------------------------------------------------------*/
1213    write_reloc_r(address, r_type, reloc_value, symval);
1215 #if LOADER_DEBUG && LOADER_PROFILE
1216    /*------------------------------------------------------------------------*/
1217    /* In profile mode, add elapsed time for this relocation to total time    */
1218    /* spent doing relocations.                                               */
1219    /*------------------------------------------------------------------------*/
1220    if (profiling_on)
1221       DLREL_total_reloc_time += (clock() - start_time);
1222    if (debugging_on)
1223       DLIF_trace("reloc_value = 0x%x\n", reloc_value);
1224 #endif
1227 /*****************************************************************************/
1228 /* REL_UNPACK_ADDEND() - Unpacks the addend from the relocation field        */
1229 /*****************************************************************************/
1230 static void rel_unpack_addend(ARM_RELOC_TYPE r_type,
1231                               uint8_t* address,
1232                               uint32_t* addend)
1234     switch (r_type)
1235     {
1236         case R_ARM_ABS32:
1237         case R_ARM_REL32:
1238         case R_ARM_ABS32_NOI:
1239         case R_ARM_REL32_NOI:
1240         {
1241             *addend = *((uint32_t*)address);
1242         }
1243         break;
1245         case R_ARM_ABS16:
1246         {
1247             *addend = *((uint16_t*)address);
1248             *addend = SIGN_EXTEND(*addend, 16);
1249         }
1250         break;
1252         case R_ARM_ABS8:
1253         {
1254             *addend = *address;
1255             *addend = SIGN_EXTEND(*addend, 8);
1256         }
1257         break;
1259         case R_ARM_CALL:
1260         case R_ARM_PC24:
1261         case R_ARM_PLT32:
1262         case R_ARM_JUMP24:
1263         {
1264             uint32_t rel_field = *((uint32_t*)address);
1265             uint32_t imm24;
1266             uint8_t Hval;
1267             if (IS_BLX(rel_field))
1268                 Hval = EXTRACT(rel_field, 24, 1);
1269             else
1270                 Hval = 0x0;
1272             imm24 = EXTRACT(rel_field, 0, 24);
1273             *addend = (((imm24 << 1) + Hval) << 1);
1274             SIGN_EXTEND(*addend, 26);
1275         }
1276         break;
1278         case R_ARM_THM_JUMP11:
1279         {
1280             *addend = EXTRACT(*((uint16_t*)address), 0, 11);
1281             *addend = *addend << 1;
1282             SIGN_EXTEND(*addend, 12);
1283             break;
1284         }
1286         case R_ARM_THM_JUMP8:
1287         {
1288             *addend = EXTRACT(*((uint16_t*)address), 0, 8);
1289             *addend = *addend << 1;
1290             SIGN_EXTEND(*addend, 9);
1291             break;
1292         }
1294         case R_ARM_THM_CALL:
1295         case R_ARM_THM_JUMP24:
1296         {
1297             uint16_t* rel_field_ptr = (uint16_t *) address;
1299             uint8_t Sval;
1300             uint16_t imm10;
1301             uint8_t I1;
1302             uint8_t I2;
1303             uint16_t imm11;
1305             Sval = EXTRACT(*rel_field_ptr, 10, 1);
1306             imm10 = EXTRACT(*rel_field_ptr, 0, 10);
1307             rel_field_ptr++;
1308             I1 = !(EXTRACT(*rel_field_ptr, 13, 1) ^ Sval);
1309             I2 = !(EXTRACT(*rel_field_ptr, 11, 1) ^ Sval);
1310             imm11 = EXTRACT(*rel_field_ptr, 0, 11);
1312             *addend = (Sval << 23) | (I1 << 22) | (I2 << 21) |
1313                 (imm10 << 11) | imm11;
1314             *addend = *addend << 1;
1315             SIGN_EXTEND(*addend, 25);
1316             break;
1317         }
1319         case R_ARM_THM_JUMP19:
1320         {
1321             uint16_t* rel_field_ptr = (uint16_t *) address;
1323             uint8_t Sval;
1324             uint8_t imm6;
1325             uint8_t J1;
1326             uint8_t J2;
1327             uint16_t imm11;
1329             Sval = EXTRACT(*rel_field_ptr, 10, 1);
1330             imm6 = EXTRACT(*rel_field_ptr, 0, 6);
1331             rel_field_ptr++;
1332             J1 = EXTRACT(*rel_field_ptr, 13, 1);
1333             J2 = EXTRACT(*rel_field_ptr, 11, 1);
1334             imm11 = EXTRACT(*rel_field_ptr, 0, 11);
1336             *addend = (Sval << 19) | (J2 << 18) | (J1 << 17) |
1337                 (imm6 << 11) | imm11;
1338             *addend = *addend << 1;
1339             SIGN_EXTEND(*addend, 21);
1340         }
1341         break;
1343         case R_ARM_LDR_PC_G0:
1344         case R_ARM_LDR_PC_G1:
1345         case R_ARM_LDR_PC_G2:
1346         case R_ARM_ABS12:
1347         {
1348             uint8_t Uval;
1349             uint16_t imm12;
1351             uint32_t* rel_field_ptr = (uint32_t*) address;
1353             Uval  = EXTRACT(*rel_field_ptr, 23, 1);
1354             imm12 = EXTRACT(*rel_field_ptr, 0, 12);
1356             *addend = (Uval == 1) ? imm12 : -((int32_t)(imm12));
1357         }
1358         break;
1360         case R_ARM_THM_PC12:
1361         {
1362             uint8_t Uval;
1363             uint16_t imm12;
1364             uint16_t* rel_field_ptr = (uint16_t*) address;
1366             Uval = EXTRACT(*rel_field_ptr, 7, 1);
1367             rel_field_ptr++;
1368             imm12 = EXTRACT(*rel_field_ptr, 0, 12);
1370             *addend = (Uval == 1) ? imm12 : -((int32_t)imm12);
1371             break;
1372         }
1374         case R_ARM_LDRS_PC_G0:
1375         case R_ARM_LDRS_PC_G1:
1376         case R_ARM_LDRS_PC_G2:
1377         {
1378             uint8_t Uval;
1379             uint8_t imm4H;
1380             uint8_t imm4L;
1381             uint32_t* rel_field_ptr = (uint32_t*) address;
1383             Uval = EXTRACT(*rel_field_ptr, 23, 1);
1384             imm4H = EXTRACT(*rel_field_ptr, 8, 4);
1385             imm4L = EXTRACT(*rel_field_ptr, 0, 4);
1387             *addend = (imm4H << 4) | imm4L;
1388             if (Uval == 0) *addend = -(*addend);
1389         }
1390         break;
1392         case R_ARM_LDC_PC_G0:
1393         case R_ARM_LDC_PC_G1:
1394         case R_ARM_LDC_PC_G2:
1395         {
1396             uint8_t Uval;
1397             uint16_t imm8;
1398             uint32_t* rel_field_ptr = (uint32_t*) address;
1400             Uval = EXTRACT(*rel_field_ptr, 23, 1);
1401             imm8 = EXTRACT(*rel_field_ptr, 0, 8);
1403             *addend = (Uval == 1) ? imm8 : -((int32_t)imm8);
1404         }
1405         break;
1407         case R_ARM_ALU_PC_G0_NC:
1408         case R_ARM_ALU_PC_G0:
1409         case R_ARM_ALU_PC_G1_NC:
1410         case R_ARM_ALU_PC_G1:
1411         case R_ARM_ALU_PC_G2:
1412         {
1413             uint8_t Rval;
1414             uint8_t Ival;
1415             uint32_t rel_field = *((uint32_t*)address);
1417             Rval = EXTRACT(rel_field, 8, 4);
1418             Ival = EXTRACT(rel_field, 0, 8);
1420             *addend = (Ival >> Rval) | (Ival << (32 - Rval));
1422             if (EXTRACT(rel_field, 22, 2) == 1)
1423                 *addend = -(*addend);
1424         }
1425         break;
1427         case R_ARM_MOVW_ABS_NC:
1428         case R_ARM_MOVT_ABS:
1429         case R_ARM_MOVW_PREL_NC:
1430         case R_ARM_MOVT_PREL:
1431         {
1432             uint8_t Ival;
1433             uint16_t Jval;
1434             uint32_t rel_field = *((uint32_t*)address);
1435             Ival = EXTRACT(rel_field, 16, 4);
1436             Jval = EXTRACT(rel_field, 0, 12);
1438             *addend = (Ival << 12) | Jval;
1439             SIGN_EXTEND(*addend, 16);
1440         }
1441         break;
1443         case R_ARM_THM_MOVW_ABS_NC:
1444         case R_ARM_THM_MOVT_ABS:
1445         case R_ARM_THM_MOVW_PREL_NC:
1446         case R_ARM_THM_MOVT_PREL:
1447         {
1448             uint8_t Ival;
1449             uint8_t Jval;
1450             uint8_t Kval;
1451             uint8_t Lval;
1453             uint16_t* rel_field_ptr = (uint16_t*)address;
1454             uint16_t rel_field = *rel_field_ptr;
1456             Ival = EXTRACT(rel_field, 0, 4);
1457             Jval = EXTRACT(rel_field, 10, 1);
1459             rel_field = *(rel_field_ptr + 1);
1460             Kval = EXTRACT(rel_field, 12, 3);
1461             Lval = EXTRACT(rel_field, 0, 8);
1463             *addend = (Ival << 12) | (Jval << 11) | (Kval << 8) | Lval;
1464             SIGN_EXTEND(*addend, 16);
1465         }
1466         break;
1468         case R_ARM_THM_ALU_PREL_11_0:
1469         {
1470             uint8_t Ival;
1471             uint8_t Jval;
1472             uint8_t Kval;
1473             uint16_t imm12;
1474             uint16_t* rel_field_ptr = (uint16_t*)address;
1475             uint16_t rel_field = *rel_field_ptr;
1476             uint8_t bits_11_10;
1478             Ival = EXTRACT(rel_field, 12, 3);
1480             rel_field = *(rel_field_ptr + 1);
1481             Jval = EXTRACT(rel_field, 12, 3);
1482             Kval = EXTRACT(rel_field, 0 , 8);
1484             imm12 = (Ival << 11) | (Jval << 8) | Kval;
1486             /*---------------------------------------------------------------*/
1487             /* Now that we've unpacked the immediate value, we need to       */
1488             /* decode it according to section 4.2 in the Thumb2 supplement:  */
1489             /* "Immediate constants in data-processing instructions"         */
1490             /*---------------------------------------------------------------*/
1491             bits_11_10 = (imm12 >> 10) & 0x3;
1493             if (bits_11_10 == 0x0)
1494             {
1495                 uint8_t bits_9_8   = (imm12 >> 8)  & 0x3;
1496                 uint8_t bits_7_0   = (imm12)       & 0xFF;
1498                 switch (bits_9_8)
1499                 {
1500                     case 0x0:  *addend = bits_7_0;
1501                     break;
1502                     case 0x1:  *addend = (bits_7_0 << 16) | (bits_7_0);
1503                     break;
1504                     case 0x2:  *addend = (bits_7_0 << 24) | (bits_7_0 << 8);
1505                     break;
1506                     case 0x3:  *addend= (bits_7_0 << 24) | (bits_7_0 << 16) |
1507                                    (bits_7_0 << 8)  | (bits_7_0);
1508                     break;
1509                 }
1510             }
1511             else
1512             {
1513                 uint8_t bits_6_0  = (imm12)      & 0x7F;
1514                 uint8_t bits_11_7 = (imm12 >> 7) & 0x1F;
1516                 uint8_t byte = 0x80 | bits_6_0;
1517                 *addend = (byte >> bits_11_7) | (byte << (32 - bits_11_7));
1518             }
1520             rel_field = *rel_field_ptr;
1522             if (EXTRACT(rel_field, 7, 1) == 1 &&
1523                 EXTRACT(rel_field, 5, 1) == 1)
1524                 *addend = -(*addend);
1525         }
1526         break;
1528         case R_ARM_THM_JUMP6:
1529         {
1530             uint8_t Ival;
1531             uint8_t Jval;
1533             uint16_t rel_field = *((uint16_t*)address);
1535             Ival = EXTRACT(rel_field, 9, 1);
1536             Jval = EXTRACT(rel_field, 3, 5);
1538             *addend = ((Ival << 5) | Jval) << 1;
1539             *addend = ((*addend + 4) & 0x7F) - 4;
1541         }
1542         break;
1544         case R_ARM_THM_ABS5:
1545         {
1546             uint16_t rel_field = *((uint16_t*)address);
1547             *addend = EXTRACT(rel_field, 6, 5);
1548             *addend = *addend << 2;
1549             break;
1550         }
1552         case R_ARM_THM_PC8:
1553         {
1554             uint16_t rel_field = *((uint16_t*)address);
1555             *addend = EXTRACT(rel_field, 0, 8);
1556             *addend = *addend << 2;
1557             *addend = ((*addend + 4) & 0x3FF) - 4;
1559             break;
1560         }
1562         case R_ARM_PREL31:
1563         {
1564             uint32_t rel_field = *((uint32_t*)address);
1565             *addend = EXTRACT(rel_field, 0, 31);
1566             SIGN_EXTEND(*addend, 31);
1567             break;
1568         }
1570         default:
1571         DLIF_error(DLET_RELOC,
1572                    "ERROR: Cannot unpack addend for relocation type %d\n",
1573                    r_type);
1574     }
1577 /*****************************************************************************/
1578 /* PROCESS_REL_TABLE() - Process REL type relocation table.                  */
1579 /*****************************************************************************/
1580 static BOOL process_rel_table(DLOAD_HANDLE handle,
1581                               DLIMP_Loaded_Segment* seg,
1582                               struct Elf32_Rel* rel_table,
1583                               uint32_t relnum,
1584                               int32_t *start_rid,
1585                               DLIMP_Dynamic_Module* dyn_module)
1587     Elf32_Addr seg_start_addr = seg->input_vaddr;
1588     Elf32_Addr seg_end_addr   = seg_start_addr + seg->phdr.p_memsz;
1589     BOOL found = FALSE;
1590     int32_t rid = *start_rid;
1592     if (rid >= relnum) rid = 0;
1594     for ( ; rid < relnum; rid++)
1595     {
1596         /*---------------------------------------------------------------*/
1597         /* If the relocation offset falls within the segment, process it */
1598         /*---------------------------------------------------------------*/
1599         if (rel_table[rid].r_offset >= seg_start_addr &&
1600             rel_table[rid].r_offset < seg_end_addr)
1601         {
1602             Elf32_Addr r_symval;
1603             ARM_RELOC_TYPE r_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 pc;
1607             uint32_t addend = 0;
1608             BOOL change_endian;
1610             found = TRUE;
1612             /*---------------------------------------------------------*/
1613             /* If symbol definition is not found don't do the          */
1614             /* relocation. An error is generated by the lookup         */
1615             /* function.                                               */
1616             /*---------------------------------------------------------*/
1617             if (!DLSYM_canonical_lookup(handle, r_symid, dyn_module, &r_symval))
1618                 continue;
1620             reloc_address =
1621                 (((uint8_t*)(seg->phdr.p_vaddr) + seg->reloc_offset) +
1622                  rel_table[rid].r_offset - seg->input_vaddr);
1623             pc = (uint32_t) reloc_address;
1624             change_endian = rel_swap_endian(dyn_module, r_type);
1625             if (change_endian)
1626                 rel_change_endian(r_type, reloc_address);
1628             rel_unpack_addend(ELF32_R_TYPE(rel_table[rid].r_info),
1629                               reloc_address,
1630                               &addend);
1632 #if LOADER_DEBUG && LOADER_PROFILE
1633             if (debugging_on)
1634             {
1635                 char *r_symname = (char*) dyn_module->symtab[r_symid].st_name;
1636                 DLIF_trace("r_type=%d, "
1637                        "pc=0x%x, "
1638                        "addend=0x%x, "
1639                        "symnm=%s, "
1640                        "symval=0x%x\n",
1641                        r_type,
1642                        pc,
1643                        addend,
1644                        r_symname,
1645                        r_symval);
1646             }
1647 #endif
1648             /*----------------------------------------------------------*/
1649             /* Perform actual relocation.  This is a really wide        */
1650             /* function interface and could do with some encapsulation. */
1651             /*----------------------------------------------------------*/
1652             reloc_do(r_type,
1653                      reloc_address,
1654                      addend,
1655                      r_symval,
1656                      pc,
1657                      0 /* static base, not yet supported */);
1660             if (change_endian)
1661                 rel_change_endian(r_type, reloc_address);
1663         }
1664         else if (found)
1665             break;
1666     }
1668     *start_rid = rid;
1669     return found;
1672 static BOOL process_rela_table(DLOAD_HANDLE handle,
1673                                DLIMP_Loaded_Segment* seg,
1674                                struct Elf32_Rela* rela_table,
1675                                uint32_t relanum,
1676                                int32_t* start_rid,
1677                                DLIMP_Dynamic_Module* dyn_module)
1679     Elf32_Addr seg_start_addr = seg->input_vaddr;
1680     Elf32_Addr seg_end_addr   = seg_start_addr + seg->phdr.p_memsz;
1681     BOOL found = FALSE;
1682     int32_t rid = *start_rid;
1684     if (rid >= relanum) rid = 0;
1686     for ( ; rid < relanum; rid++)
1687     {
1688         /*---------------------------------------------------------------*/
1689         /* If the relocation offset falls within the segment, process it */
1690         /*---------------------------------------------------------------*/
1691         if (rela_table[rid].r_offset >= seg_start_addr &&
1692             rela_table[rid].r_offset < seg_end_addr)
1693         {
1694             Elf32_Addr r_symval;
1695             ARM_RELOC_TYPE r_type = ELF32_R_TYPE(rela_table[rid].r_info);
1696             int32_t r_symid = ELF32_R_SYM(rela_table[rid].r_info);
1697             uint8_t* reloc_address;
1698             uint32_t pc;
1699             uint32_t addend;
1700             BOOL change_endian;
1702             found = TRUE;
1704             /*---------------------------------------------------------*/
1705             /* If symbol definition is not found don't do the          */
1706             /* relocation. An error is generated by the lookup         */
1707             /* function.                                               */
1708             /*---------------------------------------------------------*/
1709             if (!DLSYM_canonical_lookup(handle, r_symid, dyn_module, &r_symval))
1710                 continue;
1712             reloc_address = (((uint8_t*)(seg->phdr.p_vaddr) + seg->reloc_offset) +
1713                              rela_table[rid].r_offset - seg->input_vaddr);
1714             pc = (uint32_t) reloc_address;
1715             addend = rela_table[rid].r_addend;
1717             change_endian = rel_swap_endian(dyn_module, r_type);
1718             if (change_endian)
1719                 rel_change_endian(r_type, reloc_address);
1721 #if LOADER_DEBUG && LOADER_PROFILE
1722             if (debugging_on)
1723             {
1724                 char *r_symname = (char*) dyn_module->symtab[r_symid].st_name;
1725                 DLIF_trace("r_type=%d, "
1726                        "pc=0x%x, "
1727                        "addend=0x%x, "
1728                        "symnm=%s, "
1729                        "symval=0x%x\n",
1730                        r_type,
1731                        pc,
1732                        addend,
1733                        r_symname,
1734                        r_symval);
1735             }
1736 #endif
1738             /*----------------------------------------------------------*/
1739             /* Perform actual relocation.  This is a really wide        */
1740             /* function interface and could do with some encapsulation. */
1741             /*----------------------------------------------------------*/
1743             reloc_do(ELF32_R_TYPE(rela_table[rid].r_info),
1744                      reloc_address,
1745                      addend,
1746                      r_symval,
1747                      pc,
1748                      0);
1751             if (change_endian)
1752                 rel_change_endian(r_type, reloc_address);
1753         }
1754         else if (found)
1755             break;
1756     }
1758     *start_rid = rid;
1759     return found;
1762 /*****************************************************************************/
1763 /* READ_REL_TABLE() -                                                        */
1764 /*                                                                           */
1765 /*   Read in a REL type relocation table.  This function allocates host      */
1766 /*   memory for the table.                                                   */
1767 /*****************************************************************************/
1768 static void read_rel_table(struct Elf32_Rel** rel_table,
1769                            int32_t table_offset,
1770                            uint32_t relnum, uint32_t relent,
1771                            LOADER_FILE_DESC* elf_file,
1772                            BOOL wrong_endian)
1774    int i;
1775    *rel_table = (struct Elf32_Rel*) DLIF_malloc(relnum*relent);
1776     if (NULL == *rel_table) {
1777         DLIF_error(DLET_MEMORY,"Failed to Allocate read_rel_table\n");
1778         return;
1779     }
1780    DLIF_fseek(elf_file, table_offset, LOADER_SEEK_SET);
1781    DLIF_fread(*rel_table, relnum, relent, elf_file);
1783    if (wrong_endian)
1784       for (i=0; i<relnum; i++)
1785          DLIMP_change_rel_endian(*rel_table + i);
1788 /*****************************************************************************/
1789 /* READ_RELA_TABLE() -                                                       */
1790 /*                                                                           */
1791 /*   Read in a RELA type relocation table.  This function allocates host     */
1792 /*   memory for the table.                                                   */
1793 /*****************************************************************************/
1794 static void read_rela_table(struct Elf32_Rela** rela_table,
1795                             int32_t table_offset,
1796                             uint32_t relanum, uint32_t relaent,
1797                             LOADER_FILE_DESC* elf_file,
1798                             BOOL wrong_endian)
1800    int i;
1801    *rela_table = DLIF_malloc(relanum*relaent);
1802     if (NULL == *rela_table) {
1803         DLIF_error(DLET_MEMORY,"Failed to Allocate read_rela_table\n");
1804         return;
1805     }
1806    DLIF_fseek(elf_file, table_offset, LOADER_SEEK_SET);
1807    DLIF_fread(*rela_table, relanum, relaent, elf_file);
1809    if (wrong_endian)
1810       for (i=0; i<relanum; i++)
1811          DLIMP_change_rela_endian(*rela_table + i);
1814 /*****************************************************************************/
1815 /* PROCESS_GOT_RELOCS() -                                                    */
1816 /*                                                                           */
1817 /*   Process all GOT relocations. It is possible to have both REL and RELA   */
1818 /*   relocations in the same file, so we handle them both.                   */
1819 /*****************************************************************************/
1820 static void process_got_relocs(DLOAD_HANDLE handle,
1821                                struct Elf32_Rel* rel_table, uint32_t relnum,
1822                                struct Elf32_Rela* rela_table, uint32_t relanum,
1823                                DLIMP_Dynamic_Module* dyn_module)
1825    DLIMP_Loaded_Segment* seg =
1826       (DLIMP_Loaded_Segment*)(dyn_module->loaded_module->loaded_segments.buf);
1827    int seg_size = dyn_module->loaded_module->loaded_segments.size;
1828    int32_t rel_rid = 0;
1829    int32_t rela_rid = 0;
1830    int s;
1832    for (s=0; s<seg_size; s++)
1833    {
1834       /*---------------------------------------------------------------------*/
1835       /* Relocations into the BSS should not occur.                          */
1836       /*---------------------------------------------------------------------*/
1837       if(!seg[s].phdr.p_filesz) continue;
1839 #if LOADER_DEBUG && LOADER_PROFILE
1840       /*---------------------------------------------------------------------*/
1841       /* More details about the progress on this relocation entry.           */
1842       /*---------------------------------------------------------------------*/
1843       if (debugging_on)
1844       {
1845          DLIF_trace("Reloc segment %d:\n", s);
1846          DLIF_trace("addr=0x%x, old_addr=0x%x, r_offset=0x%x\n",
1847                 seg[s].phdr.p_vaddr, seg[s].input_vaddr, seg[s].reloc_offset);
1848       }
1849 #endif
1851       if (rela_table)
1852           process_rela_table(handle, (seg + s), rela_table, relanum,
1853                              &rela_rid, dyn_module);
1855       if (rel_table)
1856           process_rel_table(handle, (seg + s), rel_table, relnum, &rel_rid,
1857                             dyn_module);
1858     }
1861 /*****************************************************************************/
1862 /* PROCESS_PLTGOT_RELOCS                                                     */
1863 /*                                                                           */
1864 /*  Proceses all PLTGOT relocation entries.  The PLTGOT relocation table can */
1865 /*  be either REL or RELA type. All PLTGOT relocations are guaranteed to     */
1866 /*  belong to the same segment.                                              */
1867 /*****************************************************************************/
1868 static void process_pltgot_relocs(DLOAD_HANDLE handle,
1869                                   void* plt_reloc_table, int reltype,
1870                                   uint32_t pltnum,
1871                                   DLIMP_Dynamic_Module* dyn_module)
1873    Elf32_Addr r_offset = (reltype == DT_REL) ?
1874       ((struct Elf32_Rel*) plt_reloc_table)->r_offset :
1875       ((struct Elf32_Rela*) plt_reloc_table)->r_offset;
1876    DLIMP_Loaded_Segment* seg =
1877       (DLIMP_Loaded_Segment*)(dyn_module->loaded_module->loaded_segments.buf);
1878    int seg_size = dyn_module->loaded_module->loaded_segments.size;
1879    int32_t plt_rid = 0;
1880    int s;
1882    /*------------------------------------------------------------------------*/
1883    /* For each segment s, check if the relocation falls within s. If so,     */
1884    /* then all other relocations are guaranteed to fall with s. Process      */
1885    /* all relocations and then return.                                       */
1886    /*------------------------------------------------------------------------*/
1888    for (s=0; s<seg_size; s++)
1889    {
1890       Elf32_Addr seg_start_addr = seg[s].input_vaddr;
1891       Elf32_Addr seg_end_addr   = seg_start_addr + seg[s].phdr.p_memsz;
1893       /*---------------------------------------------------------------------*/
1894       /* Relocations into the BSS should not occur.                          */
1895       /*-------------------------------------------------------------------  */
1896       if(!seg[s].phdr.p_filesz) continue;
1898       if (r_offset >= seg_start_addr &&
1899           r_offset < seg_end_addr)
1900       {
1901          if (reltype == DT_REL)
1902             process_rel_table(handle, (seg + s),
1903                               (struct Elf32_Rel*) plt_reloc_table,
1904                               pltnum, &plt_rid,
1905                               dyn_module);
1906          else
1907             process_rela_table(handle, (seg + s),
1908                                (struct Elf32_Rela*) plt_reloc_table,
1909                                pltnum, &plt_rid,
1910                                dyn_module);
1912          break;
1913       }
1914    }
1917 /*****************************************************************************/
1918 /* RELOCATE() - Perform RELA and REL type relocations for given ELF object   */
1919 /*      file that we are in the process of loading and relocating.           */
1920 /*****************************************************************************/
1921 void DLREL_relocate(DLOAD_HANDLE handle,
1922                     LOADER_FILE_DESC* elf_file,
1923                     DLIMP_Dynamic_Module* dyn_module)
1926    struct Elf32_Dyn* dyn_nugget = dyn_module->dyntab;
1927    struct Elf32_Rela* rela_table = NULL;
1928    struct Elf32_Rel*  rel_table = NULL;
1929    void*              plt_table = NULL;
1931    /*------------------------------------------------------------------------*/
1932    /* Read the size of the relocation table (DT_RELASZ) and the size per     */
1933    /* relocation (DT_RELAENT) from the dynamic segment.                      */
1934    /*------------------------------------------------------------------------*/
1935    uint32_t relasz = DLIMP_get_first_dyntag(DT_RELASZ, dyn_nugget);
1936    uint32_t relaent = DLIMP_get_first_dyntag(DT_RELAENT, dyn_nugget);
1937    uint32_t relanum = 0;
1939    /*------------------------------------------------------------------------*/
1940    /* Read the size of the relocation table (DT_RELSZ) and the size per      */
1941    /* relocation (DT_RELENT) from the dynamic segment.                       */
1942    /*------------------------------------------------------------------------*/
1943    uint32_t relsz = DLIMP_get_first_dyntag(DT_RELSZ, dyn_nugget);
1944    uint32_t relent = DLIMP_get_first_dyntag(DT_RELENT, dyn_nugget);
1945    uint32_t relnum = 0;
1947    /*------------------------------------------------------------------------*/
1948    /* Read the size of the relocation table (DT_PLTRELSZ) and the type of    */
1949    /* of the PLTGOT relocation table (DT_PLTREL): one of DT_REL or DT_RELA   */
1950    /*------------------------------------------------------------------------*/
1951    uint32_t pltrelsz = DLIMP_get_first_dyntag(DT_PLTRELSZ, dyn_nugget);
1952    int      pltreltype = DLIMP_get_first_dyntag(DT_PLTREL, dyn_nugget);
1953    uint32_t pltnum = 0;
1955    /*------------------------------------------------------------------------*/
1956    /* Read the PLTGOT relocation table from the file                         */
1957    /* The PLTGOT table is a subsection at the end of either the DT_REL or    */
1958    /* DT_RELA table.  The size of the table it belongs to DT_REL(A)SZ        */
1959    /* includes the size of the PLTGOT table.  So it must be adjusted so that */
1960    /* the GOT relocation tables only contain actual GOT relocations.         */
1961    /*------------------------------------------------------------------------*/
1962    if (pltrelsz != INT_MAX)
1963    {
1964        if (pltreltype == DT_REL)
1965        {
1966           pltnum = pltrelsz/relent;
1967           relsz -= pltrelsz;
1968           read_rel_table(((struct Elf32_Rel**) &plt_table),
1969                          DLIMP_get_first_dyntag(DT_JMPREL, dyn_nugget),
1970                          pltnum, relent, elf_file,
1971                          dyn_module->wrong_endian);
1972        }
1973        else if (pltreltype == DT_RELA)
1974        {
1975            pltnum = pltrelsz/relaent;
1976            relasz -= pltrelsz;
1977            read_rela_table(((struct Elf32_Rela**) &plt_table),
1978                            DLIMP_get_first_dyntag(DT_JMPREL, dyn_nugget),
1979                            pltnum, relaent, elf_file,
1980                            dyn_module->wrong_endian);
1981        }
1982        else
1983        {
1984            DLIF_error(DLET_RELOC,
1985                       "DT_PLTREL is invalid: must be either %d or %d\n",
1986                       DT_REL, DT_RELA);
1987        }
1988    }
1990    /*------------------------------------------------------------------------*/
1991    /* Read the DT_RELA GOT relocation table from the file                    */
1992    /*------------------------------------------------------------------------*/
1993    if (relasz != INT_MAX)
1994    {
1995       relanum = relasz/relaent;
1996       read_rela_table(&rela_table, DLIMP_get_first_dyntag(DT_RELA, dyn_nugget),
1997                       relanum, relaent, elf_file, dyn_module->wrong_endian);
1998    }
2000    /*------------------------------------------------------------------------*/
2001    /* Read the DT_REL GOT relocation table from the file                     */
2002    /*------------------------------------------------------------------------*/
2003    if (relsz != INT_MAX)
2004    {
2005       relnum = relsz/relent;
2006       read_rel_table(&rel_table, DLIMP_get_first_dyntag(DT_REL, dyn_nugget),
2007                      relnum, relent, elf_file, dyn_module->wrong_endian);
2008    }
2010    /*------------------------------------------------------------------------*/
2011    /* Process the PLTGOT relocations                                         */
2012    /*------------------------------------------------------------------------*/
2013    if (plt_table)
2014       process_pltgot_relocs(handle, plt_table, pltreltype, pltnum, dyn_module);
2016    /*------------------------------------------------------------------------*/
2017    /* Process the GOT relocations                                            */
2018    /*------------------------------------------------------------------------*/
2019    if (rel_table || rela_table)
2020       process_got_relocs(handle, rel_table, relnum, rela_table, relanum,
2021                            dyn_module);
2023    /*-------------------------------------------------------------------------*/
2024    /* Free memory used for ELF relocation table copies.                       */
2025    /*-------------------------------------------------------------------------*/
2026    if (rela_table) DLIF_free(rela_table);
2027    if (rel_table)  DLIF_free(rel_table);
2028    if (plt_table)  DLIF_free(plt_table);
2031 /*****************************************************************************/
2032 /* UNIT TESTING INTERFACE.                                                   */
2033 /*****************************************************************************/
2034 #ifdef UNIT_TEST
2035 void unit_arm_reloc_do(ARM_RELOC_TYPE r_type,
2036                        uint8_t* address_space,
2037                        uint32_t addend, uint32_t symval, uint32_t pc,
2038                        uint32_t static_base, int wrong_endian)
2040     reloc_do(r_type, address_space, addend, symval, pc, static_base);
2043 void unit_arm_rel_unpack_addend(ARM_RELOC_TYPE r_type,
2044                                 uint8_t* address,
2045                                 uint32_t* addend)
2047     rel_unpack_addend(r_type, address, addend);
2050 BOOL unit_arm_rel_overflow(ARM_RELOC_TYPE r_type, int32_t reloc_value)
2052     return rel_overflow(r_type, reloc_value);
2055 void unit_arm_rel_mask_for_group(ARM_RELOC_TYPE r_type, int32_t* reloc_val)
2057     rel_mask_for_group(r_type, reloc_val);
2059 #endif