ADS简单程序编译分析
来源:互联网 发布:安卓2.2软件 编辑:程序博客网 时间:2024/05/20 08:27
前言
最近准备将公司的产品进行更新,目前的产品是ucos操作系统混合了产品程序一起烧写到LPC2148的512k FLASH内部,这样做有个弊端,就是一旦产品程序出了错误,无法让客户自行更新程序,因此希望改成操作系统与产品程序分离,在必要的时候执行将tf卡内部的程序烧写道FLASH内部进行产品程序更新。操作系统程序一旦固化入FLASH则尽量不去修改,目前没有设计更新操作系统的方法。
如此一来,512K FLASH的底层空间由操作系统占用,程序上电从0地址运行,此时为操作系统端,此后程序将运行到能够切换到用户状态加载程序处。操作系统把需要的程序接口地址写入一个约定地址(比如读取TF卡),并没有使用swi(软件中断),因为这种形式修改起来方便,都是现成的程序。如果将来再次升级系统可以改变为swi调用系统函数。
系统按照与用户程序约定的地址调用用户程序,用户调用系统程序时也使用约定的地址寻找程序地址,因此首先需要了解ADS是如何编译程序的,因此进行了下面的分析:
C代码
首先,用ADS创建一个工程,输入以下代码:
void fun1(){ char *p; int i; p = (char *)0x40004000; for(i = 0; i < 16; i++) { *p = i; p++; }}int main(){ fun1(); return 1;}
在编译器设置里,将Linker-ARM linker下的link type设置为simple,RO Base设置为0x29c00,这是程序将来将要烧写到的位置。RW Base设置为0x40003000这是将来保存变量的区域,此后在Linker-ARM fromELF功能里选择生成Text Information,设置好文件名,将会产生出文本文档形式的ELF文件详细说明,其中我们需要关注的是将要烧写到ROM中的代码段,附录里是摘抄出来的完整的编译后的汇编代码。
汇编程序分析
下面是对程序的分析:
首先,因为设置了RO Base为0x29c00,因此在执行此程序的时候,内存地址应为0x29c00,且PC(指令计数器)也应当指向此处。
__main$a!!! 0x00029c00: e28f8090 .... ADD r8,pc,#0x90 ; #0x29c98 0x00029c04: e898000f .... LDMIA r8,{r0-r3} 0x00029c08: e0800008 .... ADD r0,r0,r8 0x00029c0c: e0811008 .... ADD r1,r1,r8 0x00029c10: e0822008 . .. ADD r2,r2,r8 0x00029c14: e0833008 .0.. ADD r3,r3,r8 0x00029c18: e240b001 ..@. SUB r11,r0,#1 0x00029c1c: e242c001 ..B. SUB r12,r2,#1
可以看到第一行即程序的起始地址就是这个数,将来烧写的时候,烧写器会根据烧写地址放入对应位置(LPC2148的前512kb字节为Flash,属于非易失存储器,因此程序保存在这个范围内)。第一条语句将pc加上0x90放入r8,此时pc指向的是下一个取命令地址,也可能是因为一次取16字节命令,所以pc的值为0x29c08,则r8此后为0x29c98。下一条语句的意思是从r8开始,取连续的4个地址的值,放入r0-r3。
_region_table$d 0x00029c98: 0000032c ,... DCD 812 0x00029c9c: 00000350 P... DCD 848 0x00029ca0: 00000350 P... DCD 848 0x00029ca4: 00000368 h... DCD 872
因此r0=812, r1=848, r2=848, r3=872。
后面的几个语句为r0=r0+r8…r3=r3+r8,r11=r0-1,r12=r2-1
通过计算,r0=0x29fc4, r1=0x29fe8, r2=0x29fe8, r3=0x2a000,可以看出来,这应该还是程序段内部的地址,他们对应的是下面的代码:
Region$$Table$$Base$d 0x00029fc4: 00000000 .... DCD 0 0x00029fc8: 00000000 .... DCD 0 0x00029fcc: 00000000 .... DCD 0 0x00029fd0: 0002a000 .... DCD 172032 0x00029fd4: 40003000 .0.@ DCD 1073754112 0x00029fd8: 00000000 .... DCD 0 0x00029fdc: 0002a000 .... DCD 172032 0x00029fe0: 40003000 .0.@ DCD 1073754112 0x00029fe4: 00000000 .... DCD 0Region$$Table$$LimitZISection$$Table$$Base 0x00029fe8: 0002a000 .... DCD 172032 0x00029fec: 00000000 .... DCD 0 0x00029ff0: 40003000 .0.@ DCD 1073754112 0x00029ff4: 00000000 .... DCD 0 0x00029ff8: 40003000 .0.@ DCD 1073754112 0x00029ffc: 00000060 `... DCD 96ZISection$$Table$$Limit
可以看出分别对应了一个叫做Region表的起始和结束地址,以及一个叫做ZISection表的起始和结束地址。这大概对应了程序中的全局数据段以及函数变量段,他们的区别就是一个要全程保留且要初始化,分配在堆里面,另一个在函数内才会被分配空间,即在堆栈内分配空间,一旦函数释放了数据就没有义务被保存,初始化的时候需要清零。从名字可以看出来ZISection应当对应了Zero Initial Section,所以是函数变量的空间。他们都有几个特殊数字,分别对应了编译器指定的RO Base地址0x40003000,以及代码段的结尾0x2a000,功能后面再分析。
后面的代码为:
_move_region 0x00029c20: e1500001 ..P. CMP r0,r1 0x00029c24: 0a00000e .... BEQ _zero_region ; 0x29c64 0x00029c28: e8b00070 p... LDMIA r0!,{r4-r6} 0x00029c2c: e1540005 ..T. CMP r4,r5 0x00029c30: 0afffffa .... BEQ _move_region ; 0x29c20 0x00029c34: e3140001 .... TST r4,#1 0x00029c38: 1084400b .@.. ADDNE r4,r4,r11 0x00029c3c: e3150001 .... TST r5,#1 0x00029c40: 1085500b .P.. ADDNE r5,r5,r11 0x00029c44: e3150002 .... TST r5,#2 0x00029c48: 10855009 .P.. ADDNE r5,r5,r9 0x00029c4c: e3c55003 .P.. BIC r5,r5,#3
此段的名称可以看出来是移动region表,前二行为比较r0,r1,若相等说明没有region表,则跳到_zero_region执行。
LDMIA r0!,{r4-r6}
此句多了一个’!’符号,表示执行后将最终地址放入r0。参考region表,可以知道r4-r6均为0,r0=0x00029fd0。
0x00029c2c: e1540005 ..T. CMP r4,r5 0x00029c30: 0afffffa .... BEQ _move_region ;
若r4,r5相等则跳回_move_region执行,此时r0的值已经改变,则再次运行到此的时候,r4=172032(0x2a000), r5=1073754112(0x40004000), r6=0, r0=0x00029fdc,此后由于r4!=r5,程序向下进行。
0x00029c34: e3140001 .... TST r4,#1 0x00029c38: 1084400b .@.. ADDNE r4,r4,r11 0x00029c3c: e3150001 .... TST r5,#1 0x00029c40: 1085500b .P.. ADDNE r5,r5,r11 0x00029c44: e3150002 .... TST r5,#2 0x00029c48: 10855009 .P.. ADDNE r5,r5,r9 0x00029c4c: e3c55003 .P.. BIC r5,r5,#3
TST的意思是,r4与后面的立即数位与,并根据结果设置标志位,由于r4没有设置最低位,因此结果为0,后面的ADDNE将不会执行。
BIC是清位操作,等同于等同于 R5 &=~(0x03)
在此程序中实际上此段未进行什么实质处理。
_move_loop 0x00029c50: e2566004 .`V. SUBS r6,r6,#4 0x00029c54: 24947004 .p.$ LDRCS r7,[r4],#4 0x00029c58: 24857004 .p.$ STRCS r7,[r5],#4 0x00029c5c: 8afffffb .... BHI _move_loop ; 0x29c50 0x00029c60: eaffffee .... B _move_region ; 0x29c20
第一句SUBS r6,r6,#4
等同于r6=r6-4,并根据结果设置标志位。减法是将操作数求补后相加,这里由于执行前r6=0因此将不设置标志位。LDRCS r7,[r4],#4
找不到对应的指令说明,但根据字面意思可以得到,如果标志位被置位,则执行r7=[r4](即r4指向地址的值),r4=r4+4,这里应当不会执行。同理下面一句r7,[r5],#4
也不执行。BHI _move_loop
如果进位位被置位则跳转到_move_loop此处也不执行。
此后依然跳转回_move_region执行,将会按照前面解释的过程再执行一次,此次运行到跳转回_move_region的位置时,r0=0x00029fe8,与r1相等了,程序将跳出_move_region转到_zero_region执行。可以看出,此段程序根据region中段的数量可以进行多次拷贝,本程序共拷贝了2次。
_zero_region 0x00029c64: e1520003 ..R. CMP r2,r3 0x00029c68: 0b000018 .... BLEQ __rt_entry ; 0x29cd0 0x00029c6c: e3a07000 .p.. MOV r7,#0 0x00029c70: e8b20030 0... LDMIA r2!,{r4,r5} 0x00029c74: e3140001 .... TST r4,#1 0x00029c78: 1084400c .@.. ADDNE r4,r4,r12 0x00029c7c: e3140002 .... TST r4,#2 0x00029c80: 10844009 .@.. ADDNE r4,r4,r9 0x00029c84: e3c44003 .@.. BIC r4,r4,#3_zero_loop 0x00029c88: e2555004 .PU. SUBS r5,r5,#4 0x00029c8c: 24847004 .p.$ STRCS r7,[r4],#4 0x00029c90: 8afffffc .... BHI _zero_loop ; 0x29c88 0x00029c94: eafffff2 .... B _zero_region ; 0x29c64
与region一样,首先比较r2,r3,若相等就跳转到__rt_entry。BL是需要返回值得跳转,此语句默认设置R14作为返回值地址(在程序中不会显式的看到此操作)。实际上此段程序将会循环三次,直到第三次,r5=96,将会连续写24个0到0x40003000开头的位置。此后r2=r3=0x2a000,程序跳转到__rt_entry。
__rt_entry$a.text 0x00029cd0: eb000046 F... BL __rt_stackheap_init ; 0x29df0 0x00029cd4: eb0000ad .... BL $Ven$AT$L$$__rt_lib_init ; 0x29f90 0x00029cd8: e59fc01c .... LDR r12,0x29cfc
BL为要求返回的跳转,将会把PC的值保存在r14中,作为以后返回此处的地址。可见先调用了__rt_stackheap_init,位于地址0x29df0。此后调用了$Ven$AT$L$$__rt_lib_init,位于地址0x29f90,最后把0x29cfc赋值到r12。下面分析两个函数的功能:
1.函数__rt_stackheap_init
__rt_stackheap_init$a 0x00029df0: e1a0500e .P.. MOV r5,r14 0x00029df4: eb000047 G... BL __user_libspace ; 0x29f18 0x00029df8: e1a0e005 .... MOV r14,r5
首先,把r14保存起来,作为以后返回的地址,此后调用__user_libspace,
__user_libspace$a 0x00029f18: e59f0000 .... LDR r0,0x29f20 0x00029f1c: e12fff1e ../. BX r14$d 0x00029f20: 40003000 .0.@ DCD 1073754112
此函数功能很简单,就是把0x40003000放入r0后返回。下面回到__rt_stackheap_init,恢复此前保存的r14值,r5可以用作他处了。
0x00029dfc: e1a04000 .@.. MOV r4,r0 0x00029e00: e1a0100d .... MOV r1,r13 0x00029e04: e1a0300a .0.. MOV r3,r10
r4=0x40003000,r1=r13,r3=r10其中arm通常使用r13作为sp(堆栈)地址寄存器,所以r1表示的是当前堆栈的底部,r10的作用暂时未知,r3被赋值后未见何特殊操作。
0x00029e08: e3c00007 .... BIC r0,r0,#7 0x00029e0c: e280d060 `... ADD r13,r0,#0x60 0x00029e10: e92d4010 .@-. STMFD r13!,{r4,r14} 0x00029e14: eb000043 C... BL __user_initial_stackheap ; 0x29f28
BIC为清位操作,把r0低三位清零,这估计是因为至少保证字节对齐。把r13(堆栈)设置为r0+0x60的位置,此处可以看出,0x60=96,而在前面的_zero_region中已经开辟出了一个96字节的,从0x40003000开始的区域,因此本程序的栈底为0x40003060(注意堆栈是向下增长地址的),STMFD r13!,{r4,r14}
表示入栈操作,将r4,r14压入堆栈,此时栈底将指向0x40003058。下面跳转到__user_initial_stackheap,从名字可以看出是初始化用户的堆栈和堆。
__user_initial_stackheap$a 0x00029f28: e92d4000 .@-. STMFD r13!,{r14} 0x00029f2c: e24dd014 ..M. SUB r13,r13,#0x14 0x00029f30: e1a0100d .... MOV r1,r13 0x00029f34: e28d2004 . .. ADD r2,r13,#4 0x00029f38: e5812000 . .. STR r2,[r1,#0] 0x00029f3c: e3a00016 .... MOV r0,#0x16 0x00029f40: ef123456 V4.. SWI 0x123456 0x00029f44: e59d0004 .... LDR r0,[r13,#4] 0x00029f48: e59d100c .... LDR r1,[r13,#0xc] 0x00029f4c: e59d2008 . .. LDR r2,[r13,#8] 0x00029f50: e59d3010 .0.. LDR r3,[r13,#0x10] 0x00029f54: e3500000 ..P. CMP r0,#0 0x00029f58: 059f000c .... LDREQ r0,0x29f6c 0x00029f5c: e28dd014 .... ADD r13,r13,#0x14 0x00029f60: e8bd4000 .@.. LDMFD r13!,{r14} 0x00029f64: e12fff1e ../. BX r14$d$f 0x00029f68: 00000009 .... DCD 9_RW_Limit 0x00029f6c: 40003060 `0.@ DCD 1073754208
将r14压入用户栈,将栈向下移动20个字节,把栈底保存到r1,此时栈底为0x40003034。r2=0x40003038,并把r2的值存入r1指向的地址。此后的
0x00029f3c: e3a00016 .... MOV r0,#0x16 0x00029f40: ef123456 V4.. SWI 0x123456
具体应该是调用了软中断,这里暂时判断为没有任何作用,直接返回,也可能不返回,因为没有设置软中断。
0x00029f44: e59d0004 .... LDR r0,[r13,#4] 0x00029f48: e59d100c .... LDR r1,[r13,#0xc] 0x00029f4c: e59d2008 . .. LDR r2,[r13,#8] 0x00029f50: e59d3010 .0.. LDR r3,[r13,#0x10]
r0=[0x40003038],r1= [0x40003040],r2=[0x4000303c],r3=[0x40003044]此4个地址应当都对应了0,因此后面的CMP语句将会得到相等的结果,则执行LDREQ r0,0x29f6c
因此r0=40003060,后面恢复r13 ,r14,并返回上级调用。此段函数大概就是检查栈区是否清零过,并把r0设置为栈顶的值,返回,程序回到__rt_stackheap_init继续执行。
0x00029e18: e8bd4010 .@.. LDMFD r13!,{r4,r14} 0x00029e1c: e3c1d007 .... BIC r13,r1,#7 0x00029e20: e3a06000 .`.. MOV r6,#0 0x00029e24: e3a07000 .p.. MOV r7,#0 0x00029e28: e3a08000 .... MOV r8,#0 0x00029e2c: e3a0b000 .... MOV r11,#0 0x00029e30: e1a0c004 .... MOV r12,r4
让r4,r14的值出栈,将r1低三位清零赋值给r13,等于恢复r13的初始值且8字节对齐。r6=r7=r8=r11=0,r12=0x40003000。
0x00029e34: e8ac09c0 .... STMIA r12!,{r6-r8,r11} 0x00029e38: e8ac09c0 .... STMIA r12!,{r6-r8,r11} 0x00029e3c: e8ac09c0 .... STMIA r12!,{r6-r8,r11} 0x00029e40: e8ac09c0 .... STMIA r12!,{r6-r8,r11}
此处程序执行后,r12=0x40003040,r6-r8,r11均为0
0x00029e44: e92d4013 .@-. STMFD r13!,{r0,r1,r4,r14}
将r0,r1,r4,r14入栈,r13随之改变
0x00029e48: e3a00000 .... MOV r0,#0 0x00029e4c: e3a01000 .... MOV r1,#0 0x00029e50: ebffffff .... BL 0x29e54
r0=0,r1=0,r14=0x00029e54
0x00029e54: e2811040 @... ADD r1,r1,#0x40 0x00029e58: e0802001 . .. ADD r2,r0,r1 0x00029e5c: e2822f44 D/.. ADD r2,r2,#0x110
r1=0x40,r2=0x150
0x00029e60: e584201c . .. STR r2,[r4,#0x1c] 0x00029e64: e5841018 .... STR r1,[r4,#0x18] 0x00029e68: e3a00001 .... MOV r0,#1 0x00029e6c: e5840010 .... STR r0,[r4,#0x10] 0x00029e70: e8bd4013 .@.. LDMFD r13!,{r0,r1,r4,r14} 0x00029e74: e5840014 .... STR r0,[r4,#0x14] 0x00029e78: e1a01000 .... MOV r1,r0 0x00029e7c: e1a0f00e .... MOV pc,r14
向内存中写入一些数据,返回调用。
2.函数
$Ven$AT$L$$__rt_lib_init 0x00029f90: e59fc000 .... LDR r12,0x29f98 0x00029f94: e12fff1c ../. BX r12$d$f 0x00029f98: 00029d35 5... DCD 171317
r12=0x29d35,bx命令为条件跳转,如果最低位为0则按照arm指令继续执行跳转位置指令,如果最低位为1则按照THUMBS指令集执行。
__rt_lib_init.text 0x00029d34: b5f0 .. PUSH {r4-r7,r14} 0x00029d36: 1c04 .. MOV r4,r0 0x00029d38: 1c0d .. MOV r5,r1 0x00029d3a: b083 .. SUB r13,#0xc$b 0x00029d3c: f000f934 ..4. BL __16_fp_init ; 0x29fa8
注意THUMBS指令集的命令比ARM的指令集要短。
将r4-r7,r14入栈,改变r4,r5,r13的值,调用__16_fp_init
__16_fp_init$tx$fpl$fpinit 0x00029fa8: 4778 xG BX pc$d 0x00029faa: 0000 .. DCW 0_fp_init$a 0x00029fac: e92d4010 .@-. STMFD r13!,{r4,r14} 0x00029fb0: ebfffff1 .... BL __rt_fp_status_addr ; 0x29f7c
此时pc指向下一个命令,BX调用则切换回ARM指令集,DCW为分配一段内存空间,这里分配了0个字节,可以认为是用来凑数的,为了使命令对齐。下面将r4,r14入栈,跳转到__rt_fp_status_addr
__rt_fp_status_addr$a 0x00029f7c: e92d4010 .@-. STMFD r13!,{r4,r14} 0x00029f80: ebffffe4 .... BL __user_libspace ; 0x29f18 0x00029f84: e2800004 .... ADD r0,r0,#4 0x00029f88: e8bd4010 .@.. LDMFD r13!,{r4,r14} 0x00029f8c: e12fff1e ../. BX r14
将r4,r14入栈,跳转到__user_libspace,前面已经说过了,此函数功能很简单,就是把0x40003000放入r0后返回。此后r0=r0+4=0x40003004,取出r4,r14,返回__16_fp_init。
0x00029fb4: e3a01000 .... MOV r1,#0 0x00029fb8: e5801000 .... STR r1,[r0,#0]__fplib_config_pureend_doubles 0x00029fbc: e8bd4010 .@.. LDMFD r13!,{r4,r14} 0x00029fc0: e12fff1e ../. BX r14
r1=0, 0x40003004=r1=0,r4,r14出栈,返回__rt_lib_init,注:这里如何切换到THUMB状态的没有查到资料,但肯定是切换回THUMB指令集了。
0x00029d40: 9400 .. STR r4,[r13,#0] 0x00029d42: 9501 .. STR r5,[r13,#4]
将r4,r5的值依次放入r13增长的方向的内存
0x00029d44: 2000 . MOV r0,#0$b 0x00029d46: f000f800 .... BL 0x29d4a
r0=0,跳转到后面语句
0x00029d4a: 9002 .. STR r0,[r13,#8] 0x00029d4c: 4826 &H LDR r0,0x29de8 0x00029d4e: 4669 iF MOV r1,r13 0x00029d50: 4478 xD ADD r0,pc
把r0放入r13后第8字节开始的4个字节,r0=148,用r1保存r13,r0=r0+pc,此时pc=0x29d52, r0=0x29de6。
$b 0x00029d52: f000f800 .... BL 0x29d56 0x00029d56: 1c05 .. MOV r5,r0 0x00029d58: 1c0e .. MOV r6,r1 0x00029d5a: a900 .. ADD r1,r13,#0 0x00029d5c: c903 .. LDMIA r1!,{r0,r1}
r5=0x29de6,r6为栈底,0x40003060,r1=r13+0,r0,r1赋值
$b 0x00029d5e: f000f800 .... BL $b ; 0x29d62$b 0x00029d62: f000f800 .... BL $b ; 0x29d66$b 0x00029d66: f000f800 .... BL 0x29d6a 0x00029d6a: 2100 .! MOV r1,#0 0x00029d6c: 2000 . MOV r0,#0
r0=r1=0
$b 0x00029d6e: f000f800 .... BL 0x29d72 0x00029d72: 1c07 .. MOV r7,r0$b 0x00029d74: f000f8ce .... BL __16__user_libspace ; 0x29f14
r7=0, 跳转到__16__user_libspace,此处程序可能是向堆内写入数据看看是否能够写入。
__16__user_libspace$t.text 0x00029f14: 4778 xG BX pc$d 0x00029f16: 0000 .. DCW 0__user_libspace$a 0x00029f18: e59f0000 .... LDR r0,0x29f20 0x00029f1c: e12fff1e ../. BX r14
此处实际上还是执行了__user_libspace,r0等于0x40003000并返回。
0x00029d78: 1c04 .. MOV r4,r0 0x00029d7a: 2100 .! MOV r1,#0 0x00029d7c: 6207 .b STR r7,[r0,#0x20] 0x00029d7e: 2000 . MOV r0,#0$b 0x00029d80: f000f800 .... BL 0x29d84 0x00029d84: 1c41 A. ADD r1,r0,#1 0x00029d86: 6261 ab STR r1,[r4,#0x24] 0x00029d88: 2100 .! MOV r1,#0 0x00029d8a: 2000 . MOV r0,#0$b 0x00029d8c: f000f800 .... BL 0x29d90 0x00029d90: 2100 .! MOV r1,#0 0x00029d92: 62a0 .b STR r0,[r4,#0x28] 0x00029d94: 2000 . MOV r0,#0$b 0x00029d96: f000f800 .... BL 0x29d9a 0x00029d9a: 2100 .! MOV r1,#0 0x00029d9c: 62e0 .b STR r0,[r4,#0x2c] 0x00029d9e: 2000 . MOV r0,#0$b 0x00029da0: f000f800 .... BL 0x29da4 0x00029da4: 6320 c STR r0,[r4,#0x30]$b 0x00029da6: f000f800 .... BL $b ; 0x29daa$b 0x00029daa: f000f800 .... BL $b ; 0x29dae$b 0x00029dae: f000f800 .... BL $b ; 0x29db2$b 0x00029db2: f000f800 .... BL $b ; 0x29db6$b 0x00029db6: f000f800 .... BL $b ; 0x29dba$b 0x00029dba: f000f800 .... BL $b ; 0x29dbe$b 0x00029dbe: f000f800 .... BL $b ; 0x29dc2$b 0x00029dc2: f000f800 .... BL 0x29dc6 0x00029dc6: 1c28 (. MOV r0,r5 0x00029dc8: 1c31 1. MOV r1,r6 0x00029dca: b003 .. ADD r13,#0xc 0x00029dcc: bcf0 .. POP {r4-r7} 0x00029dce: bc08 .. POP {r3} 0x00029dd0: 4718 .G BX r3
仍然是向堆内填写数据,最后将栈底上移12字节,恢复r13,使r4-r7出栈,r3出栈,返回上级调用,注意一开始压栈了r4-r7,r14,因此r3=r14,函数返回。调用此函数的为
0x00029cd8: e59fc01c .... LDR r12,0x29cfcmainaddruse 0x00029cdc: e08cc00f .... ADD r12,r12,pc 0x00029ce0: e31c0001 .... TST r12,#1 0x00029ce4: 128fe00d .... ADDNE r14,pc,#0xd ; #0x29cf9 0x00029ce8: 01a0e00f .... MOVEQ r14,pc 0x00029cec: e12fff1c ../. BX r12
r12=0xffffffc4,r12=r12+pc=0x29ca4,下面两句不执行。r14=0x00029cec。跳转到0x29ca4,并按照ARM指令集执行
main$a.text 0x00029ca8: e59f1018 .... LDR r1,0x29cc8 0x00029cac: e3a00000 .... MOV r0,#0 0x00029cb0: e4c10001 .... STRB r0,[r1],#1 0x00029cb4: e2800001 .... ADD r0,r0,#1 0x00029cb8: e3500010 ..P. CMP r0,#0x10 0x00029cbc: bafffffb .... BLT 0x29cb0 0x00029cc0: e3a00001 .... MOV r0,#1 0x00029cc4: e12fff1e ../. BX r14$d 0x00029cc8: 40004000 .@.@ DCD 1073758208_main_redirection$t.text 0x00029ccc: 4770 pG BX r14_main 0x00029cce: 4770 pG BX r14
看起来这就是主程序了,r1=0x40004000,r0=0,把r0赋值给r1指向的位置,r1=r1+1,r0=r0+1,如果r0!=16则继续进行赋值循环。此后将r0设为1,应当是作为返回值了,此处可以看出来主程序上来就完成了c语言代码的子程序的功能,是因为设置了编译时按照空间优先,所以编译器自动把代码优化了。 BX r14
因为r14的值一直没有受到影响,因此按照调用的时候的值0x00029cec返回。
0x00029cf0: e28fc001 .... ADD r12,pc,#1 ; #0x29cf9 0x00029cf4: e12fff1c ../. BX r12
下面跳转到THUMB指令集继续运行(PC指的就是目前位置)。
thumbmainreturn$b$t 0x00029cf8: f000f812 .... BL exit ; 0x29d20
调用THUMB的exit
exit$t.text 0x00029d20: b510 .. PUSH {r4,r14} 0x00029d22: 1c04 .. MOV r4,r0$b 0x00029d24: f000f800 .... BL 0x29d28 0x00029d28: 1c20 . MOV r0,r4$b 0x00029d2a: f7ffffe9 .... BL __rt_exit ; 0x29d00
把r4,r14入栈,r4=r0,r0=r4,调用__rt_exit。
__rt_exit$t 0x00029d00: 4778 xG BX pc$d 0x00029d02: 0000 .. DCW 0__32__rt_exit$a 0x00029d04: e92d4001 .@-. STMFD r13!,{r0,r14} 0x00029d08: eb0000a3 .... BL $Ven$AT$L$$__rt_lib_shutdown ; 0x29f9c
首先将THUMB切换回ARM,使r0(返回值),r14入栈,跳转到
$Ven$AT$L$$__rt_lib_shutdown$a 0x00029f9c: e59fc000 .... LDR r12,0x29fa4 0x00029fa0: e12fff1c ../. BX r12$d$f 0x00029fa4: 00029dd3 .... DCD 171475
此段代码的目的是切换到THUMB指令集并跳转到0x00029dd2运行。
__rt_lib_shutdown 0x00029dd2: b508 .. PUSH {r3,r14}$b 0x00029dd4: f000f800 .... BL $b ; 0x29dd8$b 0x00029dd8: f000f800 .... BL $b ; 0x29ddc$b 0x00029ddc: f000f800 .... BL 0x29de0 0x00029de0: b001 .. ADD r13,#4 0x00029de2: bc08 .. POP {r3} 0x00029de4: 4718 .G BX r3
此处没有进行任何实际操作,返回__rt_exit
0x00029d0c: e8bd4001 .@.. LDMFD r13!,{r0,r14} 0x00029d10: ea000001 .... B __rt_abort1 ; 0x29d1c__rt_abort$t 0x00029d14: 4778 xG BX pc$d 0x00029d16: 0000 .. DCW 0__32__rt_abort$a 0x00029d18: e3e00000 .... MVN r0,#0__rt_abort1 0x00029d1c: ea000076 v... B _sys_exit ; 0x29efc
使r0,r14出栈,跳转到__rt_abort1,再跳转到_sys_exit。
_sys_exit$a 0x00029efc: e3a00018 .... MOV r0,#0x18 0x00029f00: e59f1008 .... LDR r1,0x29f10 0x00029f04: ef123456 V4.. SWI 0x123456 0x00029f08: e12fff1e ../. BX r14$d$f 0x00029f0c: 00000065 e... DCD 101 0x00029f10: 00020026 &... DCD 131110
调用了软中断,之后返回上级调用exit
0x00029d2e: bc10 .. POP {r4} 0x00029d30: bc08 .. POP {r3} 0x00029d32: 4718 .G BX r3
走到这里基本上就等于释放了资源退出了,由于并没有分配任何资源因此退出代码没有什么实质操作。
附录.汇编代码
ROM地址 汇编二进制码 汇编指令__main$a!!! 0x00029c00: e28f8090 .... ADD r8,pc,#0x90 ; #0x29c98 0x00029c04: e898000f .... LDMIA r8,{r0-r3} 0x00029c08: e0800008 .... ADD r0,r0,r8 0x00029c0c: e0811008 .... ADD r1,r1,r8 0x00029c10: e0822008 . .. ADD r2,r2,r8 0x00029c14: e0833008 .0.. ADD r3,r3,r8 0x00029c18: e240b001 ..@. SUB r11,r0,#1 0x00029c1c: e242c001 ..B. SUB r12,r2,#1_move_region 0x00029c20: e1500001 ..P. CMP r0,r1 0x00029c24: 0a00000e .... BEQ _zero_region ; 0x29c64 0x00029c28: e8b00070 p... LDMIA r0!,{r4-r6} 0x00029c2c: e1540005 ..T. CMP r4,r5 0x00029c30: 0afffffa .... BEQ _move_region ; 0x29c20 0x00029c34: e3140001 .... TST r4,#1 0x00029c38: 1084400b .@.. ADDNE r4,r4,r11 0x00029c3c: e3150001 .... TST r5,#1 0x00029c40: 1085500b .P.. ADDNE r5,r5,r11 0x00029c44: e3150002 .... TST r5,#2 0x00029c48: 10855009 .P.. ADDNE r5,r5,r9 0x00029c4c: e3c55003 .P.. BIC r5,r5,#3_move_loop 0x00029c50: e2566004 .`V. SUBS r6,r6,#4 0x00029c54: 24947004 .p.$ LDRCS r7,[r4],#4 0x00029c58: 24857004 .p.$ STRCS r7,[r5],#4 0x00029c5c: 8afffffb .... BHI _move_loop ; 0x29c50 0x00029c60: eaffffee .... B _move_region ; 0x29c20_zero_region 0x00029c64: e1520003 ..R. CMP r2,r3 0x00029c68: 0b000018 .... BLEQ __rt_entry ; 0x29cd0 0x00029c6c: e3a07000 .p.. MOV r7,#0 0x00029c70: e8b20030 0... LDMIA r2!,{r4,r5} 0x00029c74: e3140001 .... TST r4,#1 0x00029c78: 1084400c .@.. ADDNE r4,r4,r12 0x00029c7c: e3140002 .... TST r4,#2 0x00029c80: 10844009 .@.. ADDNE r4,r4,r9 0x00029c84: e3c44003 .@.. BIC r4,r4,#3_zero_loop 0x00029c88: e2555004 .PU. SUBS r5,r5,#4 0x00029c8c: 24847004 .p.$ STRCS r7,[r4],#4 0x00029c90: 8afffffc .... BHI _zero_loop ; 0x29c88 0x00029c94: eafffff2 .... B _zero_region ; 0x29c64_region_table$d 0x00029c98: 0000032c ,... DCD 812 0x00029c9c: 00000350 P... DCD 848 0x00029ca0: 00000350 P... DCD 848 0x00029ca4: 00000368 h... DCD 872main$a.text 0x00029ca8: e59f1018 .... LDR r1,0x29cc8 0x00029cac: e3a00000 .... MOV r0,#0 0x00029cb0: e4c10001 .... STRB r0,[r1],#1 0x00029cb4: e2800001 .... ADD r0,r0,#1 0x00029cb8: e3500010 ..P. CMP r0,#0x10 0x00029cbc: bafffffb .... BLT 0x29cb0 0x00029cc0: e3a00001 .... MOV r0,#1 0x00029cc4: e12fff1e ../. BX r14$d 0x00029cc8: 40004000 .@.@ DCD 1073758208_main_redirection$t.text 0x00029ccc: 4770 pG BX r14_main 0x00029cce: 4770 pG BX r14__rt_entry$a.text 0x00029cd0: eb000046 F... BL __rt_stackheap_init ; 0x29df0 0x00029cd4: eb0000ad .... BL $Ven$AT$L$$__rt_lib_init ; 0x29f90 0x00029cd8: e59fc01c .... LDR r12,0x29cfcmainaddruse 0x00029cdc: e08cc00f .... ADD r12,r12,pc 0x00029ce0: e31c0001 .... TST r12,#1 0x00029ce4: 128fe00d .... ADDNE r14,pc,#0xd ; #0x29cf9 0x00029ce8: 01a0e00f .... MOVEQ r14,pc 0x00029cec: e12fff1c ../. BX r12 0x00029cf0: e28fc001 .... ADD r12,pc,#1 ; #0x29cf9 0x00029cf4: e12fff1c ../. BX r12thumbmainreturn$b$t 0x00029cf8: f000f812 .... BL exit ; 0x29d20mainaddr$d$f 0x00029cfc: ffffffc4 .... DCD 4294967236__rt_exit$t 0x00029d00: 4778 xG BX pc$d 0x00029d02: 0000 .. DCW 0__32__rt_exit$a 0x00029d04: e92d4001 .@-. STMFD r13!,{r0,r14} 0x00029d08: eb0000a3 .... BL $Ven$AT$L$$__rt_lib_shutdown ; 0x29f9c 0x00029d0c: e8bd4001 .@.. LDMFD r13!,{r0,r14} 0x00029d10: ea000001 .... B __rt_abort1 ; 0x29d1c__rt_abort$t 0x00029d14: 4778 xG BX pc$d 0x00029d16: 0000 .. DCW 0__32__rt_abort$a 0x00029d18: e3e00000 .... MVN r0,#0__rt_abort1 0x00029d1c: ea000076 v... B _sys_exit ; 0x29efcexit$t.text 0x00029d20: b510 .. PUSH {r4,r14} 0x00029d22: 1c04 .. MOV r4,r0$b 0x00029d24: f000f800 .... BL 0x29d28 0x00029d28: 1c20 . MOV r0,r4$b 0x00029d2a: f7ffffe9 .... BL __rt_exit ; 0x29d00 0x00029d2e: bc10 .. POP {r4} 0x00029d30: bc08 .. POP {r3} 0x00029d32: 4718 .G BX r3__rt_lib_init.text 0x00029d34: b5f0 .. PUSH {r4-r7,r14} 0x00029d36: 1c04 .. MOV r4,r0 0x00029d38: 1c0d .. MOV r5,r1 0x00029d3a: b083 .. SUB r13,#0xc$b 0x00029d3c: f000f934 ..4. BL __16_fp_init ; 0x29fa8 0x00029d40: 9400 .. STR r4,[r13,#0] 0x00029d42: 9501 .. STR r5,[r13,#4] 0x00029d44: 2000 . MOV r0,#0$b 0x00029d46: f000f800 .... BL 0x29d4a 0x00029d4a: 9002 .. STR r0,[r13,#8] 0x00029d4c: 4826 &H LDR r0,0x29de8 0x00029d4e: 4669 iF MOV r1,r13 0x00029d50: 4478 xD ADD r0,pc$b 0x00029d52: f000f800 .... BL 0x29d56 0x00029d56: 1c05 .. MOV r5,r0 0x00029d58: 1c0e .. MOV r6,r1 0x00029d5a: a900 .. ADD r1,r13,#0 0x00029d5c: c903 .. LDMIA r1!,{r0,r1}$b 0x00029d5e: f000f800 .... BL $b ; 0x29d62$b 0x00029d62: f000f800 .... BL $b ; 0x29d66$b 0x00029d66: f000f800 .... BL 0x29d6a 0x00029d6a: 2100 .! MOV r1,#0 0x00029d6c: 2000 . MOV r0,#0$b 0x00029d6e: f000f800 .... BL 0x29d72 0x00029d72: 1c07 .. MOV r7,r0$b 0x00029d74: f000f8ce .... BL __16__user_libspace ; 0x29f14 0x00029d78: 1c04 .. MOV r4,r0 0x00029d7a: 2100 .! MOV r1,#0 0x00029d7c: 6207 .b STR r7,[r0,#0x20] 0x00029d7e: 2000 . MOV r0,#0$b 0x00029d80: f000f800 .... BL 0x29d84 0x00029d84: 1c41 A. ADD r1,r0,#1 0x00029d86: 6261 ab STR r1,[r4,#0x24] 0x00029d88: 2100 .! MOV r1,#0 0x00029d8a: 2000 . MOV r0,#0$b 0x00029d8c: f000f800 .... BL 0x29d90 0x00029d90: 2100 .! MOV r1,#0 0x00029d92: 62a0 .b STR r0,[r4,#0x28] 0x00029d94: 2000 . MOV r0,#0$b 0x00029d96: f000f800 .... BL 0x29d9a 0x00029d9a: 2100 .! MOV r1,#0 0x00029d9c: 62e0 .b STR r0,[r4,#0x2c] 0x00029d9e: 2000 . MOV r0,#0$b 0x00029da0: f000f800 .... BL 0x29da4 0x00029da4: 6320 c STR r0,[r4,#0x30]$b 0x00029da6: f000f800 .... BL $b ; 0x29daa$b 0x00029daa: f000f800 .... BL $b ; 0x29dae$b 0x00029dae: f000f800 .... BL $b ; 0x29db2$b 0x00029db2: f000f800 .... BL $b ; 0x29db6$b 0x00029db6: f000f800 .... BL $b ; 0x29dba$b 0x00029dba: f000f800 .... BL $b ; 0x29dbe$b 0x00029dbe: f000f800 .... BL $b ; 0x29dc2$b 0x00029dc2: f000f800 .... BL 0x29dc6 0x00029dc6: 1c28 (. MOV r0,r5 0x00029dc8: 1c31 1. MOV r1,r6 0x00029dca: b003 .. ADD r13,#0xc 0x00029dcc: bcf0 .. POP {r4-r7} 0x00029dce: bc08 .. POP {r3} 0x00029dd0: 4718 .G BX r3__rt_lib_shutdown 0x00029dd2: b508 .. PUSH {r3,r14}$b 0x00029dd4: f000f800 .... BL $b ; 0x29dd8$b 0x00029dd8: f000f800 .... BL $b ; 0x29ddc$b 0x00029ddc: f000f800 .... BL 0x29de0 0x00029de0: b001 .. ADD r13,#4 0x00029de2: bc08 .. POP {r3} 0x00029de4: 4718 .G BX r3$d 0x00029de6: 0000 .. DCW 0 0x00029de8: 00000094 .... DCD 148__16__rt_stackheap_init$t.text 0x00029dec: 4778 xG BX pc$d 0x00029dee: 0000 .. DCW 0__rt_stackheap_init$a 0x00029df0: e1a0500e .P.. MOV r5,r14 0x00029df4: eb000047 G... BL __user_libspace ; 0x29f18 0x00029df8: e1a0e005 .... MOV r14,r5 0x00029dfc: e1a04000 .@.. MOV r4,r0 0x00029e00: e1a0100d .... MOV r1,r13 0x00029e04: e1a0300a .0.. MOV r3,r10 0x00029e08: e3c00007 .... BIC r0,r0,#7 0x00029e0c: e280d060 `... ADD r13,r0,#0x60 0x00029e10: e92d4010 .@-. STMFD r13!,{r4,r14} 0x00029e14: eb000043 C... BL __user_initial_stackheap ; 0x29f28 0x00029e18: e8bd4010 .@.. LDMFD r13!,{r4,r14} 0x00029e1c: e3c1d007 .... BIC r13,r1,#7 0x00029e20: e3a06000 .`.. MOV r6,#0 0x00029e24: e3a07000 .p.. MOV r7,#0 0x00029e28: e3a08000 .... MOV r8,#0 0x00029e2c: e3a0b000 .... MOV r11,#0 0x00029e30: e1a0c004 .... MOV r12,r4 0x00029e34: e8ac09c0 .... STMIA r12!,{r6-r8,r11} 0x00029e38: e8ac09c0 .... STMIA r12!,{r6-r8,r11} 0x00029e3c: e8ac09c0 .... STMIA r12!,{r6-r8,r11} 0x00029e40: e8ac09c0 .... STMIA r12!,{r6-r8,r11} 0x00029e44: e92d4013 .@-. STMFD r13!,{r0,r1,r4,r14} 0x00029e48: e3a00000 .... MOV r0,#0 0x00029e4c: e3a01000 .... MOV r1,#0 0x00029e50: ebffffff .... BL 0x29e54 0x00029e54: e2811040 @... ADD r1,r1,#0x40 0x00029e58: e0802001 . .. ADD r2,r0,r1 0x00029e5c: e2822f44 D/.. ADD r2,r2,#0x110 0x00029e60: e584201c . .. STR r2,[r4,#0x1c] 0x00029e64: e5841018 .... STR r1,[r4,#0x18] 0x00029e68: e3a00001 .... MOV r0,#1 0x00029e6c: e5840010 .... STR r0,[r4,#0x10] 0x00029e70: e8bd4013 .@.. LDMFD r13!,{r0,r1,r4,r14} 0x00029e74: e5840014 .... STR r0,[r4,#0x14] 0x00029e78: e1a01000 .... MOV r1,r0 0x00029e7c: e1a0f00e .... MOV pc,r14__16__rt_heap_extend$t 0x00029e80: 4778 xG BX pc$d 0x00029e82: 0000 .. DCW 0__rt_heap_extend$a 0x00029e84: e92d4010 .@-. STMFD r13!,{r4,r14} 0x00029e88: e92d0003 ..-. STMFD r13!,{r0,r1} 0x00029e8c: eb000021 !... BL __user_libspace ; 0x29f18 0x00029e90: e1a04000 .@.. MOV r4,r0 0x00029e94: e8bd0003 .... LDMFD r13!,{r0,r1} 0x00029e98: e594301c .0.. LDR r3,[r4,#0x1c] 0x00029e9c: e04d3003 .0M. SUB r3,r13,r3 0x00029ea0: e5942014 . .. LDR r2,[r4,#0x14] 0x00029ea4: e5812000 . .. STR r2,[r1,#0] 0x00029ea8: e082e000 .... ADD r14,r2,r0 0x00029eac: e15e0003 ..^. CMP r14,r3 0x00029eb0: 8a00000b .... BHI _heap_overflow ; 0x29ee4 0x00029eb4: e093300e .0.. ADDS r3,r3,r14 0x00029eb8: e1a03063 c0.. MOV r3,r3,RRX 0x00029ebc: e3c33007 .0.. BIC r3,r3,#7 0x00029ec0: e28e1d40 @... ADD r1,r14,#0x1000 0x00029ec4: e2811007 .... ADD r1,r1,#7 0x00029ec8: e3c11007 .... BIC r1,r1,#7 0x00029ecc: e1510003 ..Q. CMP r1,r3 0x00029ed0: 81a01003 .... MOVHI r1,r3 0x00029ed4: e0410002 ..A. SUB r0,r1,r2 0x00029ed8: e5841014 .... STR r1,[r4,#0x14] 0x00029edc: e8bd4010 .@.. LDMFD r13!,{r4,r14} 0x00029ee0: e12fff1e ../. BX r14_heap_overflow 0x00029ee4: e1a02000 . .. MOV r2,r0 0x00029ee8: e3a00000 .... MOV r0,#0 0x00029eec: ebffffff .... BL 0x29ef0 0x00029ef0: e8bd4010 .@.. LDMFD r13!,{r4,r14} 0x00029ef4: e12fff1e ../. BX r14__16_sys_exit$t.text 0x00029ef8: 4778 xG BX pc$d 0x00029efa: 0000 .. DCW 0_sys_exit$a 0x00029efc: e3a00018 .... MOV r0,#0x18 0x00029f00: e59f1008 .... LDR r1,0x29f10 0x00029f04: ef123456 V4.. SWI 0x123456 0x00029f08: e12fff1e ../. BX r14$d$f 0x00029f0c: 00000065 e... DCD 101 0x00029f10: 00020026 &... DCD 131110__16__user_libspace$t.text 0x00029f14: 4778 xG BX pc$d 0x00029f16: 0000 .. DCW 0__user_libspace$a 0x00029f18: e59f0000 .... LDR r0,0x29f20 0x00029f1c: e12fff1e ../. BX r14$d 0x00029f20: 40003000 .0.@ DCD 1073754112__16__user_initial_stackheap$t.text 0x00029f24: 4778 xG BX pc$d 0x00029f26: 0000 .. DCW 0__user_initial_stackheap$a 0x00029f28: e92d4000 .@-. STMFD r13!,{r14} 0x00029f2c: e24dd014 ..M. SUB r13,r13,#0x14 0x00029f30: e1a0100d .... MOV r1,r13 0x00029f34: e28d2004 . .. ADD r2,r13,#4 0x00029f38: e5812000 . .. STR r2,[r1,#0] 0x00029f3c: e3a00016 .... MOV r0,#0x16 0x00029f40: ef123456 V4.. SWI 0x123456 0x00029f44: e59d0004 .... LDR r0,[r13,#4] 0x00029f48: e59d100c .... LDR r1,[r13,#0xc] 0x00029f4c: e59d2008 . .. LDR r2,[r13,#8] 0x00029f50: e59d3010 .0.. LDR r3,[r13,#0x10] 0x00029f54: e3500000 ..P. CMP r0,#0 0x00029f58: 059f000c .... LDREQ r0,0x29f6c 0x00029f5c: e28dd014 .... ADD r13,r13,#0x14 0x00029f60: e8bd4000 .@.. LDMFD r13!,{r14} 0x00029f64: e12fff1e ../. BX r14$d$f 0x00029f68: 00000009 .... DCD 9_RW_Limit 0x00029f6c: 40003060 `0.@ DCD 1073754208__I_use_semihosting_swi__semihosting_swi_guard$t.text 0x00029f70: 4778 xG BX pc$d 0x00029f72: 0000 .. DCW 0__32__I_use_semihosting_swi$a 0x00029f74: e12fff1e ../. BX r14__16__rt_fp_status_addr$t.text 0x00029f78: 4778 xG BX pc$d 0x00029f7a: 0000 .. DCW 0__rt_fp_status_addr$a 0x00029f7c: e92d4010 .@-. STMFD r13!,{r4,r14} 0x00029f80: ebffffe4 .... BL __user_libspace ; 0x29f18 0x00029f84: e2800004 .... ADD r0,r0,#4 0x00029f88: e8bd4010 .@.. LDMFD r13!,{r4,r14} 0x00029f8c: e12fff1e ../. BX r14$Ven$AT$L$$__rt_lib_init 0x00029f90: e59fc000 .... LDR r12,0x29f98 0x00029f94: e12fff1c ../. BX r12$d$f 0x00029f98: 00029d35 5... DCD 171317$Ven$AT$L$$__rt_lib_shutdown$a 0x00029f9c: e59fc000 .... LDR r12,0x29fa4 0x00029fa0: e12fff1c ../. BX r12$d$f 0x00029fa4: 00029dd3 .... DCD 171475__16_fp_init$tx$fpl$fpinit 0x00029fa8: 4778 xG BX pc$d 0x00029faa: 0000 .. DCW 0_fp_init$a 0x00029fac: e92d4010 .@-. STMFD r13!,{r4,r14} 0x00029fb0: ebfffff1 .... BL __rt_fp_status_addr ; 0x29f7c 0x00029fb4: e3a01000 .... MOV r1,#0 0x00029fb8: e5801000 .... STR r1,[r0,#0]__fplib_config_pureend_doubles 0x00029fbc: e8bd4010 .@.. LDMFD r13!,{r4,r14} 0x00029fc0: e12fff1e ../. BX r14Region$$Table$$Base$d 0x00029fc4: 00000000 .... DCD 0 0x00029fc8: 00000000 .... DCD 0 0x00029fcc: 00000000 .... DCD 0 0x00029fd0: 0002a000 .... DCD 172032 0x00029fd4: 40003000 .0.@ DCD 1073754112 0x00029fd8: 00000000 .... DCD 0 0x00029fdc: 0002a000 .... DCD 172032 0x00029fe0: 40003000 .0.@ DCD 1073754112 0x00029fe4: 00000000 .... DCD 0Region$$Table$$LimitZISection$$Table$$Base 0x00029fe8: 0002a000 .... DCD 172032 0x00029fec: 00000000 .... DCD 0 0x00029ff0: 40003000 .0.@ DCD 1073754112 0x00029ff4: 00000000 .... DCD 0 0x00029ff8: 40003000 .0.@ DCD 1073754112 0x00029ffc: 00000060 `... DCD 96ZISection$$Table$$Limit
- ADS简单程序编译分析
- ADS简单程序编译分析(2)
- 用ADS编译ARM程序后生成镜像Image的信息分析
- 手机端C程序编译运行的简单分析
- 简单算符优先文法分析程序(编译原理)
- 一个简单的编译原理词法语法语义分析程序
- ADS编译问题
- ADS程序调试出错
- ADS学习1:破解ADS安装程序
- ADS编译ARM程序时对RO,RW,ZI段的理解
- ADS编译ARM程序时对RO,RW,ZI段的理解
- ADS 1.2 在WIN7 64 下——编译测试程序出错的问题
- ADS编译选项小技巧
- 简单聊天程序分析
- 简单词法分析程序
- Android程序简单分析
- ADS简单模型参数总结
- 命令行下编译简单程序
- android简单图片上传
- QT线程编程
- 蓝桥杯_算法训练_数字三角形
- 远程通信的几种选择(RPC,Webservice,RMI,JMS的区别)
- ffmpeg ios代码加字幕相关
- ADS简单程序编译分析
- 西普实验吧CTF-双基回文数
- git使用
- 对症下药,营销没那么难
- Linux添加Tomcat,多个服务同时运行
- Mongo在存储大量数据时,有数据存储不上的情况?
- SQL Server 判断除数是否为0
- 在linux中下载安装jdk1.6
- 500 Internal Server Error php