0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

【专栏精选】Cortex-M 的反编译入门

电子发烧友论坛 来源:未知 2023-05-16 09:35 次阅读

电子发烧友技术探索官,分享你的原创电子行业文章!

本期为大家推荐一篇嵌入式相关技术文章,作者主要从事嵌入式领域的开发,感兴趣的小伙伴可以关注学习哦~


本期推

专栏作者嵌入式大杂烩(点击查看作者主页)

介绍:该专栏主要介绍嵌入式开发相关的知识,与大家一起交流学习。


我们在写单片机裸机程序时,在主函数之前,会有一段启动代码,而启动代码是用汇编写的,有些朋友可能看到汇编头都大了,当时要想深入研究底层架构,这快硬骨头就必须去啃。


汇编:汇编文件转换为目标文件(里面是机器码)。

反汇编:可执行文件(目标文件,里面是机器码),转换为汇编文件。

关于汇编的基础知识,请关注笔者专栏,阅读以前的文章。

今天笔者以STM32F1的点灯程序为例,带领大家进行反汇编,并阅读反汇编后的代码。

1 新建LED裸机程序

1.新建文件夹

新建文件夹“STM32F1”,当然名字也可以另取,在 STM32F1文件夹下,我们新建五个文件夹,分别为CMSIS、Listing、Output、Project、User。

其中CMSIS文件夹放启动文件:


笔者的开发板芯片是STM32F103ZE,这个文件是根据STM32的固件库startup_stm32f10x_md.s文件修改而来。

2.新建工程

打开Keil,在工具栏 Project->New μVision Project…新建我们的工程文件。


输入工程名,保存即可。


窗口是让我们选择公司跟芯片的型号,我们用的芯片是 ST 公司的STM32F103ZE,有64K SRAM,512K Flash,属于高集成度的芯片。按如下选择即可。



后点击项目管理。


最后修改后的内容如下:


并添加相应的文件。


其中main.c的内容如下所示:

/**
* @brief 延时函数
* @param d
* @retval None
*/
void delay(int d)
{
while(d--);
}


/**
* @brief main
* @param None
* @retval int
*/
int main(void)
{
unsigned int *pReg;

/* 使能GPIOB */
pReg = (unsigned int *)(0x40021000 + 0x18);
*pReg |= (1<<3);

/* 设置GPIOB0为输出引脚 */
pReg = (unsigned int *)(0x40010C00 + 0x00);
*pReg |= (1<<0);


pReg = (unsigned int *)(0x40010C00 + 0x0C);

while (1)
{
/* 设置GPIOB0输出1 */
*pReg |= (1<<0);

delay(1000000);


/* 设置GPIOB0输出0 */
*pReg &= ~(1<<0);

delay(1000000);
}
}

startup.s文件的内容如下:

;************************************ STM32F1 ************************************
;* File Name : startup.s
;* Author : BruceOu
;* Version : V1.0
;* Date : 2021-06-27
;* Description : STM32F10x Medium Density Devices vector table for MDK-ARM
;* toolchain.
;* This module performs:
;* - Set the initial SP
;* - Set the initial PC == Reset_Handler
;* - Set the vector table entries with the exceptions ISR address
;* - Configure the clock system
;* - Branches to __main in the C library (which eventually
;* calls main()).
;* After Reset the CortexM3 processor is in Thread mode,
;* priority is Privileged, and the Stack is set to Main.
;*******************************************************************************
PRESERVE8
THUMB




; Vector Table Mapped to Address 0 at Reset
AREA RESET, DATA, READONLY
EXPORT __Vectors

__Vectors DCD 0
DCD Reset_Handler ; Reset Handler


AREA |.text|, CODE, READONLY


; Reset handler
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT main


LDR SP, =(0x20000000+0x10000)
BL main


ENDP

END

接下来还有配置工程。


选择Output文件夹。


选择Listing文件夹。


基本配置就这些,接下来编译工程。


只要没有错误就可以了,最后就是下载程序,笔者使用的是J-Link,最后的现象如下:


LED会不停闪烁。

2 Keil反汇编

接下来才是今天正题,反汇编。

在KEIL的User选项中,如下图添加这两项:

fromelf --bin --output=STM32F1.bin ../Output/STM32F1.axf

fromelf --text -a -c --output=STM32F1.dis ../Output/STM32F1.axf

然后重新编译,即可得到二进制文件STM32F1.bin(以后会分析)、反汇编文件STM32F1.dis。

如下图所示:


正常编译过程是分为四个阶段进行的,即预处理(也称预编译,Preprocessing)、编译(Compilation)、汇编 (Assembly)和链接(Linking)。

但是反编译是讲为二进制文件反编译成汇编文件,因此反汇编的流程如下:

3 反汇编代码解析

接下来就是查看反编译代码,打开反编译文件Project/STM32F1.dis。这里只截取一段查看,因为格式都是一样的,知识每条内容不同罢了。


第一列是链接地址,第二列是机器码,第三列是汇编指令。

根本汇编指令,我们找到ARMv7-M Architecture Reference Manual_DDI 0403E.d (ID070218)中的LDR指令。


我们将F8DFD004变成二进制。


这个使用的32位的Thumb2指令集。


其中b0~b11是立即数,这里是4,对应的汇编代码的也是4,这里要注意的是,ARM指令采用流水线机制,当前执行地址A的指令,同时已经在对下一条指令进行译码同时已经在读取下下一条指令:PC = A +4 (Thumb/Thumb2指令集)。


B12~b15是寄存器,这段大小是0XC,对应的寄存器就是sp;


后面16bit除了23位意外,全是固定的,其中‘U’表示无条件执行,这里置为1。

其他的汇编指令对应的机器码也是类似的,值得注意的是,不同的架构对应的机器码也是不同的,这也就回答了为了不同的处理器架构会对应不同的指令集。

有兴趣的可以对比Cortex-M系列和Cortex-A系列的的指令集。请参考以下手册:

ARM Architecture Reference Manual ARMv7-A and ARMv7-R edition.pdf

ARMv7-M Architecture Reference Manual.pdf

4 反汇编代码全解析

进入debug模式,在View下选择disassembly window。


这样就可将机器码和对应的代码对应起来。当程序运行起来了,也就从异常向量表中跳转到Reset_Handler中,然后跳转到main函数中,而main函数是在栈中,因此需要设置占空间的起始位置。根据STM32的参考手册,SRAM的其起始地址和大小如下:


因此栈顶为起始位置加上栈的大小即可,只要不超过SRAM即可。


值得注意的是,栈是__向低地址扩展的数据结构__,是一块连续的内存区域,栈顶的地址和栈的最大容量是在通过LDR设置,因此需要根据应用需求合理分配栈空间。

接下来往下走,如果在汇编中不打断点,会默认进入main函数的一条指令,就从这里分析。为了分析方便,这里还有使用上一节方便出来的文件。



【C代码33行】

从内存地址0x0800 017c拷贝数据0x40021018到r3中,也就是

r3 = * 0x0800 017c

也就是将pReg指针保存到r3中。


【C代码34行】

这里对应3条指令


首先将r3拷贝到r0中,然后将r0或上1左移3位,也就是

ORR r0,r0,#8

最后将r0的值写入r3所指地址中。

【C代码37行】

同33行,从内存地址0x0800 0180拷贝数据40010c00到r3中


【C代码38行】

同34行,这里也对应3条指令:


【C代码40行】

和33行不同的是,这里分了两条指令:


笔者认为前面是编译器优化了。根据ARM指令采用流水线机制,当前执行地址A的指令,同时已经在对下一条指令进行译码同时已经在读取下下一条指令:PC = A +4 (Thumb/Thumb2指令集)。因此前面类似的代码被优化了。

接下来就进入循环中。

后面就移植在死循环中,不断操作GPIO的亮灭。

【C代码45行】

这里是将B0设置为1,和34行类似。


【C代码47行】

这里将进入延时函数。


进入延时函数:


NOP是字节对齐,减少指令的内存访问次数。首先将变量d保存到r0,然后将r0赋给r1,接着是r0自减1,紧接着是r1与0比较,如果r1等于0,则会返回,否则,又从头开始,值得注意的是,这里先比较,然后r0才自减的。

为了进一步说明,可以看--d的汇编代码。


这里就是相当于r1先减1,然后再比较的。

【C代码50行】

这行代码对应一下指令,很简单。

5 总结

在前面使用Keil进行了反汇编,也对相应的C代码进行了分析。我们看到的反汇编代码如下:


根据反汇编的代码,可将其对应到Flash,在Flash上的内容如下表所示:

地址Flash****内容
0x0800000000000000
0x0800000408000009
0x08000008f8dfd004
0x0800000cf000f80c

最后总结下点灯的流程:

第一步:设置栈CPU会从0x08000000读取值,用来设置SP。

第二步:跳转:CPU从0x08000004得到地址值,根据它的BIT0切换为ARM状态或Thumb状态,然后跳转。

__第三步:__对于cortex M3/M4,它只支持Thumb状态,所以0x08000004上的值bit0必定是1,0x08000004上的值 = Reset_Handler + 1。从Reset_Handler继续执行。

第四步:然后进入到主函数中执行相应C代码。


原文地址:https://www.elecfans.com/d/2071474.html




版权说明:

本内容为作者发布至电子发烧友平台原创文章,相关创作版权归原作者所有,如未经作者授权,禁止转载!




声明本文由电子发烧友社区发布,转载请注明以上来源。如需社区合作及入群交流,请添加微信EEFans0806,或者发邮箱liuyong@huaqiu.com。


更多热点文章阅读

  • 电子工程师分享:常用电平转换电路、电源自动切换电路、太阳能充电电路总结

  • 基于32位RISC-V设计的互联型微控制器,沁恒微CH32V307开发样例

  • RK3568!四核64位ARMv8.2A架构,汇聚编译源码及实战样例

  • 尺寸仅有21mm*51mm,板边采用邮票孔设计,合宙 Air105 核心板开发总结

  • 基于ESP32芯片,搭载OpenHarmony操作系统,NiobeU4开发板应用实例


原文标题:【专栏精选】Cortex-M 的反编译入门

文章出处:【微信公众号:电子发烧友论坛】欢迎添加关注!文章转载请注明出处。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

原文标题:【专栏精选】Cortex-M 的反编译入门

文章出处:【微信号:gh_9b9470648b3c,微信公众号:电子发烧友论坛】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    如何使用Ozone分析Cortex-M异常

    Ozone可以帮助用户快速分析和查找导致CPU故障的软件bug。本文解释如何使用Ozone的调试功能,深入了解Cortex-M架构上的这些错误。
    的头像 发表于 11-29 11:14 753次阅读
    如何使用Ozone分析<b class='flag-5'>Cortex-M</b>异常

    java反编译能拿到源码吗

    Java反编译是一种将编译后的Java字节码(.class文件)转换回Java源代码的过程。虽然反编译可以帮助理解代码的逻辑和结构,但它并不总是能完美地还原原始源代码。反编译工具通常会
    的头像 发表于 09-02 11:03 1047次阅读

    java反编译的代码可以修改么

    Java反编译是一种将编译后的Java字节码(.class文件)转换回源代码的过程。反编译后的代码可以进行修改,但是需要注意,反编译代码的质量和可读性可能会受到原始
    的头像 发表于 09-02 11:00 722次阅读

    ida反编译出来代码能直接用吗

    IDA反编译出来的代码通常 不能直接使用 ,这主要基于以下几个方面的原因: 一、代码的不完整性 IDA反编译生成的代码可能缺少原始源代码中的某些关键信息。在编译过程中,编译器会优化代码
    的头像 发表于 09-02 10:55 711次阅读

    单片机hex文件反编译成C语言的过程

    使用C语言编写,然后编译成机器码并烧录到单片机的存储器中。 Hex文件是一种用于存储单片机程序的文件格式,它包含了程序的机器码和一些附加信息,如起始地址、结束地址等。Hex文件通常用于烧录单片机程序,也可以用于程序的传输和存储。 Hex文件反编译的基本概念 Hex文
    的头像 发表于 09-02 10:49 3393次阅读

    使用Keil uVision对TLE9893_2QK Evalkit进行编程,显示\"未找到Cortex-M SW设备\",为什么?

    我正在使用 Keil uVision 对 TLE9893_2QK Evalkit 进行编程。 当我尝试调试时,得到以下错误信息。 我还收到一个窗口,显示\"未找到 Cortex-M SW
    发表于 06-03 08:10

    [RK3588从入门到精通]系列内容专栏目录及介绍

    [RK3588从入门到精通] 专栏目录及介绍
    的头像 发表于 04-10 10:40 748次阅读
    [RK3588从<b class='flag-5'>入门</b>到精通]系列内容<b class='flag-5'>专栏</b>目录及介绍

    CW32F003E4芯片入门学习:1.开发环境安装

    、学生、学者等群体非商业免费评估和使用。 没有代码大小限制。 支持Arm Compiler 6:可为所有基于Arm Cortex-M的产品提供精简的代码和强大的性能。 可访问超过9500款支持
    的头像 发表于 03-27 09:27 582次阅读
    CW32F003E4芯片<b class='flag-5'>入门</b>学习:1.开发环境安装

    Cortex-M0+内核介绍

    和8位的价位实现32位性能。处理器的低门数使其能够部署在需要简单功能的应用中。 作为ARM Cortex-M处理器系列的最新成员,32位Cortex-M0+处理器采用了低成本90纳米低功耗(LP)工艺,耗电量仅9μA/MHz,约为主流8位或16位处理器的1/3,却能提供更
    的头像 发表于 03-27 09:13 1086次阅读
    <b class='flag-5'>Cortex-M</b>0+内核介绍

    Cortex-M3芯片有哪些

    Cortex-M3芯片是一款基于ARM架构的低功耗、高性能的嵌入式处理器。目前市面上有众多厂商生产了基于Cortex-M3内核的芯片,如意法半导体的STM32F系列、恩智浦半导体的LPC1800系列等。这些芯片广泛应用于工业控制、智能家居、物联网等领域。
    的头像 发表于 03-11 17:07 1607次阅读

    Cortex-M3芯片怎么样

    Cortex-M3芯片是一款高性能、低功耗的32位RISC处理器,特别适用于嵌入式系统和实时控制领域。其架构采用哈佛结构,实现指令和数据存储器的独立访问,提高了系统效率。Cortex-M3支持内部和外部总线接口,提供了广泛的外设连接和扩展性支持。
    的头像 发表于 03-08 16:00 1356次阅读

    Cortex-M85内核单片机如何快速上手

    2022年4月,Arm推出了全新的MCU级内核Cortex-M85。截止目前(2024年2月),Cortex-M85是最新、最强的Cortex-M内核。
    发表于 02-29 09:35 762次阅读
    <b class='flag-5'>Cortex-M</b>85内核单片机如何快速上手

    入门级64位ARM®CORTEX®-A55 MPU数据手册

    电子发烧友网站提供《入门级64位ARM®CORTEX®-A55 MPU数据手册.pdf》资料免费下载
    发表于 02-19 10:59 1次下载
    <b class='flag-5'>入门</b>级64位ARM®<b class='flag-5'>CORTEX</b>®-A55 MPU数据手册

    请问mbed物联网操作系统会成为cortex-m中的android吗?

    mbed 物联网操作系统会成为cortex-m中的android吗?
    发表于 01-17 07:14

    如何使用Keil打开GD32 FPU及使用ARM DSP库 ?

    GD32目前支持ARM Cortex-M和RISC-V两种内核系列芯片,其中Cortex-M内核已经支持的有M3、M4、M23、
    的头像 发表于 01-13 09:42 3694次阅读
    如何使用Keil打开GD32 FPU及使用ARM DSP库 ?