122 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			122 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|  | /*
 | ||
|  |  * Copyright (c) 2006-2018, RT-Thread Development Team | ||
|  |  * | ||
|  |  * SPDX-License-Identifier: Apache-2.0 | ||
|  |  *  | ||
|  |  * Change Logs: | ||
|  |  * Date           Author      Notes | ||
|  |  * 2018/08/29     Bernard     first version | ||
|  |  */ | ||
|  | 
 | ||
|  | #include "../dlmodule.h"
 | ||
|  | #include "../dlelf.h"
 | ||
|  | 
 | ||
|  | #ifdef __arm__
 | ||
|  | int dlmodule_relocate(struct rt_dlmodule *module, Elf32_Rel *rel, Elf32_Addr sym_val) | ||
|  | { | ||
|  |     Elf32_Addr *where, tmp; | ||
|  |     Elf32_Sword addend, offset; | ||
|  |     rt_uint32_t upper, lower, sign, j1, j2; | ||
|  | 
 | ||
|  |     where = (Elf32_Addr *)((rt_uint8_t *)module->mem_space | ||
|  |                            + rel->r_offset | ||
|  |                            - module->vstart_addr); | ||
|  |     switch (ELF32_R_TYPE(rel->r_info)) | ||
|  |     { | ||
|  |     case R_ARM_NONE: | ||
|  |         break; | ||
|  |     case R_ARM_ABS32: | ||
|  |         *where += (Elf32_Addr)sym_val; | ||
|  |         RT_DEBUG_LOG(RT_DEBUG_MODULE, ("R_ARM_ABS32: %x -> %x\n", | ||
|  |                                        where, *where)); | ||
|  |         break; | ||
|  |     case R_ARM_PC24: | ||
|  |     case R_ARM_PLT32: | ||
|  |     case R_ARM_CALL: | ||
|  |     case R_ARM_JUMP24: | ||
|  |         addend = *where & 0x00ffffff; | ||
|  |         if (addend & 0x00800000) | ||
|  |             addend |= 0xff000000; | ||
|  |         tmp = sym_val - (Elf32_Addr)where + (addend << 2); | ||
|  |         tmp >>= 2; | ||
|  |         *where = (*where & 0xff000000) | (tmp & 0x00ffffff); | ||
|  |         RT_DEBUG_LOG(RT_DEBUG_MODULE, ("R_ARM_PC24: %x -> %x\n", | ||
|  |                                        where, *where)); | ||
|  |         break; | ||
|  |     case R_ARM_REL32: | ||
|  |         *where += sym_val - (Elf32_Addr)where; | ||
|  |         RT_DEBUG_LOG(RT_DEBUG_MODULE, | ||
|  |                      ("R_ARM_REL32: %x -> %x, sym %x, offset %x\n", | ||
|  |                       where, *where, sym_val, rel->r_offset)); | ||
|  |         break; | ||
|  |     case R_ARM_V4BX: | ||
|  |         *where &= 0xf000000f; | ||
|  |         *where |= 0x01a0f000; | ||
|  |         break; | ||
|  | 
 | ||
|  |     case R_ARM_GLOB_DAT: | ||
|  |     case R_ARM_JUMP_SLOT: | ||
|  |         *where = (Elf32_Addr)sym_val; | ||
|  |         RT_DEBUG_LOG(RT_DEBUG_MODULE, ("R_ARM_JUMP_SLOT: 0x%x -> 0x%x 0x%x\n", | ||
|  |                                        where, *where, sym_val)); | ||
|  |         break; | ||
|  | #if 0        /* To do */
 | ||
|  |     case R_ARM_GOT_BREL: | ||
|  |         temp   = (Elf32_Addr)sym_val; | ||
|  |         *where = (Elf32_Addr)&temp; | ||
|  |         RT_DEBUG_LOG(RT_DEBUG_MODULE, ("R_ARM_GOT_BREL: 0x%x -> 0x%x 0x%x\n", | ||
|  |                                        where, *where, sym_val)); | ||
|  |         break; | ||
|  | #endif
 | ||
|  | 
 | ||
|  |     case R_ARM_RELATIVE: | ||
|  |         *where = (Elf32_Addr)sym_val + *where; | ||
|  |         RT_DEBUG_LOG(RT_DEBUG_MODULE, ("R_ARM_RELATIVE: 0x%x -> 0x%x 0x%x\n", | ||
|  |                                        where, *where, sym_val)); | ||
|  |         break; | ||
|  |     case R_ARM_THM_CALL: | ||
|  |     case R_ARM_THM_JUMP24: | ||
|  |         upper  = *(rt_uint16_t *)where; | ||
|  |         lower  = *(rt_uint16_t *)((Elf32_Addr)where + 2); | ||
|  | 
 | ||
|  |         sign   = (upper >> 10) & 1; | ||
|  |         j1     = (lower >> 13) & 1; | ||
|  |         j2     = (lower >> 11) & 1; | ||
|  |         offset = (sign << 24) | | ||
|  |                  ((~(j1 ^ sign) & 1) << 23) | | ||
|  |                  ((~(j2 ^ sign) & 1) << 22) | | ||
|  |                  ((upper & 0x03ff) << 12) | | ||
|  |                  ((lower & 0x07ff) << 1); | ||
|  |         if (offset & 0x01000000) | ||
|  |             offset -= 0x02000000; | ||
|  |         offset += sym_val - (Elf32_Addr)where; | ||
|  | 
 | ||
|  |         if (!(offset & 1) || | ||
|  |             offset <= (rt_int32_t)0xff000000 || | ||
|  |             offset >= (rt_int32_t)0x01000000) | ||
|  |         { | ||
|  |             rt_kprintf("Module: Only Thumb addresses allowed\n"); | ||
|  | 
 | ||
|  |             return -1; | ||
|  |         } | ||
|  | 
 | ||
|  |         sign = (offset >> 24) & 1; | ||
|  |         j1   = sign ^ (~(offset >> 23) & 1); | ||
|  |         j2   = sign ^ (~(offset >> 22) & 1); | ||
|  |         *(rt_uint16_t *)where = (rt_uint16_t)((upper & 0xf800) | | ||
|  |                                               (sign << 10) | | ||
|  |                                               ((offset >> 12) & 0x03ff)); | ||
|  |         *(rt_uint16_t *)(where + 2) = (rt_uint16_t)((lower & 0xd000) | | ||
|  |                                                     (j1 << 13) | (j2 << 11) | | ||
|  |                                                     ((offset >> 1) & 0x07ff)); | ||
|  |         upper = *(rt_uint16_t *)where; | ||
|  |         lower = *(rt_uint16_t *)((Elf32_Addr)where + 2); | ||
|  |         break; | ||
|  |     default: | ||
|  |         return -1; | ||
|  |     } | ||
|  | 
 | ||
|  |     return 0; | ||
|  | } | ||
|  | #endif
 |