是火星MIPS模拟器Big或Little Endian

JG5*_*G55 3 assembly mips endianness mars-simulator

我必须确定火星模拟器是大或小端作为家庭作业,这看起来非常简单,但我有一些问题.

首先我尝试在内存中存储4个字节,内存为0,0,0,1,在内存中显示为0x01000000,因此,以相反的顺序,这似乎表示模拟器是小端,但是,当我加载4字节作为寄存器的整数,寄存器中出现的内容再次为0x01000000,据我所知,如果它是小端,将加载的是0x00000001.

此外,当使用.word 1存储4个字节时,存储的是0x00000001,此时没有字节反转.

我想知道模拟器是大端还是小端,并解释这种行为

Ped*_*d7g 6

你的问题有几个层面,所以我试着逐个解决它们......

机:

机器具有可通过字节寻址的内存.第一个字节有地址0,第二个字节有地址1等等...每当我在这个答案中写下内存内容时,我会使用这种格式:01 02 0E 0F 10 ...使用十六进制值并在字节之间使用空格,地址连续从起始地址开始走向结束地址.即如果此内容将从地址0x800000开始,则内存将为(全部为六进制):

address | byte value
------- | ----------
800000  | 01
800001  | 02
800002  | 0E
800003  | 0F
800004  | 10
800005  | ...
Run Code Online (Sandbox Code Playgroud)

到目前为止无关紧要,无论目标MIPS平台是小端还是大端,只要涉及字节大小的内存,字节顺序就是"正常".

如果要将地址中的字节加载0x800000t0(带lb指令),t0则将等于value 1.

如果你将地址中的单词加载0x800000t0(带lw指令)中,那么结尾将最终发挥作用.

little-endian机器t0上将等于值0x0F0E0201,word的第一个字节(在内存中)是256 0(最低功率)的量,第二个是256 1的数量,...最后一个是256 3的数量.

big-endian机器t0上将等于值0x01020E0F,word的第一个字节(在内存中)是256 3的数量,第二个是256 2的数量,...最后一个是256 0的数量.

(256是2 8,该幻数来自"一个字节是8位",一个位可以包含两个值(0或1),一个字节有8位,因此一个字节可以包含2 8个不同的值)

在这两种情况下,CPU将从存储器读取相同的四个字节(地址0x800000至0x800003),但字节顺序定义它们将以哪个顺序显示为字值的最后32位.

t0物理由32位CPU芯片上形成的,它没有地址.当你想在CPU指令中解决它(即使用存储的值t0)时,你将它编码为指令作为$8寄存器(为了方便你的汇编器$8$t0别名,所以我使用的是t0别名).

字节序不适用于32位寄存器,它们已经是32位b0-b31,一旦0x0F0E0201加载了这些值,那么32位被设置为0000 1111 0000 1110 ...(我将它从顶部b31位向下写入底部b0,到理解移位左/右指令并使其工作为人类格式化二进制数),没有必要考虑寄存器的字节顺序或存储在芯片上的物理顺序,这足以将其视为完整的32位值,在算术指令中,它将起作用.

当将字节值加载lb到寄存器中时,它进入b0-b7位,其中b8-b31包含b7的副本(将带符号的8位值符号扩展为带符号的32位值).

当将寄存器的值存储到存储器中时,字节顺序再次适用,即将word值存储0x11223344到存储器中将设置单个字节为44 33 22 11.

汇编程序(源代码和编译)

为其目标平台配置良好的汇编程序将隐藏程序员的字节序,以方便使用字值.

所以当你定义内存值时:

myPreciousValue .word 0x11223344
Run Code Online (Sandbox Code Playgroud)

汇编程序将解析文本(您的源代码是文本(!),即一个字符是一个字节值 - 以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
Run Code Online (Sandbox Code Playgroud)

要么:

11 22 33 44           # big-endian target
Run Code Online (Sandbox Code Playgroud)

然后当你使用lw代码中的指令,myPreciousValue从内存加载到寄存器时,寄存器将包含预期的字值0x11223344(只要你没有混淆汇编程序配置并使用错误的字节顺序,就不会发生在MARS中)/SPIM,因为它只支持所有内容中的小端配置(VM,汇编程序,调试程序)).

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

如果程序员想要01 02 03 04在内存中定义四个字节,她可以"智能"并.word 0x04030201用于小端目标平台,但这会模糊原始意图,所以我建议.byte 1, 2, 3, 4在这种情况下使用,因为程序员的意图是定义字节,而不是字.

当您使用.byte指令声明字节值时,它们按照您编写它们的顺序进行编译,不会对其应用任何字节顺序.

调试器

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

0x800000: 31 32 33 34 41 42 43 44 | 1234ABCD
Run Code Online (Sandbox Code Playgroud)

当你将它切换到"word"视图时,它将使用配置的字节顺序来连接目标平台顺序中的字节,即在MARS/SPIM中作为little-endian平台,它将显示在同一个内存中:

0x800000: 34333231 44434241
Run Code Online (Sandbox Code Playgroud)

(如果还包含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
Run Code Online (Sandbox Code Playgroud)

到底有什么好处呢?只要您为单个目标平台编写软件,并且您正在通过目标CPU存储/加载单词,您就不需要关心字节顺序.

但是如果你有多平台的软件,它确实保存了二进制文件......为了使文件在大/小端平台上以相同的方式工作,文件结构的规范也必须指定文件数据的字节顺序.然后根据该规范,一种类型的目标平台可能将其读作"本机"字值,另一种目标平台必须将字值中的字节混洗以读取正确的字值(加上规范还应指定多少字节"单词"是:)).然后这样的运行时测试可能很方便,如果你将shuffler包含在save/load例程中,使用endianness检测例程来决定是否必须对字节字节进行洗牌.这将使目标平台的字节顺序"透明"到剩余的代码,这将简单地发送到保存/加载例程它的本地"字"值,并且您的保存/加载可以在每个平台上使用相同的源(至少只要你使用像C这样的多平台可移植编程语​​言,当然MIPS的程序集根本不能在不同的CPU上运行,需要从头开始重写.

此外,网络通信通常使用自定义二进制协议(通常包含在网络层的最常见TCP/IP数据包中,甚至加密,但您的应用程序将在一个点上从中提取原始字节内容),然后发送/接收数据的字节顺序很重要,而"其他"平台必须将字节混洗以读取正确的值.

其他平台(非MIPS)

可以从上面应用几乎所有内容,只需检查一下是什么byte以及word在另一个平台上(我认为byte在过去的35年中,它是相当的8位,但word可能有所不同,例如在x86平台word上只有16位).仍然是little-endian机器将以"反向"顺序读取"字"字节,第一个字节用作最小256 0功率的量,最后一个字节用作最高256功率的量(x86平台上256个1,因为只有两个在那里,字节形成字,MIPS"字"在x86世界中被称为"双字"或"双字".


小智 5

这是来自网站:http : //courses.missouristate.edu/KenVollmar/mars/Help/MarsHelpDebugging.html

Memory addresses and values, and register values, can be viewed in either
decimal or hexadecimal format. All data are stored in little-endian
byte order (each word consists of byte 3 followed by byte 2 then 1 then 0).
Note that each word can hold 4 characters of a string and those 4 
characters will appear in the reverse order from that of the string literal
Run Code Online (Sandbox Code Playgroud)

如您所见,它是小端的

  • @JG55:他们不是。`.byte 0,0,0,1` 加载到带有 `lw` 的寄存器中应该给你 `0x01000000`,它符合你的观察。 (3认同)