1: void f(mystruct *a)
2: void f(const mystruct *a)
Run Code Online (Sandbox Code Playgroud)
更改1-> 2的函数签名是否会破坏C中的API/ABI?
如何改变2-> 1?
那就是你怎么知道的
特定系统调用所需的参数数量,
注册每个参数应该在,
最后每个参数意味着什么?
是否有man相似的命令告诉你?
我正在尝试C++使用 LLVM/Clang 3.7.0 构建一个简单的(“hello world”)程序,该程序是根据工具链的源代码构建的libc++,使用命令行:
clang++ -std=c++14 -stdlib=libc++ -fno-exceptions hello.cpp\nRun Code Online (Sandbox Code Playgroud)\n\n但是,我收到以下错误:
\n\n/usr/bin/ld: warning: libc++abi.so.1, needed by /bulk/workbench/llvm/3.7.0\n/toolchain4/bin/../lib/libc++.so, not found (try using -rpath or -rpath-link)\n/bulk/workbench/llvm/3.7.0/toolchain4/bin/../lib/libc++.so: undefined reference to `__cxa_rethrow_primary_exception\'\n/bulk/workbench/llvm/3.7.0/toolchain4/bin/../lib/libc++.so: undefined reference to `__cxa_decrement_exception_refcount\'\n/bulk/workbench/llvm/3.7.0/toolchain4/bin/../lib/libc++.so: undefined reference to `std::out_of_range::~out_of_range()\'\n[...]\nRun Code Online (Sandbox Code Playgroud)\n\n未LD_LIBRARY_PATH设置,工具链的安装目录已添加到我的工作中PATH中:
export PATH=$PATH:/bulk/workbench/llvm/3.7.0/toolchain4/bin/\nRun Code Online (Sandbox Code Playgroud)\n\n我上线了Ubuntu GNU/Linux 14.04,并且尚未从任何存储库安装任何 LLVM 或 Clang 相关的软件包。
根据libc++ 文档:
\n\n\n在 Linux 上,libc++ 通常只能与 \xe2\x80\x98-stdlib=libc++\xe2\x80\x99 一起使用。然而,某些 libc++ 安装需要用户自己手动链接 libc++abi。如果在使用 …
struct Test {
uint ui;
string s;
}
function test(Test t) public {
emit Log(t.ui, t.s);
}
Run Code Online (Sandbox Code Playgroud)
我对ABI有一些了解。我使用实验性 ABIEncoderV2 选项签订了这份合同。总之,这个函数的签名是0x6056f4cc,我在操作码中找到了这个值。我用 sha3 尝试了一些 case test(uint256,string), test(tuple(uint256,string)), test(tuple), test(tuple[uint256,string])) ...但没有人做出正确的签名。Solidity 如何使用元组进行函数签名?
在某些情况下,我们使用标签来区分函数。标签通常是一个空结构:
struct Tag { };
Run Code Online (Sandbox Code Playgroud)
假设我有一个使用此标签的函数:
void func(Tag, int a);
Run Code Online (Sandbox Code Playgroud)
现在,我们调用这个函数:
func(Tag(), 42);
Run Code Online (Sandbox Code Playgroud)
并检查生成的 x86-64 反汇编,godbolt:
mov edi, 42
jmp func(Tag, int) # TAILCALL
Run Code Online (Sandbox Code Playgroud)
没关系,标签得到了完全优化:没有为其分配寄存器/堆栈空间。
但是,如果我查看其他平台,就会发现该标签存在一些。
在 ARM 上,r0用作标签,并且它被归零(似乎没有必要):
mov r1, #42
mov r0, #0
b func(Tag, int)
Run Code Online (Sandbox Code Playgroud)
对于 MSVC,ecx被用作标记,并且它是从堆栈中“初始化”的(同样,似乎没有必要):
movzx ecx, BYTE PTR $T1[rsp]
mov edx, 42 ; 0000002aH
jmp void func(Tag,int) ; func
Run Code Online (Sandbox Code Playgroud)
我的问题是:是否有一种标签技术在所有这些平台上都得到了同样的优化?
注意:我没有找到 SysV ABI 指定可以在参数传递时优化空类的地方...(甚至,Itanium C++ ABI说:“空类的传递与普通类没有什么不同”。)
无论如何,就 x86 汇编代码而言。我一直在阅读有关函数调用的内容,但仍然无法完全掌握对基/帧指针 (EBP) 和堆栈指针 (ESP) 的需求。
当我们调用一个函数时,EBP的当前值会被放入栈中,然后EBP获取当前的ESP值。
函数的返回值、函数参数和局部变量的占位符然后将被放置在堆栈中,并且堆栈指针 ESP 值将减少(或增加)指向放置在堆栈上的最后一个占位符之后。
现在我们让 EBP 指向当前堆栈帧的开头,而 ESP 指向堆栈帧的结尾。
由于与 EBP 的恒定偏移量,EBP 将用于访问函数的参数和局部变量。那没关系。我不明白的是,为什么 ESP 不能通过使用其偏移量来访问这些变量。EBP指向栈帧的开头,ESP指向栈帧的结尾。有什么不同?
一旦所有局部变量等有了占位符,ESP 就不应该改变,还是应该改变?
注意:这个问题是关于 x86_64 架构和 Linux ABI。
当程序启动时,会为堆栈分配一些空间。稍后,在程序执行期间,堆栈区域可以调整大小(当需要更多空间时)达到操作系统指定的某个最大值。
让我们以简单的程序为例:
int main() {
char bytes[7 * 1024 * 1024];
}
Run Code Online (Sandbox Code Playgroud)
让我们在 gdb 下运行它并设置断点:main 之前和声明数组之后。
gdb> b *main
gdb> b main
gdb> r
gdb> info proc mapping // breakpoint before pushing stack
Start Addr End Addr Size Offset objfile
0x7ffffffde000 0x7ffffffff000 0x21000 0x0 [stack]
gdb> c
gdb> info proc mapping // breakpoint after pushing stack
Start Addr End Addr Size Offset objfile
0x7fffff8fe000 0x7ffffffff000 0x701000 0x0 [stack]
Run Code Online (Sandbox Code Playgroud)
所以我们可以看到堆栈实际上被调整了大小。
问题是操作系统如何知道何时必须调整堆栈大小?. 一些互联网资源说操作系统处理page fault …
Jason Turner在他的演讲中提议打破 C++ ABI 以保持该语言的发展。他还提到,如果出于兼容性原因需要,可以通过将 C++ 库包装到 C 库中来隔离 C++ ABI 更改。
27:30相关截图:
这里“BinaryLibrary”和“Old C++ stdlib”使用旧的 ABI,“NewExecutable”使用假设的更新 ABI。
据我了解,这是有效的,因为“BinaryLibrary”的旧 C++ ABI 被烘焙成具有更稳定接口的单独二进制文件。
但是什么让 C 成为一个好的替代方案呢?难道它的ABI也不能改变吗?
我将 GUI 代码中的问题缩小到SetWindowTextW(HWND, wchar_t *)如果新窗口标题未与两个字节对齐则默默失败。在本例中,SetWindowText()返回1( success ) 但不设置新文本。
MSVC 上的自然对齐wchar_t是 2 个字节,所以这绝对是我的错误。但为了确保我尝试找到 Win32 字符串的对齐规则。
我没有找到官方文档,只是一个旧的新闻组帖子提到了 Open Watcom 编译器\xc2\xa0\xe2\x80\x93的错误报告,该报告声称Windows NT 上的 Win32 和 COM 实际上需要4 字节对齐!虽然这对我来说似乎很奇怪,但我注意到 MSVC 确实将每个wchar_t文字对齐到四个字节,而不是两个。实际上,您可以wchar_t通过 使 MSVC 更密集地打包常量字符串alignas(2)。Win32 中的堆粒度也 >=8 字节。
如果 Win32 需要对宽字符字符串进行四字节对齐(如源声明),并且 API 调用在错误的数据对齐上默默失败(如SetWindowText()1 字节对齐),我感觉遇到了很大的麻烦。
有没有官方文档说明 Win32/COM 中宽字符串的明确对齐要求?是两个字节还是四个字节?
\n重现问题的代码:
\n#include <Windows.h>\n#include <CommCtrl.h>\n#include <cassert>\n\nint main() {\n\n auto …Run Code Online (Sandbox Code Playgroud)