SylixOS中AARCH64跳轉表實現原理

1. 跳轉表存在的意義

1.1 內核模塊反彙編

以下的程序清單,爲一個內核模塊的源碼。sass

#define  __SYLIXOS_KERNEL
#include <SylixOS.h>
#include <module.h>
 

/*
 *  SylixOS call module_init() and module_exit() automatically.
 */
int module_init (void)
{
    printk("hello_module init!\n");
    return 0;
}

void module_exit (void)
{
}

反彙編以後的內容以下所示。函數

kmTest.ko:     file format elf64-littleaarch64
Disassembly of section .text:
0000000000000000 <module_init>:
/*
 *  SylixOS call module_init() and module_exit() automatically.
 */
int module_init (void)
{
   0:	a9bf7bfd 	stp	x29, x30, [sp, #-16]!
   4:	910003fd 	mov	x29, sp
    printk("hello_module init!\n");
   8:	90000000 	adrp	x0, 0 <module_init>
   c:	91000000 	add	x0, x0, #0x0
  10:	f9400000 	ldr	x0, [x0]
  14:	94000000 	bl	0 <API_LogPrintk>
    return 0;
  18:	52800000 	mov	w0, #0x0                   	// #0
}
  1c:	a8c17bfd 	ldp	x29, x30, [sp], #16
  20:	d65f03c0 	ret
  24:	d503201f 	nop
	...
0000000000000030 <module_exit>:
void module_exit (void)
{
}
  30:	d503201f 	nop
  34:	d65f03c0 	ret

從以上反彙編結果可知,printk函數調用會被彙編爲BL指令,而且跳轉的目的地址爲0,這是由於實際的跳轉地址會在動態加載時進行調整。3d

94000000 	bl	0 <API_LogPrintk>

1.2 BL指令分析

查閱ARMv8手冊,BL指令的結構以下圖所示。 BL指令結構 按照該結構可知,BL指令最大的跳轉範圍爲4×226 = 256MB,即±128MB。可是「實際需跳轉位置」與「當前指令位置」的地址偏移頗有可能超過該範圍。因此在動態加載時,須要修改這條指令的實現,使得其具備跳轉到整個64位地址空間的能力。code

2. AARCH64跳轉表實現

2.1 利用跳轉表進行跳轉

一般的作法是採用跳轉表進行實現。 跳轉表使用的方式以下圖所示,其中「跳轉表所在的位置」與「當前指令位置」的地址偏移範圍爲±128MB以內,所以,能夠首先從當前位置跳轉到跳轉表中的某一個表項。 利用跳轉表進行跳轉orm

2.2 BR跳轉指令

BR跳轉指令使用寄存器進行跳轉,那麼該指令具體264地址空間跳轉的能力,所以跳轉表能夠藉助該指令進行實現。blog

2.3 跳轉表結構

字節 指令內容
[16:19] movn x16, #0x….
[12:15] movk x16, #0x…., lsl #16
[08:11] movk x16, #0x…., lsl #32
[04:07] movk x16, #0x…., lsl #48
[00:03] br x16
由於MOV指令不能一次將一個64位數移入寄存器,因此必須將移位操做分爲四步完成,如上表所示。
此時,在動態加載時,按照以下方式進行跳轉:

一、 將原來的BL指令中目的跳轉位置,調整爲跳轉表對應表項的位置;v8

二、 跳轉表會將實際跳轉地址更新到X16寄存器中;源碼

三、 經過BR指令跳轉到實際的目標地址。it

相關文章
相關標籤/搜索