
标题: [其他] GBA平台ASM学习手记【更新至第三天】 [打印本页]
作者: liuyanghejerry 时间: 2009-4-6 00:48 标题: GBA平台ASM学习手记【更新至第三天】
引用:
之前一直在BLOG里放着,最近发现PTB的大家越来越强了,干脆放到这大家一起学习吧~
在学懂了脚本之后,开始钻研如何让口袋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代码的意思.
以往对:这一部分完全不理解,查ARM指令表亦不得其解. 现在终于明白了这部分前面是汇编器用来包含功能的代码,和我们的ASM本身无关. 后面的push命令本身也不是标准ARM指令,而是使用THUMB方法时将寄存器内容压入栈的方法.因为这里被压入了,所以最终还要再压出,也就是最后的pop指令了. 目前的疑惑是,我们应当如何获取ROM运行时各个数据在RAM中的位置,比如这段:代码:
.text .align 2 .thumb .thumb_func .global main main:;这句懂... push {r0-r4, lr}至少应该有一张地图来说明RAM中各数据的位置吧... 另外在拜读了6遍之后,终于明白了"ldr r0, [r0]"的含义:r0在当前状态装载的是一个内存地址,该语句则把内存地址所对应的值读入到r0. 看来汇编中也有类似指针的东西啊... 借鉴了HackMew的教程,顺便写了一段ASM:代码:
.pokedata: .word 0x02024284 .var1: .word 0x020370b8 .var2: .word 0x020370ba .var3: .word 0x020370b8该ASM代码可以读出游戏已经进行的时间(仅小时数,而且是16进制值),存放到变量0x800D中. 以下是转好的HEX,把它们写到一个ROM空位里: 在脚本中我们可以这样用:代码:
.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)来看下效果吧: 以上只是一个例子,事实上这里提供了一种获得时间的命令,拿它可以做的事还很多.代码:
#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!
作者: pokemon002 时间: 2009-4-6 17:20
以上的几乎全部看不懂......ARM是什么东西我现在还不知道......我好老土.......
作者: chaotix 时间: 2009-4-7 21:27
原来差距是这么大....
我没事...我很好....
后悔编程没学下去啊
我
作者: roywillow 时间: 2009-4-11 22:41
各个版本,尤其是不同语言版本,里面各个var的地址都不一样啊……这也许是为什么英文版的shiny routine在中文上一启动就挂掉的原因吧……
我等着花子的shiny routine……然后我再做个修改器……
你有没有发现……7后面直接回车了……你的代码里面好像没有/n吧……
编译thumb的工具俺好像已经下下来了……
噢噢噢噢,似乎看懂了这段诶……
.PLAYER_DATA:
.word 0x0300500C
.VAR1:
.word 0x020270B6 + (0x800D * 2)
是不是就相识对变量赋值……然后给上面的用?好像c的自定义函数……
不过…… + (0x800D * 2)………………?????
[ 本帖最后由 roywillow 于 2009-4-11 22:46 编辑 ]
作者: liuyanghejerry 时间: 2009-4-11 22:53
代码是在PSP里写的,后来写进ROM的是用XSE又优化的,所以多了个/n~
那段啊……和变量的定义很像,不过这些都是编译器的功劳,ASM本身没有这些功能……
VAR1的那个表达式其实是HM为了便于理解写的……
作者: 冰の都 时间: 2009-4-12 20:50
你们读电脑专棵的么...
作者: 5944 时间: 2009-4-12 23:16
我也看不懂呀!
晕晕的!
原来汇编是这样的!!!!!
作者: roywillow 时间: 2009-4-18 18:40
var1的表达式是为了便于理解写的?我怎么还是不理解……
……花子要不要讲讲编程语言的历程……机器语言、汇编语言、然后那个C叫什么的语言、脚本语言……
作者: liuyanghejerry 时间: 2009-4-18 21:26
VAR1:
.word 0x020270B6 + (0x800D * 2)
本来只是0x20370D0,而HM为了说明这个地址其实是变量 0x800D,于是写成了这种形式。
作者: youd 时间: 2009-4-18 21:44
其实汇编语言属于底层语言,非高级计算机语言的范畴。所以看起来晦涩,但是较于机器码有便于识别纠错的好处,较于高级语言有执行效率高的好处。这东西第一次听说……GBA上寄存器的命名真可爱呀……比电脑上的好记多了0 0
其实观察来看,那些脚本和汇编语言有相似之处,概念也有类似的地方。仔细看看应该不至于不懂
作者: liuyanghejerry 时间: 2009-4-18 22:47
引用:
原帖由 youd 于 2009-4-18 21:44 发表
其实汇编语言属于底层语言,非高级计算机语言的范畴。所以看起来晦涩,但是较于机器码有便于识别纠错的好处,较于高级语言有执行效率高的好处。这东西第一次听说……GBA上寄存器的命名真可爱呀……比电脑上的好记多了 ...
作者: roywillow 时间: 2009-4-18 22:48
那也只限于你把……
我倒有个一个一个查找var地址的方法
写两个脚本,先把你要查找的var设定为255,然后搜索255(要是从0开始,可能找不到)
然后执行第二个脚本,执行一次就把这个var的数值减去一,搜索……
最后总会搜索到一个地址的
不知道搜索的是不是08什么的……
懒的话问老外怎么找到的
作者: 神的火焰 时间: 2009-4-18 23:55
好东西,不过我给研究研究,这东西不好懂啊
作者: liuyanghejerry 时间: 2009-4-19 10:30
引用:
原帖由 roywillow 于 2009-4-18 22:48 发表
那也只限于你把……
我倒有个一个一个查找var地址的方法
写两个脚本,先把你要查找的var设定为255,然后搜索255(要是从0开始,可能找不到)
然后执行第二个脚本,执行一次就把这个var的数值减去一,搜索……
...
| 欢迎光临 口袋社区-Poke The BBS (https://poketb.com/bbs/) | Powered by Discuz! 6.1.0F |
