返回元组时 GCC/Clang x86_64 C++ ABI 不匹配?

2024-03-15

当尝试时优化 x86_64 上的返回值 https://stackoverflow.com/q/25381736/3919155,我注意到一个奇怪的事情。即,给定代码:

#include <cstdint>
#include <tuple>
#include <utility>

using namespace std;

constexpr uint64_t a = 1u;
constexpr uint64_t b = 2u;

pair<uint64_t, uint64_t> f() { return {a, b}; }
tuple<uint64_t, uint64_t> g() { return tuple<uint64_t, uint64_t>{a, b}; }

Clang 3.8 输出 https://gcc.godbolt.org/#compilers:!((compiler:clang380,options:'-std%3Dc%2B%2B11+-O2',sourcez:MQSwdgxgNgrgJgUwAQB4IGcAudyYHwBQoksiqmMADlAocdPMijJiFCJgJ6EEzrgBzJGACGAWwTpKIiMixwA3AQIQA9mCwIAHpQBOSGLgBsAFgD6mJCKQBeJAEYYStRsza9B4%2BcsAjW0gAmJ2VpEF1mLwsAGk8wTFMLPCQAMwAKAEokAG8kXQQKXTBskRifAF8FJDKCCmoECLiEzBjDRu8kgQzs3PyYQqRamgb47xbI/CySpHLK6oIsEVYIMxF0dARdTFT%2BAC8EVTTQ8NaR6NjT/HSCJBvbu7ubO139tJOmzIBqJGeD1LfvdIxABEQPSSgWSxWaw2Wx%2BaUG9X%2BZyRl2u93RN0e3xAe1%2BR2GTTGbUSgKQILBQAAA%3D%3D)),filterAsm:(commentOnly:!t,directives:!t,labels:!t),version:3该汇编代码为f:

movl $1, %eax
movl $2, %edx
retq

这对于g:

movl $2, %eax
movl $1, %edx
retq

看起来最优。然而,当使用 GCC 6.1 编译 https://gcc.godbolt.org/#compilers:!((compiler:g6,options:'-std%3Dc%2B%2B11+-O2',sourcez:MQSwdgxgNgrgJgUwAQB4IGcAudyYHwBQoksiqmMADlAocdPMijJiFCJgJ6EEzrgBzJGACGAWwTpKIiMixwA3AQIQA9mCwIAHpQBOSGLgBsAFgD6mJCKQBeJAEYYStRsza9B4%2BcsAjW0gAmJ2VpEF1mLwsAGk8wTFMLPCQAMwAKAEokAG8kXQQKXTBskRifAF8FJDKCCmoECLiEzBjDRu8kgQzs3PyYQqRamgb47xbI/CySpHLK6oIsEVYIMxF0dARdTFT%2BAC8EVTTQ8NaR6NjT/HSCJBvbu7ubO139tJOmzIBqJGeD1LfvdIxABEQPSSgWSxWaw2Wx%2BaUG9X%2BZyRl2u93RN0e3xAe1%2BR2GTTGbUSgKQILBQAAA%3D%3D)),filterAsm:(commentOnly:!t,directives:!t,labels:!t),version:3,而生成的程序集为f与 Clang 输出相同,生成的程序集g is:

movq %rdi, %rax
movq $2, (%rdi)
movq $1, 8(%rdi)
ret

看起来返回值的类型被 GCC 分类为 MEMORY,但被 Clang 分类为 INTEGER。我可以确认将 Clang 代码与 GCC 代码链接,此类代码可能会导致分段错误(Clang 调用 GCC 编译的g()写入任何地方%rdi碰巧指向)并且返回无效值(GCC 调用 Clang 编译g())。哪个编译器有问题?

Related:

  • 构建共享库时,G++ 和 clang++ 与标准库不兼容? https://stackoverflow.com/q/35586332/3919155
  • [cxx-abi-dev] 不平凡的移动构造函数 http://sourcerytools.com/pipermail/cxx-abi-dev/2016-February/002884.html

See also

  • System V 应用程序二进制接口。 AMD64 架构处理器补充。草案版本0.99.5 http://www.x86-64.org/documentation/abi.pdf

ABI 规定参数值根据特定算法进行分类。这里相关的是:

  1. 如果聚合的大小超过一个八字节,则每个字节将被单独分类。每个八字节被初始化为 NO_CLASS 类。

  2. 对象的每个字段都被递归分类,以便始终考虑两个字段。根据八字节中字段的类别计算得到的类别:

在这种情况下,每个字段(对于元组或对)都是类型uint64_t因此占据了整个“八字节”。那么,每八字节中要考虑的“两个字段”是“NO_CLASS”(按照 3)和uint64_t字段,被分类为 INTEGER。

还有,与参数相关passing:

如果 C++ 对象具有非平凡的复制构造函数或非平凡的析构函数,则它通过不可见引用传递(该对象在参数列表中被具有类 INTEGER 的指针替换)

不满足这些要求的对象必须有一个地址,因此需要位于内存中,这就是上述要求存在的原因。返回值也是如此,尽管规范中似乎省略了这一点(可能是偶然的)。

最后还有:

(c) 如果聚合的大小超过两个八字节,并且第一个八字节不是 SSE 或任何其他八字节不是 SSEUP,则整个参数 是在内存中传递的。

显然,这并不适用于此。聚合的大小正好是两个八字节。

在返回值时,文本显示:

  1. 使用分类算法对返回类型进行分类

如上所述,这意味着元组应归类为 INTEGER。然后:

  1. 如果类别为 INTEGER,则序列的下一个可用寄存器 使用%rax、%rdx。

这是很清楚的。

唯一仍然悬而未决的问题是这些类型是否是非平凡复制构造/可破坏的。如上所述,这种类型的值不能在寄存器中传递或返回,即使规范似乎没有认识到返回值的问题。然而,我们可以使用以下程序轻松证明元组和对都是可平凡复制构造和平凡破坏的:

测试程序:

#include <utility>
#include <cstdint>
#include <tuple>
#include <iostream>

using namespace std;

int main(int argc, char **argv)
{
    cout << "pair is trivial? : " << is_trivial<pair<uint64_t, uint64_t> >::value << endl;
    cout << "pair is trivially_copy_constructible? : " << is_trivially_copy_constructible<pair<uint64_t, uint64_t> >::value << endl;
    cout << "pair is standard_layout? : " << is_standard_layout<pair<uint64_t, uint64_t> >::value << endl;
    cout << "pair is pod? : " << is_pod<pair<uint64_t, uint64_t> >::value << endl;
    cout << "pair is trivially_destructable? : " << is_trivially_destructible<pair<uint64_t, uint64_t> >::value << endl;
    cout << "pair is trivially_move_constructible? : " << is_trivially_move_constructible<pair<uint64_t, uint64_t> >::value << endl;

    cout << "tuple is trivial? : " << is_trivial<tuple<uint64_t, uint64_t> >::value << endl;
    cout << "tuple is trivially_copy_constructible? : " << is_trivially_copy_constructible<tuple<uint64_t, uint64_t> >::value << endl;
    cout << "tuple is standard_layout? : " << is_standard_layout<tuple<uint64_t, uint64_t> >::value << endl;
    cout << "tuple is pod? : " << is_pod<tuple<uint64_t, uint64_t> >::value << endl;
    cout << "tuple is trivially_destructable? : " << is_trivially_destructible<tuple<uint64_t, uint64_t> >::value << endl;
    cout << "tuple is trivially_move_constructible? : " << is_trivially_move_constructible<tuple<uint64_t, uint64_t> >::value << endl;
    return 0;
}

使用 GCC 或 Clang 编译时的输出:

pair is trivial? : 0
pair is trivially_copy_constructible? : 1
pair is standard_layout? : 1
pair is pod? : 0
pair is trivially_destructable? : 1
pair is trivially_move_constructible? : 1
tuple is trivial? : 0
tuple is trivially_copy_constructible? : 1
tuple is standard_layout? : 0
tuple is pod? : 0
tuple is trivially_destructable? : 1
tuple is trivially_move_constructible? : 0

这意味着海湾合作委员会的做法是错误的。返回值应以%rax,%rdx 形式传递。

(这些类型之间的主要显着差异是pair是标准布局,并且可以简单地移动构造,而tuple不是,所以 GCC 可能总是通过指针返回非平凡移动构造的值,例如)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

返回元组时 GCC/Clang x86_64 C++ ABI 不匹配? 的相关文章

  • c# 从另一个类中的另一个静态事件引发事件

    需要帮助从另一个班级调用事件 我有已声明事件的课程 public class MxPBaseGridView GridView public event AddNewItemsToPopUpMenuEventHandler AddNewIt
  • XPATH 查询、HtmlAgilityPack 和提取文本

    我一直在尝试从名为 tim new 的类中提取链接 我也得到了解决方案 给出了解决方案 片段和必要的信息here https stackoverflow com questions 2982862 extracting a table ro
  • 并行化斐波那契序列生成器

    我正在学习并行化 在一项练习中 我得到了一些我应该提高性能的算法 其中之一是斐波那契数列生成器 array 0 0 array 1 1 for q 2 q lt MAX q array q array q 1 array q 2 我怀疑 这
  • 司机和提供商之间的区别

    数据库中的驱动程序和提供程序有什么区别 有没有解释一下 不胜感激 样本 ADO NET driver for MySQL vs providerName System Data EntityClient 来自 MSDN 论坛 驱动程序是安装
  • C++ 将联合强制转换为其成员类型之一

    以下对我来说似乎完全符合逻辑 但不是有效的 C 联合不能隐式转换为其成员类型之一 有人知道为什么不这样做的充分理由吗 union u int i char c function f int i int main u v v i 6 f v
  • 带有运算符语法的错误消息,但不带有函数语法的错误消息

    为什么我在调用 unary 时收到错误消息 使用运算符语法 如果我用函数语法调用它就可以了 现场演示 https godbolt org z j7AbeQ template
  • while循环中的变量初始化

    我有一个可以分块读取文件的函数 public static DataObject ReadNextFile 数据对象看起来像这样 public DataObject public string Category get set And ot
  • 将日期时间转换为指定格式

    我有这个日期格式yy MM dd HH mm ss ex 12 02 21 10 56 09 问题是 当我尝试使用以下代码将其转换为不同格式时 CDate 12 02 21 10 56 09 ToString MMM dd yyyy HH
  • 静态类与类的实例

    我有一个静态类 用于访问我的公共属性 整个应用程序的全局属性 和我在应用程序运行期间使用的方法 例如 我在静态类中设置了一些属性 并且在应用程序运行时我可以从属性中获取值 但我可以使用单例模式创建非静态类并以相同的方式使用它 问题 对于我的
  • 在 C++11 中移出 stdpriority_queue 的元素

    最小的工作示例 include
  • 如何使用递归查找数字中的最小元素 [C]

    好的 所以我正在准备我的 C 考试 当谈到递归时我有点卡住了我是大学一年级的学生 这对我来说似乎有点困难 练习要求在给定的数字中使用递归函数我需要找到最小的元素 例如 52873 是 2 程序需要打印 2 include
  • Xamarin - SignalR 挂在连接上

    我正在尝试将我的 Xamarin 应用程序连接到托管在 Azure 上的 SignalR 后端 我遇到的问题是每次我在 HubConnection 上调用 StartAsync 时 它都会挂起客户端并且请求永远不会完成 我尝试通过应用程序进
  • 为什么不能调用带有 auto& 参数的 const mutable lambda?

    include
  • 将错误代码映射到 C++ 中的字符串

    将错误代码从枚举映射到字符串的更有效方法是什么 在 C 中 例如 现在我正在做这样的事情 std string ErrorCodeToString enum errorCode switch errorCode case ERROR ONE
  • 为什么 f(i = -1, i = -1) 是未定义的行为?

    我正在读关于违反评估顺序 http en cppreference com w cpp language eval order 他们举了一个令我困惑的例子 1 如果标量对象上的副作用相对于同一标量对象上的另一个副作用是无序的 则行为未定义
  • 使用 xslt 将 xml 转换为 xsl-fo 时动态创建超链接?

    我想使用 xsl 文件在 PDF 报告中创建标题 如果源文件包含超链接 则应将其呈现为超链接 否则呈现为纯文本 例如 我的 xml 如下所示 a href http google com target blank This is the h
  • C 中使用 getrandom 实现随机浮点数

    我试图生成一个介于 0 和 1 之间的随机浮点数 无论是在 0 1 还是 0 1 对我来说都不重要 网上关于此的每个问题似乎都涉及rand 呼叫 播种time NULL 但我希望能够每秒多次调用我的程序 并每次都获得不同的随机数 这引导我找
  • Linq.Select() 中的嵌套表达式方法调用

    I use Select i gt new T 每次手动点击数据库后将我的实体对象转换为 DTO 对象 以下是一些示例实体和 DTOS 用户实体 public partial class User public int Id get set
  • printf或iostream如何指定点后的最大位数

    字符串采用什么格式printf or iomanip我应该使用 iostream 中的运算符以以下格式打印浮点数 125 0 gt 125 125 1 gt 125 1 125 12312 gt 125 12 1 12345 gt 1 12
  • 这种尺寸对齐是如何工作的

    对于所提供的评论 我无法理解以下代码 这段代码的作用是什么 以及等效的代码是什么8 aligned segment size must be 4 aligned attr gt options ssize 3 Here ssize is o

随机推荐

  • Python3 + PyGobject + GTK3 和 cx_freeze 缺少 DLL

    当我使用 py python3 pygobject gtk3 应用程序制作 exe 时从 pygobject 站点来看 它缺少一些 DLL 文件 缺少什么文件 我已经手动尝试过需要哪些 DLL 因此 如果这对某人有帮助 the 必须进行编辑
  • 如何将嵌套 Java Collection 中的所有项目展平到单个列表中?

    给定一个复杂的嵌套对象集合 例如 Set
  • WPF 同一系列的多个字体文件

    我有以下字体文件 MyFont Regular tff MyFont Bold tff MyFont Italic tff 我该如何使用它们 我可以做以下事情
  • 显示精灵的另一个实例

    是否可以显示精灵的另一个实例 我想做的是反射动画精灵 到目前为止 我得到的是我的 Sprite 称为 canvas 它内部有使用 AS3 进行动画处理的内容 我想要做的是显示它翻转的副本 在它下面看起来像倒影 我尝试了以下代码 但没有运气
  • 类库(传统便携式)?

    我有一台装有 Microsoft Visual Studio Community 2017 的电脑 版本 15 2 它有一个类库 便携式 的项目模板 另一台版本为 15 3 1 的 PC 有一个类库模板 Legacy Portable PC
  • 请解释如何使用CheckBoxTableCell

    我想了解更多有关如何实际使用或子类化 如果需要 CheckBoxTableCell 的信息 在一种特定情况下 我想使用此类 其中复选框不绑定到基础数据模型属性 假设我有一个名为 选择 的列 其中包含复选框 该列或多或少充当该行的视觉标记 用
  • 亚马逊s3上传多个文件android

    如果有人仍在寻找解决方案 我最终会在代码上使用循环 但我没有找到官方 api 来执行多个文件上传 我有一个 ImageFiles 的 ArrayList 我想将其上传到 Amazon s3 他们的文档提供了以下代码 credentials
  • 通过距离和摩擦力计算速度

    我正在用 Javascript Canvas HTML5 编写一个游戏 我刚刚发现了一个与高等数学相关的大问题 该游戏是平面 2D 游戏 因此您可以从另一个角度看世界 这意味着没有重力 只有摩擦力 CODE var friction 0 9
  • 当没有导航栏时,如何在 EKEventeditViewController 中获得“完成”或“后退”按钮?

    我的 iOS 应用程序中有一个日历事件列表 单击时将在 EKEventViewController 中打开 这是我的代码 void tableView UITableView tableView didSelectRowAtIndexPat
  • 如何在表格行上使用slideDown(或show)函数?

    我正在尝试向表中添加一行并将该行滑入视图中 但是 Slidedown 函数似乎向表行添加了 display block 样式 这会弄乱布局 有什么想法可以解决这个问题吗 这是代码 get some url val1 id function
  • 在 Promise catch 中重新抛出错误

    我在教程中找到了以下代码 promise then function result some code catch function error throw error 我有点困惑 catch 调用有什么作用吗 在我看来 它没有任何效果 因
  • Windows 搜索 sql - 无法访问 System.Search.QueryFocusedSummary

    我正在尝试使用 sql 查询 Windows Search 4 0 该物业 我感兴趣的是 System Search QueryFocusedSummary 我正在尝试从 SystemIndex 读取此属性 我收到 列不存在 错误消息 我能
  • 安装nvm后无法卸载全局npm包

    我发现了与此问题相关的几个线程 但似乎没有一个专门处理我的案例 并且我无法使用我找到的建议来解决 当我跑步时npm uninstall g some package 它只是返回 up to date in 043s 全球一揽子计划仍然存在
  • cakephp 3.x 保存多个实体 - newEntities

    我在保存多条记录方面遇到了最困难的时期 我已经尝试了一百万次 但最终遇到了同样的问题 我的记录没有保存 而且我看不到任何错误 请记住 我是 cakephp 的新手 也是一名新手编码员 我是否遗漏了一些明显且关键的东西 Table this
  • Google 在 React 中使用 firebase 登录 chrome 扩展

    使用 Firebase 进行 Google 登录 并使用 React 创建的 Chrome 扩展程序 我已经使用设置了 oauthGoogleConsole并能够使用 chrome 扩展程序成功登录 chrome identity getA
  • Leaflet Draw spritesheet 图标问题 - 缺失且未对齐

    我已将传单绘制纳入我的一个项目中 我的问题是图标没有显示在工具栏中 它看起来像这样 环顾四周我发现THIS https github com Leaflet Leaflet draw issues 617发布并按照其说明进行操作 我在 Le
  • 在 apache (ubuntu 12) 下将 python 脚本作为 cgi 运行时出现问题

    披露 我搜索了很多 我认为我的问题 针对我的配置 在这里没有得到解答 例如作为 cgi apache 服务器运行 python 脚本 https stackoverflow com questions 15878010 run python
  • Unity android 项目抛出“抱歉,您的硬件不支持此应用程序”错误

    我已经调查了2天了 我读了很多东西 总结一下我读到的内容 非 NEON 设备无法与 UNITY 5 版本一起使用 您应该将安装位置设置为 自动或强制内部 您应该将写入权限设置为 仅限内部 除了上述设置之外 我还尝试了这些纹理压缩设置 不要覆
  • 如何更改 actionPerformed() 内的 Swing Timer Delay

    所以我正在构建这个音乐播放器应用程序 它可以播放拖放到 JLabel 上的音符 当我按下播放按钮时 我希望每个音符都突出显示 并带有与该音符对应的延迟值 我为此使用了 Swing Timer 但问题是 它只是以构造函数中指定的恒定延迟循环
  • 返回元组时 GCC/Clang x86_64 C++ ABI 不匹配?

    当尝试时优化 x86 64 上的返回值 https stackoverflow com q 25381736 3919155 我注意到一个奇怪的事情 即 给定代码 include