• 正文
  • 相关推荐
申请入驻 产业图谱

手把手教你分析C语言if架构代码最终如何用arm汇编实现

10/30 13:31
467
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

汇编语言是最接近机器语言的一门语言,汇编指令是最微观,它与大型软件关系类似于细胞核器官的关系,

c语言程序最终都要翻译成汇编代码,按照一定规则组织成可执行程序,然后才可以在硬件上执行。

只有真正理解了汇编代码,才能清楚的知道如何编写c代码效率才能最高,

才能真正写出高质量的c代码。

掌握了汇编代码,会让大家更快的成为真正的编程大师。

本文通过一个基于arm裸机开发工程的简单实例给大家讲解,if else架构的代码最终翻译成什么样的arm汇编代码。

测试环境参考下面文章:

《linux驱动、ARM学习环境搭建

4. 从0开始学ARM-ARM汇编指令其实很简单

《7. 从0学ARM-汇编伪指令、lds详解》

1、c代码

废话不多说,直接上c代码,这个代码非常简单,就不多说了。

/*
?* main.c
?*
?* ?Created on: 2025-10-23
?* ?Author: pengdan
?*/

int?main(void)
{
?int?sum =?0;
?int?a =?10;
?int?b =?22;

?int?flag =?15;

?if(flag >?11)
?{
? sum = a+b;
?}else{
? sum = a-b;
?}
? ??return?0;
}

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: ? ea00000f ? ?b ? 40008048 <__main_from_arm>
?10?
?11 40008008 <main>:
?12 40008008: ? b480 ? ? ? ?push ? ?{r7}
?13 4000800a: ? b085 ? ? ? ?sub sp,?#20
?14 4000800c: ? af00 ? ? ? ?add r7, sp,?#0
?15 4000800e: ? 2300 ? ? ? ?movs ? ?r3,?#0
?16 40008010: ? 60fb ? ? ? ?str r3, [r7,?#12]
?17 40008012: ? 230a ? ? ? ?movs ? ?r3,?#10
?18 40008014: ? 60bb ? ? ? ?str r3, [r7,?#8]
?19 40008016: ? 2316 ? ? ? ?movs ? ?r3,?#22
?20 40008018: ? 607b ? ? ? ?str r3, [r7,?#4]
?21 4000801a: ? 230f ? ? ? ?movs ? ?r3,?#15
?22 4000801c: ? 603b ? ? ? ?str r3, [r7,?#0]
?23 4000801e: ? 683b ? ? ? ?ldr r3, [r7,?#0]
?24 40008020: ? 2b0b ? ? ? ?cmp r3,?#11
?25 40008022: ? dd04 ? ? ? ?ble.n ? 4000802e <main+0x26>
?26 40008024: ? 68ba ? ? ? ?ldr r2, [r7,?#8]
?27 40008026: ? 687b ? ? ? ?ldr r3, [r7,?#4]
?28 40008028: ? 4413 ? ? ? ?add r3, r2
?29 4000802a: ? 60fb ? ? ? ?str r3, [r7,?#12]
?30 4000802c: ? e003 ? ? ? ?b.n 40008036 <main+0x2e>
?31 4000802e: ? 68ba ? ? ? ?ldr r2, [r7,?#8]
?32 40008030: ? 687b ? ? ? ?ldr r3, [r7,?#4]
?33 40008032: ? 1ad3 ? ? ? ?subs ? ?r3, r2, r3
?34 40008034: ? 60fb ? ? ? ?str r3, [r7,?#12]
?35 40008036: ? 2300 ? ? ? ?movs ? ?r3,?#0
?36 40008038: ? 4618 ? ? ? ?mov r0, r3
?37 4000803a: ? 3714 ? ? ? ?adds ? ?r7,?#20
?38 4000803c: ? 46bd ? ? ? ?mov sp, r7
?39 4000803e: ? f85d 7b04 ? ldr.w ? r7, [sp],?#4
?40 40008042: ? 4770 ? ? ? ?bx ?lr
?41 40008044: ? 0000 ? ? ? ?movs ? ?r0, r0
?42 ? ? ...
?43?

3、 汇编代码分析

1)变量压栈

?11 40008008 <main>:
?12 40008008: ? b480 ? ? ? ?push ? ?{r7}
?13 4000800a: ? b085 ? ? ? ?sub sp,?#20
?14 4000800c: ? af00 ? ? ? ?add r7, sp,?#0

这几行代码,为我们在栈顶预留了20字节的空间,r7指向分配的栈顶。

并且为变量:flag、b、a、sum分配了对应的栈空间,对应的栈地址如下:

分配过程参考下图:

2)if代码块

if分支代码,对应的汇编代码块,详见下图:

从上图可以得出,if代码块翻译成汇编代码的思路就是,

23行:先将变量从栈中读取到寄存器r3,

24行:通过汇编指令cmp比较r3和立即数11,该指令会影响寄存器cpsr状态位

25、30行:通过汇编指令b.n 根据cpsr的n状态位,决定执行那一段代码块

26-27、31-32行:进入if分治后,从栈中取出a、b的值,分别到r2/r3

28、29行:flag大于11,r3=r2+r3,然后将和存入到栈中sum对应的位置

32、33行:flag小于11,r3=r2-r3,然后将差存入到栈中sum对应的位置

完整分析如下:

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) }
}

更多嵌入式知识,请加彭老师好友:yikoupen

相关推荐

登录即可解锁
  • 海量技术文章
  • 设计资源下载
  • 产业链客户资源
  • 写文章/发需求
立即登录

公众号『一口Linux』号主彭老师,拥有15年嵌入式开发经验和培训经验。曾任职ZTE,某研究所,华清远见教学总监。拥有多篇网络协议相关专利和软件著作。精通计算机网络、Linux系统编程、ARM、Linux驱动、龙芯、物联网。原创内容基本从实际项目出发,保持原理+实践风格,适合Linux驱动新手入门和技术进阶。