是火星MIPS模拟器Big或Little Endian

时间:2017-10-02 20:41:22

标签: assembly mips endianness mars-simulator

我必须确定火星模拟器是作为家庭作业的大或小端,这一开始看起来非常简单,但我遇到了一些问题。

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

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

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

2 个答案:

答案 0 :(得分:5)

您的问题涉及多个层次,因此我尝试逐一解决这些问题......

机:

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

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

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

如果您要将字节从地址0x800000加载到t0(使用lb指令),t0将等于值{{ 1}}。

如果您要将从地址1加载到0x800000(使用t0指令),则最终将会播放字节序。

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

big-endian 机器上,0x0F0E0201将等于值t0,单词的第一个字节(在内存中)为256 3 < / sup>,第二个是256 2 的数量,...最后一个是256 0 的数量。

256 is 28,该幻数来自&#34;一个字节是8位&#34;,一个位可以包含两个值(0或1),一个字节有8位,所以一个字节可以包含2个 8 不同的值)

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

0x01020E0F在CPU芯片上由32位物理构成,它没有地址。如果要在CPU指令中处理它(即使用存储在t0中的值),则将其编码为指令t0寄存器($8具有$8别名,以方便你的汇编程序,所以我使用的是$t0别名。

字节顺序不适用于32位寄存器,它们已经是32位b0-b31,加载值t0后,这些32位被设置为0x0F0E0201(I&# 39; m从顶部b31位向下写入底部b0,以理解左/右移位指令,并使其工作为人格式化二进制数),没有必要考虑寄存器的字节顺序或在比特存储在芯片上的物理顺序中,它足以将其视为完整的32位值,并且在算术指令中它将起作用。

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

当将寄存器的值存储到内存中时,字节顺序再次适用,即将lbword存储到内存中会将单个字节设置为0x11223344

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

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

因此,当您定义内存值时:

44 33 22 11

汇编程序将解析文本(您的源代码是文本(!),即一个字符是一个字节值 - 以ASCII编码,如果您在UTF8文本编辑器中编写源并使用非ASCII字符,则它们可能被编码跨多个字节,ASCII可打印字符在ASCII和UTF8中具有相同的编码,并且仅占用单个字节)&#34; 0x11223344&#34; (10个字节myPreciousValue .word 0x11223344 ),从中计算出32位字值30 78 31 31 32 32 33 33 34 34,然后它将目标平台字节序应用于此产生四个字节的机器代码:

0x11223344

或:

44 33 22 11           # little-endian target

当您在代码中使用11 22 33 44 # big-endian target 指令时,要将lw从内存加载到寄存器中,寄存器将包含预期的字值myPreciousValue(只要您没有&# 39;混淆汇编程序配置并使用错误的字节顺序,不能在MARS / SPIM中发生,因为它只支持所有内容中的小端配置(VM,汇编程序,调试程序)。)

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

如果程序员想要在内存中定义四个字节0x11223344,那么她就可以&#34;智能&#34;并将01 02 03 04用于little-endian目标平台,但这会混淆原始意图,所以我建议在这种情况下使用.word 0x04030201,因为程序员的意图是定义字节,而不是字。

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

调试器

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

.byte

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

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

(如果还包括ASCII视图,那么它是&#34;措辞&#34;如果是,那么它将看起来像0x800000: 34333231 44434241 。我没有安装MARS / SPIM时检查调试器中的内存视图实际上是什么样的,抱歉)

所以你作为程序员可以阅读&#34; word&#34;值直接来自显示,而不是将字节拖入&#34;纠正&#34;顺序,你已经看到&#34; word&#34;值将是(来自存储器内容的四个字节)。

寄存器视图通常默认显示十六进制字值,即在将地址0x800000中的字加载到4321 DCBA后,寄存器t0将包含值$80x34333231十进制)。

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

代码中的运行时检测。

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

875770417

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

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

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

其他平台(非MIPS)

可以从上面应用几乎所有内容,只需检查另一个平台上的.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 byte(我认为word相当于最后35+的8位年,但byte可能会有所不同,例如在x86平台上word仅为16位)。仍然是小端机器会读&#34;字&#34; &#34;反转&#34;顺序,第一个字节用作最小256 0 功率的量,最后一个字节用作最高256功率的量(x86平台上256 1 ,仅为两个字节在那里形成单词,MIPS&#34;单词&#34;在x86世界中被称为&#34;双字&#34;或&#34; dword&#34;。

答案 1 :(得分:4)

这是来自网站: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

你可以看到它是小端