代码之家  ›  专栏  ›  技术社区  ›  Juan González

火星MIPS模拟器是大端还是小端

  •  8
  • Juan González  · 技术社区  · 7 年前

    作为作业,我必须确定火星模拟器是大端还是小端,起初这看起来很简单,但我有一些问题。

    此外,当用存储4个字节时。字1,存储的是0x00000001,这次没有反转字节。

    我想知道模拟器是大端还是小端,以及对这种行为的解释

    3 回复  |  直到 7 年前
        1
  •  1
  •   A P    2 年前

    你的问题涉及多个层面,所以我试着一个一个地解决它们。。。

    机器的内存可按字节寻址。第一个字节有地址0,第二个字节有地址1,等等。。。每当我在这个答案中写关于内存内容的内容时,我都会使用以下格式: 01 02 0E 0F 10 ... ,使用十六进制值并在字节之间使用空格,地址从起始地址持续到结束地址。也就是说,如果该内容从地址0x800000开始,则内存将为(全部为十六进制):

    address | byte value
    ------- | ----------
    800000  | 01
    800001  | 02
    800002  | 0E
    800003  | 0F
    800004  | 10
    800005  | ...
    

    如果你愿意加载 发件人地址 0x800000 进入 t0 (带 lb 说明), 将等于值 1 .

    单词 发件人地址 进入 (带 lw

    在…上 机器 t0 0x0F0E0201 0 1. , ... 最后一个是256 .

    在…上 大端元 机器 t0 将等于值 0x01020E0F ,字的第一个字节(内存中)为256 3. 2. , ... 最后一个是256 .

    ( 256 is 2 8 ,这个幻数来自“一个字节是8位”,一位可以包含两个值(0或1),一个字节有8位,所以一个字节可以包含2 不同的值)

    在这两种情况下,CPU将从内存中读取相同的四个字节(在地址0x800000到0x800003处),但端序定义了它们作为字值的最后32位出现的顺序。

    这个 是由CPU芯片上的32位物理组成的,它没有地址。当您想在CPU指令中对其进行寻址时(即使用存储在 ),将其编码为指令 $8 寄存器( $8 $t0 t0 别名)。

    0x0F0E0201 0000 1111 0000 1110 ... (我把它从b31位的顶部写到b0的底部,以理解左/右移位指令,并使其作为人类格式化的二进制数工作),没有必要考虑寄存器的端序或位在芯片上存储的物理顺序,只需将其视为完整的32位值,在算术指令中它就会这样工作。

    在寄存器中,它进入b0-b7位,其中b8-b31包含b7的副本(符号将有符号8位值扩展为有符号32位值)。

    word 0x11223344 在内存中,将单个字节设置为 44 33 22 11

    为其目标平台配置良好的汇编器将对程序员隐藏端点,以利用字值 实用的

    所以当你定义内存值时,比如:

    myPreciousValue .word 0x11223344
    

    汇编程序将解析文本(您的源代码是text(!),i、 e.一个字符是一个字节值-在ASCII编码中,如果您在UTF8文本编辑器中写入源代码并使用非ASCII字符,则它们可能跨多个字节进行编码,ASCII可打印字符在ASCII和UTF8中具有相同的编码,并且仅占用单个字节)“0x11223344”(10个字节) 30 78 31 31 32 32 33 33 34 34 ),计算32位字值 0x11223344

    44 33 22 11           # little-endian target
    

    或:

    11 22 33 44           # big-endian target
    

    然后使用 要加载的代码中的指令 myPreciousValue 从内存到寄存器,寄存器将包含预期的字值

    因此,程序员不必每次在源代码中某处写入32位值时都考虑endianness,汇编程序将解析并将其处理为字节值的目标变量。

    如果程序员想要定义四个字节 01 02 03 04 .word 0x04030201 对于little endian目标平台,但这混淆了原始意图,因此我建议使用 .byte 1, 2, 3, 4

    当用声明字节值时 .byte 指令,它们是按照您编写它们的顺序编译的,没有endianness。

    调试器

    最后是调试器的内存/寄存器视图。。。这个工具将再次努力工作 直观/方便 因此,当您检查内存视图并将其配置为字节时,内存将显示为:

    0x800000: 31 32 33 34 41 42 43 44 | 1234ABCD
    

    当您将其切换到“word”视图时,它将使用配置的端序以目标平台顺序连接字节,即在MARS/SPIM中,作为小端序平台,它将显示在同一内存中:

    0x800000: 34333231 44434241
    

    (如果还包括ASCII视图,它是否也“文字化”了?如果是,那么它将看起来像 4321 DCBA . 我目前没有安装MARS/SPIM来检查调试器中的内存视图实际上是什么样子,对不起)

    默认情况下,寄存器视图通常显示十六进制字值,即从该地址0x800000将字加载到 t0 ,寄存器 $8 将包含值 0x34333231 ( 875770417

    如果您感兴趣的是用于该加载的内存中第一个字节的值是多少,此时您必须应用您对该目标平台的端序的知识,并查看寄存器视图中的前两个数字“34”(大端序),或最后两个数字“31”(小端序)(或者更确切地说,在字节视图模式下使用内存视图以避免任何错误)。

    因此,有了以上所有信息,运行时检测代码应该很容易理解(遗憾的是,我目前没有MARS/SPIM,所以我没有验证它是否有效,请告诉我):

    .data
    
    checkEndianness: .word 0    # temporary memory for function
        # can be avoided by using stack memory instead (in function)
    
    .text
    
    main:
        jal  IsLittleEndian
        # ... do something with v0 value ...
        ... exit (TODO by reader)
    
    # --- functions ---
    
    # returns (in v0) 0 for big-endian machine, and 1 for little-endian
    IsLittleEndian:
        # set value of register to 1
        li $v0,1
        # store the word value 1 into memory (4 bytes written)
        sw $v0,(checkEndianness)
          # memory contains "01 00 00 00" on little-endian machine
          #              or "00 00 00 01" on big-endian machine
        # load only the first byte back
        lb $v0,(checkEndianness)
        jr $ra
    

    它有什么好处?只要您为单目标平台编写软件,并且由目标CPU存储/加载文字,您就不需要关心Endiance。

    但如果你有多平台的软件,它确实可以保存二进制文件。。。为了使文件在两个大/小端点平台上以相同的方式工作,文件结构的规范还必须指定文件数据的端点。然后根据该规范,一种类型的目标平台可能会将其读取为“本机”字值,另一种平台将不得不洗牌字值中的字节以读取正确的字值(此外,规范还应指定“字”的字节数:)。如果您将洗牌器包括到保存/加载例程中,使用端点检测例程来决定是否必须洗牌字字节,那么这样的运行时测试可能很方便。这将使目标平台的endianness对其余代码“透明”,剩下的代码只需将其本机“word”值发送到保存/加载例程,您的保存/加载可能在每个平台上使用相同的源代码(至少只要您使用一些多平台的可移植编程语言,如C,当然MIPS的程序集根本无法在不同的CPU上工作,需要从头重写)。

    此外,网络通信通常使用自定义二进制协议(通常包装在网络层最常见的TCP/IP数据包中,甚至是加密的,但您的应用程序将在某一点从中提取原始字节内容),然后发送/接收数据的端序性问题,“其他”平台必须洗牌字节以读取正确的值。

    其他平台(非MIPS)

    可以应用上面的几乎所有内容,只需检查 byte 在另一个平台上(我认为 单词 可能有所不同,例如在x86平台上 单词 0 功率和最后一个字节用作最高256功率(256 1. 在x86平台上,由于只有两个字节构成字,因此MIPS“字”在x86世界中称为“双字”或“dword”)。