中关村村草 发表于 2012-02-17 23:15

深入分析S3C2440启动代码中大小端问题

深入分析S3C2440启动代码中大小端问题









深入分析S3C2440启动代码中大小端问题
一、ADS1.2中关于大小端的设置以及对编译后的代码的影响



下面是一段代码在线段模式下编译,生成的二进制文件的内容


大端模式下编译,生成二进制文件的内容

根据上面的内容可以看出:它们的字节序是相反的,也就是说,ADS1.2中对大小端的设置会影响最终生成的二进制文件的字节序。
二、S3C2440启动代码中与大小管相关的代码
Option.inc中相关代码 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中相关代码

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, ;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, ;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, ;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的代码时类似的。




欢迎讨论,如有错误请指出,谢谢

小忻黑夜 发表于 2012-02-17 23:16

谢谢分享
页: [1]
查看完整版本: 深入分析S3C2440启动代码中大小端问题