您尚未登录。

楼主 #1 2018-05-03 18:47:35

xinxiaoci
会员
注册时间: 2018-04-18
已发帖子: 71
积分: 71

c程序控制led灯及反汇编代码分析

《单片机小白转嵌入式Linux学习记录,基于S3C2440----目录》

低位存放在低地址:小字节序 小端 little endian
高位存放在低地址:大字节序 大端 big endian

一般ARM芯片都是小字节顺序

编写c程序控制led
a.谁来调用main函数
b.main函数中的局部变量保存在内存中,这个内存地址是多少?
答:我们需要写一个汇编代码,给main函数设置内存(栈),然后调用main函数;局部变量保存在栈中,栈对应一块内存。

----------------------------------------------
start.S 汇编代码

.text
.global _start

_start:

    /* 设置内存:sp 栈 */
    ldr sp,=4096    /* nand启动设置在内部ram的顶部4k位置 */

        //ldr sp,=0x40000000+4096   /* nor启动 */

    /* 调用main函数 */
    bl main

    /* 死循环 */
halt:
    b halt
-----------------------------------------------
led.c c代码

int main()
{
    unsigned int *pGPFCON = (unsigned int *)0x56000050;//控制寄存器
    unsigned int *pGPFDAT = (unsigned int *)0x56000054;//数据寄存器
    /* 配置GPF5为输出引脚 */
    *pGPFCON=0x400;
    /* 设置GPF5输出0 */
    *pGPFDAT=0;

    return 0;
}
----------------------------------------------
Makefile 文件

all:
    arm-linux-gcc -c -o start.o start.S
    arm-linux-gcc -c -o led.o led.c
    arm-linux-ld -Ttext 0 start.o led.o -o led.elf
    arm-linux-objcopy -O binary -S led.elf led.bin
    arm-linux-objdump -D led.elf > led.dis

clean:
    rm *.bin *.o *.elf *.dis

---------------------------------------------

led.dis反汇编


led.elf:     file format elf32-littlearm

Disassembly of section .text:

00000000 <_start>:
   0:    e3a0da01     mov    sp, #4096    ; 0x1000
   4:    eb000000     bl    c <main>                        ;调用main函数 并把返回地址保存在lr中 lr=0x08

00000008 <halt>:
   8:    eafffffe     b    8 <halt>

0000000c <main>:
   c:    e1a0c00d     mov    ip, sp                            ;ip保存了栈顶的值 4096
  10:    e92dd800     stmdb    sp!, {fp, ip, lr, pc}        ;保存fp,ip,lr,pc 更新sp的值 sp=4096-4*4=4080
  14:    e24cb004     sub    fp, ip, #4    ; 0x4                ;fp=ip-4=4096-4=4092
  18:    e24dd008     sub    sp, sp, #8    ; 0x8                ;sp=sp-8=4080-8=4072
  1c:    e3a03456     mov    r3, #1442840576    ; 0x56000000    ;r3=0x56000000
  20:    e2833050     add    r3, r3, #80    ; 0x50                ;r3=r3+0x50=0x56000050 pGPFCON寄存器
  24:    e50b3010     str    r3, [fp, #-16]                    ;将r3的值保存在fp-16的内存(栈)中 fp-16=4092-16=4076 (*(int *)4076)=0x56000050
  28:    e3a03456     mov    r3, #1442840576    ; 0x56000000    ;r3=0x56000000
  2c:    e2833054     add    r3, r3, #84    ; 0x54                ;r3=r3+0x54=0x56000054
  30:    e50b3014     str    r3, [fp, #-20]                    ;将r3的值写入fp-20的内存(栈)中 fp-20=4092-20=4072 (*(int *)4072)=0x56000054
  34:    e51b2010     ldr    r2, [fp, #-16]                    ;读取fp-16内存中的值到r2  r2=(*(int *)4076)=0x56000050
  38:    e3a03b01     mov    r3, #1024    ; 0x400                ;r3=0x400     GPF5寄存器
  3c:    e5823000     str    r3, [r2]                        ;将r3的值写入r2指向的内存中 (*(int *)0x56000050)=0x400  GPF5为输出模式
  40:    e51b2014     ldr    r2, [fp, #-20]                    ;同上面三行代码(*(int *)0x56000054)=0        输出低电平 点亮LED
  44:    e3a03000     mov    r3, #0    ; 0x0
  48:    e5823000     str    r3, [r2]
  4c:    e3a03000     mov    r3, #0    ; 0x0                    ;r3=0
  50:    e1a00003     mov    r0, r3                            ;r0=r3=0  r0-r3 用于调用者与被调用者之间传递参数
  54:    e24bd00c     sub    sp, fp, #12    ; 0xc                ;sp=fp-12=4092-12=4080
  58:    e89da800     ldmia    sp, {fp, sp, pc}            ;从4080位置开始还原进入函数之前的fp=fp,sp=ip,pc=lr=0x08 所以程序跳转至0x08位置执行
Disassembly of section .comment:

00000000 <.comment>:
   0:    43434700     cmpmi    r3, #0    ; 0x0
   4:    4728203a     undefined
   8:    2029554e     eorcs    r5, r9, lr, asr #10
   c:    2e342e33     mrccs    14, 1, r2, cr4, cr3, {1}
  10:    Address 0x10 is out of bounds.
 
-----------------------------------------------------
汇编指令
add,sub
举例:
add r0,r1,#4    ;r0=r1+4
add r0,r1,r2    ;r0=r1+r2

sub    r0,r1,#4    ;r0=r1-4
sub r0,r1,r2    ;r0=r1-r2

bl    break link 跳转并保存返回地址

举例:
bl     c <main>    ;跳转到内存0x0c 并保存下一条指令的地址,用于调用返回

ldm        ;many 读内存,写入多个cpu寄存器
stm     ;把多个cpu寄存器的值写入内存
ldmia    ;ia 先读后蹭
stmdb    ;db 先减后存

举例:
stmdb sp!,{fp,ip,lr,pc}        ;1> 大括号中的cpu寄存器的存取顺序与,书写顺序无关。高编号cpu寄存器存
                            在高地址。
                            ;2> sp! : ! 表示sp=sp最终被修改后的值,假如sp初始值是4096 那么运行该
                            条汇编后sp的值为4080
执行流程:
1.sp=4096-4=4092
2.将pc寄存器的值存入4092指向的内存(栈)中
3.sp=4092-4=4088
4.将lr寄存器的值存入4088指向的内存(栈)中
5.sp=4088-4=4084
6.将ip寄存器的值存入4084指向的内存(栈)中
7.sp=4084-4=4080
8.将fp寄存器的值存入4080指向的内存(栈)中
9.将当前的栈指针更新


        ->4096
pc值
        ->4092
lr值
        ->4088
ip值
        ->4084
fp值
        ->4080
       
ldmia sp,{fp,sp,pc}            ; sp 无 ! 号,表示sp修改后的值不存入sp
                            ; 先读后增,假如sp的初始值为4080
                           
执行流程:
1.fp=内存(栈)中fp的值(4080内存指向的值)
2.sp=4080+4=4084
3.sp=内存(栈)中ip的值(4084内存指向的值)
4.sp=4084+4=4088
5.pc=内存(栈)中lr的值(4088内存指向的值)
6.sp=4088+4=4092

最近编辑记录 xinxiaoci (2018-05-03 18:52:10)

离线

#2 2018-05-03 19:05:22

awfans
会员
注册时间: 2018-04-03
已发帖子: 264
积分: 264

Re: c程序控制led灯及反汇编代码分析

非常详细, 感谢分享!

离线

页脚

工信部备案:粤ICP备20025096号 Powered by FluxBB

感谢为中文互联网持续输出优质内容的各位老铁们。 QQ: 516333132, 微信(wechat): whycan_cn (哇酷网/挖坑网/填坑网) service@whycan.cn