叫花子
管理员
哦哦哦!!!
俱乐部 改版爱好者 威望 34
- 帖子
- 5313
- 精华
- 15
- 积分
- 8228
- PT币
- 96939 枚
- 热度
- 429 °C
- 贡献值
- 0 点
|
骨棒与孤独 Lv.43 |
         |
|
|
楼主
大 中
小 发表于 2009-4-6 00:48 只看该作者
GBA平台ASM学习手记【更新至第三天】
引用:之前一直在BLOG里放着,最近发现PTB的大家越来越强了,干脆放到这大家一起学习吧~ GBA平台ARM学习手记
在学懂了脚本之后,开始钻研如何让口袋ROM做一些原本做不成的事,比如黄版的跟随皮卡丘、赠送定制能力的PM等,于是心里痒痒的开始学ARM了...
先发一下牢骚吧- -
国内的GBA ARM教程实在是太少了,只有几个GBA汉化组放出过基于ROM破解所写的简易教程,这些教程水平参差不齐,甚至连一些基本的概念都解释不清.更麻烦的是其完整程度和精细程度都不怎么样,大多属于"头大无尾"的作品,例程更是稀少...
有些嵌入式ARM程序企业也有教程,但却又不是0起步,基本都是辅助资料,而且因为不是针对GBA的,我甚至搞不清究竟哪些才配合GBA...
外国的GBA ARM教程稍好些,但是也缺乏相对完整的,而且因为是外文的,读起来并不流畅...
当然...也不可能什么都准备的那么充分,饭不能让别人喂着吃嘛.
于是呢,我打算把我学习的历程做成一个手记,一来便于自己来复习,二来也算是填补一下国内和PM改版界的空白吧,希望对大家也有帮助.
注:因为我有一些浅薄的VB+PHP+Delphi+C++基础,平时也比较乐于涉猎电脑的相关知识,所以整个过程会比较跳跃. 引用:第一天
1.GBA使用ARM处理器,这种处理器的汇编理论和Intel不同,所以汇编语言也不同,Win32的汇编教程也就不能作为参考了.
2.常用的GBA汇编编译器是Goldroad.
3.汇编给我的感觉就是在CPU上运算,然后把结果放在寄存器里.
4.寄存器类似于高级语言中的变量,储存用.
5.GBA所提供的寄存器共16个,分别是:r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,r13,r14,r15.
6.在这些寄存器中,r0—r12可以归我们调用,r13和堆栈制度有关,r14用于存放子程序的返回地址,r15是程序计数器和标志寄存的地方.
7.ARM汇编语言以符号";"为注释符号,作用域只有一行.
8.符号"@"后面的语句类似于Delphi中的声明部分.
9.一个非命令的纯英数字符串可以作为标签,相当于一个高级语言中的一个模块或者一个过程.
10.ARM汇编语言的基本样式:
@include screen.h
@textarea
ldr r1,=REG_DISPCNT
ldr r2,=(BG2_ENABLE|MODE_3)
str r2,[r1]
ldr r1,=0x0FF
ldr r2,=vram+2410
str r1,[r2]
label1
B label1
@pool
@endarea
命令大多为3个字符,每条一行.
11.Goldroad允许我们使用数据包含的功能,类似于C中的#include,但这些数据不是汇编语言,不能被执行. 引用:第二天
基本命令的基本用法:
LDR
例:ldr r1,=0x0FF
ldr命令有2个参数,
r1是寄存器,0x0FF被称为立即数.
ldr命令把立即数装入寄存器.
STR *有疑问
例:str r1,[r2]
str命令有2个参数,
第一个数是寄存器,第二个则是内存单元.
str命令把前面的寄存器的内容拷贝给内存单元.
(这里有一点迷惑,教程里这样说:"是将r1寄存器的内容放进r2寄存器所指向的内存单元",那么[r2]究竟是r2么?内存单元是什么?)
MOV
例:mov r0,r1
mov命令有2个参数,
二者都是寄存器.
mov命令把后一个寄存器中的值(其实也可以是一个立即数)复制给前面那个寄存器.
(教程里特别强调了当r1的位置是立即数时,该立即数只能是8位,也就是一个字节,LDR则可以是32位,4字节;但另一个ARM速查文档中却没有提到)
CMP
例:CMP r0, r4
CMP有2个基本参数(CMP有拓展用法)
两个参数分别可以是内存单元、寄存器、立即数中的任意一个.
CMP将用第一个参数的值减去第二个参数的值,然后判断结果.CMP的减法结果不会被保存.
CMP将会产生以下几种结果:
EQ :EQual(相等)
NE :Not Equal(不相等)
VS :oVerflow Set(溢出设置)
VC :oVerflow Clear(溢出清除)
HI :HIgher(高,大)
LS :Lower or the Same(低或相等)
PL :PLus(加)
MI :MInus(减)
CS :Carry Set(进位设置)
CC :Carry Clear(进位清除)
GE :Greater than or Equal(比较起来大或相等)
GT :Greater Than(比较起来大)
LE :Less than or Equal(比较起来小或相等)
LT :Less Than(比较起来小)
Z :is Zero(零)
NZ :is Not Zero(非零)
这些结果会被储存在r15这个标志位寄存器中留给后面的语句使用.(标志位也被叫做S位,二者是一个意思么?)
B
例:b label1
B命令只有一个参数,它是标签名.
B命令相当于VB中的GOTO,把程序的焦点转移到目标标签,这时的B是无条件跳转.B没有执行完标签返回的功能.
B命令也可以用在CMP之类的命令后,作为有条件的跳转:
CMP r0, r4
BEQ label34;我们可以把BEQ假想为"B to label34 if EQ".label34只是个标签 引用:第三天
今天看到了HackMew放出的ASM教程,收获很大.原来GBA的ASM分为THUMB模式和ARM模式,二者的命令差不多,但THUMB的方式会比ARM更快更轻量.
借助HackMew的教程,我新认识了一种汇编工具(名字忘了...),同时进一步明白了thethethethe的ASM代码的意思.
以往对:复制内容到剪贴板 代码: .text
.align 2
.thumb
.thumb_func
.global main
main:;这句懂...
push {r0-r4, lr} 这一部分完全不理解,查ARM指令表亦不得其解.
现在终于明白了这部分前面是汇编器用来包含功能的代码,和我们的ASM本身无关.
后面的push命令本身也不是标准ARM指令,而是使用THUMB方法时将寄存器内容压入栈的方法.因为这里被压入了,所以最终还要再压出,也就是最后的pop指令了.
目前的疑惑是,我们应当如何获取ROM运行时各个数据在RAM中的位置,比如这段:复制内容到剪贴板 代码:.pokedata:
.word 0x02024284
.var1:
.word 0x020370b8
.var2:
.word 0x020370ba
.var3:
.word 0x020370b8 至少应该有一张地图来说明RAM中各数据的位置吧...
另外在拜读了6遍之后,终于明白了"ldr r0, [r0]"的含义:r0在当前状态装载的是一个内存地址,该语句则把内存地址所对应的值读入到r0.
看来汇编中也有类似指针的东西啊...
借鉴了HackMew的教程,顺便写了一段ASM:复制内容到剪贴板 代码:.text
.align 2
.thumb
.thumb_func
.global asm1
main: ;FR_ONLY
push {r0-r1, lr}
ldr r0, .PLAYER_DATA
ldr r0, [r0]
ldr r1, .VAR1
ldrh r0, [r0, #0xE] ;带有h后缀的读写命令表示为半字节操作
strh r0, [r1]
pop {r0-r1, pc}
.align 2
.PLAYER_DATA:
.word 0x0300500C
.VAR1:
.word 0x020270B6 + (0x800D * 2) 该ASM代码可以读出游戏已经进行的时间(仅小时数,而且是16进制值),存放到变量0x800D中.
以下是转好的HEX,把它们写到一个ROM空位里:
在脚本中我们可以这样用:复制内容到剪贴板 代码:#org @1
lock
faceplayer
callasm 0x[地址]+1'注意了,HEX插入的地址必须+1,这是THUMB模式必须的
buffernumber 0x00 0x800D'buffer系的命令可以把HEX换成DEC
message @2 0x2
release
end
#org @2
= You've been playing for [buffer1] hours! 来看下效果吧:
以上只是一个例子,事实上这里提供了一种获得时间的命令,拿它可以做的事还很多.
附件: 您所在的用户组无法下载或查看附件
想死你们了!
|