无论C还是C++,程序的基本单元都是函数,入口点都是 main,这一切可以在链接时改变但作为习惯... wait...所谓“习惯”是对软件开发者而言,as、ld这些工具是看不到什么函数的,到了cpu只有依次对齐的机器码而已。但C的影响如此之深以致有了专门的寄存器 sp 做栈指针,换言之,要搞函数先备栈。
C/C++不可能自己设置栈指针的,通常这由在 main 之前执行的汇编代码完成(head.s):
.text .global _start _start: ldr sp, =0x40001000 @ 设置堆栈,注意:不能大于4k, 因为现在可用的内存只有4K bl main @ 调用C程序中的main函数 _end: b _end
上面把 sp 设置到 0x40001000说明我的板子要从nor 启动,如果是从nand启动片内ram 在0~0x1000这里就只能写
ldr sp, =0x1000
更详细的参考上一篇《mini2440 点灯》。
有了这个头之后下来就该 C/C++ 展身手了(led.cpp):
int main() { unsigned long* dog = reinterpret_cast<unsigned long*>(0x53000000); *dog = 0; unsigned long* gpbcon = reinterpret_cast<unsigned long*>(0x56000010); *gpbcon = 0x15400; unsigned long* gpbdata = reinterpret_cast<unsigned long*>(0x56000014); *gpbdata = 0; return 0; }
g++ 要求 main 返回 int,c++ 要求常量赋值要有类型转换。编译如下:
arm-linux-gcc -c -o head.o head.s arm-linux-g++ -c -o led.o led.cpp arm-linux-ld -Ttext 0x40000000 -g led.o head.o -o led++.elf
调试过程同《mini2440 点灯》。
下面让我们看看这个程序的效率吧
arm-linux-objdump -D -m arm led.elf > led.dis arm-linux-objdump -D -m arm led++.elf > led++.dis
led.dis 和 led++.dis 分别为纯汇编和C++编译得到的可视机器码结果,先看led.dis
led.elf: file format elf32-littlearm Disassembly of section .text: 40000000 <_start>: 40000000: e3a00453 mov r0, #1392508928 ; 0x53000000 40000004: e3a01000 mov r1, #0 ; 0x0 40000008: e5801000 str r1, [r0] 4000000c: e59f0010 ldr r0, [pc, #16] ; 40000024 <_end+0x4> 40000010: e3a01b55 mov r1, #87040 ; 0x15400 40000014: e4801004 str r1, [r0], #4 40000018: e3a01000 mov r1, #0 ; 0x0 4000001c: e4801004 str r1, [r0], #4 40000020 <_end>: 40000020: eafffffe b 40000020 <_end> 40000024: 56000010 .word 0x56000010 Disassembly of section .ARM.attributes: 00000000 <.ARM.attributes>: 0: 00001741 andeq r1, r0, r1, asr #14 4: 61656100 cmnvs r5, r0, lsl #2 8: 01006962 tsteq r0, r2, ror #18 c: 0000000d andeq r0, r0, sp 10: 00543405 subseq r3, r4, r5, lsl #8 14: 01080206 tsteq r8, r6, lsl #4
下来是led++.dis
led++.elf: file format elf32-littlearm Disassembly of section .text: 40000000 <main>: 40000000: e52db004 push {fp} ; (str fp, [sp, #-4]!) 40000004: e28db000 add fp, sp, #0 ; 0x0 40000008: e24dd014 sub sp, sp, #20 ; 0x14 4000000c: e3a03453 mov r3, #1392508928 ; 0x53000000 40000010: e50b3010 str r3, [fp, #-16] 40000014: e51b2010 ldr r2, [fp, #-16] 40000018: e3a03000 mov r3, #0 ; 0x0 4000001c: e5823000 str r3, [r2] 40000020: e3a03456 mov r3, #1442840576 ; 0x56000000 40000024: e2833010 add r3, r3, #16 ; 0x10 40000028: e50b300c str r3, [fp, #-12] 4000002c: e51b200c ldr r2, [fp, #-12] 40000030: e3a03b55 mov r3, #87040 ; 0x15400 40000034: e5823000 str r3, [r2] 40000038: e3a03456 mov r3, #1442840576 ; 0x56000000 4000003c: e2833014 add r3, r3, #20 ; 0x14 40000040: e50b3008 str r3, [fp, #-8] 40000044: e51b2008 ldr r2, [fp, #-8] 40000048: e3a03000 mov r3, #0 ; 0x0 4000004c: e5823000 str r3, [r2] 40000050: e3a03000 mov r3, #0 ; 0x0 40000054: e1a00003 mov r0, r3 40000058: e28bd000 add sp, fp, #0 ; 0x0 4000005c: e8bd0800 pop {fp} 40000060: e12fff1e bx lr 40000064 <_start>: 40000064: e59fd004 ldr sp, [pc, #4] ; 40000070 <_end+0x4> 40000068: ebffffe4 bl 40000000 <main> 4000006c <_end>: 4000006c: eafffffe b 4000006c <_end> 40000070: 40001000 .word 0x40001000 Disassembly of section .ARM.exidx: 40000074 <__data_start-0x8008>: 40000074: 7fffff8c svcvc 0x00ffff8c 40000078: 00000001 andeq r0, r0, r1 Disassembly of section .comment: 00000000 <.comment>: 0: 43434700 movtmi r4, #14080 ; 0x3700 4: 5328203a teqpl r8, #58 ; 0x3a 8: 6372756f cmnvs r2, #465567744 ; 0x1bc00000 c: 20797265 rsbscs r7, r9, r5, ror #4 10: 202b2b47 eorcs r2, fp, r7, asr #22 14: 6574694c ldrbvs r6, [r4, #-2380]! 18: 30303220 eorscc r3, r0, r0, lsr #4 1c: 2d337138 ldfcss f7, [r3, #-224]! 20: 20293237 eorcs r3, r9, r7, lsr r2 24: 2e332e34 mrccs 14, 1, r2, cr3, cr4, {1} 28: Address 0x00000028 is out of bounds. Disassembly of section .ARM.attributes: 00000000 <.ARM.attributes>: 0: 00002741 andeq r2, r0, r1, asr #14 4: 61656100 cmnvs r5, r0, lsl #2 8: 01006962 tsteq r0, r2, ror #18 c: 0000001d andeq r0, r0, sp, lsl r0 10: 00543405 subseq r3, r4, r5, lsl #8 14: 01080206 tsteq r8, r6, lsl #4 18: 01140412 tsteq r4, r2, lsl r4 1c: 03170115 tsteq r7, #1073741829 ; 0x40000005 20: 01190118 tsteq r9, r8, lsl r1 24: 061e021a undefined
同样的事情 .text 段长了一倍多,编译 led.cpp 是加个 -O2再看看结果
led++.elf: file format elf32-littlearm Disassembly of section .text: 40000000 <main>: 40000000: e3a00000 mov r0, #0 ; 0x0 40000004: e3a01456 mov r1, #1442840576 ; 0x56000000 40000008: e3a03453 mov r3, #1392508928 ; 0x53000000 4000000c: e3a02b55 mov r2, #87040 ; 0x15400 40000010: e5830000 str r0, [r3] 40000014: e5812010 str r2, [r1, #16] 40000018: e5810014 str r0, [r1, #20] 4000001c: e12fff1e bx lr 40000020 <_start>: 40000020: e59fd004 ldr sp, [pc, #4] ; 4000002c <_end+0x4> 40000024: ebfffff5 bl 40000000 <main> 40000028 <_end>: 40000028: eafffffe b 40000028 <_end> 4000002c: 40001000 .word 0x40001000 Disassembly of section .ARM.exidx: 40000030 <__data_start-0x8008>: 40000030: 7fffffd0 svcvc 0x00ffffd0 40000034: 00000001 andeq r0, r0, r1 Disassembly of section .comment: 00000000 <.comment>: 0: 43434700 movtmi r4, #14080 ; 0x3700 4: 5328203a teqpl r8, #58 ; 0x3a 8: 6372756f cmnvs r2, #465567744 ; 0x1bc00000 c: 20797265 rsbscs r7, r9, r5, ror #4 10: 202b2b47 eorcs r2, fp, r7, asr #22 14: 6574694c ldrbvs r6, [r4, #-2380]! 18: 30303220 eorscc r3, r0, r0, lsr #4 1c: 2d337138 ldfcss f7, [r3, #-224]! 20: 20293237 eorcs r3, r9, r7, lsr r2 24: 2e332e34 mrccs 14, 1, r2, cr3, cr4, {1} 28: Address 0x00000028 is out of bounds. Disassembly of section .ARM.attributes: 00000000 <.ARM.attributes>: 0: 00002741 andeq r2, r0, r1, asr #14 4: 61656100 cmnvs r5, r0, lsl #2 8: 01006962 tsteq r0, r2, ror #18 c: 0000001d andeq r0, r0, sp, lsl r0 10: 00543405 subseq r3, r4, r5, lsl #8 14: 01080206 tsteq r8, r6, lsl #4 18: 01140412 tsteq r4, r2, lsl r4 1c: 03170115 tsteq r7, #1073741829 ; 0x40000005 20: 01190118 tsteq r9, r8, lsl r1 24: 021e021a andseq r0, lr, #-1610612735 ; 0xa0000001
注意对比一下 main 里的汇编码(机器码)和led.s 中的,可见编译器优化还是蛮有效的。