root/tools/elf2flt/elf-arm.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. apply_realloc
  2. apply_import

   1 /*
   2  * Basic ARM relocation processing
   3  *
   4  * Based on Linux elfloader
   5  *
   6  *      (c)2011 Sergey Taranenko aka tsvstar
   7  */
   8 #include <stdlib.h>
   9 #include <string.h>
  10 
  11 #include "myio.h"
  12 #include "elfflt.h"
  13 
  14 extern uint32_t offs_divsi3_skip_div0_test;
  15 extern uint32_t offs_div0_from_arm;
  16 extern uint32_t offs__aeabi_uidiv;
  17 
  18 int apply_realloc( struct relevant_section* base_sect, 
  19                    struct elf32_rela *rela, 
  20                    struct relevant_section* tgt_sect, 
  21                    struct elf32_sym *sym,
  22                    int i                                        // idx of symbol (for printf)
  23                    /*unsigned int tgtoffset*/)
  24 {
  25   unsigned int type  = ELF32_R_TYPE(rela->r_info);
  26   uint32_t locoffset = base_sect->flat_offset + rela->r_offset;
  27   char*    loc       = (char*)(flat_buf + locoffset );
  28   uint32_t tgt_fulloffset = tgt_sect->flat_offset + sym->st_value;      // full offset in flat target symbol
  29 
  30   int relindex = tgt_sect->number;      // to printf: num of tgt segment
  31   char symbuf[30];
  32   char* symname="";                     // to printf: name of symbol
  33   char* reloc_name="";
  34   int ret = b_seek_read(strtaboff + sym->st_name, symbuf, sizeof(symbuf));
  35   if (ret > 0) { symname=symbuf; symbuf[sizeof(symbuf)-1]=0; }
  36 
  37 
  38   int32_t offset;
  39   uint32_t upper, lower, sign, j1, j2;
  40   char* patch_name="";          // detected build-in function
  41 
  42 
  43   if (rela->r_offset > base_sect->size - sizeof(uint32_t)) {
  44             PRINTERR(stderr, "section %u(%s) reloc %u sym '%s': out of bounds relocation, offset %d size %u\n",
  45                     relindex, base_sect->name, i, symname,
  46                    rela->r_offset, base_sect->size);
  47             return ELFFLT_OUTOF_RANGE;
  48   }
  49 
  50   switch(type) {
  51     case R_ARM_ABS32:
  52         {
  53                 uint32_t addend = *(uint32_t*)loc;
  54             *(uint32_t*)loc += tgt_fulloffset;
  55 
  56                         if ( FLAG_DUMP_RELOC )
  57                                 printf( "R_ARM_ABS32: %p(%s+0x%x=%x): ptr=%x [%s+0x%x+0x%x] sym:%s\n", 
  58                                         base_sect->base_addr+rela->r_offset,  base_sect->name, rela->r_offset, locoffset,
  59                                         tgt_sect->base_addr + addend + sym->st_value,
  60                                         tgt_sect->name, sym->st_value, addend, symname
  61                                                 );
  62 
  63             if ( FLAG_VERBOSE)            
  64                printf("=== flt%p(reloc+%x: %x): [%x]=0x%x\n",flat_reloc_cur, (char*)flat_reloc_cur-(char*)flat_reloc, (char*)flat_reloc_cur-flat_buf, locoffset, *(uint32_t*)loc);
  65                 *flat_reloc_cur = locoffset;
  66                 flat_reloc_cur++;
  67             flat_reloc_count++;
  68         }
  69         break;
  70 
  71       case R_ARM_THM_CALL:
  72       case R_ARM_THM_JUMP24:    //needed on arm-none-eabi
  73               upper = *(uint16_t *)loc;
  74               lower = *(uint16_t *)(loc + 2);
  75       
  76               /*
  77                * 25 bit signed address range (Thumb-2 BL and B.W
  78                * instructions):
  79                *   S:I1:I2:imm10:imm11:0
  80                * where:
  81                *   S     = upper[10]   = offset[24]
  82                *   I1    = ~(J1 ^ S)   = offset[23]
  83                *   I2    = ~(J2 ^ S)   = offset[22]
  84                *   imm10 = upper[9:0]  = offset[21:12]
  85                *   imm11 = lower[10:0] = offset[11:1]
  86                *   J1    = lower[13]
  87                *   J2    = lower[11]
  88                */
  89               sign = (upper >> 10) & 1;
  90               j1 = (lower >> 13) & 1;
  91               j2 = (lower >> 11) & 1;
  92               offset = (sign << 24) | ((~(j1 ^ sign) & 1) << 23) |
  93                       ((~(j2 ^ sign) & 1) << 22) |
  94                       ((upper & 0x03ff) << 12) |
  95                       ((lower & 0x07ff) << 1);
  96               if (offset & 0x01000000)
  97                       offset -= 0x02000000;
  98               offset += tgt_fulloffset - locoffset;
  99       
 100               /*
 101                * For function symbols, only Thumb addresses are
 102                * allowed (no interworking).
 103                *
 104                * For non-function symbols, the destination
 105                * has no specific ARM/Thumb disposition, so
 106                * the branch is resolved under the assumption
 107                * that interworking is not required.
 108                */
 109                 if ((ELF32_ST_TYPE(sym->st_info) == STT_FUNC &&
 110                       !(offset & 1)) ||
 111                   offset <= (int32_t)0xff000000 ||
 112                   offset >= (int32_t)0x01000000) {
 113                       PRINTERR(stderr, "section %u reloc %u sym '%s': relocation %u out of range (%#lx -> %#x)\n",
 114                               relindex, i, symname,
 115                              ELF32_R_TYPE(rela->r_info), locoffset,
 116                              sym->st_value);
 117                       return ELFFLT_OUTOF_RANGE;
 118               }
 119       
 120                           if ( FLAG_DUMP_RELOC )
 121                         printf( "R_ARM_THM_CALL: %p(%s+0x%x=%x):  %04x %04x ptr=%x [loc%-d] sym:%s\n", 
 122                                         base_sect->base_addr+rela->r_offset,  base_sect->name, rela->r_offset, locoffset,
 123                                         upper, lower,
 124                                         tgt_sect->base_addr+rela->r_offset+offset, offset,
 125                                         symname);
 126 
 127               sign = (offset >> 24) & 1;
 128               j1 = sign ^ (~(offset >> 23) & 1);
 129               j2 = sign ^ (~(offset >> 22) & 1);
 130               *(uint16_t *)loc = (uint16_t)((upper & 0xf800) | (sign << 10) |
 131                                   ((offset >> 12) & 0x03ff));
 132               *(uint16_t *)(loc + 2) = (uint16_t)((lower & 0xd000) |
 133                                         (j1 << 13) | (j2 << 11) |
 134                                         ((offset >> 1) & 0x07ff));
 135               break;
 136 
 137       case R_ARM_PC24:
 138       case R_ARM_JUMP24:
 139       case R_ARM_CALL:
 140                           // R_ARM_PC24 is generated by Win arm-gcc. And in some buildin funcs change
 141                                 // this pointer to different function. This part is emulate this behaviour.
 142 
 143               patch_name=0;
 144                           if ( strcmp(symname,"__div0") == 0 )
 145               {
 146                               if ( locoffset == offs_divsi3_skip_div0_test )
 147                                         patch_name=".divsi3_skip_div0_test";
 148                               else if ( locoffset == offs__aeabi_uidiv )
 149                                         patch_name="__aeabi_uidiv";
 150 
 151                               if ( !patch_name ) {
 152                                             PRINTERR( stderr, "%s is requested from unusual place .text+0x%x\n", reloc_name,locoffset-text.flat_offset);
 153                                             return ELFFLT_UNHANDLED_RELOC;
 154                               }
 155 
 156                               // this is redirection to the new func
 157                               tgt_fulloffset = (text.flat_offset + offs_div0_from_arm);
 158                   // Falls through to next case - no break ***
 159               }
 160 
 161       case R_ARM_PLT32:
 162                         // R_ARM_PLT32 is generated by linux arm-gcc and it doesn't change binary when instance into fixed adress
 163 
 164 //      case R_ARM_CALL:                // not needed
 165 //      case R_ARM_JUMP24:              // not needed
 166 
 167                           reloc_name = (type==R_ARM_PC24)?"R_ARM_PC24":"R_ARM_PLT32";
 168 
 169               offset = (*(uint32_t *)loc & 0x00ffffff) << 2;
 170               if (offset & 0x02000000)
 171                   offset -= 0x04000000;
 172       
 173               offset += tgt_fulloffset - locoffset;
 174 
 175 /* it is possible to have offset close to upper border
 176               if (offset & 3 ||
 177                   offset <= (int32_t)0xfe000000 ||
 178                   offset >= (int32_t)0x02000000) {
 179                       PRINTERR(stderr, "section %u reloc %u sym '%s': relocation %u out of range (%#lx -> %#x)\n",
 180                              relindex, i, symname,
 181                              ELF32_R_TYPE(rela->r_info), locoffset,
 182                              tgt_fulloffset);
 183                 return ELFFLT_OUTOF_RANGE;
 184               }
 185 */
 186      
 187               offset >>= 2;
 188 
 189               if ( FLAG_DUMP_RELOC )
 190               {
 191                   printf( "%s: %p(%s+0x%x=%x):  %08x ptr=%x [loc%-d] sym:%s\n", reloc_name,
 192                       base_sect->base_addr+rela->r_offset,  base_sect->name, rela->r_offset, locoffset,
 193                       *(uint32_t *)loc,
 194                       base_sect->base_addr+rela->r_offset+offset*4, offset*4,
 195                       symname);
 196                   if ((type==R_ARM_PC24) && patch_name)
 197                       printf( "...Patched 0x%x(__div0)->0x%x (__div0_from_arm) for %s\n",  sym->st_value, offs_div0_from_arm, patch_name);
 198               }
 199 
 200               *(uint32_t *)loc &= 0xff000000;
 201               *(uint32_t *)loc |= offset & 0x00ffffff;
 202               break;
 203         default:
 204                 PRINTERR(stderr, "Unknown relocation type %d\n",type);
 205                 return ELFFLT_UNHANDLED_RELOC;
 206         }
 207  
 208   return ELFFLT_OK;
 209 }
 210 
 211 
 212 
 213 
 214 int apply_import( struct relevant_section* base_sect, 
 215                    struct elf32_rela *rela, 
 216                    int importidx, 
 217                    struct elf32_sym *sym
 218                  )
 219 {
 220   unsigned int type  = ELF32_R_TYPE(rela->r_info);
 221   uint32_t locoffset = base_sect->flat_offset + rela->r_offset;
 222   char*    loc       = (char*)(flat_buf + locoffset );
 223 
 224   char symbuf[30];
 225   char* symname="";                     // to printf: name of symbol
 226   int ret = b_seek_read(strtaboff + sym->st_name, symbuf, sizeof(symbuf));
 227   if (ret > 0) { symname=symbuf; symbuf[sizeof(symbuf)-1]=0; }
 228 
 229   switch(type) {
 230     case R_ARM_ABS32:
 231         {
 232                 flat_import_cur->offs = locoffset;
 233                 flat_import_cur->importidx = importidx;
 234 
 235                 if ( FLAG_DUMP_RELOC )
 236                                 printf( "R_ARM_ABS32: %p(%s+0x%x=%x): import_value=%d (sym:%s)+0x%x %d\n", 
 237                                         base_sect->base_addr+rela->r_offset,  base_sect->name, rela->r_offset, locoffset,
 238                                          importidx, symname, *(uint32_t*)loc, flat_import_count
 239                                                 );
 240                 flat_import_cur++;
 241             flat_import_count++;
 242         }
 243         break;
 244 
 245         default:
 246                 // Use only ABS32 because we can't be sure that module will be loaded not too far from core to PC24/THM_CALL
 247                 PRINTERR(stderr, "Only R_ARM_ABS32 relocations could be processed as imported symbol (%s). Please compile with -mlong-call or use manual import\n",symname);
 248                 return ELFFLT_UNHANDLED_RELOC;
 249   }
 250   return ELFFLT_OK;
 251 }

/* [<][>][^][v][top][bottom][index][help] */