JG5*_*G55 3 assembly mips endianness mars-simulator
我必须确定火星模拟器是大或小端作为家庭作业,这看起来非常简单,但我有一些问题.
首先我尝试在内存中存储4个字节,内存为0,0,0,1,在内存中显示为0x01000000,因此,以相反的顺序,这似乎表示模拟器是小端,但是,当我加载4字节作为寄存器的整数,寄存器中出现的内容再次为0x01000000,据我所知,如果它是小端,将加载的是0x00000001.
此外,当使用.word 1存储4个字节时,存储的是0x00000001,此时没有字节反转.
我想知道模拟器是大端还是小端,并解释这种行为
你的问题有几个层面,所以我试着逐个解决它们......
机器具有可通过字节寻址的内存.第一个字节有地址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平台是小端还是大端,只要涉及字节大小的内存,字节顺序就是"正常".
如果要将地址中的字节加载0x800000
到t0
(带lb
指令),t0
则将等于value 1
.
如果你将地址中的单词加载0x800000
到t0
(带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数据包中,甚至加密,但您的应用程序将在一个点上从中提取原始字节内容),然后发送/接收数据的字节顺序很重要,而"其他"平台必须将字节混洗以读取正确的值.
可以从上面应用几乎所有内容,只需检查一下是什么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)
如您所见,它是小端的