参考:
http://thinkingeek.com/2013/01/10/arm-assembler-raspberry-pi-chapter-2/
先上代码。
/* first.s */
.global main /* main is our entry point and must be global*/
main: /* This is main */
/* whitespace is ignored at the beginning of the line */
mov r0, #2 /* Put a 2 inside the register r0 */
bx lr /* Return from main. bx means branch & exchange*/
写完.s源文件之后,可以通过as
命令编译,然后用gcc
。但有些麻烦,这里最好写到当前目录的Makefile
里面,直接make
命令就弄好了。
cqq@snort-ids:~/repos/asm_demo$ make
Makefile:8: *** missing separator (did you mean TAB instead of 8 spaces?). Stop.
cqq@snort-ids:~/repos/asm_demo$ vi Makefile
cqq@snort-ids:~/repos/asm_demo$ make
as -o first.o first.s
gcc -o first first.o
cqq@snort-ids:~/repos/asm_demo$ ls
Makefile first first.o first.s sum01.s
cqq@snort-ids:~/repos/asm_demo$ ./first ; echo $?
2
cqq@snort-ids:~/repos/asm_demo$ cat Makefile
# Makefile
### $@: the whole params that passes to the script
### $+:
all: first
first: first.o
gcc -o $@ $+
first.o: first.s
as -o $@ $<
clean:
rm -rf first *.o
注意:Makefile
里面的是TAB
,而不是8个空格。
Makefile
很方便,直接make命令就可以得到可执行文件,然后想要清除的时候,直接make clean
即可。
cqq@snort-ids:~/repos/asm_demo/asm_sum01$ make clean
rm -rf sum01 *.o
比如这段汇编代码,把2传给r0(Raspbery Pi 有16个整型寄存器r0~r15,可容纳32bits)。这样程序退出之后,r0中存储的值就是2。于是通过
cqq@snort-ids:~/repos/asm_demo$ ./first; echo $?
2
可以得到这个值。
$?
可以获取上一个命令的退出状态。所谓退出状态,就是上一个命令执行后的返回结果。退出状态是一个数字,一般情况下,大部分命令执行成功会返回 0,失败返回 1。不过,也有一些命令返回其他值,表示不同类型的错误。
参考:
http://c.biancheng.net/cpp/view/2739.html
然后可以来这么一段代码,将r1和r2的值装载到r0上,然后最后程序退出,返回r0的值。
/* sum01.s */
.global main
main:
mov r1, #3 /* r1 <- 3 */
mov r2, #4 /* r2 <- 4 */
add r0, r1, r2 /* r0 <- r1 + r2 */
bx lr
然后得到返回值为7。
cqq@snort-ids:~/repos/asm_demo/asm_sum01$ ./sum01 ;echo $?
7
当然,我们也可以重用r0寄存器,不劳r2费心。
/* sum02.s */
.global main
main:
mov r0, #3 /* r0 <- 3 */
mov r1, #4 /* r1 <- 4 */
add r0, r0, r1 /* r0 <- r0 + r1 */
bx lr
同样可以得到预期的结果。
cqq@snort-ids:~/repos/asm_demo/asm_sum02$ ./sum02 ; echo $?
7
前两章里面,我们学习了如何使用mov
指令将值传给寄存器(registers),然后使用add
指令将两个registers中的值相加。如果我们的处理器只能在registers上操作那就太局限了。
这节主要将两个操作。”load from memory to register”以及”store from register to memory”。这两个操作,叫做load
和store
。有很多方式load和store,但是今天只讨论两个ldr
和str
。
从memory中load数据有点复杂,因为,因为我们要谈论addresses。
要访问数据,我们就要给它一个名字,不然我们就不能指代我们想要哪一部分数据。然而当然一个计算机并不能给在内存中的每一片数据都赋一个名字。好吧,其实也有一个可以算是名字的,那就是地址(addresses)。地址就是一个数字,在ARM中就是一个32位的数字,用来标识在内存中的每个字节(8 bits)。
内存就像一串字节,其中每个字节都有其自己的地址。
When loading or storing data from/to memory,我们需要计算地址。可以通过很多方式来计算地址。这每一种方式都叫做一个寻址方式。ARM有好几个寻址模式,现在我们只讲通过register来寻址(addressing through a register)。
在ARM平台,ARM有32位
的整型registers,并且memory的地址也是32位
的数字。这意味着我们可以在register中存放一个内存地址!
只要我们在register中存放了一个内存地址,我们就可以用那个register来load或者store一些数据(因为这个地址对应着memory中的位置,既可以从那里读,也可以将数据写到那里)。
//TODO