本文通过一个基于arm裸机开发工程的简单实例给大家讲解,c语言的循环代码最终翻译成什么样的arm汇编代码。
测试环境参考下面文章:
《手把手教你分析C语言if架构代码最终如何用arm汇编实现》
1、c代码
废话不多说,直接上c代码,这个代码非常简单,就不多说了。
1 /*
2 * main.c
3 *
4 * Created on: 2025-11-26
5 * Author: pengdan
6 */
7
8 int main(void)
9 {
10 int i = 1;
11 int sum = 0;
12
13 for(i=0;i<=100;i++)
14 {
15 sum+=i;
16 }
17
18 return 0;
19 }
2、编译代码
最终编译城的程序gcd.bin就可以烧录到arm板子上运行,
为方便理解,我们可以用arm-linux-gnueabihf-objdump去掉程序中符号信息,生成程序gcd.dis
gcd.dis
1
2 gcd.elf: file format elf32-littlearm
3
4
5 Disassembly of section .text:
6
7 40008000 <_start>:
8 40008000: e3a0d207 mov sp, #1879048192 ; 0x70000000
9 40008004: ea00000d b 40008040 <__main_from_arm>
10
11 40008008 <main>:
12 40008008: b480 push {r7}
13 4000800a: b083 sub sp, #12
14 4000800c: af00 add r7, sp, #0
15 4000800e: 2300 movs r3, #0
16 40008010: 607b str r3, [r7, #4]
17 40008012: 2300 movs r3, #0
18 40008014: 603b str r3, [r7, #0]
19 40008016: 2300 movs r3, #0
20 40008018: 607b str r3, [r7, #4]
21 4000801a: e006 b.n 4000802a <main+0x22>
22 4000801c: 683a ldr r2, [r7, #0]
23 4000801e: 687b ldr r3, [r7, #4]
24 40008020: 4413 add r3, r2
25 40008022: 603b str r3, [r7, #0]
26 40008024: 687b ldr r3, [r7, #4]
27 40008026: 3301 adds r3, #1
28 40008028: 607b str r3, [r7, #4]
29 4000802a: 687b ldr r3, [r7, #4]
30 4000802c: 2b64 cmp r3, #100 ; 0x64
31 4000802e: ddf5 ble.n 4000801c <main+0x14>
32 40008030: 2300 movs r3, #0
33 40008032: 4618 mov r0, r3
34 40008034: 370c adds r7, #12
35 40008036: 46bd mov sp, r7
36 40008038: f85d 7b04 ldr.w r7, [sp], #4
37 4000803c: 4770 bx lr
38 ...
3、 汇编代码分析
1)变量压栈
11 40008008 <main>:
12 40008008: b480 push {r7}
13 4000800a: b085 sub sp, #12
14 4000800c: af00 add r7, sp, #0
这几行代码,为我们在栈顶预留了12字节的空间,r7指向分配的栈顶。
并且为变量:i、sum分配了对应的栈空间,对应的栈地址如下:
分配过程参考下图:
2)for循环代码块
for循环代码,对应的汇编代码块,详见下图:
从上图可以得出,if代码块翻译成汇编代码的思路就是,
19-20行:初始化变量i值为0:将寄存器写入值0,然后将该值压入栈0x04位置,
22-23行:从栈中分别取出i,sum存入r2、r3
24行 :将i的值累加到sum:r2与r3相加结果存入r3
25行 :将sum写入栈中:将r3压栈
26-27行:i++ :从栈中i值到r3,然后将1累加到寄存器r3
28-29 行:将i的值写入到栈,然后再读出到r3
30行 :将i值和100比较,cmp指令会影响cpsr的状态位
31行 :通过b指令,判断cpsr中的状态位,如果小于等于(ble),则跳转到0x4000801c位置,否则往下执行
完整分析如下:
4、其他编译文件
gcd.s
.text
.global _start
_start:
ldr sp,=0x70000000 /*get stack top pointer*/
b main
Makefile
TARGET=gcd
TARGETC=main
all:
arm-linux-gnueabihf-gcc -lto -g -c -o $(TARGETC).o $(TARGETC).c
arm-linux-gnueabihf-gcc -lto -g -c -o $(TARGET).o $(TARGET).s
arm-linux-gnueabihf-gcc -lto -g -S -o $(TARGETC).s $(TARGETC).c
arm-linux-gnueabihf-ld $(TARGETC).o $(TARGET).o -Tmap.lds -o $(TARGET).elf
arm-linux-gnueabihf-objcopy -O binary -S $(TARGET).elf $(TARGET).bin
arm-linux-gnueabihf-objdump -D $(TARGET).elf > $(TARGET).dis
clean:
rm -rf *.o *.elf *.dis *.bin
map.lds文件
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
/*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
. = 0x40008000;
. = ALIGN(4);
.text :
{
gcd.o(.text)
*(.text)
}
. = ALIGN(4);
.rodata :
{ *(.rodata) }
. = ALIGN(4);
.data :
{ *(.data) }
. = ALIGN(4);
.bss :
{ *(.bss) }
}
更多嵌入式知识,请加彭老师好友:yikoupeng
240