分享到新浪微博 分享到QQ空间 打印

[其他] GBA平台ASM学习手记【更新至第三天】

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!
来看下效果吧:


以上只是一个例子,事实上这里提供了一种获得时间的命令,拿它可以做的事还很多.
附件: 您所在的用户组无法下载或查看附件


想死你们了!

TOP

以上的几乎全部看不懂......ARM是什么东西我现在还不知道......我好老土.......
简约唯美

TOP

原来差距是这么大....
我没事...我很好....
后悔编程没学下去啊
另一个我
闪耀吧...我的希望!

TOP

各个版本,尤其是不同语言版本,里面各个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 编辑 ]

TOP

代码是在PSP里写的,后来写进ROM的是用XSE又优化的,所以多了个/n~
那段啊……和变量的定义很像,不过这些都是编译器的功劳,ASM本身没有这些功能……
VAR1的那个表达式其实是HM为了便于理解写的……


想死你们了!

TOP

你们读电脑专棵的么...

TOP

我也看不懂呀!
晕晕的!
原来汇编是这样的!!!!!

TOP

var1的表达式是为了便于理解写的?我怎么还是不理解……

……花子要不要讲讲编程语言的历程……机器语言、汇编语言、然后那个C叫什么的语言、脚本语言……

TOP

VAR1:
  .word 0x020270B6 + (0x800D * 2)
本来只是0x20370D0,而HM为了说明这个地址其实是变量 0x800D,于是写成了这种形式。


想死你们了!

TOP

其实汇编语言属于底层语言,非高级计算机语言的范畴。所以看起来晦涩,但是较于机器码有便于识别纠错的好处,较于高级语言有执行效率高的好处。这东西第一次听说……GBA上寄存器的命名真可爱呀……比电脑上的好记多了0 0
其实观察来看,那些脚本和汇编语言有相似之处,概念也有类似的地方。仔细看看应该不至于不懂

TOP

引用:
原帖由 youd 于 2009-4-18 21:44 发表
其实汇编语言属于底层语言,非高级计算机语言的范畴。所以看起来晦涩,但是较于机器码有便于识别纠错的好处,较于高级语言有执行效率高的好处。这东西第一次听说……GBA上寄存器的命名真可爱呀……比电脑上的好记多了 ...
是啊- -WIN32的汇编看着就不爽,要记的东西太多,受不了……


想死你们了!

TOP

那也只限于你把……

我倒有个一个一个查找var地址的方法
写两个脚本,先把你要查找的var设定为255,然后搜索255(要是从0开始,可能找不到)
然后执行第二个脚本,执行一次就把这个var的数值减去一,搜索……
最后总会搜索到一个地址的
不知道搜索的是不是08什么的……

懒的话问老外怎么找到的

TOP

好东西,不过我给研究研究,这东西不好懂啊

TOP

引用:
原帖由 roywillow 于 2009-4-18 22:48 发表
那也只限于你把……

我倒有个一个一个查找var地址的方法
写两个脚本,先把你要查找的var设定为255,然后搜索255(要是从0开始,可能找不到)
然后执行第二个脚本,执行一次就把这个var的数值减去一,搜索……
...
这些var运行的时候都是内存地址,怎么个搜索法……调试可能得出……


想死你们了!

TOP