QEMU ARM64 Uboot

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)

相关推荐
小糖学代码27 分钟前
LLM系列:1.python入门:3.布尔型对象
linux·开发语言·python
shizhan_cloud31 分钟前
Shell 函数的知识与实践
linux·运维
Deng87234734834 分钟前
代码语法检查工具
linux·服务器·windows
霍夫曼3 小时前
UTC时间与本地时间转换问题
java·linux·服务器·前端·javascript
月熊3 小时前
在root无法通过登录界面进去时,通过原本的普通用户qiujian如何把它修改为自己指定的用户名
linux·运维·服务器
大江东去浪淘尽千古风流人物4 小时前
【DSP】向量化操作的误差来源分析及其经典解决方案
linux·运维·人工智能·算法·vr·dsp开发·mr
赖small强5 小时前
【Linux驱动开发】NOR Flash 技术原理与 Linux 系统应用全解析
linux·驱动开发·nor flash·芯片内执行
IT运维爱好者6 小时前
【Linux】LVM理论介绍、实战操作
linux·磁盘扩容·lvm
LEEE@FPGA6 小时前
ZYNQ MPSOC linux hello world
linux·运维·服务器
郝学胜-神的一滴6 小时前
Linux定时器编程:深入理解setitimer函数
linux·服务器·开发语言·c++·程序人生