2411rust,正与整128
原文
长期以来,Rust
在x86-32
和x86-64
架构上128
位整数的对齐
与C语言
不一致.最近已解决此问题
,但该修复
带来了一些值得注意
的效果
.
作为用户,除非如下,否则不用担心:
1,假设i128/u128
对齐,而不是用align_of
2,忽略improper_ctypes*
检查,并在FFI
中使用这些类.
除x86-32
和x86-64
外,其他架构
不变.如果你的代码大量使用128
位整数,会注意到运行时性能
提高,但可能会增加内存使用
.
背景
数据类型
有两个与内存
中的排列方式
有关的内部值
:大小和对齐
.类型的大小
是它在内存
中消费的空间量
,对齐
指定了允许在哪些地址放置它
.
像原语
此类简单类型
的大小
一般是无歧义
的,是它们所表示的数据
的没有填充(未使用的空间)
的确切大小
.如,i64
的大小总是为64
位或8字节
.
但是,对齐
可能会有所不同.可在(1字节对齐
)任意内存地址
中保存8字节整数
,但大多数64
位计算机如果按8的倍数(8字节对齐)
保存,则会取得最佳性能
.
因此,与其他语言
一样,Rust
中的原语
默认有该最有效的对齐
.在创建复合类型
时可见该效果:
use core::mem::{align_of, offset_of};
#[repr(C)]
struct Foo {a: u8, //1字节对齐b: u16, //2字节对齐
}
#[repr(C)]
struct Bar {a: u8, //1字节对齐b: u64, //8字节对齐
}
println!("Offset of b (u16) in Foo: {}", offset_of!(Foo, b));
println!("Alignment of Foo: {}", align_of::<Foo>());
println!("Offset of b (u64) in Bar: {}", offset_of!(Bar, b));
println!("Alignment of Bar: {}", align_of::<Bar>());
输出:
`Foo`中`b(u16)`的偏移:2`Foo`对齐:2`栏`中`b(u64)`的偏移:8`bar`对齐:8
看到,在一个结构
中,总是在它的偏移
是其对齐的倍数
位置放置一个类型
,即使表明未使用的空间
,当不使用repr(C)
时,Rust
默认最小化它.
这些数字
不是任意的;应用二进制接口
(ABI
)说明了它们应该是什么
.在系统V
(Unix&Linux
)的x86-64psABI
(处理器相关的ABI
)中,图3.1
:标量类型
准确地告诉了应该如何表示原语
:
C型 | Rust 等价 | sizeof | 对齐(字节) |
---|---|---|---|
符 | i8 | 1 | 1 |
正符 | u8 | 1 | 1 |
短 | i16 | 2 | 2 |
正短 | u16 | 2 | 2 |
长 | i64 | 8 | 8 |
正长 | u64 | 8 | 8 |
ABI
仅指定了C类型
,但Rust
在兼容和性能优势方面
都遵守相同定义
.
错误的对齐问题
如果两个实现
在数据类型
的对齐
上有分歧,则无法可靠
地共享包含该类型的数据
.Rust
对128
位类型的对齐
不一致:
println!("alignment of i128: {}", align_of::<i128>());
//`rustc1.76.0`版本
// `i128`对齐:8
printf("alignment of __int128: %zu\n", _Alignof(__int128));
//`GCC`版本`13.2`
// __int128对齐:16
// Clang17.0.1
// __int128对齐:16
回头看一下psABI
,可见Rust
在此的对齐
是错误的:
C型 | Rust 等价 | sizeof | 对齐(字节) |
---|---|---|---|
__int128 | i128 | 16 | 16 |
正__int128 | u128 | 16 | 16 |
表明,这并不是因为Rust
积极地做错
了什么:原语
的布局
来自Rust
和Clang
等语言使用的LLVMcodegen
后端,且它有硬编码
为8字节
的i128
对齐.
Clang
使用正确的对齐
只是因为变通,即在把类型交给LLVM
前,手动按16
字节设置对齐
.这解决
了布局问题
,但也是其他一些小问题的根源
.
Rust
无此手动调整,因此在https://github.com/rustlang/rust/issues/54341
上报告了它
.
调用约定问题
还有一个问题
:LLVM
在按函数参数
传递128
位整数时,并不总是正确
.在发现它与Rust
相关前,这是LLVM
中的一个已知问题
.
调用函数
时,会在寄存器
中传递参数
,直到没有更多的槽
,然后会"溢出"
到栈中(程序的内存
).
ABI
在3.2.3
传递参数一节中,也告诉了该怎么做
:
__int128
类型的参数
与INTEGER
操作相同
,但它们不适合一个通用寄存器
,而是需要两个寄存器
.为了分类,按如下
实现对待__int128
:
typedef struct {long low, high;
} __int128;
但在内存中保存
的__int128
类型的参数
必须在16
字节边界
上对齐
.
可手动实现调用约定
来试此操作.在下面C示例
中,用内联汇编
按val
为0x11223344556677889900aabbccddeeff
值,来调用foo(0xaf,val,val,val)
.
x86-64
使用RDI,RSI,RDX,RCX,R8
和R9
寄存器,来按顺序
传递函数参数
.每个寄存器
适合一个字(64位
),不合适的都压进
栈中.
/*`<https://godbolt.org/z/5c8cb5cxs>`的完整示例*/
/*要查看问题,需要一个`内边距`值来"搞砸"参数对齐*/
void foo(char pad, __int128 a, __int128 b, __int128 c) {printf("%#x\n", pad & 0xff);print_i128(a);print_i128(b);print_i128(c);
}
int main() {asm(/*`加载`适合`寄存器`的参数*/"movl $0xaf,%edi\n\t"/*第1个槽位`(EDI)`:填充符(`"EDI"`是*与`"RDI"`相同,只是访问大小较小)*/"movq $0x9900aabbccddeeff,%rsi\n\t"/*第2个槽`(RSI):"a"`的下半部分*/"movq $0x1122334455667788,%rdx\n\t"/*第3个槽`(RDX):"a"`的上半部分*/"movq $0x9900aabbccddeeff,%rcx\n\t"/*第4个槽`(RCX):"b"`的下半部分*/"movq $0x1122334455667788,%r8\n\t"/*第5个槽位`(r8):'b'`的上半部分*/"movq $0xdeadbeef4c0ffee0,%r9\n\t"/*第6个槽`(R9)`:应该未使用,但来欺骗`Clang`!*//*重用保存的`寄存器`来加载栈*/"pushq %rdx\n\t"/*在栈上传递`'c'`的上半部分*/"pushq %rsi\n\t"/*在栈上传递`'c'`的下半部分*/"call foo\n\t"/*调用函数*/"addq $16,%rsp\n\t"/*重置栈*/);
}
使用GCC
运行上述操作打印以下期望输出:
0xaf0x11223344556677889900aabbccddeeff0x11223344556677889900aabbccddeeff0x11223344556677889900aabbccddeeff
但是使用Clang17
打印:
0xaf0x11223344556677889900aabbccddeeff0x11223344556677889900aabbccddeeff0x9900aabbccddeeffdeadbeef4c0ffee0^^^^^^^^^^^^^^^^这应该是下半部分^^^^^^^^^^^^^^^^很熟悉
惊喜!
这说明了第二个问题:LLVM
期望i128
在可能时一半在寄存器
中传递,一半在栈
上传递,但ABI
禁止这样做
.
因为该行为来自LLVM
且没有合理的解决方法
,因此这在Clang
和Rust
中都是一个问题
.
方法
NikitaPopov
修复了D158169
的调用约定问题.这两项更改
都已纳入LLVM18
,即所有相关的ABI
问题都使用在此版本
的Clang
和Rust
中得到解决.
因为这些更改
,Rust
现在生成正确的对齐
:
println!("alignment of i128: {}", align_of::<i128>());
//`rustc1.77.0`版本
i128
对齐:16
如上,ABI
指定数据类型对齐
的部分原因
是因为它在该架构
上效率更高
.更改手动对齐
的初始性能
运行,表明大大改进了编译器性能
(严重依赖128
位整数来处理整数文字).
增加对齐
的缺点是在内存中复合类型
并不总是很好地组合
在一起,从而导致使用量增加
.可惜,即需要牺牲一些性能优势
,以避免增加内存成本
.
兼容
总之,使用LLVM18
(默认版本从1.78
开始)的Rust
的i128
和u128
将与版本的GCC
及Clang18
及更高版本
(2024
年3月发布)完全兼容
.
相关文章:
2411rust,正与整128
原文 长期以来,Rust在x86-32和x86-64架构上128位整数的对齐与C语言不一致.最近已解决此问题,但该修复带来了一些值得注意的效果. 作为用户,除非如下,否则不用担心: 1,假设i128/u128对齐,而不是用align_of 2,忽略improper_ctypes*检查,并在FFI中使用这些类. 除x86-32和x86-64…...

将 HTML 转换为 JSX:JSX 和 JSX 规则
JSX 是 JavaScript 的语法扩展。您可以在 JavaScript 文件中编写 HTML 格式。 它基于 Web、Html、Css 和 JavaScript。Web 开发人员将页面内容分别编写为 Html 文件,将设计编写为 Css 文件,将逻辑编写为 JavaScript 文件。 须知 : JSX 是一个…...

将 FastAPI 部署到生产服务器(一套 全)
将 FastAPI 部署到生产服务器(全) 文章目录 将 FastAPI 部署到生产服务器(全)一、前言二、Fastapi项目 生产环境配置1. 准备环境2. 编写 FastAPI 应用3. 使用 Uvicorn 运行应用4. 配置生产级服务器 Gunicorn4.1 配置 Gunicorn 和 …...

题解 洛谷 Luogu P1873 [COCI 2011/2012 #5] EKO / 砍树 二分答案 C/C++
题目传送门: P1873 [COCI 2011/2012 #5] EKO / 砍树 - 洛谷 | 计算机科学教育新生态https://www.luogu.com.cn/problem/P1873思路: 很简单的二分答案 每次找区间中点 m,判断以 m 为高度砍下的木头是否够 h 即可 代码: #defin…...
SpringCloud SaToken整合微服务 集成Redis 网关路由权限拦截 服务间内部调用鉴权
介绍 作为 API 网关,通常负责路由、负载均衡、安全控制等功能。进行 统一鉴权 的做法意味着将所有微服务的认证和授权逻辑集中到网关层,而不是每个微服务单独实现。这样做有许多好处,微服务只关心核心业务逻辑,不需要处理身份验证…...

Oracle ADB 导入 BANK_GRAPH 的学习数据
Oracle ADB 导入 BANK_GRAPH 的学习数据 1. 下载数据2. 导入数据运行 setconstraints.sql 1. 下载数据 访问 https://github.com/oracle-quickstart/oci-arch-graph/tree/main/terraform/scripts,下载, bank_accounts.csvbank_txns.csvsetconstraints.…...
优化 MFC CGridCtrl 的表格布局与功能
在使用 MFC 的 CGridCtrl 控件创建表格时,遇到的一个典型问题是,当表格滚动条出现时,最后一列会显示空白。这篇博客将记录解决这一问题的详细过程,同时总结了 CGridCtrl 初始化及优化的关键步骤,帮助开发者快速搭建一个…...
koa-body 的详细使用文档
目录 koa-body install Features Hello World - Quickstart Usage with koa-router Usage with unsupported text body type Options 关于 parsedMethods 的说明 文件支持 关于未解析请求主体的说明 一些强大的选择 使用总结 koa-body 功能齐全的 koa body 解析器中…...
信息系统与互联网中的安全、隐私及伦理问题
1 伦理(Ethics) 1.1 伦理框架(Ethical Frameworks) 自然法与权利(Natural Law and Rights) 定义:基于人类自然权利的伦理思想,强调生命、自由和财产等基本权利。应用:隐…...

Java安全—log4j日志FastJson序列化JNDI注入
前言 log4j和fastjson都是这几年比较火的组件,前者是用于日志输出后者则是用于数据转换,今天我们从源码来说一下这两个组件为何会造成漏洞。 实验环境 这里的idea要进行一下配置,因为我们要引用第三方组件,而这些第三方组件都是…...

【STM32开发笔记】移植AI框架TensorFlow到STM32单片机【DSP指令加速篇】
【STM32开发笔记】移植AI框架TensorFlow到STM32单片机【DSP指令加速篇】 一、前文回顾二、CMSIS-NN简介2.1 为什么介绍CMSIS-NN?2.2 CMSIS-NN是什么?2.3 CMSIS-NN核心特性2.4 CMSIS-NN算子支持 三、TFLMCMSIS-NN集成3.1 包含TFLM的STM32项目3.2 理解TFLM…...

Python中如何判断一串文本是不是数字
目录 1. 内置函数2. 尝试类型转换3. 正则表达式 在编程中,我们经常需要确定一段文本是否为数字。 这不仅关系到数据的准确性,还涉及到后续的计算和处理。 1. 内置函数 在Python中,可以使用str.isdigit()、str.isnumeric()和str.isdecimal()…...

基于YOLOv8深度学习的智慧农业山羊行为检测系统研究与实现(PyQt5界面+数据集+训练代码)
随着智慧农业的快速发展,利用先进的技术手段对牲畜的行为进行自动化监测和管理,已经成为现代农业中的重要研究方向之一。在传统的农业管理模式中,牲畜的行为监测通常依赖于人工观测,耗时耗力且难以实现大规模实时监控。然而&#…...

Redis环境部署(主从模式、哨兵模式、集群模式)
一、概述 REmote DIctionary Server(Redis) 是一个由 Salvatore Sanfilippo 写的 key-value 存储系统,是跨平台的非关系型数据库。Redis 是一个开源的使用 ANSI C 语言编写、遵守 BSD 协议、支持网络、可基于内存、分布式、可选持久性的键值对(Key-Value)存储数据库…...

高阶C语言之六:程序环境和预处理
本文介绍程序的环境,在Linux下对编译链接理解,较为简短,着重在于编译的步骤。 C的环境 在ANSI C(标准C语言)的任何一种实现中,存在两个不同的环境。 翻译环境:在这个环境中,源代码…...
Vue 3 国际化 (i18n) 最佳实践指南
1. 安装依赖 npm install vue-i18n@9 2. 项目结构建议 src/ ├── i18n/ │ ├── index.ts # i18n 配置文件 │ ├── languages/ # 语言文件目录 │ │ ├── zh-CN.ts # 中文 │ │ ├── en-US.ts # 英文 │ │ └─…...

Acme PHP - Let‘s Encrypt
Lets Encrypt是一个于2015年三季度推出的数字证书认证机构,旨在以自动化流程消除手动创建和安装证书的复杂流程,并推广使万维网服务器的加密连接无所不在,为安全网站提供免费的SSL/TLS证书。 使用PHP来更新证书: Acme PHP | Rob…...
获取DOM 节点的四大方式
前言: 在 Vue 中,获取 DOM 节点可以通过多种方式,如自定义属性、ref 引用、类选择器和 ID 选择器等。 一、使用 ref 获取 DOM 实例 ref 是 Vue 中推荐的获取 DOM 节点的方式,它为每个节点分配一个唯一的引用,可以直…...

ROS2 Humble 机器人建模和Gazebo仿真
一.Ubuntu22.04系统虚拟机安装 1.下载镜像并安装 Index of /ubuntu-releases/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror 2.安装选英文版,安装类型选清除磁盘。 3.遇到无法复制windows内容到虚拟机里。需安装VMware tools。VMware tools安装不了&a…...
docker容器镜像的制作、使用以及传递
目录 制作容器镜像使用Dockerfile制作镜像准备所需文件构建镜像怎么不使用基础镜像来构建容器镜像 使用容器镜像传递容器镜像 这篇文章讨论一下怎么使用docker制作容器镜像,容器镜像的使用,以及怎么传递容器镜像。 制作容器镜像 docker制作容器镜像推荐…...

IDEA运行Tomcat出现乱码问题解决汇总
最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…...
Python爬虫实战:研究MechanicalSoup库相关技术
一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...

Spark 之 入门讲解详细版(1)
1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室(Algorithms, Machines, and People Lab)开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目,8个月后成为Apache顶级项目,速度之快足见过人之处&…...
Oracle查询表空间大小
1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...

el-switch文字内置
el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...

c#开发AI模型对话
AI模型 前面已经介绍了一般AI模型本地部署,直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型,但是目前国内可能使用不多,至少实践例子很少看见。开发训练模型就不介绍了&am…...
实现弹窗随键盘上移居中
实现弹窗随键盘上移的核心思路 在Android中,可以通过监听键盘的显示和隐藏事件,动态调整弹窗的位置。关键点在于获取键盘高度,并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
【Go语言基础【12】】指针:声明、取地址、解引用
文章目录 零、概述:指针 vs. 引用(类比其他语言)一、指针基础概念二、指针声明与初始化三、指针操作符1. &:取地址(拿到内存地址)2. *:解引用(拿到值) 四、空指针&am…...

AI语音助手的Python实现
引言 语音助手(如小爱同学、Siri)通过语音识别、自然语言处理(NLP)和语音合成技术,为用户提供直观、高效的交互体验。随着人工智能的普及,Python开发者可以利用开源库和AI模型,快速构建自定义语音助手。本文由浅入深,详细介绍如何使用Python开发AI语音助手,涵盖基础功…...