从汇编到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<<)) @config corresponding register
str r0, [r1] ldr sp, = SVC_STACK @set stack bl led_blink b . @while()
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()
{
*GPJ0DAT &=~((0x01<<)|(0x01<<)|(0x01<<));
delay();
*GPJ0DAT |=((0x01<<)|(0x01<<)|(0x01<<));
delay();
}
} void delay(void)
{
volatile unsigned int times =;
while(times--); }
三. 编译测试
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 .bin %.o : %.S
arm-linux-gcc -o $@ $< -c %.o : %.c
arm-linux-gcc -o $@ $< -c clean:
rm *.o *.elf *.bin *.dis mkx210 -f
3.2. 编译结果
a. 编译报错:led.o:(.ARM.exidx+0x0): undefined reference to `__aeabi_unwind_cpp_pr1'
b. google问题后解决方法是编译命令后加上-nostdlib
root@ubuntu:/mnt/hgfs/windows_share/baseC/lesson1.5.3-set-stack2# ls
led.c Makefile mkv210_image.c set_stack.S write2sd 说明.txt
root@ubuntu:/mnt/hgfs/windows_share/baseC/lesson1.5.3-set-stack2#
root@ubuntu:/mnt/hgfs/windows_share/baseC/lesson1.5.3-set-stack2#
root@ubuntu:/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_pr1'
led.o:(.ARM.exidx+0x8): undefined reference to `__aeabi_unwind_cpp_pr0'
make: *** [set_stack.bin] Error
root@ubuntu:/mnt/hgfs/windows_share/baseC/lesson1.5.3-set-stack2#
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 .bin %.o : %.S
arm-linux-gcc -o $@ $< -c -nostdlib %.o : %.c
arm-linux-gcc -o $@ $< -c -nostdlib clean:
rm *.o *.elf *.bin *.dis mkx210 -f
b. 重新make
root@ubuntu:/mnt/hgfs/windows_share/baseC/lesson1.5.3-set-stack2# make clean
rm *.o *.elf *.bin *.dis mkx210 -f
root@ubuntu:/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 .bin
root@ubuntu:/mnt/hgfs/windows_share/baseC/lesson1.5.3-set-stack2#
参考《朱老师.1.2ARM裸机课件》
从汇编到C的更多相关文章
- u-boot源码汇编段简要分析
Hi,大家好!我是CrazyCatJack,你们可以叫我CCJ或者疯猫.今天我给大家带来的是u-boot的源代码汇编段分析,以后还会给大家讲解后续的C代码,请持续关注哦^_^ 先简单说一下u-boot ...
- GCC 预处理、编译、汇编、链接..
1简介 GCC 的意思也只是 GNU C Compiler 而已.经过了这么多年的发展,GCC 已经不仅仅能支持 C 语言:它现在还支持 Ada 语言.C++ 语言.Java 语言.Objective ...
- GDB调试汇编堆栈过程分析
GDB调试汇编堆栈过程分析 分析过程 这是我的C源文件:click here 使用gcc - g example.c -o example -m32指令在64位的机器上产生32位汇编,然后使用gdb ...
- Beennan的内嵌汇编指导(译)Brennan's Guide to Inline Assembly
注:写在前面,这是一篇翻译文章,本人的英文水平很有限,但内嵌汇编是学习操作系统不可少的知识,本人也常去查看这方面的内容,本文是在做mit的jos实验中的一篇关于内嵌汇编的介绍.关于常用的内嵌汇编(AT ...
- 从linux0.11中起动部分代码看汇编调用c语言函数
上一篇分析了c语言的函数调用栈情况,知道了c语言的函数调用机制后,我们来看一下,linux0.11中起动部分的代码是如何从汇编跳入c语言函数的.在LINUX 0.11中的head.s文件中会看到如下一 ...
- C内嵌汇编-格式
C内嵌汇编-格式: __asm__(汇编语句部分:输出部分:输入部分破坏描述部分);C内嵌汇编以关键字"__asm__"或"asm"开始, 下辖四个部分, 各部 ...
- 20145212——GDB调试汇编堆栈过程分析
GDB调试汇编堆栈过程分析 测试代码 #include <stdio.h> short val = 1; int vv = 2; int g(int xxx) { return xxx + ...
- C程序汇编运行模式简析
SJTUBEAR 原创作品转载请注明出处 /<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 1. 汇编 ...
- 生成ARM汇编
使用ndk即可生成arm汇编 1.首先写好hello.c 2.编写makefile #ndk根目录 NDK_ROOT=E:\Android\android-ndk-r10b #编译器根目录 TOOLC ...
- gdb调试汇编堆栈过程的学习
gdb调试汇编堆栈过程的学习 以下为C源文件 使用gcc - g code.c -o code -m32指令在64位的机器上产生32位汇编,然后使用gdb example指令进入gdb调试器: 进入之 ...
随机推荐
- Spring IOC(一)
最近复习,准备整理下复习笔记 Spring IOC 部分: 控制反转(Inversion of Control) IOC是什么 简言之 IOC完成的事情原先由程序员主动通过new实例化对象事情,转交给 ...
- 【NOIP2014模拟11.3】噪音
题目 FJ有M个牛棚,编号1至M,刚开始所有牛棚都是空的.FJ有N头牛,编号1至N,这N头牛按照编号从小到大依次排队走进牛棚,每一天只有一头奶牛走进牛棚.第i头奶牛选择走进第p[i]个牛棚.由于奶牛是 ...
- IntelliJ IDEA 2019.3激活破解教程(亲测有效,可激活至 2089 年)
IntelliJ IDEA 2019.3激活破解教程(亲测有效,可激活至 2089 年) 所有软件安装位置,作者均在无中文.无空格目录下进行操作的 IntelliJ IDEA 2019.3激活破解教程 ...
- python-魔法属性和反射
python魔法属性和反射 #!/usr/bin/python3 # coding:utf-8 # Auther:AlphaPanda # Description:与类相关的魔法属性 # Versio ...
- 8. ClustrixDB 监控
一. 列出集群中当前会话 sql> select * from system.sessions\G 二. 显示CPU利用率.磁盘读/写利用率和缓冲区缓存失误率 MySQL [system]> ...
- spring mvc @Valid 数据验证
//对书的单价校验不能是空,价格在20-100之间 @DecimalMax(value = "100", message = "价格不超过100元") ...
- cpp 面向对象初步探索
需求 尝试定义一个complex(复数类) 简略实现 headers/complex.h #ifndef __COMPLEX__ #define __COMPLEX__ class complex { ...
- Ubuntu16.04 同时连接无线网络和以太网端口
背景: 激光雷达VLP16通过以太网线连接电脑.在本博客所述的设置之前,一旦连接以太网线,本机(dell笔记本)的无线网络立即断开,即无法同时连接无线网络和以太网端口. 问题查找: 命令行 $ ip ...
- Task的用法
创建任务 无返回值的方式 方式1: var t1 = new Task(() => TaskMethod("Task 1")); t1.Start(); Task.WaitA ...
- C# walls
在学习C#的阶段中,我们一点一点的往前爬, 此代码需要添加selenium ,和 获取 引用. using Ivony.Html.Parser; using Ivony.Html; using Ope ...