|
本帖最后由 jiangzhengwenjz 于 2016-9-13 23:24 编辑
【改版进阶教程】使用DevkitARM中的GNU Toolchain改版
这个教程可说是进阶教程中的入门级,很多原理性的东西不会涉及,而非主体部分的操作也尽量作简单处理。
先给出几个问题的解答:
1. 为什么要用devkitarm改版?
答:因为这个软件是免费的,也能满足普通改版者的需求。
2. 所有改版者都需要devkitarm吗?
答:并不,使用该开发包需要改版者预先掌握GBA ASM和C基础。
3. 我们需要用它做什么?
答:能够编译你C和ASM源文件。
4. 为什么要自寻麻烦,不用IDE?
答:因为好像没有好用的IDE。
下面开始正文了
一、软件的安装:
所有教程里需要的软件在本帖末尾附带的链接中均可直接下载。
先下载devkitProUpdater-1.6.0.exe,并进行安装。完毕后将其安装目录下的devkitarm\bin目录添加到PATH变量(不如就加到系统变量吧)
然后下载make-3.81.exe,并进行安装。完毕后同样将bin目录加到PATH变量。(也可用MinGW中的make.exe,我就是用这个)
此外如果安装devkitpro时出现报错的话,请注意 安装目录\msys\bin是否已经添加到PATH变量,若没有则手动添加,否则程序无法正常运行。
最后,下载armips.exe并将其路径添加到PATH变量。
至此,我们的开发环境已然搭建完成了。
二、测试:
在实际上手编写程序之前,先测试一下开发环境是否正确搭建,是非常有必要的。这时需要随便找一个可以用这些程序来进行编译的工程,比如野生双战工程https://github.com/jiangzhengwenjz/Double_wild_battle
一般而言,在Readme文件中都会有详细的编译方法,对于这个工程也不例外。由于我们只是测试编译,所以没必要修改文件了,直接放入名为bpre0.gba的美版火红1.0 ROM,双击compile.bat就能进行编译。如果看到你的ROM被修改了,或是打开ROM测试一番,有几率遭遇野生双战了,那就说明编译成功了。(当然,要实际使用这个工程请仔细阅读readme,不然某些情况下100%死机)
如果没成功,就检验第一步有什么遗漏。
三、各程序简介:
其实在添加环境变量时就很明显了,devkitpro安装目录下的devkitarm\bin里就是它所附带的GNU Toolchain,里面有非常多的工具,不过常用的并不多,这里只介绍一部分。- arm-none-eabi-as - 依据asm源文件输出中间目标文件
- arm-none-eabi-gcc - 依据c源文件输出中间目标文件
- arm-none-eabi-ld - 对目标文件进行连接
- arm-none-eabi-nm - 列举目标文件中的符号
- arm-none-eabi-objcopy - 从目标文件中获取纯数据
复制代码 而armips的功能则较为复杂,它本身是asm的编译器(只不过部分用法和arm-none-eabi-as不同罢了,具体请阅读https://github.com/Kingcom/armips/blob/master/Readme.txt),不过可以直接打开/关闭某个文件,执行写入。此外,它还可以导入目标文件,并使用其中的全局变量。
因此,如何编写程序其实已经很明显了,先通过as或是gcc生成目标文件(一般扩展名.o),然后对生成的目标文件进行连接,最后用armips进行字节变更,并导入用ld连接后的目标文件即可。
但是,由于并没有一个IDE生成makefile,如果一个个文件去编译,连接,在文件较多的情况下,每次都要输入如此众多的命令,显然是不现实的。这也是为何我们要用make的原因。make是一个很强大的程序,默认的文件名为makefile,无扩展名。(或是用-f参数选择文件输入)我们能在其中预先定义好编译的规则,这样,只需要在命令窗口中输入make即可完成整体的编译。windows下在某目录下打开命令窗口的方法是:shift+右键即可看到该选项。
当然,makefile有其专门的语法,不过我们的重点并不在此,只需掌握一些基本的方法即可。
四、实战:
空中楼阁般的谈话很难让人抓住问题的关键,所以干脆来看个例子吧。依然是刚才的野生双战。具体如何书写代码不是本教程的重点,不过看过这个例子应该也就了解得差不多了。
了解makefile语法可以看这篇:http://blog.csdn.net/ruglcc/article/details/7814546/
(不过我个人觉得不需要看就是了,因为我们只需用到基本中的基本,复杂的部分要用到也可以依葫芦画瓢。。。)
如果要用我这个模板的话,你也需建立一个src文件夹,用来存放源文件(当然,也可以有子文件夹)
.gitignore, ReadMe.txt, compile.bat, compile.sh与工程本身无关,大可无视。我们直接来看makefile好了。(只需在cmd中输入make即可编译)- #后的是注释
- #在这里我们定义变量,这样写规则时会简单
- #这个工程没有C文件,所以不用gcc
- #所有的源码都依赖于跳出,无需获得.bin以及各代码具体的地址,故无需objcopy及nm
- AS=arm-none-eabi-as
- LD=arm-none-eabi-ld
- ARS=armips
- #这种变量都相当于C中的宏
- #gcc的参数可以看我其他工程
- ASFLAGS=-mthumb
- LDFLAGS=-z muldefs
- BLDPATH:=build
- #这段不用懂,你可以认为就是设定了src中.asm文件的编译规则吧。
- rwildcard=$(wildcard $1$2) $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2))
- ASSRC := $(call rwildcard,src/,*.asm)
- ASOBJS := $(ASSRC:%.asm=$(BLDPATH)/%.o)
- $(BLDPATH)/%.o: %.asm
- $(shell mkdir -p $(dir $@))
- $(AS) $(ASFLAGS) -c $< -o $@
- #all实际上是一个伪目标,不过不用.PHONY也无所谓的
- #--relocatable是为了从armips中导入链接后的.o文件,也就是暂时不指定链接的地址
- #除非用objcopy直接获取bin,这就需要在linker.lsc中指定地址
- all: $(ASOBJS)
- $(LD) $(LDFLAGS) -T linker.lsc --relocatable -o "build\linked.o" $(ASOBJS)
- $(ARS) insert.s
复制代码 linker.lsc:
(这个文件在链接时使用,来确定数据的排布,如果用objcopy的话,将0x08000000改为写入的地址,才能生成对应的bin)- OUTPUT_ARCH(arm)
- MEMORY {
- rom : ORIGIN = 0x08000000, LENGTH = 32M
- ewram : ORIGIN = 0x02000000, LENGTH = 4M - 4k
- }
- SECTIONS {
- .text : {
- FILL (0xABCD)
- __text_start = . ;
- *(.init)
- *(.text)
- *(.ctors)
- *(.dtors)
- *(.rodata)
- *(.fini)
- *(.data)
- *(COMMON)
- __text_end = . ;
- __bss_start__ = . ;
- *(.bss)
- __bss_end__ = . ;
- _end = __bss_end__ ;
- __end__ = __bss_end__ ;
- } >rom = 0xff
- }
复制代码 再来看看armips所需的文件吧,也在makefile中要求编译了:- //一切C源码中的变量,和asm中的全局变量都可以直接在这里引用
- //.open和.close打开 关闭文件
- .gba
- .thumb
- .open "bpre0.gba", 0x8000000
- ;remove the stupid limiter
- .org 0x807F760
- .byte 0,0
- ;misc fixes
- .org 0x802D812
- .byte 0,0
- .org 0x802D858
- .byte 0,0
- .org 0x802D8A6
- .byte 0,0
- .org 0x802D8F4
- .byte 1,0x1C
- .org 0x802DF36
- .byte 8,0x1C
- .org 0x802DE58
- .byte 0,0
- .org 0x802DE84
- .byte 0,0
- .org 0x802DEA4
- .byte 0,0
- .org 0x802DEC2
- .byte 4,0x1C
- .org 0x802D874
- .word 0x2023D6C
- .org 0x802D94C
- .word 0x2023D6C
- .org 0x802DF64
- .word 0x2023D6C
- .org 0x802DF04
- .word 0x2023D6C
- ;flee fix
- .org 0x8016824
- ldr r0, =double_wild_flee_fix+1
- bx r0
- .pool
- ;audio fix
- .org 0x8021D46
- .byte 0,0x47
- .org 0x8021D94
- .word double_wild_audio_fix+1
- ;pokemon catch
- .org 0x802D44C
- .byte 0x30,0x47
- .org 0x802D480
- .word double_wild_catch_fix+1
- ;dex fix
- .org 0x802D95C
- ldr r0, =double_wild_dex_fix+1
- bx r0
- .pool
- ;dex fix 2
- .org 0x802D9DE
- .byte 0,0x47
- .org 0x802DA00
- .word double_wild_dex_fix_2+1
- ;ball throw fix
- .org 0x80EF5F8
- .byte 0x10,0x47
- .org 0x80EF680
- .word double_wild_ball_throw_fix+1
- ;pokeball fix
- .org 0x80A1E1C
- ldr r1, =double_wild_pokeball_fix+1
- bx r1
- .pool
- ;main func for normal RAND wildbattle
- .org 0x8082AF4
- ldr r3, =double_wild_main_fix+1
- bx r3
- .pool
- ;my fault: the pure function deactivation
- .org 0x8082A0C
- .word 0
- ;fade fix
- .org 0x8011D72
- mov r0, #0xA
- lsl r0, r0, #0x10
- .org 0x8011DFE
- mov r0, #0xA
- lsl r0, r0, #0x10
- ;switch battle script fix
- .org 0x81D86AD
- .byte 0x28
- .word double_wild_switch_bs_fix
- ;skip fix
- .org 0x801417E
- mov pc, r1
- lsl r0, r0, #0
- lsl r0, r0, #0
- lsl r0, r0, #0
- .org 0x80141B0
- .word skiphack
- .org 0x8019688
- ldr r0, =skipmsghack
- mov r15, r0
- .pool
- //这里导入之前在makefile中链接好的目标文件
- .org 0x8F00000
- .importobj "build/linked.o"
- .close
复制代码 了解了基本的方法以后,就可以看一个更为复杂的例子了。下载HGSSANIMATION.zip,这是一个只完成了一小部分的HG开头动画(就是GAME FREAK那边),可以从中看一些参数,因为这用到了asm和C的混合编程。用C编程基本和网上入门书籍里面的内容差不多,甚至更简单一些。其中的bpre.ld是用于直接定义symbol的值的,很容易看懂。不过使用前还要再声明一下就是了,无论是常量,还是函数指针。连接时使用它就万事大吉了。
五、杂项:
我觉得看过整个教程后,很多人会疑惑Hackmew的thumb编译器是怎么弄的呢?实际上也很简单,他的基本思路也就是先使用as生成目标文件,再用objcopy生成纯数据文件(.bin)。不过,只是用这么一个batch的话,当然也就不能处理多文件工程(除非你统统.include或是.incbin - -),同时也不能发挥ld的巨大作用了。若是直接用.org也是无法直接写入ROM的。因此,在面对文件较多或是涉及C语言的工程时,还是应当使用上述的方法,而非用Hackmew的batch。当然,.global, .thumb_func等原先用不上的directive现在也变得很重要了,这点也是很明显的。
就我个人观点,除了地图等必须可视化操作的数据,大部分的数据都可以用这种方法直接写入ROM,不用找空位,留空,计算空间等,同时也是一键写入,随时可增减、修改源码,也能避免很多低级错误,无疑是十分方便的(本质上,这是编译器帮我们处理了大量的工作)。不过对于很多表格等,也需要自己编写对应的程序来输出源文件便于阅读和修改,这点稍显麻烦。不过无疑用这种方法改版绝对是利大于弊的,能够随意地使用SYMBOL,绝对是无比快意的。
六、资料:
程序参数(大部分时候照抄就可以了,除了一些目录什么的):
https://www.mankier.com/1/gcc
https://www.mankier.com/1/ld
https://www.mankier.com/1/as
https://www.mankier.com/1/nm
https://www.mankier.com/1/objcopy
教程中资料下载:
全文完 |
|