QEMU ARM64 Uboot
以virt machine 为例,
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
make qemu_arm64_defconfig
make -j16
make CROSS_COMPILE=aarch64-linux-gnu- -j2
QEMU启动
qemu-system-aarch64 \
-M virt \
-cpu cortex-a72 \
-smp 2 \
-m 2048M \
-kernel u-boot \
-nographic
qemu-system-aarch64: unable to find CPU model 'cortex-a72'
qemu-system-aarch64 -M virt -cpu cortex-a53 -smp 2 -m 2048M -kernel u-boot -nographic
qemu-system-aarch64 -M virt -cpu cortex-a53 -m 2048M -kernel u-boot -nographic
qemu quit:
ctrl+A -> wait a moment ->+X
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* relocate - common relocation function for AArch64 U-Boot
*
* (C) Copyright 2013
* Albert ARIBAUD <albert.u.boot@aribaud.net>
* David Feng <fenghua@phytium.com.cn>
*/
#include <asm-offsets.h>
#include <config.h>
#include <elf.h>
#include <linux/linkage.h>
#include <asm/macro.h>
//ARM64 有34个寄存器,包括31个通用寄存器,SP,PC,CPSR.
//x0-x30 64bit 通用寄存器,如果有需要可以当做32bit使用:W0-W30.
//其中x0 - x7:这 8 个寄存器主要用来存储传递参数.如果参数超过 8 个,
//则会通过栈来传递; x0 也用来存放上文方法的返回值.
//FP(x29) 64bit 保存栈帧地址(栈底指针),指向当前方法栈的底部。
//LR(x30) 64bit 通常称x30为程序链接寄存器,因为这个寄存器会记录着当前方法的调用方地址 ,
//即当前方法调用完成时应该返回的位置。例如我们遇到 Crash 要获取方法堆栈,
//其本质就是不断的向上递归每一个 x30 寄存器的记录状态(也就是栈上 X30 寄存器的内容)
//来找到上层调用方。
//SP 64bit 保存栈指针,使用 SP/WSP来进行对SP寄存器的访问。
//指向当前方法栈的顶部。
//PC 64bit 程序计数器,俗称PC指针,总是指向即将要执行的下一条指令,
//在arm64中,软件是不能改写PC寄存器的。
//CPSR 64bit 状态寄存器
ENTRY( fuck_code )
LDR X10, =0x42000000
MOV W0, #21
CMP W0, #20
MOV W1, #20
CSEL W0, W0, W1, LS
STR W0, X10, #0x00
STR W1, X10, #0x08
MOV W1, #0xA
CMP W0, W1
CSEL W0, W0, W1, CS
STR W0, X10, #0x10
STR W1, X10, #0x18
UDIV W0, W0, W1
//ADRL X1, fuck_codexxx IDA
ADR X1, fuck_codexxx
//加L编译会报错 unknown mnemonic `adrl' -- `adrl X1,fuck_codexxx'
SUB W0, W0, #1
LDR X0, X1,X0,LSL#3
mov x1, 0x9000000
STRb W0, X1
STR W0, X1
RET
ENDPROC(fuck_code)
fuck_codexxx:
.ascii "123456789abcdef444444445555557778888"
ENTRY( fuck_code1 )
LDR X10, =0x42000000
STR X29, X10, #0x00
STR lr, X10, #0x08
MOV X8, SP
STR x8, X10, #0x10
mov x9, 0
STR x9, X10, #0x18
STP X29, X30, SP,#-0x100!
MOV X29, SP
STR X29, X10, #0x20
MOV W0, #0xFFFFFFf0
STR W0, X29,#0x38
loc_1:
LDR W1, X29,#0x38
TBZ W1, #0x1F, loc_3718a
ADD W2, W1, #8
ADD x9, x9, 1
STR W2, X29,#0x38
CMP W2, #0
B.LE loc_1
loc_3718a:
LDR X4, =0x1234
STR W1, X10, #0xa0
STR X1, X10, #0xb0
STR W2, X10, #0xc0
STR X2, X10, #0xd0
B quit
loc_3728a:
LDR X4, =0x55aa
quit:
STR X4, X10, #0xe0
STR X9, X10, #0xf0
LDP X29, X30, SP, 0x100
MOV X29, SP
STR X29, X10, #0x28
ret
ENDPROC(fuck_code1)
ENTRY( fuck_log1 )
STP X29, X30, SP,#-0x100!
//变量sp+0x00 存储 X29, X30 的原始值
MOV X29, SP
LDR X10, =0x42000000
STR X10, x10, #0x00
ADD X0, X29, #0x100
//x0 栈顶指针 指向函数调用之前的堆栈sp
//函数的参数如果是8个以内(包含8个) 用x0-x7来传递 (param0-param7)
//超过8个的部分 从此sp开始依次先储存好 比如超过3个
//sp+0x00->param8 sp+0x08->param9 sp+0x10->param10
STR X19, SP,#0x10
//变量sp+0x10 存储 x19 的原始值
ldr X19, =0x42000200 //"xoutputx: %s.\n" printf的第一个参数 x0
mov X11, X0
STR X11, x10, #0x08
ldr X12, X11
STR X12, x10, #0x10
add X11, x11, #0x08
STR X11, x10, #0x18
ldr X12, X11
STR X12, x10, #0x20
add X11, x11, #0x08
STR X11, x10, #0x28
ldr X12, X11
STR X12, x10, #0x30
add X11, x11, #0x08
STR X11, x10, #0x38
ldr X12, X11
STR X12, x10, #0x40
//add X11, x11, #0x08
STR X7, x10, #0x48
ldr X12, X7
STR X12, x10, #0x50
STR X6, x10, #0x58
ldr X12, X6
STR X12, x10, #0x60
STP X0, X0, X29, #0x20
//变量sp+0x20 sp+0x28 存储 x0 栈顶指针
ADD X0, X29, #0xC0
STR X0, X29,#0x30
//变量sp+0x30 = sp+0xc0
MOV W0, #0xFFFFFFC8
STR W0, X29,#0x38
//变量sp+0x38 = 0xFFFFFFC8 4字节
MOV W0, #0xFFFFFF80
STR W0, X29,#0x3C
//变量sp+0x3C = 0xFFFFFF80 4字节
STP X1, X2, X29,#0xC8
STP X3, X4, X29,#0xD8
STP X5, X6, X29,#0xE8
STR X7, X29,#0xF8
//传递进来的参数 依次压入堆栈 x1-x7 c8-d8-e8-f8-0x100-x0 栈顶指针的位置
STR Q0, X29,#0x40
STR Q1, X29,#0x50
STR Q2, X29,#0x60
STR Q3, X29,#0x70
STR Q4, X29,#0x80
STR Q5, X29,#0x90
STR Q6, X29,#0xA0
STR Q7, X29,#0xB0
//0x40-0xc0 用0填充这块区域 没有用到
loc_36FC:
LDR W1, X29,#0x38
//变量sp+0x38 = 0xFFFFFFC8 4字节
LDR X0, X29,#0x20
//栈顶指针
TBZ W1, #0x1F, loc_3718
//测试 sp+0x38 0xFFFFFFC8 & 0x1F 是否等于0,等于0的话跳转到loc_3718
//否则执行下一条指令
ADD W2, W1, #8
//sp+0x38 & 0x1f 不等于0, 自加8
CMP W2, #0
STR W2, X29,#0x38
B.LE loc_3728
//不等于0 跳转
loc_3718:
//等于0 说明经过7次循环 x1-x7已经用完了
ADD X1, X0, #0xF
AND X1, X1, #0xFFFFFFFFFFFFFFF8
STR X1, X29,#0x20
B loc_3730
loc_3728:
LDR X0, X29,#0x28
//sp+0x28 存储 x0 栈顶指针
ADD X0, X0, W1,SXTW
//x0+w1 w1符号扩展 此例是一个负数
//传递进来的参数 依次压入堆栈 x1-x7 c8-d8-e8-f8-0x100-x0 栈顶指针的位置
//栈顶指针的位置 + 负数 精确计算好了 第一次是定位到 x1
//7*8=56 0x38 0xFFFFFFC8 + 0x38 = 0x00000000 即-0x38
//下一次循环就是 -0x30 总共循环7次
loc_3730:
LDR X1, X0
//取得压入堆栈的x1的值 第二次是x2 ...
CBZ X1, loc_3744
//等于空退出函数
MOV X0, X19
BL printf
B loc_36FC
loc_3744:
LDR X19, SP,#0x10
//变量sp+0x10 恢复 x19 的原始值
LDP X29, X30, SP,#0x100
//恢复 X29, X30 的原始值,sp堆栈平衡
RET
//程序返回
ENDPROC(fuck_log1)