- 论坛徽章:
- 0
|
深入分析S3C2440启动代码中大小端问题
深入分析S3C2440启动代码中大小端问题
一、ADS1.2中关于大小端的设置以及对编译后的代码的影响
下面是一段代码在线段模式下编译,生成的二进制文件的内容
大端模式下编译,生成二进制文件的内容
根据上面的内容可以看出:它们的字节序是相反的,也就是说,ADS1.2中对大小端的设置会影响最终生成的二进制文件的字节序。
二、S3C2440启动代码中与大小管相关的代码
Option.inc中相关代码- [plain] view plaincopyprint?<span style="white-space:pre"> </span>GBLL<span style="white-space:pre"> </span>ENDIAN_CHANGE
- ENDIAN_CHANGE<span style="white-space:pre"> </span>SETL<span style="white-space:pre"> </span>{TRUE}
-
-
- <span style="white-space:pre"> </span>GBLA<span style="white-space:pre"> </span>ENTRY_BUS_WIDTH
- ENTRY_BUS_WIDTH<span style="white-space:pre"> </span>SETA<span style="white-space:pre"> </span>16
- <span style="white-space:pre"> </span>GBLL<span style="white-space:pre"> </span>ENDIAN_CHANGE
- ENDIAN_CHANGE<span style="white-space:pre"> </span>SETL<span style="white-space:pre"> </span>{TRUE}
- <span style="white-space:pre"> </span>GBLA<span style="white-space:pre"> </span>ENTRY_BUS_WIDTH
- ENTRY_BUS_WIDTH<span style="white-space:pre"> </span>SETA<span style="white-space:pre"> </span>16
- 2440init.s中相关代码
- [plain] view plaincopyprint? AREA Init,CODE,READONLY
-
- ENTRY
-
- EXPORT __ENTRY
- __ENTRY
- ResetEntry
- ;1)The code, which converts to Big-endian, should be in little endian code.
- ;2)The following little endian code will be compiled in Big-Endian mode.
- ; The code byte order should be changed as the memory bus width.
- ;3)The pseudo instruction,DCD can not be used here because the linker generates error.
- ASSERT :DEF:ENDIAN_CHANGE
- [ ENDIAN_CHANGE
- ASSERT :DEF:ENTRY_BUS_WIDTH
- [ ENTRY_BUS_WIDTH=32
- b ChangeBigEndian ;DCD 0xea000007
- ]
-
- [ ENTRY_BUS_WIDTH=16
- andeq r14,r7,r0,lsl #20 ;DCD 0x0007ea00
- ]
-
- [ ENTRY_BUS_WIDTH=8
- streq r0,[r0,-r10,ror #1] ;DCD 0x070000ea
- ]
- |
- b ResetHandler
- ]
- b HandlerUndef ;handler for Undefined mode
- b HandlerSWI ;handler for SWI interrupt
- b HandlerPabort ;handler for PAbort
- b HandlerDabort ;handler for DAbort
- b . ;reserved
- b HandlerIRQ ;handler for IRQ interrupt
- b HandlerFIQ ;handler for FIQ interrupt
-
- ;@0x20
- b EnterPWDN ; Must be @0x20.
- ChangeBigEndian
- ;@0x24
- [ ENTRY_BUS_WIDTH=32
- DCD 0xee110f10 ;0xee110f10 => mrc p15,0,r0,c1,c0,0
- DCD 0xe3800080 ;0xe3800080 => orr r0,r0,#0x80; //Big-endian
- DCD 0xee010f10 ;0xee010f10 => mcr p15,0,r0,c1,c0,0
- ]
- [ ENTRY_BUS_WIDTH=16
- DCD 0x0f10ee11
- DCD 0x0080e380
- DCD 0x0f10ee01
- ]
- [ ENTRY_BUS_WIDTH=8
- DCD 0x100f11ee
- DCD 0x800080e3
- DCD 0x100f01ee
- ]
- DCD 0xffffffff ;swinv 0xffffff is similar with NOP and run well in both endian mode.
- DCD 0xffffffff
- DCD 0xffffffff
- DCD 0xffffffff
- DCD 0xffffffff
- b ResetHandler
- AREA Init,CODE,READONLY
- ENTRY
-
- EXPORT __ENTRY
- __ENTRY
- ResetEntry
- ;1)The code, which converts to Big-endian, should be in little endian code.
- ;2)The following little endian code will be compiled in Big-Endian mode.
- ; The code byte order should be changed as the memory bus width.
- ;3)The pseudo instruction,DCD can not be used here because the linker generates error.
- ASSERT :DEF:ENDIAN_CHANGE
- [ ENDIAN_CHANGE
- ASSERT :DEF:ENTRY_BUS_WIDTH
- [ ENTRY_BUS_WIDTH=32
- b ChangeBigEndian ;DCD 0xea000007
- ]
- [ ENTRY_BUS_WIDTH=16
- andeq r14,r7,r0,lsl #20 ;DCD 0x0007ea00
- ]
- [ ENTRY_BUS_WIDTH=8
- streq r0,[r0,-r10,ror #1] ;DCD 0x070000ea
- ]
- |
- b ResetHandler
- ]
- b HandlerUndef ;handler for Undefined mode
- b HandlerSWI ;handler for SWI interrupt
- b HandlerPabort ;handler for PAbort
- b HandlerDabort ;handler for DAbort
- b . ;reserved
- b HandlerIRQ ;handler for IRQ interrupt
- b HandlerFIQ ;handler for FIQ interrupt
- ;@0x20
- b EnterPWDN ; Must be @0x20.
- ChangeBigEndian
- ;@0x24
- [ ENTRY_BUS_WIDTH=32
- DCD 0xee110f10 ;0xee110f10 => mrc p15,0,r0,c1,c0,0
- DCD 0xe3800080 ;0xe3800080 => orr r0,r0,#0x80; //Big-endian
- DCD 0xee010f10 ;0xee010f10 => mcr p15,0,r0,c1,c0,0
- ]
- [ ENTRY_BUS_WIDTH=16
- DCD 0x0f10ee11
- DCD 0x0080e380
- DCD 0x0f10ee01
- ]
- [ ENTRY_BUS_WIDTH=8
- DCD 0x100f11ee
- DCD 0x800080e3
- DCD 0x100f01ee
- ]
- DCD 0xffffffff ;swinv 0xffffff is similar with NOP and run well in both endian mode.
- DCD 0xffffffff
- DCD 0xffffffff
- DCD 0xffffffff
- DCD 0xffffffff
- b ResetHandler
复制代码 我们可以看到,在Option.inc将ENDIAN_CHANGE设置FALSE,程序将直接运行b ResetHandler,S3C2440默认是处于小端模式,ADS1.2中的设置默认也是小段模式,一切风平浪静。
现在,我们在ADS1.2中设为打断模式,并把ENDIAN_CHANGE设置FALSE设为TURE,现在问题就来了,请看下面的分析。
在编译程序时,根据ENTRY_BUS_WIDTH宏会将下面三条指令的之一放在0地址处
b ChangeBigEndian ;DCD 0xea000007
andeq r14,r7,r0,lsl #20 ;DCD 0x0007ea00
streq r0,[r0,-r10,ror #1] ;DCD 0x070000ea
其实这三条指令的功能都是一样,只是根据数据带宽调整了字节序,都是跳转到0x24处的ChangeBigEndian执行,ChangeBigEndian的作用就是通过协处理CP15中的寄存器C1来改变S3C2440的大小端模式。
先来看一下这三条指令。因为我们已经在ADS中设置为大端模式,所以这些指令是以大端模式进行编译的,而S3C2440此时还是小端模式,S3C2440怎么能执行大端模式下的指令呢,比如b ChangeBigEndian ;DCD 0xea000007???
原因如下:
如果一个基于 ARM 芯片将存储器系统配置为其中一种存储器格式(如小端) ,而实际连接的存储器系统配置为相反的格式(如大端) ,那么只有以字为单位的指令取指、数据装载和数据保存能够可靠实现。其它的存储器访问将出现不可预期的结果。也就就是说在32位模式下,大小端模式对指令取指、数据装载和数据保存没有影响。
b ChangeBigEndian在大端模式下机器码是0xea000007,这是32位模式下,其四个字节从低到高分别是:07 00 00 ea。那没b ChangeBigEndian这条指令在8位模式下,要被小端模式的S3C2440执行,就要人为的修改为0x070000ea。
b ChangeBigEndian这条指令在16位模式下,要被小端模式的S3C2440执行,就要人为的修改为 0x0007ea00。后面修改协处理CP15中的寄存器C1的代码时类似的。
欢迎讨论,如有错误请指出,谢谢 |
|