从汇编到C

Posted linux-37ge

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从汇编到C相关的知识,希望对你有一定的参考价值。

一. 设置栈

  1.1. C语言运行时需要和栈的意义

    1.1.1. “C语言运行时(runtime)”需要一定的条件,这些条件由汇编来提供。C语言运行时主要是需要栈

    1.1.2. C语言与栈的关系

      a. C语言中的局部变量都是用栈来实现的。如果我们汇编部分没有给C部分预先设置合理合法的栈地址,那么C代码中定义的局部变量就会落空,整个程序就死掉了。

      b. 我们平时在编写单片机程序(譬如51单片机)或者编写应用程序时并没有去设置栈,但是C程序还是可以运行的。原因是:在单片机中由硬件初始化时提供了一个默认可用的栈,在应用程序中我们编写的C程序其实并不是全部,编译器(gcc)在链接的时候会帮我们自动添加一个头,这个头就是一段引导我们的C程序能够执行的一段汇编实现的代码,这个代码中就帮我们的C程序设置了栈及其他的运行时需要。

    1.1.3. CPU模式和各种模式下的栈

      1.1.3. 在ARM中37个寄存器中,每种模式下都有自己的独立的SP寄存器(r13),为什么这么设计?

        a. 如果各种模式都使用同一个SP,那么就意味着整个程序(操作系统内核程序、用户自己编写的应用程序)都是用一个栈的。你的应用程序如果一旦出错(譬如栈溢出),就会连累操作系统的栈也损坏,整个操作系统的程序就会崩溃。这样的操作系统设计是非常脆弱的,不合理的。

        b. 解决方案就是各种模式下用不同的栈。我的操作系统内核使用自己的栈,每个应用程序也使用自己独立的栈,这样各是各的,一个损坏不会连累其他人。

        PS: S5PV210系统在复位后默认是进入SVC模式的,裸机程序运行在此模式

  1.2. 汇编程序设置栈

    a. 栈必须是当前一段可用的内存(可用的意思是这个地方必须有被初始化过可以访问的内存,而且这个内存只会被我们用作栈,不会被其他程序征用)

    b. 当前CPU刚复位(刚启动),外部的DRRAM尚未初始化,目前可用的内存只有内部的SRAM(因为它不需初始化即可使用)。因此我们只能在SRAM中找一段内存来作为SVC的栈。

    c. 栈有四种:满减栈 满增栈 空减栈 空增栈,详情查看《ARM汇编3

    d. 查阅《iROM_application_note》中的memory map,可知SVC栈应该设置为0xd0037D80

#define SVC_STACK 0xd0037d80
ldr sp, = SVC_STACK   @set stack

二. 使用c编程

  2.1. 汇编启动代码

    a. 设置栈地址

    b. 调用C函数led_blink

技术分享图片
/* 
 * file name :set_stack.S
 * author:   MUSK
 * description:set stack,
*/
#define WATCHCON 0xE2700000
#define SVC_STACK 0xd0037d80
.global _start
_start:
    ldr r1, =WATCHCON    @Watchdog Timer Control Register address
    ldr r0, [r1]         @config corresponding register
    and r0, r0,#(~(0x01<<5))        @config corresponding register    
    str r0, [r1]
    
    ldr sp, = SVC_STACK   @set stack
    
    bl led_blink
    
    b .   @while(1)
View Code

  2.2. 编写C文件

    a. 该文件主要实现LED的闪烁

技术分享图片
#define GPJ0CON  ((volatile unsigned int *)0xE0200240)
#define GPJ0DAT  ((volatile unsigned int *)0xE0200244)
void delay(void);
void led_blink(void)
{
    //led初始化,    

    *GPJ0CON &=0xff000fff;
    *GPJ0CON |=0x00111000;
    while(1)
    {
        *GPJ0DAT &=~((0x01<<3)|(0x01<<4)|(0x01<<5));
        delay();
        *GPJ0DAT |=((0x01<<3)|(0x01<<4)|(0x01<<5));
        delay();
    }    
}

void delay(void)
{
    volatile unsigned int times =900000;
    while(times--);
    
}
View Code

三. 编译测试

  3.1. 编译前Makefile文件

技术分享图片
set_stack.bin: set_stack.o led.o
    arm-linux-ld -Ttext 0x0 -o set_stack.elf $^
    arm-linux-objcopy -O binary set_stack.elf set_stack.bin
    arm-linux-objdump -D set_stack.elf > set_stack_elf.dis
    gcc mkv210_image.c -o mkx210
    ./mkx210 set_stack.bin 210.bin
    
%.o : %.S
    arm-linux-gcc -o [email protected] $< -c 

%.o : %.c
    arm-linux-gcc -o [email protected] $< -c 

clean:
    rm *.o *.elf *.bin *.dis mkx210 -f

    
    
View Code

  3.2. 编译结果

    a. 编译报错:led.o:(.ARM.exidx+0x0): undefined reference to `__aeabi_unwind_cpp_pr1‘

    b. google问题后解决方法是编译命令后加上-nostdlib

技术分享图片
[email protected]:/mnt/hgfs/windows_share/baseC/lesson1.5.3-set-stack2# ls
led.c  Makefile  mkv210_image.c  set_stack.S  write2sd  说明.txt
[email protected]:/mnt/hgfs/windows_share/baseC/lesson1.5.3-set-stack2# 
[email protected]:/mnt/hgfs/windows_share/baseC/lesson1.5.3-set-stack2# 
[email protected]:/mnt/hgfs/windows_share/baseC/lesson1.5.3-set-stack2# make
arm-linux-gcc -o set_stack.o set_stack.S -c #-nostdlib
arm-linux-gcc -o led.o led.c -c #-nostdlib
arm-linux-ld -Ttext 0x0 -o set_stack.elf set_stack.o led.o
led.o:(.ARM.exidx+0x0): undefined reference to `__aeabi_unwind_cpp_pr1led.o:(.ARM.exidx+0x8): undefined reference to `__aeabi_unwind_cpp_pr0make: *** [set_stack.bin] Error 1
[email protected]:/mnt/hgfs/windows_share/baseC/lesson1.5.3-set-stack2#
View Code

  3.3. 修改后的Makefile文件

    a. 增加-nostdlib

技术分享图片
set_stack.bin: set_stack.o led.o
    arm-linux-ld -Ttext 0x0 -o set_stack.elf $^
    arm-linux-objcopy -O binary set_stack.elf set_stack.bin
    arm-linux-objdump -D set_stack.elf > set_stack_elf.dis
    gcc mkv210_image.c -o mkx210
    ./mkx210 set_stack.bin 210.bin
    
%.o : %.S
    arm-linux-gcc -o [email protected] $< -c -nostdlib

%.o : %.c
    arm-linux-gcc -o [email protected] $< -c -nostdlib

clean:
    rm *.o *.elf *.bin *.dis mkx210 -f

    
    
View Code

    b. 重新make

技术分享图片
[email protected]:/mnt/hgfs/windows_share/baseC/lesson1.5.3-set-stack2# make clean
rm *.o *.elf *.bin *.dis mkx210 -f
[email protected]:/mnt/hgfs/windows_share/baseC/lesson1.5.3-set-stack2# make
arm-linux-gcc -o set_stack.o set_stack.S -c -nostdlib
arm-linux-gcc -o led.o led.c -c -nostdlib
arm-linux-ld -Ttext 0x0 -o set_stack.elf set_stack.o led.o
arm-linux-objcopy -O binary set_stack.elf set_stack.bin
arm-linux-objdump -D set_stack.elf > set_stack_elf.dis
gcc mkv210_image.c -o mkx210
./mkx210 set_stack.bin 210.bin
[email protected]:/mnt/hgfs/windows_share/baseC/lesson1.5.3-set-stack2#
View Code

 

参考《朱老师.1.2ARM裸机课件》

 

以上是关于从汇编到C的主要内容,如果未能解决你的问题,请参考以下文章

36.从汇编到C(bl1到bl2)

C从源码到运行发生了哪些事

从汇编到C

在C代码中将结构体变量作为参数传递效率忒低

Keil stm32,使用汇编,分散文件和c。如何将c代码入口点导出到程序集?

从 C 调用汇编函数时出现分段错误错误