CPU大小端和网络序的理解

news2024/11/27 5:34:09
  1. 引子
    Big/Little Endian是Host CPU如何去理解在内存中的数据,内存中的数据是没有Big/Little Endian之分的(内存仅仅作为存储介质),而Host CPU才有Big/Little Endian之分。
    不同Endian的CPU,从内存读取数据的时候,按自己的Endian模式转换数据,放入CPU的寄存器reg中,假如寄存器是32bits,此时寄存器bit31存储数据的MSB高位,即寄存器bit[31-0]符合我们人类的阅读顺序(我们程序中定义的变量,是在CPU寄存器完成操作,因此在编程时对变量值的赋值或者读取是符合人类阅读顺序的)。数据从CPU写入到内存,同样需要类似的转换。

  2. Big Endian和Little Endian
    本章解释Big Endian和Little Endian的具体行为,从软件人员的角度理解是这样的: 大小端字节序指的是多字节类型的字节数据在内存中的存储顺序,字节内的各bit位置并不变化。

例如数据:0x12345678 (符合人类的阅读顺序,或者程序中常量的顺序,即寄存器bit31-0)

在大端模式下的存储情况为:

内存地址0123
十六进制数据0x120x340x560x78
二进制数据0001 00100011 01000101 01100111 1000

在小端模式下的存储情况为:

内存地址0123
十六进制数据0x780x560x340x12
二进制数据0111 10000101 01100011 01000001 0010
  1. Networks Order
    其实网络报文在线路上传播的时候并没有和内存打交道,但在接收或者发送的时候,需要存入内存,或者从内存中读取报文内容进行发送。不同的CPU Endian模式,可能会造成报文内容的差异,因此规定不管CPU是什么Endian模式,针对网络报文必须这样处理:报文的第一个字节被认为是报文的高字节MSB,放入内存的低地址上(报文是从第一个字节开始收发,内存是从低地址开始申请,因此这种定义是符合实际的)。这种跟CPU Endian模式无关,只针对网络报文的定义并称为网络字节序(Networks Order)。
    可见,网络序的定义是和Big Endian的行为一致的,因此在Big Endian CPU上处理网络序并不需要特殊处理了。而在Little Endian CPU上的软件需要特殊处理(请注意是软件处理),比如报文的DMAC高4字节是0x12345678,在作为网络报文时,软件通过htonl函数转成网络序,在Little Endian CPU对应的内存中存放的格式同Big Endian CPU。硬件处理发送接收报文的模块(例如网卡,非CPU),按网络序发送到网络线路上或从网络线路上接收。

  2. 多字节如何转换Big/Little Endian
    第二章描述了多字节数据在不同Big/Little Endian CPU的存储情况,普通的应用程序是不需要转换的,读写都是CPU自动完成。但是作为运行在CPU上的网卡驱动,需要去配置网卡硬件中的寄存器或者网卡内部Memory。然而,Host CPU和网卡的Endian模式可能是不同的,因此网卡驱动软件需转换数据的Big/Little Endian。
    例如网迅的网卡是Little Endian的,若驱动运行在Big Endian的Host CPU上,驱动的转换代码就会生效。
    a) 通过PCIE bar直接配置寄存器:
    寄存器往往是32bits的,软件定义u32变量和其对齐。驱动通过wr32配置,在wr32函数内会进行Big/Little Endian转换:

#define wr32(reg, val) \
do { \
	u8 *base = hw->base; \
	writel((val), &base[(reg)]); \
} while (0)

static inline void writel(u32 value, volatile void __iomem *addr)
{
	__io_bw();
	__raw_writel((u32 __force)__cpu_to_le32(value), addr);
	__io_aw();
}

b) 通过Admin queue配置网卡内部Memory:
Adminq中的data,对应的是网卡内部的Memory,可能是u32,u16,u8类型,软件要选择和硬件对齐的数据类型来定义。驱动在data buffer中已经组装成了Little Endian的格式,方便固件直接Copy到网卡内部Memory。Adminq Desc描述符本身也是Little Endian,驱动负责转换大小端。

网络报文内容相关的网卡硬件寄存器或者内部Memory,则要定义为Networks Order(Big Endian)。

5. 芯片硬件人员的大小端理解
咨询了网卡的硬件开发人员,Little Endian是从高bit到低bit取数据,Big Endian是从低bit到高bit取数据。例如读取16bit的一个数据(寄存器或者网卡内部Memory),Little Endian的网卡按bit[15:0]方式,而Big Endian是按bit[0:15]的方式。

以数据0x1234为例:

SRAM物理连线编号0123456789101112131415
Little Endian的位序7654321015141312111098
Big Endian的位序0123456789101112131415
二进制值0001001000110100

在Little Endian网卡硬件上,以bit[15:0]的方式取到的是0x3412。在Big Endian硬件上,以bit[0:15]的方式取到的是0x1234。

 这里最主要的一点是,Little Endian和Big Endian硬件对SRAM存储介质的第一根物理连线认为是bit几是不同的,Little Endian硬件认为是bit7,而Bit Endian硬件认为是bit0。
 硬件ASIC应该是通过总线来读写SRAM中的值,上述这点可能是总线的行为操作。

  1. 单字节为什么不需要转换
    第5章节已经能知道为什么单字节不需要转换。

以数据0x12为例:

SRAM物理连线编号01234567
Little Endian的位序76543210
Big Endian的位序01234567
二进制值00010010

在Little Endian网卡硬件上,以bit[7:0]的方式取到的是0x12。在Big Endian硬件上,以bit[0:7]的方式取到的是0x12。

  1. 位域bit field如何转换Big/Little Endian
    位域在大小端系统的差异是软件编程和编译器的行为了。主要是针对结构体定义的内存分配原则。

    在对Struct(结构体)中成员进行内存分配的时候,“按排列顺序分配,先分配排在前面的”:
    1.大端(big endian)模式,从高位向地位分配
    对字节,先分配高字节(内存低地址中),再分配低字节(内存高地址中)。
    对位域,先分配高bit位,再分配低bit位。大端的高bit位序是bit0
    2.小端(little endian)模式,从地位向高位分配
    对字节,先分配低字节(内存低地址中),再分配高字节(内存高地址中)。
    对位域,先分配低bit位,再分配高bit位。小端的低bit位序是bit0

若能够理解第5章节的硬件行为,这个原则其实是统一的。不管大小端,对字节:从内存地址开始;对位域,在对应的字节数内,从硬件的位序bit0开始。

7.1 例子

定义如下结构体:
typedef struct tagBigOrLittleData
{
UINT32 uiA:5; /对应数据赋值:00101/ 简单起见,对应的值刚好是位域长度
UINT32 uiB:9; /对应数据赋值:000001001/
UINT32 uiC:12;/对应数据赋值:000000001100/
UINT32 uiD:6; /对应数据赋值:000110/
}BigOrLittleData_S;

大端模式下,硬件以bit[0:31]方式读取为(0x28240306),分配从bit0(物理连线编号0)开始,为uiA分配bit[0:4], uiB分配bit[5:13],依次类推,如下:
在这里插入图片描述

小端模式下,硬件以bit[0:31]方式读取为(0x18030125),分配从bit0(物理连线编号7)开始,为uiA分配bit[4:0](物理编号为3-7),为uiB分配bit[13:5] (物理连线编号10-15,0,1,2),如下:
在这里插入图片描述

可见,在相同的结构体定义下,在大小端上的值不同,为此软件定义结构体位域需要区分大小端。重新定义如下(大端不变,小端重新定义了一下):
typedef struct tagBigOrLittleData
{
#ifdef BIG_ENDIAN
UINT32 uiA:5; /对应数据赋值:00101/
UINT32 uiB:9; /对应数据赋值:000001001/
UINT32 uiC:12;/对应数据赋值:000000001100/
UINT32 uiD:6; /对应数据赋值:000110/
#else
UINT32 uiD:6; /对应数据赋值:000110/
UINT32 uiC:12;/对应数据赋值:000000001100/
UINT32 uiB:9; /对应数据赋值:000001001/
UINT32 uiA:5; /对应数据赋值:00101/
#endif
}BigOrLittleData_S;

重新定义的小端模式,硬件以bit[0:31]方式读取为(0x28240306),与之前的大端模式值相同。
在这里插入图片描述

  1. 参考资料

https://blog.csdn.net/AlbertoNo1/article/details/50862364
https://blog.csdn.net/chen_xing_hai/article/details/126279425

END

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/722244.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux进度条

Linux进度条 一.基本概念1.回车和换行2.缓冲区2.实现倒计时 二.进度条1.前置工作2.代码实现 一.基本概念 1.回车和换行 回车:指光标移到该行的起始位置(\r)。 换行:换到下一行(\n)。 在c语音里\n将回车和换…

spring.boot 随笔0 springFactoriesInstance入门

0. 其实也没有那么入门 明天还要上班,速度write,直接放一张多样性比较好的 spring.factories 文件(取自 spring-boot-2.3.4.RELEASE.jar) # PropertySource Loaders org.springframework.boot.env.PropertySourceLoader\ org.springframework.boot.env…

知识图谱实战应用19-基于Py2neo的英语单词关联记忆知识图谱项目

大家好,我是微学AI,今天给大家介绍一下知识图谱实战应用19-基于Py2neo的英语单词关联记忆知识图谱项目。基于Py2neo的英语单词关联记忆知识图谱项目可以帮助用户更系统地学习和记忆英语单词,通过图谱的可视化展示和智能推荐功能,提供了一种全新的、更高效的记忆方法,并促进…

AtomicInteger使用详解

AtomicInteger使用详解 1、get():获取当前AtomicInteger对象的值。2、set(int newValue):将AtomicInteger对象的值设置为指定的newValue。3、getAndSet(int newValue):先获取当前AtomicInteger对象的值,然后将对象的值设置为指定的…

ROS1/2机器人课程的价值和规模

价值用价格,规模用销量。 免费的ROS1/2课程也很多。 2023版,15元,24人。 2022版,1.99元,21人。 价格不贵,人数很少,店家也很少。 当然,有朋友说,有免费冲击&#xff0…

宏晶微 音频处理芯片 MS7124

MS7124是一款高性能24bit数字立体声音频DAC,该DAC采用Sigma-Delta结构,支持标准的I2S数字信号输入,输出支持立体声和单声道。

比对Excel数据

以a个为准绳比对b表数据,添加比对结果列输出。 (本笔记适合初通 Python 的 coder 翻阅) 【学习的细节是欢悦的历程】 Python 官网:https://www.python.org/ Free:大咖免费“圣经”教程《 python 完全自学教程》,不仅仅是基础那么…

大数据Doris(五十七):RECOVER数据删除恢复

文章目录 RECOVER数据删除恢复 一、Recover语法 二、数据恢复案例 RECOVER数据删除恢复 Doris为了避免误操作造成的灾难,支持对误删除的数据库/表/分区进行数据恢复,在drop table或者 drop database之后,Doris不会立刻对数据进行物理删除…

C语言进阶--文件操作

目录 一.何为文件 二.文件名 三.文件的打开和关闭 3.1.流 3.2.文件指针 3.3.文件的打开与关闭 打开文件: 模式: 关闭文件: 四.文件的顺序读写 4.1.常见的顺序读写函数 4.2.字符的输入输出fgetc/fputc 输出函数: 输入…

计算机存储层次及常用存储简介

计算机存储层次(Memory hierarchy) 存储层次是在计算机体系结构下存储系统层次结构的排列顺序。 每一层于下一层相比 都拥有 较高的速度 和 较低延迟性 ,以及 较小的容量 (也有少量例外,如AMD早期的Duron CPU&#xf…

pod 控制器 3

简单回顾 之前我们学习过的的 docker ,例如我们运行 docker run busybox echo "hello wrold" 他的实际内在逻辑是这个样子的 程序将指令推送给 dockerdocker 会检查本地是否有 busybox 镜像,若没有则去 docker hub 上面拉取镜像,…

windows下mysql配置文件my.ini在这个位置

windows下mysql配置文件my.ini在这个位置 选中服务邮件 右键----属性,弹出下图 一般默认路径: "D:\Program Files\MySQL\MySQL Server 8.0\bin\mysqld.exe" --defaults-file"C:\ProgramData\MySQL\MySQL Server 8.0\my.ini" MySQ…

信息安全管理与评估赛题第4套

全国职业院校技能大赛 高等职业教育组 信息安全管理与评估 赛题四 模块一 网络

simulink 常用模块

add sub pro div加减乘除 Relational Operator 数值比较模块 < < > > ! Compare To Constant 直接和某数字比较&#xff0c;是上面的封装 Logical Operator 逻辑运算 & | ~ switch 相当于c语言的if 中间是条件&#xff0c;满足走上&#xff0c;否则走下…

上门按摩小程序开发|同城预约上门小程序定制

上门按摩小程序对实体按摩商家来说是非常适合的。下面是对上门按摩小程序适合实体按摩商家开发的简单介绍&#xff1a;   扩展服务范围&#xff1a;上门按摩小程序可以让实体按摩商家将服务范围扩展到用户的家中或办公场所。用户可以通过小程序预约上门按摩服务&#xff0c;无…

【openGauss数据库】--运维指南03--数据导出

【openGauss数据库】--运维指南03--数据导出 &#x1f53b; 一、openGauss导出数据&#x1f530; 1.1 概述&#x1f530; 1.2 导出单个数据库&#x1f537; 1.2.1 导出数据库&#x1f537; 1.2.2 导出模式&#x1f537; 1.2.3 导出表 &#x1f530; 1.3 导出所有数据库&#x1…

计算两个二维数组arr1和arr2中对应位置元素的商

代码实现 &#xff1a;一个嵌套循环&#xff0c;用于计算两个二维数组arr1和arr2中对应位置元素的商&#xff0c;并将结果存储在result数组中。首先&#xff0c;定义了一个空数组result用于存储结果。然后&#xff0c;通过两个for循环遍历arr1数组的每一行和每一列。在内层循环…

[SWPUCTF 2021 新生赛] ez_unserialize

打开链接但是没有题目 使用御剑扫一下 flag.php打不开&#xff0c;但是在robots.txt里面我们找到了一个路径 /cl45s.php 打开之后是PHP源码 简单审一下,构造pop链&#xff1a; 链尾&#xff08;就是最终我们想要利用的地方&#xff09;&#xff0c;在echo $flag 并且include了…

基于改进莱维飞行和混沌映射的粒子群算法(10种混沌映射随意切换),附matlab代码

“ 本篇文章对粒子群优化算法进行改进&#xff0c;首先通过引入混沌映射机制&#xff0c;对其群体进行初始化&#xff0c;增加粒子群个体的多样性&#xff1b;然后在粒子群个体的位置更新公式上引入改进的莱维飞行机制&#xff0c;提高搜索精度&#xff0c;帮助粒子群个体跳出局…

云原生(第三篇)-k8s资源管理的两种方式

陈述式资源管理方法&#xff1a; 1.kubernetes 集群管理集群资源的唯一入口是通过相应的方法调用 apiserver 的接口 2.kubectl 是官方的CLI命令行工具&#xff0c;用于与 apiserver 进行通信&#xff0c;将用户在命令行输入的命令&#xff0c;组织并转化为 apiserver 能识别的…