在64位CPU上使用32位指令“swi”
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在64位CPU上使用32位指令“swi”相关的知识,希望对你有一定的参考价值。
我正在使用raspberry pi 3制作我的内核(没有蓝牙)。我的内核使用arm汇编语言(32位),c和uboot启动我的内核。
我找到了中断向量表并将其应用到我的代码中。
.globl _ram_entry
_ram_entry:
bl kernel_init
b _ram_entry //
ldr pc,=print_mem1
b print_mem1
b print_mem1
b print_mem2
b print_mem3
b print_mem4
b print_mem1
b print_mem2
b print_mem3
b print_mem4
#define svc_stack 0xa0300000
#define irq_stack 0xa0380000
#define sys_stack 0xa0400000
.global kernel_init
kernel_init:
ldr r0,=0x00080008
mov r1,#0x0000
ldmia r0!,{r2,r3,r4,r5}
stmia r1!,{r2,r3,r4,r5}
ldmia r0!,{r2,r3,r4,r5}
stmia r1!,{r2,r3,r4,r5}
ldmia r0!,{r2,r3,r4,r5}
stmia r1!,{r2,r3,r4,r5}
ldmia r0!,{r2,r3,r4,r5}
stmia r1!,{r2,r3,r4,r5}
bl main
b _ram_entry
.global print_mem1
print_mem1:
bl print_c_mem1
.global print_mem2
print_mem2:
bl print_c_mem2
.global print_mem3
print_mem3:
bl print_c_mem3
.global print_mem4
print_mem4:
bl print_c_mem4
_ram_entry从0x00080008开始,这是我的中断向量表。当我打印我的内存时,0x00有bl kernel_init。所有中断处理程序只打印简单数字。
但是,如果我像这个主代码一样使用swi,则调用重置处理程序。
int main()
{
R_GPIO_REGS * gp_regs= (R_GPIO_REGS*)GPIO_BASE_ADDRESS;
gp_regs->GPFSEL[1] =0x1000000;
uart_init();
printf("hellow world
");
vector_memory_dump();
unsigned int destrst=0xea020000;
unsigned int destirq=0xea020000;
unsigned int destswi=0xea020000;
PUT32(MEMZERO,destrst);
PUT32(MEMY,destirq);
PUT32(MEMSWI,destswi);
vector_memory_dump();
//asm("b 0x04");
asm("swi 0"); //which call swi handler on 0x08. I thought.
while(1)
{
gp_regs->GPSET[0]=0x40000;
}
return 0;
}
有什么问题?
所以从标签等我认为这是一个覆盆子pi3,在aarch32模式,可能是HYP模式。注意我非常感谢您直接或间接阅读/借用我的一些代码。
使用您的代码可以从这里开始:
ldr r0,=0x00080008
mov r1,#0x0000
这在技术上不是一个错误,但有点错过了该副本的作用。
b print_mem1
b print_mem1
b print_mem2
b print_mem3
b print_mem4
b print_mem1
b print_mem2
b print_mem3
b print_mem4
结合这些然后是的,这是一个问题。因为它们是位置依赖的,并且让工具链为您创建表格的整个想法然后复制它就会丢失。
Disassembly of section .text:
00080000 <_ram_entry>:
80000: eb00000a bl 80030 <kernel_init>
80004: eafffffd b 80000 <_ram_entry>
80008: e59ff074 ldr pc, [pc, #116] ; 80084 <print_c_mem4+0x4>
8000c: ea000013 b 80060 <print_mem1>
80010: ea000012 b 80060 <print_mem1>
80014: ea000012 b 80064 <print_mem2>
80018: ea000012 b 80068 <print_mem3>
8001c: ea000012 b 8006c <print_mem4>
80020: ea00000e b 80060 <print_mem1>
80024: ea00000e b 80064 <print_mem2>
80028: ea00000e b 80068 <print_mem3>
8002c: ea00000e b 8006c <print_mem4>
当我组装然后反汇编,ldr pc,这是正确的方法来做到这一点,但登陆错误的地方显示0x80084,这是84-8 = 0x7C提前,这是1111100 0x1F寄存器用于复制到那么远所以...
ldmia r0!,{r2,r3,r4,r5}
stmia r1!,{r2,r3,r4,r5}
ldmia r0!,{r2,r3,r4,r5}
stmia r1!,{r2,r3,r4,r5}
ldmia r0!,{r2,r3,r4,r5}
stmia r1!,{r2,r3,r4,r5}
ldmia r0!,{r2,r3,r4,r5}
stmia r1!,{r2,r3,r4,r5}
32个寄存器,复制0x80字节。技术上,覆盖第一个矢量可能是第二个,但肯定不是swi矢量。
当你再次查看arm文档时(armv7-ar,因为这是aarch32或armv7-兼容模式)0x00000008是supervisor / svc / swi调用的入口点。
因此,您需要一条从0x00000008到所需地址/标签的指令。
所以,如果你回到这个例子或你从中借鉴/学习的任何例子。
.globl _start
_start:
ldr pc,reset_handler
ldr pc,undefined_handler
ldr pc,swi_handler
ldr pc,prefetch_handler
ldr pc,data_handler
ldr pc,unused_handler
ldr pc,irq_handler
ldr pc,fiq_handler
reset_handler: .word reset
undefined_handler: .word hang
swi_handler: .word hang
prefetch_handler: .word hang
data_handler: .word hang
unused_handler: .word hang
irq_handler: .word irq
fiq_handler: .word hang
reset:
mov r0,#0x80000
mov r1,#0x0000
ldmia r0!,{r2,r3,r4,r5,r6,r7,r8,r9}
stmia r1!,{r2,r3,r4,r5,r6,r7,r8,r9}
ldmia r0!,{r2,r3,r4,r5,r6,r7,r8,r9}
stmia r1!,{r2,r3,r4,r5,r6,r7,r8,r9}
Disassembly of section .text:
00080000 <_stack>:
80000: e59ff018 ldr pc, [pc, #24] ; 80020 <reset_handler>
80004: e59ff018 ldr pc, [pc, #24] ; 80024 <undefined_handler>
80008: e59ff018 ldr pc, [pc, #24] ; 80028 <swi_handler>
8000c: e59ff018 ldr pc, [pc, #24] ; 8002c <prefetch_handler>
80010: e59ff018 ldr pc, [pc, #24] ; 80030 <data_handler>
80014: e59ff018 ldr pc, [pc, #24] ; 80034 <unused_handler>
80018: e59ff018 ldr pc, [pc, #24] ; 80038 <irq_handler>
8001c: e59ff018 ldr pc, [pc, #24] ; 8003c <fiq_handler>
00080020 <reset_handler>:
80020: 00080040 andeq r0, r8, r0, asr #32
00080024 <undefined_handler>:
80024: 00080058 andeq r0, r8, r8, asr r0
00080028 <swi_handler>:
80028: 00080058 andeq r0, r8, r8, asr r0
0008002c <prefetch_handler>:
8002c: 00080058 andeq r0, r8, r8, asr r0
00080030 <data_handler>:
80030: 00080058 andeq r0, r8, r8, asr r0
00080034 <unused_handler>:
80034: 00080058 andeq r0, r8, r8, asr r0
00080038 <irq_handler>:
80038: 0008005c andeq r0, r8, ip, asr r0
0008003c <fiq_handler>:
8003c: 00080058 andeq r0, r8, r8, asr r0
00080040 <reset>:
80040: e3a00702 mov r0, #524288 ; 0x80000
80044: e3a01000 mov r1, #0
80048: e8b003fc ldm r0!, {r2, r3, r4, r5, r6, r7, r8, r9}
8004c: e8a103fc stmia r1!, {r2, r3, r4, r5, r6, r7, r8, r9}
80050: e8b003fc ldm r0!, {r2, r3, r4, r5, r6, r7, r8, r9}
80054: e8a103fc stmia r1!, {r2, r3, r4, r5, r6, r7, r8, r9}
00080058 <hang>:
80058: eafffffe b 80058 <hang>
0008005c <irq>:
8005c: eafffffe b 8005c <irq>
它强制将8个字的入口点从异常处理程序表中启动,然后在接下来的8个单词中将这些地址放在pc相对访问权限之后,这样你就需要复制16个单词让汇编程序为你完成工作。不必计算这些东西。 32个字,4个指令各8个寄存器,即32个字。或者如果你喜欢8套指令,每个指令4个单词也可以。
这就是你对整个方法的追求
80008: e59ff018 ldr pc, [pc, #24] ; 80028 <swi_handler>
00080028 <swi_handler>:
80028: 00080058
使工具为您完成工作
如果我这样做怎么办:
.globl _start
_start:
ldr pc,reset_handler
ldr pc,undefined_handler
ldr pc,swi_handler
ldr pc,prefetch_handler
ldr pc,data_handler
ldr pc,unused_handler
b irq
ldr pc,fiq_handler
reset_handler: .word reset
undefined_handler: .word hang
swi_handler: .word hang
prefetch_handler: .word hang
data_handler: .word hang
unused_handler: .word hang
irq_handler: .word irq
fiq_handler: .word hang
reset:
mov r0,#0x80000
mov r1,#0x0000
ldmia r0!,{r2,r3,r4,r5,r6,r7,r8,r9}
stmia r1!,{r2,r3,r4,r5,r6,r7,r8,r9}
ldmia r0!,{r2,r3,r4,r5,r6,r7,r8,r9}
stmia r1!,{r2,r3,r4,r5,r6,r7,r8,r9}
hang:
b hang
irq:
b irq
我明白了
80018: ea00000f b 8005c <irq>
而不是这个
80018: e59ff018 ldr pc, [pc, #24] ; 80038 <irq_handler>
后者是说从pc + 24读取,在这种情况下,pc是8,因此指令地址+ 32是指令地址+ 0x20。
还有这个
80018: ea00000f b 8005c <irq>
说要在指令地址之前转移到地址0x44
现在让我们从不同的基地址进行反汇编,例如对象(而不是链接的elf二进制文件)是一个很好的选择
00000000 <_start>:
0: e59ff018 ldr pc, [pc, #24] ; 20 <reset_handler>
4: e59ff018 ldr pc, [pc, #24] ; 24 <undefined_handler>
8: e59ff018 ldr pc, [pc, #24] ; 28 <swi_handler>
c: e59ff018 ldr pc, [pc, #24] ; 2c <prefetch_handler>
10: e59ff018 ldr pc, [pc, #24] ; 30 <data_handler>
14: e59ff018 ldr pc, [pc, #24] ; 34 <unused_handler>
18: ea00000f b 5c <irq>
1c: e59ff018 ldr pc, [pc, #24] ; 3c <fiq_handler>
注意所有其他机器的机器代码,将该指令前的0x20字节加载到pc中。
分支表示程序计数器前面的分支0x44字节。
我们使用工具链制作该表
00080020 <reset_handler>:
80020: 00080040 andeq r0, r8, r0, asr #32
00080024 <undefined_handler>:
80024: 00080058 andeq r0, r8, r8, asr r0
00080028 <swi_handler>:
80028: 00080058 andeq r0, r8, r8, asr r0
0008002c <prefetch_handler>:
8002c: 00080058 andeq r0, r8, r8, asr r0
00080030 <data_handler>:
80030: 00080058 andeq r0, r8, r8, asr r0
00080034 <unused_handler>:
80034: 00080058 andeq r0, r8, r8, asr r0
00080038 <irq_handler>:
80038: 0008005c andeq r0, r8, ip, asr r0
0008003c <fiq_handler>:
8003c: 00080058 andeq r0, r8, r8, asr r0
如果我们将0x40字节从0x80000复制到0x00000,那么当它到达0x18处的机器代码(从0x38读取并将其放入程序计数器)然后它将获得0008005c这是正确的位置
但如果相反它找到
18: ea00000f b 5c <irq>
这意味着分支到0x5c,我们没有处理程序。
所以除了没有设置堆栈指针,你的代码如何使它成为swi,但无论如何,如果你构建了这个
80008: e59ff074 ldr pc, [pc, #116] ; 80084 <print_c_mem4+0x4>
8000c: ea000013 b 80060 <print_mem1>
80010: ea000012 b 80060 <print_mem1>
80014: ea000012 b 80064 <print_mem2>
80018: ea000012 b 80068 <print_mem3>
8001c: ea000012 b 8006c <print_mem4>
80020: ea00000e b 80060 <print_mem1>
80024: ea00000e b 80064 <print_mem2>
80028: ea00000e b 80068 <print_mem3>
8002c: ea00000e b 8006c <print_mem4>
或类似的东西,因为你的print_mems不只是占位符来得到这个例子来构建这个答案。但仍然是pc相对分支机构。
以上是关于在64位CPU上使用32位指令“swi”的主要内容,如果未能解决你的问题,请参考以下文章
64bit到底是啥?操作系统和cpu都在说64bit,但我不了解这到底是啥。