C语言编译成汇编:
arm-linux-gcc -S test.c -o test.S
C语言编译成可执行文件:
arm-linux-gcc test.c -o test
多个文件编译链接:
arm-linux-gcc –c main.c –o main.o
arm-linux-gcc –c abc.S –o abc.o
arm-linux-gcc main.o abc.o –o test.o
汇编编译两种方式:
arm-linux-as test.S -o test.o
arm-linux-gcc –c test.S –o test.o
ARM裸机程序编译:
arm-linux-gcc -c start.S -o start.o
arm-linux-ld -Ttext=0x40000000 start.o -o start.elf
arm-linux-objcopy -I elf32-littlearm -O binary start.elf –o start.bin
查看代码地址信息:
arm-linux-objdump -h test
ARM反汇编:
arm-linux-objdump -D elf_file > dis_file
一、arm内嵌汇编
#include <stdio.h>
int main(void){
int a = 88;
__asm__ __volatile__(
"mov r0, %1\n"
"mov r1, #1\n"
"add %0, r0, r1\n"
: "=r" (a)
:"r" (a)
: "r0", "r1"
);
printf("a = %d\n",a);
return 0;
}
有些知识:
a) __asm__(下划线每次两根):表示嵌入汇编。__volatitle__:表示编译不优化。
b) c语言中我们是这样定义字符串的char *str = “Hello, world”;但同时我也可以这样定义:char *str = “Hello,” “world”;,这样同样是表示一个字符串。内嵌汇编中通过\n来分开每条指令,如:”mov r0,r1\nmov r1,r2”。显然这样连着不方便阅读,我想要一条指令一行,这样好些,有两种写法:
1)”mov r0,r1\n \
mov r1,r2”
就是用\作为连字符
2)”mov r0,r1\n”
“mov r1,r2”
就是和上面说的c中定义字符串的第二种形式。
冒号后面相关含义:
: "=r" (a):内嵌汇编输出部分(通过=r来判断为输出)
:"r" (a):内嵌汇编输入部分(通过r来判断输入)
: "r0", "r1":需要保护的寄存器(破坏部分)
用占位符来引用输入输出变量,按位置从%0、%1以此类推,如:这里输入部分a在前面即它为%0,输出a即为%1。
再比如::”=r” (a),”=r”b
:”r” (a)
则顺序为%0、%1、%2
除了用%n之外还可以用标号:
:[a] “=r” (a)
:[b] “r” (b)
使用:mov %[b],%[a]
二、汇编调用C函数
汇编文件main.S
.section .text
.global main
main:
mov ip, sp
stmfd sp!, {fp, ip, lr, pc}
sub fp, ip, #4
bl abc
ldr r0, =str
mov r1, #'a'
strb r1, [r0]
bl printf
sub sp,fp ,#12
ldmfd sp, {fp, sp, pc}
.section .data
str:
.asciz "hello world.\n"
str1:
.ascii "hello world.\n0"
.comm l1, 10000
l2: .space 1000
C文件abc.c
void abc(void)
{
printf("hello, c file\n");
}
三、C调用汇编函数
C文件main.c
#include <stdio.h>
extern void abc(void);
void main(void)
{
printf("start call asm fun\n");
abc();
printf("end call asm fun\n");
}
汇编文件abc.S
.global abc
abc:
mov ip, sp
stmfd sp!, {fp, ip, lr, pc}
sub fp, ip, #4
adr r0, str
bl printf
b next
str:
.asciz "hello, s file\n"
.align 2
next:
sub sp,fp ,#12
ldmfd sp, {fp, sp, pc}
其中,这个C和汇编的互调还是不太理解,先做个笔记先。