阅读:4361回复:8
IDA反汇辅助BDI2000调试EBOOT
虽然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下的反汇编代码阅读写个拙笨的帖子,就看休假回来还有没有这个心力了。 明天我就要回家了,祝版上各位朋友新春愉快,加薪晋级。 |
|
沙发#
发布于:2008-01-29 16:09
hunbalo
俺爱死你了 讲的贼拉好 |
|
板凳#
发布于:2008-01-29 16:10
多些 你和楚狂人
世界更加perfect |
|
地板#
发布于:2008-01-31 12:10
很不错,其实0x00000000是一条跳转到eboot的汇编指令吗?
|
|
地下室#
发布于:2008-12-08 00:41
反汇编一下eboot.nb0
请问是怎么反汇编的?用的那个软件?是用ADS吗? |
|
5楼#
发布于:2008-12-15 16:51
引用第4楼xb202于2008-12-08 00:41发表的 : IDA反汇编软件不错,很牛B。 |
|
|
6楼#
发布于:2008-12-15 17:06
楚狂人写的《天天夜读》,哪里有卖呢?我在网上找不到啊
或者哪里有下载。 |
|
|
7楼#
发布于:2008-12-25 19:08
引用第6楼gooogleman于2008-12-15 17:06发表的 : 在本论坛搜索一下,有电子版的下载。注:是《天书夜读》,不是《天天夜读》 |
|
|
8楼#
发布于:2009-05-19 20:04
up up
|
|