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月发布)完全兼容.

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

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

相关文章

使用win32com将ppt(x)文件转换为pdf文件

本文来记录下如何使用win32com将ppt(x)文件转换为pdf文件 文章目录 win32com概述win32com优缺点代码实例本文小结 win32com概述 Pywin32 是一个用于与 Microsoft Windows 操作系统交互的 Python 扩展模块&#xff0c;它提供了对多个 Windows API 的访问&#xff0c;包括对 Mic…

java itext后端生成pdf导出

public CustomApiResult<String> exportPdf(HttpServletRequest request, HttpServletResponse response) throws IOException {// 防止日志记录获取session异常request.getSession();// 设置编码格式response.setContentType("application/pdf;charsetUTF-8")…

HarmonyOs实战项目=>App首页架构沉浸式效果

1.沉浸式效果方案采用> 窗口全屏布局方案不隐藏状态栏和导航条(不隐藏避让区) 2.沉浸式效果截图 3.主要代码截图 4.大功告成&#xff0c;代码见资源

华为HCCDA云技术认证--网络服务

大家好呀&#xff01;我是reload。今天继续带大家学习华为HCCDA云技术认证&#xff0c;涵盖华为云最为核心的计算、存储、网络、数据库、安全、部署等服务。今天学习网络服务相关内容。 登录华为云官网&#xff1a;https://www.huaweicloud.com/ &#xff0c;进入首页&#xff…

如何提升自己的情商?

在当今社会&#xff0c;情商的重要性越来越被人们所认识和重视。无论是职场发展、人际关系&#xff0c;还是自我成长&#xff0c;情商都起着关键的作用。那么&#xff0c;如何提升自己的情商呢&#xff1f; 一、自我认知&#xff1a;了解自己&#xff0c;方能明智处世 自我认…

SSM post接口传递json 报错 HTTP状态 415 - 不支持的媒体类型

这篇文章是写给哪些在小破站学习ssm教程的兄弟们&#xff0c;我们都是萌新&#xff0c;大佬就让行吧感谢理解&#xff01; 本文章主要讲解B站赵伟风SSM教程第108节(JSON数据的接收) 我所有的配置都跟老师一样&#xff0c;老师就很顺利发出去了&#xff0c;我的就是一直415&am…

《Python编程实训快速上手》第七天--文件与文件路径

该章节将使用Python在硬盘上创建、读取和保存文件 一、文件与文件路径 1、Windows中使用\以及macOS和Linux中使用/ 使用pathlib模块中的Path()函数进行文件名和目录的拼接,返回文件路径字符串 from pathlib import Path print(Path("spam","bacon",&qu…

StarRocks 架构

StarRocks 是什么&#xff1f;&#xff08; What is StarRocks?&#xff09; StarRocks 是 MPP 的查询引擎&#xff0c;用来做实时查询&#xff0c;提供亚秒级的查询性能。 兼容 MYSQL 协议&#xff0c;可以和大部分 BI 工具进行无缝衔接。 Apache 2.0 开源产品。 使用场景&…

A038-基于SpringBoot的乡村养老服务管理系统登录

&#x1f64a;作者简介&#xff1a;在校研究生&#xff0c;拥有计算机专业的研究生开发团队&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取&#xff0c;记得注明来意哦~&#x1f339; 赠送计算机毕业设计600…

WPF应用程序的生命周期-笔记

应用程序的生命周期 窗体的生命周期: window是一个控件 window中的事件:从window创建到关闭我们称之为窗体的生命周期 每一个窗体的生命周期都是独立的,窗体与窗体之间的生命周期都是独立的 最早加载的事件 控件的事件触发 基本所有的控件都继承与Framework 在WPF中基本所有的…

H.265流媒体播放器EasyPlayer.js视频流媒体播放器关于直播流播放完毕是否能监听到

EasyPlayer属于一款高效、精炼、稳定且免费的流媒体播放器&#xff0c;可支持多种流媒体协议播放&#xff0c;无须安装任何插件&#xff0c;起播快、延迟低、兼容性强&#xff0c;使用非常便捷。 EasyPlayer.js播放器不仅支持H.264与H.265视频编码格式&#xff0c;也能支持WebS…

智能停车解决方案之停车场室内导航系统(二):核心技术与系统架构构建

hello~这里是维小帮&#xff0c;如有项目需求和技术交流欢迎大家私聊我们&#xff01;点击文章最下方获取智慧停车场方案~撒花&#xff01; 随着城市化进程的加速&#xff0c;停车难问题日益凸显。智能停车系统作为缓解停车压力的有效手段&#xff0c;其核心技术与架构的构建至…

美赛优秀论文阅读--2023C题

文章目录 1.题目说明2.我对于这个题目信息的理解3.优秀论文学习3.1摘要3.2相关的算法模型 4.总结 1.题目说明 今天阅读的这个文章来自于这个2023年的这个美赛的这个C题的论文&#xff1b; 我们的这个题目可以到网上去找&#xff0c;这个还是比较容易找到的&#xff0c;大致就…

无人机飞手入门指南

无人机飞手入门指南旨在为初学者提供一份全面的学习路径和实践建议&#xff0c;帮助新手快速掌握无人机飞行技能并了解相关法规知识。以下是一份详细的入门指南&#xff1a; 一、了解无人机基础知识 1. 无人机构造&#xff1a;了解无人机的组成部分&#xff0c;如机身、螺旋桨…

【JavaEE初阶 — 多线程】定时器的应用及模拟实现

目录 1. 标准库中的定时器 1.1 Timer 的定义 1.2 Timer 的原理 1.3 Timer 的使用 1.4 Timer 的弊端 1.5 ScheduledExecutorService 2. 模拟实现定时器 2.1 实现定时器的步骤 2.1.1 定义类描述任务 定义类描述任务 第一种定义方法 …

AIGC----生成对抗网络(GAN)如何推动AIGC的发展

AIGC: 生成对抗网络(GAN)如何推动AIGC的发展 前言 随着人工智能领域的迅猛发展&#xff0c;AI生成内容&#xff08;AIGC&#xff0c;AI Generated Content&#xff09;正成为创意产业和技术领域的重要组成部分。在AIGC的核心技术中&#xff0c;生成对抗网络&#xff08;GAN&am…

基于css的Grid布局和vue实现点击左移右移轮播过渡动画效果

直接上代码&#xff0c;以下代码基于vue2,需要Vue3或者react可以使用国内直连GPT/Claude来帮你转换下 代码如下&#xff1a; // ScrollCardsGrid.vue <template><div class"scroll-cards-container"><!-- 左箭头 --><div v-show"showLef…

Springboot如何打包部署服务器

文章目的&#xff1a;java项目打包成jar包或war包&#xff0c; 放在服务器上去运行 一、编写打包配置 1. pom.xml 在项目中的pom.xml文件里面修改<build>...</build>的代码 >> 简单打包成Jar形式&#xff0c;参考示例&#xff1a; <build><fina…

RabbitMQ-死信队列(golang)

1、概念 死信&#xff08;Dead Letter&#xff09;&#xff0c;字面上可以理解为未被消费者成功消费的信息&#xff0c;正常来说&#xff0c;生产者将消息放入到队列中&#xff0c;消费者从队列获取消息&#xff0c;并进行处理&#xff0c;但是由于某种原因&#xff0c;队列中的…

ALSA - (高级Linux声音架构)是什么?

ALSA是Linux声音系统的核心组件&#xff0c;让用户可以精细控制声音硬件和声音进出。它通过抽象层屏蔽了硬件复杂性&#xff0c;使开发者能够专注于功能实现。这篇文章将逐步解析ALSA的基础知识&#xff0c;包括其运作原理、应用场景&#xff0c;以及如何完成一个基本配置和使用…