SylixOS中AARCH64跳轉表實現原理
阿新 • • 發佈:2018-10-23
body 當前位置 當前 () sylixos water 實現原理 armv8 .text 1. 跳轉表存在的意義
跳轉表使用的方式如下圖所示,其中“跳轉表所在的位置”與“當前指令位置”的地址偏移範圍為±128MB之內,因此,可以首先從當前位置跳轉到跳轉表中的某一個表項。
1.1 內核模塊反匯編
如下的程序清單,為一個內核模塊的源碼。
#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,這是因為實際的跳轉地址會在動態加載時進行調整。
94000000 bl 0 <API_LogPrintk>
1.2 BL指令分析
查閱ARMv8手冊,BL指令的結構如下圖所示。
按照該結構可知,BL指令最大的跳轉範圍為4×226 = 256MB,即±128MB。但是“實際需跳轉位置”與“當前指令位置”的地址偏移很有可能超過該範圍。所以在動態加載時,需要修改這條指令的實現,使得其具有跳轉到整個64位地址空間的能力。
2. AARCH64跳轉表實現
2.1 利用跳轉表進行跳轉
通常的做法是采用跳轉表進行實現。
2.2 BR跳轉指令
BR跳轉指令使用寄存器進行跳轉,那麽該指令具體264地址空間跳轉的能力,因此跳轉表可以借助該指令進行實現。
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位數移入寄存器,所以必須將移位操作分為四步完成,如上表所示。
此時,在動態加載時,按照如下方式進行跳轉:
1、 將原來的BL指令中目的跳轉位置,調整為跳轉表對應表項的位置;
2、 跳轉表會將實際跳轉地址更新到X16寄存器中;
3、 通過BR指令跳轉到實際的目標地址。
SylixOS中AARCH64跳轉表實現原理