hunbalo
驱动牛犊
驱动牛犊
  • 注册日期2004-04-21
  • 最后登录2020-10-20
  • 粉丝0
  • 关注0
  • 积分11分
  • 威望124点
  • 贡献值0点
  • 好评度85点
  • 原创分1分
  • 专家分0分
  • 社区居民
阅读:4361回复:8

IDA反汇辅助BDI2000调试EBOOT

楼主#
更多 发布于:2008-01-29 10:24
       虽然eboot的全部源代码已经发布,但是在对于一个bootloader程序员来说,适当看一点反汇编还是有必要的,毕竟这才是实际在处理器上跑的代码。
    BDI2000是调试LINUX bootloader的优秀工具,通过它可以直接用gdb调试uboot,乃至linux kernel. 但是gdb并不能识别*.pdb的符号表文件,因此,这么优秀的工具调试起eboot就不那么方便了。虽然eboot也有相应的工具调试,但是重复投资也不划算,其实借助与IDA 反汇编工具结合BDI2000,也可以达到近似与源码级调试的效果。
    Bootloader的第一条指令所在的ROM地址是cpu的程序入口,这一点,无论是x86的BIOS,还是UBOOT,EBOOT都是一个道理,和裸奔的单片机程序也别无二样。对于ARM系列处理器来说,这个地址就是0x00000000,也就是RESET VECTOR地址。
以PXA270Mainstone ii平台为例,eboot编译链接后生成eboot.exe, romimage会后生成eboot.bin和eboot.nb0, eboot.bin是eboot自更新用的。对于裸片也可以利用烧写器将eboot.nb0写入XIP的BOOT FLASH中。Eboot.exe和eboot.nb0的区别在于前者是PE格式的,反汇编时可以看到程序入口是0x00011000,68K偏移的地方,这个文件的方便之处在于反汇编的时候,可以把PDB加载进来,C语言及汇编中的全局变量名及函数名还能完全还原出来,以便阅读和搜索,但是它的链接地址和执行地址还不一样,下面是eboot.exe入口startup反汇编后的代码。
.text:00011000
.text:00011000
.text:00011000                 EXPORT StartUp
.text:00011000 StartUp
.text:00011000
.text:00011000 ; FUNCTION CHUNK AT .text:0002CE94 SIZE 00000038 BYTES
.text:00011000 ; FUNCTION CHUNK AT .text:0002CEE0 SIZE 00000010 BYTES
.text:00011000
.text:00011000                 BL      sub_110A0
.text:00011000
.text:00011004                 TST     R10, #1
.text:00011008                 BNE     loc_11020
.text:00011008
.text:0001100C                 TST     R10, #4
.text:00011010                 BNE     loc_11020
.text:00011010
.text:00011014                 TST     R10, #8
.text:00011018                 BNE     loc_1106C
.text:00011018
.text:0001101C                 BEQ     OALStartUp

        在$(WINCEROOT)\PLATFORM\COMMON\SRC\ARM\INTEL\PXA27X\STARTUP\start.s
对应上述反汇编的源代码
   LEAF_ENTRY StartUp

    ; Perform pre-initialization (enter supervisor mode, disable MMU and caches,
    ; and determine the reason for the reset.
    ;
    bl      PreInit

    ; r10 now contains the contents of the power manager registers RCSR in the
    ; lower half and PSSR in the upper half.  If we're in this routine because
    ; of a hardware/power-on reset, then we need to continue in this routine and
    ; initialize all hardware.  Otherwise, we'll assume the hardware's already
    ; been initialized and we can skip.
    ;
    tst     r10, #RCSR_HARD_RESET
    bne   MemInit

    tst    r10, #RCSR_SLEEP_RESET
    bne  MemInit
  
    ; If we're here because of a GPIO reset, skip the memory controller
    ; initialization because all memory registers (except for configuration
    ; registers are maintained across the reboot).
    ;
    tst    r10, #RCSR_GPIO_RESET
    bne  Continue_StartUp
    beq  OALStartUp


        在$(_TGTPLAT)\src\eboot\下的source文件中有EXEENTRY=StartUp链接指示将入口链接为startup。
但是这段代码并不是在0x00000000执行的,这段代码是在0x00001000,4Kb的地方执行的,我们反汇编一下eboot.nb0可以看到,第一条指令是
ROM:00000000                 B       loc_1000
跳转到4KB的start.s执行。
     一般说来就ARM来讲,开始几条指令应当依次是
0x00000000 b reset;
0x00000004 b isr0;
0x00000008 b isr1;
……
    这个结构对于用过UBOOT和blob等linux下bootloader的人应该并不陌生。
但是eboot本身并不支持中断,cpu初始化后也是完全处于关中断状态下的,所以中断处理完全没有必要,就只需要一个b reset了,reset就是0x000001000。而PE格式的Eboot.exe中对应的地址是0x00011000,这样如果我们看着eboot.exe的反汇编用bdi2000设置断点的时候就要自己手动计算这个地址了。
    比如说,我要在OALStartUp设置断点,那么,我先看eboot.exe的反汇编.
text:0001E668 OALStartUp
可以计算出OALStartUp的地址是0xE668, 可以直接用BDI2000在0xE668设断点。
    但是EBOOT的很大一部分是拷贝到RAM中执行的。EBOOT做了一些简单的初始化,诸如初始化内存控制器,创建页表等的工作后,就把自己拷贝到内存执行了,那么到内存中执行时我们要怎么设置断点呢?
    且看$(WINCEROOT)\PLATFORM\MAINSTONEII\SRC\BOOTLOADER\EBOOT下start.s中的这一段代码
CODEINRAM

    ;bl        LED_ON
    ; We're now running out of RAM.
    ;
    ;ldr     r0, =MAINSTONEII_BASE_REG_PA_FPGA
    ;mov     r1, pc              ; Get the RAM-based PC.
    ;setHexLED  r0, r1           ; Display it.

    ; Now that we're running out of RAM, construct the first-level Section descriptors
    ; to create 1MB mapped regions from the addresses defined in the OEMAddressTable.
    ; This will allow us to enable the MMU and use a virtual address space that matches
    ; the mapping used by the OS image.
    ;
    ; We'll create two different mappings from the addresses specified:
    ;     [8000 0000 --> 9FFF FFFF] = Cacheable, Bufferable
    ;     [A000 0000 --> BFFF FFFF] = NonCacheable, nonBufferable
    ;
BUILDTTB
    add     r11, pc, #g_oalAddressTable - (. + 8)    ; Pointer to OEMAddressTable.
    
    ; Set the TTB.
    ;
    ldr     r9, =MAINSTONEII_BASE_PA_SDRAM    ; Physical address of the first-level table (base of SDRAM).
    ldr     r0, =0xFFFFC000                   ;
    and     r9, r9, r0                        ; Mask off TTB[31:0] (must be 0's).
    mcr     p15, 0, r9, c2, c0, 0             ; Set the TTB.

    add     r11, pc, #g_oalAddressTable - (. + 8)    ; Pointer to OEMAddressTable.
在我的代码中,注解了几条指令。
这段代码计算出add     r11, pc, #g_oalAddressTable - (. + 8) 这条指令在RAM中的物理地址偏移,再跳转过去,在image_cfg.h中可以看到IMAGE_BOOT_BLDRIMAGE_RAM_PA_START的值是0xA0020000,如果我们要对add     r11, pc, #g_oalAddressTable - (. + 8)设置断点怎么做呢?
看看反汇编eboot.exe的相应代码
.text:0001E84C                 ADR     R11, g_oalAddressTable
这个地址是E84C+0xA0020000 = 0xA002E84C,于是我们BDI设置BI 0xA002E84C。
接着,设置完页表后,RAM物理地址被映射到0x8000 0000处,开启MMU后,RAM的地址又要重新计算。
0xA0020000被映射到0x8002 0000处。如果我要对main函数设置断点,看相应的反汇编.text:00018C28 main                                    ; CODE XREF: .text:0001E90Cp
.text:00018C28                                         ; DATA XREF: .pdata:000370E0o
.text:00018C28
.text:00018C28 var_4           = -4
.text:00018C28 arg_4           =  4
.text:00018C28
.text:00018C28                 STR     LR, [SP,#var_4]!
.text:00018C2C                 SUB     SP, SP, #4
设置0x800028C28断点即可。
  综合上述,就是在EBOOT运行的各个阶段,断点的设置不一样,根据eboot.exe的地址和平台的配置,可以计算出索要设置断点的地址。
    写了这些,不指导表述清楚了没有,如果能对人有所帮助,我很高兴,如果没啥帮助,我也不郁闷,以后会继续写点有用的。
    反汇编工具及BDI2000的使用,很多地方都介绍过,我也不再赘述。看过 楚狂人写的《天天夜读》,对X86下反汇编代码阅读写的甚为明晰,我本也想对ARM下的反汇编代码阅读写个拙笨的帖子,就看休假回来还有没有这个心力了。
明天我就要回家了,祝版上各位朋友新春愉快,加薪晋级。
sdydding
驱动牛犊
驱动牛犊
  • 注册日期2006-08-03
  • 最后登录2010-08-10
  • 粉丝0
  • 关注0
  • 积分200分
  • 威望22点
  • 贡献值0点
  • 好评度21点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2008-01-29 16:09
hunbalo
俺爱死你了
讲的贼拉好

 
sdydding
驱动牛犊
驱动牛犊
  • 注册日期2006-08-03
  • 最后登录2010-08-10
  • 粉丝0
  • 关注0
  • 积分200分
  • 威望22点
  • 贡献值0点
  • 好评度21点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2008-01-29 16:10
多些 你和楚狂人

世界更加perfect
pdodge
驱动牛犊
驱动牛犊
  • 注册日期2007-04-24
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分100分
  • 威望11点
  • 贡献值0点
  • 好评度10点
  • 原创分1分
  • 专家分0分
地板#
发布于:2008-01-31 12:10
很不错,其实0x00000000是一条跳转到eboot的汇编指令吗?
xb202
驱动牛犊
驱动牛犊
  • 注册日期2004-02-27
  • 最后登录2010-10-06
  • 粉丝0
  • 关注0
  • 积分2分
  • 威望20点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
地下室#
发布于:2008-12-08 00:41
反汇编一下eboot.nb0

请问是怎么反汇编的?用的那个软件?是用ADS吗?
gooogleman
驱动牛犊
驱动牛犊
  • 注册日期2007-03-02
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分15分
  • 威望179点
  • 贡献值0点
  • 好评度18点
  • 原创分0分
  • 专家分0分
5楼#
发布于:2008-12-15 16:51
引用第4楼xb202于2008-12-08 00:41发表的  :
反汇编一下eboot.nb0

请问是怎么反汇编的?用的那个软件?是用ADS吗?

IDA反汇编软件不错,很牛B。
WINCEqq 群39063007
gooogleman
驱动牛犊
驱动牛犊
  • 注册日期2007-03-02
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分15分
  • 威望179点
  • 贡献值0点
  • 好评度18点
  • 原创分0分
  • 专家分0分
6楼#
发布于:2008-12-15 17:06
 楚狂人写的《天天夜读》,哪里有卖呢?我在网上找不到啊
或者哪里有下载。
WINCEqq 群39063007
pilixuanke
驱动中牛
驱动中牛
  • 注册日期2005-10-31
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分1018分
  • 威望626点
  • 贡献值0点
  • 好评度512点
  • 原创分0分
  • 专家分0分
7楼#
发布于:2008-12-25 19:08
引用第6楼gooogleman于2008-12-15 17:06发表的  :
 楚狂人写的《天天夜读》,哪里有卖呢?我在网上找不到啊
或者哪里有下载。


在本论坛搜索一下,有电子版的下载。注:是《天书夜读》不是《天天夜读》
向底层开发进军!!!
ielts5316
驱动小牛
驱动小牛
  • 注册日期2005-05-18
  • 最后登录2018-08-27
  • 粉丝0
  • 关注0
  • 积分478分
  • 威望940点
  • 贡献值0点
  • 好评度72点
  • 原创分0分
  • 专家分0分
  • 社区居民
8楼#
发布于:2009-05-19 20:04
up up
游客

返回顶部