大小端格式由编译器还是CPU决定的?

关注、星标公众,不错过精彩内容

编辑:黄工

素材来源:网络

有读者问了这么一个问题:大小端与编译器和操作系统有关吗?

其实大小端主要由CPU决定,与编译器、操作系统这些没有直接关系。

因为我以前学习的时候,有很长一段时间也是存在这样的疑问。我觉得应该还有很多人都没搞明白,所以,今天来分享一下相关内容。

一、关于大小端

大小端也可以理解为字节顺序,或者端序、尾序,也就是你们看到的大端序(Big-Endian)、小端序(Little-Endian)。

关于大小端的解释网上很多教程,也不难理解。

大端模式:是指数据的高字节保存在内存的低地址中;

小端模式:是指数据的高字节保存在内存的高地址中;

大小端模式:

https://baike.baidu.com/item/大小端模式/6750542

字节顺序:

https://zh.wikipedia.org/wiki/字节序

也可以参看我之前分享过的文章:你真的懂CPU大小端模式吗?

二、CPU是大小端存储的决定因素

可能部分初学者被一些外界信息给误导,从而有这样的疑惑。

比如:

操作系统是大端还是小端存储?

Keil C51是大端模式,认为与编译器有关。

你了解大小端之后,你会发现,大小端主要有用于存储的顺序,与存储器(硬件)关系比较大,编译器和操作系统仅仅是配合CPU编译好相应的代码,而不是决定大小端的因素。

三、ARM大小端模式

ARM处理器默认是小端模式,但它是支持大端模式。

我们在Cortex-M3手册中有这么一些描述:在Cortex-M3中, 存储器系统支持 both 小端配置和大端配置。

Cortex-M3 支持 both 小端模式和大端模式。但是,单片机其它部分的设计,包括总线的连接,内存控制器以及外设的性质等, 一定要先在单片机的数据手册上查清楚可以使用的端。在绝大多数情况下,基于 CM3 的单片机都使用小端模式。为了避免不必要的麻烦,基本清一色地使用小端模式。

归根结底,ARM的大小端模式还是与CPU有关,而与编译器和操作系统没有直接关系。

免责声明:本文部分素材来源网络,版权归原作者所有。如涉及作品版权问题,请与我联系删除。

‧  END  

推荐阅读:

精选汇总 | 目录 | 搜索

VS Code V1.43支持远程开发、同步预览

Cortex-M微控制器软件接口标准CMSIS详细内容

关注微信公众号『strongerHuang』,后台回复“1024”,查看更多精彩内容。

长按前往图中包含的公众号关注

<think>我们讨论的是汇编指令的机器码的字节序问题。注意,这里不是指数据存储的字节序(如大端或小端),而是指指令本身的机器码在内存中的存储顺序。 在x86架构中,指令的机器码在内存中是以字节为单位顺序存储的,并且其顺序是固定的。例如,一条指令的操作码在前,然后是操作数(如果有的话)。对于多字节的操作数(如立即数或地址),x86架构采用小端字节序(Little-Endian)存储。 但是,这里需要区分: 1. 指令本身的操作码部分:操作码是单字节或多字节,其顺序是固定的,由CPU设计决定。例如,前缀字节在前,操作码在后。 2. 指令中的立即数或地址:这些数值在机器码中是以小端字节序存储的。 例如,指令 `mov dword ptr [eax], 0x12345678` 的机器码可能是: C7 00 78 56 34 12 其中: - C7 00 是操作码部分(表示将立即数移动到内存地址,地址由eax寄存器给出) - 后面的4个字节是32位立即数0x12345678,按照小端存储:低字节78在低地址,然后是56,34,12。 因此,对于指令机器码中的立即数和地址部分,x86架构使用小端字节序。 但是,指令的操作码部分(包括前缀、操作码等)在机器码中的顺序是固定的,并不称为大端或小端,因为它们是按字节顺序排列的,每个字节都有其固定位置。 所以,要判断一条汇编指令的机器码的存储方式,我们可以说: - 整个指令的字节流在内存中按地址递增顺序存放。 - 指令中的多字节操作数(立即数、地址偏移量等)采用小端字节序。 例如,在问题中给出的指令: mov [ecx+edx*4+00422000h], 0Ah 这条指令的机器码可能包含多个字节,其中立即数0Ah(一个字节,所以无字节序问题)和位移量00422000h(4个字节)会出现在机器码中。位移量00422000h在机器码中会以小端方式存储:00 20 42 00(即低字节00在低地址,然后是20,42,00)。 因此,我们可以通过检查指令中多字节操作数在机器码中的表示来确定:如果操作数的低位字节存储在低地址,高位字节存储在高地址,那么就是小端。 总结:在x86架构中,指令机器码的存储顺序是操作码在前,操作数在后,并且操作数中的多字节数值采用小端字节序存储。 所以,对于x86指令集,机器码中多字节操作数的存储方式是小端(Little-Endian)。 注意:这个结论只针对x86架构。不同的架构可能有不同的设计。例如,ARM架构既支持大端也支持小端,但通常操作系统会统一采用一种字节序(如小端)。而MIPS架构同样可以选择字节序,但常见系统也是小端。 因此,确定一条汇编指令的机器码的字节序,需要看目标平台。在常见的x86和ARM(小端模式)平台,都是小端存储。 如何验证? 我们可以使用汇编器将汇编指令转换为机器码,然后查看机器码的字节排列。例如,使用NASM汇编器或在线汇编器。 例如,使用NASM汇编以下指令(在32位模式下): mov dword [ecx+edx*4+0x00422000], 0x0A 我们可以写一个简单的汇编程序,然后使用nasm编译,再用ndisasm反汇编查看机器码,或者用objdump查看。 步骤: 1. 编写一个汇编文件(test.asm): bits 32 mov dword [ecx+edx*4+0x00422000], 0x0A 2. 使用nasm编译:nasm -f bin test.asm -o test.bin 3. 使用十六进制查看工具查看test.bin的内容。 预期机器码(根据指令编码): 操作码:C7(mov r/m32, imm32) 然后是一个ModR/M字节和SIB字节(因为寻址方式复杂) 接着是4字节的位移量(小端存储)和4字节的立即数(小端存储) 实际编码可能为: C7 84 91 00 20 42 00 0A 00 00 00 解释: C7: mov指令的操作码(用于32位立即数到内存) 84 91: ModR/M和SIB字节(表示基址为ecx,变址为edx*4,位移量为32位) 00 20 42 00: 位移量0x00422000的小端表示(00 20 42 00) 0A 00 00 00: 立即数0x0A(即10)的小端表示(因为是32位立即数,所以扩展为4字节) 从机器码中我们可以看到: 位移量00422000h存储为:00 20 42 00(小端) 立即数0Ah存储为:0A 00 00 00(小端) 因此,可以确定是小端存储。 结论:在x86架构中,汇编指令的机器码中出现的多字节数值(如地址位移量、立即数)采用小端字节序存储。 注意:指令操作码本身(如C7,84,91)是按顺序存储的,这些字节没有大小端的问题,因为每个字节都是独立的。 所以,对于给定的汇编指令,我们判断其机器码的字节序(针对多字节操作数)是小端存储。 相关问题: 1. 如何查看汇编指令对应的机器码? 2. 在ARM架构中,指令的机器码是否也采用小端存储? 3. 机器码中的操作码部分是否受字节序影响? 4. 如果立即数是8位(如0Ah),在机器码中如何存储? 5. 大端存储的CPU架构(如PowerPC)中,指令的机器码中的多字节操作数如何存储?</think>### 如何确定汇编指令机器码的字节序(大端/小端) 在汇编指令中,**机器码的字节序由CPU架构决定**,与数据存储的字节序规则一致。以下是判断方法: #### 1. **x86/x64架构(主流桌面/服务器CPU)** - **小端存储**(Little-Endian) - 特征: - 多字节操作数(如立即数、地址)**低位字节在前** - 示例:指令 `mov dword ptr [eax], 12345678h` 的机器码: ```assembly C7 00 78 56 34 12 ; 78(低字节)在56前,34在12前 ``` 其中 `78 56 34 12` 是小端格式的 `12345678h`。 #### 2. **ARM架构(多数移动设备/嵌入式)** - **可配置大小端**,但**默认小端存储** - 现代ARM系统(Android/iOS)通常采用小端模式 - 示例:指令 `LDR R0, =0x12345678` 在小端模式下机器码包含 `78 56 34 12` #### 3. **MIPS/PowerPC/RISC-V架构** - **大端存储**(Big-Endian)常见于网络设备/旧系统 - 特征: - 多字节操作数**高位字节在前** - 示例:指令 `li r3, 0x12345678` 在大端模式下机器码包含 `12 34 56 78` --- ### 验证方法 #### 方法1:反汇编工具 使用 `objdump` 或 `ndisasm` 查看机器码: ```bash echo "C70078563412" | xxd -r -p | ndisasm -b 32 - # 输出: 00000000 C70078563412 mov dword [eax],0x12345678 ``` 观察操作数部分 `78563412` → 小端格式的 `12345678h`。 #### 方法2:调试器查看 在GDB中执行: ```bash (gdb) x/6xb &instruction # 查看6字节机器码 0x8048000: 0xc7 0x00 0x78 0x56 0x34 0x12 ``` 操作数部分 `78 56 34 12` 符合小端存储。 #### 方法3:编译器输出 编译代码并导出机器码: ```c // test.c int main() { __asm__("movl $0x12345678, (%eax)"); } ``` 编译查看: ```bash gcc -c test.c && objdump -d test.o ``` --- ### 关键结论 1. **指令字节序 = 数据存储字节序**,由CPU架构决定 2. **x86/x64/ARM默认小端**,网络设备/旧系统可能用大端 3. 多字节操作数(地址/立即数)需按字节序解析: - 小端:`78 56 34 12` → `0x12345678` - 大端:`12 34 56 78` → `0x12345678` > 示例中指令 `mov [ecx+edx*4+00422000h], 0Ah` 的机器码(x86): > - 地址 `00422000h` 会拆分为 `00 20 42 00`(小端) > - 立即数 `0Ah` 扩展为 `0A 00 00 00`(小端)[^1] --- ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值