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)

相关推荐
小O_好好学3 分钟前
vi | vim基本使用
linux·编辑器·vim
-SGlow-4 分钟前
Linux相关概念和重要知识点(4)(自举、vim)
linux·运维·vim
多多*28 分钟前
OJ在线评测系统 登录页面开发 前端后端联调实现全栈开发
linux·服务器·前端·ubuntu·docker·前端框架
王哲晓1 小时前
Linux通过yum安装Docker
java·linux·docker
gopher95112 小时前
linux驱动开发-中断子系统
linux·运维·驱动开发
码哝小鱼2 小时前
firewalld封禁IP或IP段
linux·网络
鼠鼠龙年发大财2 小时前
【x**3专享】安装SSH、XFTP、XShell、ARM Linux
linux·arm开发·ssh
nfgo2 小时前
快速体验Linux发行版:DistroSea详解与操作指南
linux·ubuntu·centos
Rookie_explorers3 小时前
Linux下go环境安装、环境配置并执行第一个go程序
linux·运维·golang
weixin_424215843 小时前
shell运算实战案例-KFC点餐系统
linux·centos