当前位置: 首页 > news >正文

2411rust,正与整128

原文

长期以来,Rustx86-32x86-64架构上128位整数的对齐C语言不一致.最近已解决此问题,但该修复带来了一些值得注意效果.

作为用户,除非如下,否则不用担心:
1,假设i128/u128对齐,而不是用align_of
2,忽略improper_ctypes*检查,并在FFI中使用这些类.

x86-32x86-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对齐(字节)
i811
正符u811
i1622
正短u1622
i6488
正长u6488

ABI仅指定了C类型,但Rust兼容和性能优势方面遵守相同定义.

错误的对齐问题

如果两个实现数据类型对齐上有分歧,则无法可靠地共享包含该类型的数据.Rust128位类型的对齐不一致:

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对齐(字节)
__int128i1281616
正__int128u1281616

表明,这并不是因为Rust积极地做错了什么:原语布局来自RustClang等语言使用的LLVMcodegen后端,且它有硬编码8字节i128对齐.

Clang使用正确的对齐只是因为变通,即在把类型交给LLVM前,手动按16字节设置对齐.这解决布局问题,但也是其他一些小问题的根源.

Rust无此手动调整,因此在https://github.com/rustlang/rust/issues/54341报告了它.

调用约定问题

还有一个问题:LLVM按函数参数传递128位整数时,并不总是正确.在发现它与Rust相关前,这是LLVM中的一个已知问题.

调用函数时,会在寄存器传递参数,直到没有更多的槽,然后会"溢出"到栈中(程序的内存).

ABI3.2.3传递参数一节中,也告诉了该怎么做:

__int128类型的参数INTEGER操作相同,但它们不适合一个通用寄存器,而是需要两个寄存器.为了分类,按如下实现对待__int128:

typedef struct {long low, high;
} __int128;

但在内存中保存__int128类型的参数必须在16字节边界对齐.

可手动实现调用约定来试此操作.在下面C示例中,用内联汇编val0x11223344556677889900aabbccddeeff值,来调用foo(0xaf,val,val,val).

x86-64使用RDI,RSI,RDX,RCX,R8R9寄存器,来按顺序传递函数参数.每个寄存器适合一个字(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没有合理的解决方法,因此这在ClangRust都是一个问题.

方法

NikitaPopov修复了D158169的调用约定问题.这两项更改都已纳入LLVM18,即所有相关的ABI问题都使用在此版本ClangRust中得到解决.

因为这些更改,Rust现在生成正确的对齐:

println!("alignment of i128: {}", align_of::<i128>());
//`rustc1.77.0`版本

i128对齐:16

如上,ABI指定数据类型对齐部分原因是因为它在该架构效率更高.更改手动对齐初始性能运行,表明大大改进了编译器性能(严重依赖128位整数来处理整数文字).

增加对齐的缺点是在内存中复合类型并不总是很好地组合在一起,从而导致使用量增加.可惜,即需要牺牲一些性能优势,以避免增加内存成本.

兼容

总之,使用LLVM18(默认版本从1.78开始)的Rusti128u128将与版本的GCCClang18更高版本(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 文件&#xff0c;将设计编写为 Css 文件&#xff0c;将逻辑编写为 JavaScript 文件。 须知 &#xff1a; JSX 是一个…...

将 FastAPI 部署到生产服务器(一套 全)

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

题解 洛谷 Luogu P1873 [COCI 2011/2012 #5] EKO / 砍树 二分答案 C/C++

题目传送门&#xff1a; P1873 [COCI 2011/2012 #5] EKO / 砍树 - 洛谷 | 计算机科学教育新生态https://www.luogu.com.cn/problem/P1873思路&#xff1a; 很简单的二分答案 每次找区间中点 m&#xff0c;判断以 m 为高度砍下的木头是否够 h 即可 代码&#xff1a; #defin…...

SpringCloud SaToken整合微服务 集成Redis 网关路由权限拦截 服务间内部调用鉴权

介绍 作为 API 网关&#xff0c;通常负责路由、负载均衡、安全控制等功能。进行 统一鉴权 的做法意味着将所有微服务的认证和授权逻辑集中到网关层&#xff0c;而不是每个微服务单独实现。这样做有许多好处&#xff0c;微服务只关心核心业务逻辑&#xff0c;不需要处理身份验证…...

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&#xff0c;下载&#xff0c; bank_accounts.csvbank_txns.csvsetconstraints.…...

优化 MFC CGridCtrl 的表格布局与功能

在使用 MFC 的 CGridCtrl 控件创建表格时&#xff0c;遇到的一个典型问题是&#xff0c;当表格滚动条出现时&#xff0c;最后一列会显示空白。这篇博客将记录解决这一问题的详细过程&#xff0c;同时总结了 CGridCtrl 初始化及优化的关键步骤&#xff0c;帮助开发者快速搭建一个…...

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 伦理&#xff08;Ethics&#xff09; 1.1 伦理框架&#xff08;Ethical Frameworks&#xff09; 自然法与权利&#xff08;Natural Law and Rights&#xff09; 定义&#xff1a;基于人类自然权利的伦理思想&#xff0c;强调生命、自由和财产等基本权利。应用&#xff1a;隐…...

Java安全—log4j日志FastJson序列化JNDI注入

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

【STM32开发笔记】移植AI框架TensorFlow到STM32单片机【DSP指令加速篇】

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

Python中如何判断一串文本是不是数字

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

基于YOLOv8深度学习的智慧农业山羊行为检测系统研究与实现(PyQt5界面+数据集+训练代码)

随着智慧农业的快速发展&#xff0c;利用先进的技术手段对牲畜的行为进行自动化监测和管理&#xff0c;已经成为现代农业中的重要研究方向之一。在传统的农业管理模式中&#xff0c;牲畜的行为监测通常依赖于人工观测&#xff0c;耗时耗力且难以实现大规模实时监控。然而&#…...

Redis环境部署(主从模式、哨兵模式、集群模式)

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

高阶C语言之六:程序环境和预处理

本文介绍程序的环境&#xff0c;在Linux下对编译链接理解&#xff0c;较为简短&#xff0c;着重在于编译的步骤。 C的环境 在ANSI C&#xff08;标准C语言&#xff09;的任何一种实现中&#xff0c;存在两个不同的环境。 翻译环境&#xff1a;在这个环境中&#xff0c;源代码…...

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年三季度推出的数字证书认证机构&#xff0c;旨在以自动化流程消除手动创建和安装证书的复杂流程&#xff0c;并推广使万维网服务器的加密连接无所不在&#xff0c;为安全网站提供免费的SSL/TLS证书。 使用PHP来更新证书&#xff1a; Acme PHP | Rob…...

获取DOM 节点的四大方式

前言&#xff1a; 在 Vue 中&#xff0c;获取 DOM 节点可以通过多种方式&#xff0c;如自定义属性、ref 引用、类选择器和 ID 选择器等。 一、使用 ref 获取 DOM 实例 ref 是 Vue 中推荐的获取 DOM 节点的方式&#xff0c;它为每个节点分配一个唯一的引用&#xff0c;可以直…...

ROS2 Humble 机器人建模和Gazebo仿真

一.Ubuntu22.04系统虚拟机安装 1.下载镜像并安装 Index of /ubuntu-releases/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror 2.安装选英文版&#xff0c;安装类型选清除磁盘。 3.遇到无法复制windows内容到虚拟机里。需安装VMware tools。VMware tools安装不了&a…...

docker容器镜像的制作、使用以及传递

目录 制作容器镜像使用Dockerfile制作镜像准备所需文件构建镜像怎么不使用基础镜像来构建容器镜像 使用容器镜像传递容器镜像 这篇文章讨论一下怎么使用docker制作容器镜像&#xff0c;容器镜像的使用&#xff0c;以及怎么传递容器镜像。 制作容器镜像 docker制作容器镜像推荐…...

【kafka】Golang实现分布式Masscan任务调度系统

要求&#xff1a; 输出两个程序&#xff0c;一个命令行程序&#xff08;命令行参数用flag&#xff09;和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽&#xff0c;然后将消息推送到kafka里面。 服务端程序&#xff1a; 从kafka消费者接收…...

中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试

作者&#xff1a;Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位&#xff1a;中南大学地球科学与信息物理学院论文标题&#xff1a;BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接&#xff1a;https://arxiv.…...

Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)

目录 1.TCP的连接管理机制&#xff08;1&#xff09;三次握手①握手过程②对握手过程的理解 &#xff08;2&#xff09;四次挥手&#xff08;3&#xff09;握手和挥手的触发&#xff08;4&#xff09;状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...

为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?

在建筑行业&#xff0c;项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升&#xff0c;传统的管理模式已经难以满足现代工程的需求。过去&#xff0c;许多企业依赖手工记录、口头沟通和分散的信息管理&#xff0c;导致效率低下、成本失控、风险频发。例如&#…...

【Go】3、Go语言进阶与依赖管理

前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课&#xff0c;做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程&#xff0c;它的核心机制是 Goroutine 协程、Channel 通道&#xff0c;并基于CSP&#xff08;Communicating Sequential Processes&#xff0…...

HBuilderX安装(uni-app和小程序开发)

下载HBuilderX 访问官方网站&#xff1a;https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本&#xff1a; Windows版&#xff08;推荐下载标准版&#xff09; Windows系统安装步骤 运行安装程序&#xff1a; 双击下载的.exe安装文件 如果出现安全提示&…...

selenium学习实战【Python爬虫】

selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...

Go 语言并发编程基础:无缓冲与有缓冲通道

在上一章节中&#xff0c;我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道&#xff0c;它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好&#xff0…...

比较数据迁移后MySQL数据库和OceanBase数据仓库中的表

设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...

提升移动端网页调试效率:WebDebugX 与常见工具组合实践

在日常移动端开发中&#xff0c;网页调试始终是一个高频但又极具挑战的环节。尤其在面对 iOS 与 Android 的混合技术栈、各种设备差异化行为时&#xff0c;开发者迫切需要一套高效、可靠且跨平台的调试方案。过去&#xff0c;我们或多或少使用过 Chrome DevTools、Remote Debug…...