扫码加入

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

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

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

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

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驱动新手入门和技术进阶。