Keil开发的ARM程序main函数之前的汇编分析

——BIN文件中RW段的数据移动

系统平台:

STM32系列STM32F103ZE,512KB内部FLASH,64KB片内存储;

FLASH地址范围0x0800 0000 ~ 0x0808 0000,用于存放代码;

片内存储地址范围0x2000 0000 ~ 0x2001 0000,用于存放数据;

Cortex-M3上电后来到复位中断(已将前4个字节的值存入MSP堆栈指针),转到__main标号,完成RW段的移动、ZI段的初始化,建立堆栈,初始化库函数,然后跳转到main函数,开启C程序之旅,执行流程如图1所示。

图1 main函数之前的汇编程序执行流程图

本文主要讨论RW段的移动,RW段就是程序中赋了初值的变量,它的搬移我看到过两种方式。在BIN文件中,RO段和RW段之间有8个双字的Region$$Table,4个双字一组,分别用于完成RW段的搬移和ZI段的初始化。

(1)       __scatterload_copy来完成

此时RW段的内容保存到内存开始的地方,本文中是0x20000000,用这一方式完成后,内存中存放的不是RW数据的内容,而是一个地址。这个地址是在FLASH中,即指向了其在RO段的地址,实际的内容是在RO段中。

(2)       通过__uncompressed1实现

RW是程序中初始化的变量,但是这些变量有可能初值是0,因此为了节省空间,实际在BIN文件中RW段是压缩过的。调用__uncompressed1解压缩RW段的数据内容,并将其保存到内存开始的地方。

图2 BIN文件中压缩RW段内容

图2是BIN文件中RW段的数据内容,影印部分显示,大小是164字节。其中0x0001 C72C前面8个双字的内容是Region$$Table,将其列出如下。

0x0801 C72C         BIN文件中RW段的开始地址

0x2000 0000          RW段要存放到RAM中的地址

0x0000 0334          要存放到RAM中的RW段数据大小

0x0800 0184          执行函数__scatterload_copy或者__uncompressed1的地址

上面4个双字完成RW段的搬移。

0x0801 C7D0        BIN文件的末尾,ZI段的开始

0x2000 0334          ZI段放到RAM中的起始位置

0x0000 F4BC        ZI段的大小

0x0800 01E0         执行函数__scatterload_zeroinit的地址

这4个双字完成ZI段的初始化。

图3 RW段内容解压缩后在RAM中排布

将BIN文件中RW解压缩以后(这个解压缩从反汇编可以看到,但是没有看明白),实际内容如图3所示,大小变为820个字节,该补0的地方都已经补足了。

Keil开发的ARM程序main函数之前的汇编分析的更多相关文章

  1. 转:iOS程序main函数之前发生了什么

    原文地址:http://blog.sunnyxx.com/2014/08/30/objc-pre-main/ 我是前言 一个iOS app的main()函数位于main.m中,这是我们熟知的程序入口. ...

  2. iOS程序main函数之前发生了什么

    我是前言 一个iOS app的main()函数位于main.m中,这是我们熟知的程序入口.但对objc了解更多之后发现,程序在进入我们的main函数前已经执行了很多代码,比如熟知的+ load方法等. ...

  3. 问题:C#控制台程序参数;结果:设置与读取C#控制台应用程序Main函数中的参数args

    设置与读取C#控制台应用程序Main函数中的参数args 在项目属性面版->调试->命令行参数设置.空格分隔.读取:string[] str = Environment.GetComman ...

  4. linux中应用程序main函数中没有开辟进程的,它应该在那个进程中运行呢?

    1.main函数是一个进程还是一个线程? 不知道你是用c创建的,还是用java创建的. 因为它们都是以main()做为入口开始运行的. 是一个线程,同时还是一个进程. 在现在的操作系统中,都是多线程的 ...

  5. C 语言main 函数终极探秘(&& 的含义是:如果 && 前面的程序正常退出,则继续执行 && 后面的程序,否则不执行)

           所有的C程序必须定义一个称之为main的外部函数,这个函数是程序的入口,也就是当程序启动时所执行的第一个函数,当这个函数返回时,程序也将终止,并且这个函数的返回值被看成是程序成功或失败的 ...

  6. .NET中Main函数使用小技巧

    摘要:任何语言开发出来的程序,都会有一个程序入口函数,可能每个语言所使用的程序入口函数名称不一样,但是它们的作用都是一样的,都是被操作系统去调用.那么本文主要总结.NET中的程序入口函数Main使用的 ...

  7. keil c51中C程序的启动过程

    汇编是从org 0000h开始启动,那么keil c51是如何启动main()函数的?keil c51有一个启动程序startup.a51,它总是和c程序一起编译和链接.下面看看它和main()函数是 ...

  8. 【逆向工具】IDA使用1-VS2015版本debug查找Main函数,加载符号文件

    IDA 常见操作 空格,切换反汇编视图 选择CALL或是跳转 进入函数内部或是跳转处 返回键 ESC daq.exe 分析32位程序 ,生成的IDA数据库文件是 .idb Idap64.exe 分析6 ...

  9. WPF点滴(1) Main 函数

    应用程序的入口函数是main函数,在Console程序和Winform程序main函数都有清晰的定义,可以很容易找到,但是WPF的工程文件中却找不到main函数的定义,是WPF不需要main函数吗?N ...

随机推荐

  1. Hibernate (ORM)

    1 框架体系结构 2 hibernate入门 2.1 ORM框架 Hibernate是一个数据持久化层的ORM框架. Object:对象,java对象,此处特指JavaBean Relational: ...

  2. MongoDB 创建集合

    createCollection() 方法 MongoDB db.createCollection(name, options) 是用来创建集合. 语法: 基本的 createCollection() ...

  3. mysql 更新sql报错:You can't specify target table 'wms_cabinet_form' for update in FROM clause

    数据库里面有两个字段的位置不对,要把他们对调换下.因为没有数据库写的权限,需要用sql语句来实现.原来以为简单的 update table a set a.字段a=(select b字段 from t ...

  4. Java基础之多线程详细分析

    在了解多线程之前,先来了解一下进程与线程之间的关系. 进程和线程: 进程是指在系统中正在执行的一个程序,每个进程之间是独立的. 线程是进程的一个基本执行单元.一个进程要想执行任务,必须得有线程(每1个 ...

  5. atom 常用配置

    基本配置 setting 位于 File -> setting 显示HTML标签闭合的竖线 Setting -> Editor Setting -> 勾选 Show Indent G ...

  6. angular2 应用 不同的environment 进行 build/serve

    文件目录如下: 命令行使用:ng serve --e=dev/offline/prod build 不同,像上面那样写没用.必须后面再加--prod 如: ng build --e=offline - ...

  7. [使用经验]cocostudio UI编辑器的裁剪

    日志-2015/03/16 描述:在程序使用UI编辑器导出文件的时候,该panel中大于panel的部分都没有显示出来,例如人物,一些特效等 原因:UI编辑器panel都勾上了裁剪 解决:在编辑器中把 ...

  8. nginx的开机自启、server命令启动、nginx.conf配置

    1.将Nginx设置为开机自动启动 a.当上面6步完成之后,说明安装已经完全成功了,但是每次开机我们面临的一个问题,就是每次都要执行命令(1: cd /usr/local/nginx/sbin/   ...

  9. $.on()方法和addEventListener改变this指向

    jQuery $.on()方法和addEventListener改变this指向 标签(空格分隔): jQuery JavaScript jQuery $.on() jq的绑定事件使用$([selec ...

  10. eclipse通过maven进行打包并且对hdfs上的文件进行wordcount

    在eclipse中配置自己的maven仓库 1.安装maven(用于管理仓库,jar包的管理) -1.解压maven安装包 -2.把maven添加到环境变量/etc/profile -3.添加mave ...