据我所知,调用约定取决于平台是Windows还是Linux。
我想知道,
哪一个是真的?如果只有 2 为真,则调用约定是由平台定义的,编译器是否只遵循定义的约定?
我有一个简单的汇编程序,它试图通过在内存中存储临时变量来返回3:
.text
.global _start
_start:
movl $2, %ebx
mov %ebx, -0x4(%ebp)
movl $1, %ebx
add -0x4(%ebp), %ebx
movl $1, %eax
int $0x80
Run Code Online (Sandbox Code Playgroud)
但是,当我运行它时,这会给我一个分段错误:
$ as out.s -o out.o
$ ld -s -o out out.o
$ ./out
segmentation fault
Run Code Online (Sandbox Code Playgroud)
我想这是因为我从不初始化%ebp.如果我只使用寄存器而不访问相关的主内存,我的程序运行正常%ebp.
应该初始化到什么价值?程序malloc在启动时应该是自己的堆栈吗?
我目前正在通过反汇编C程序并试图了解它们的作用来进行汇编阅读.
我被困在一个简单的问题:一个简单的你好世界计划.
#include <stdio.h>
#include <stdlib.h>
int main() {
printf("Hello, world!");
return(0);
}
Run Code Online (Sandbox Code Playgroud)
当我拆卸主要时:
(gdb) disassemble main
Dump of assembler code for function main:
0x0000000000400526 <+0>: push rbp
0x0000000000400527 <+1>: mov rbp,rsp
0x000000000040052a <+4>: mov edi,0x4005c4
0x000000000040052f <+9>: mov eax,0x0
0x0000000000400534 <+14>: call 0x400400 <printf@plt>
0x0000000000400539 <+19>: mov eax,0x0
0x000000000040053e <+24>: pop rbp
0x000000000040053f <+25>: ret
Run Code Online (Sandbox Code Playgroud)
我理解前两行:基本指针保存在堆栈上(通过push rbp,这会导致堆栈指针的值减少8,因为它已经"增长")并且堆栈指针的值被保存在基指针中(这样,参数和局部变量可以分别通过正偏移和负偏移轻松到达,而堆栈可以保持"增长").
第三行提出了第一个问题:为什么0x4005c4("Hello,World!"字符串的地址)在edi寄存器中移动而不是在堆栈中移动?printf函数不应该将该字符串的地址作为参数吗?据我所知,函数从堆栈中获取参数(但在这里,看起来参数放在该寄存器中:edi)
在StackOverflow上的另一篇文章中,我读到"printf @ ptl"就像一个调用真正的printf函数的存根函数.我试图反汇编这个功能,但它变得更加混乱:
(gdb) disassemble printf
Dump of assembler code for function __printf:
0x00007ffff7a637b0 <+0>: sub rsp,0xd8
0x00007ffff7a637b7 <+7>: test al,al …Run Code Online (Sandbox Code Playgroud) 关于数据类型对齐的怀疑,我现在正在学习对齐,还有一些问题,所以我知道在用gcc编译i386体系结构时,linux中double对齐为4个字节,因此double的地址与a对齐4的倍数,但只有在使用数据结构时,才会在使用堆栈时发生
#include <stdio.h>
int main(void) {
double x = 5; // 8
char s = 'a'; // +1
double y = 2; // ---- = 9 + 8 = 17 + alignment = 20
//int x = 5; // 4
//char s = 'a'; +1
//int y = 2; --------= 5 + 4 = 9 + alignment = 12
size_t a, b;
a = (size_t)&s;
b = (size_t)&y;
printf("%zu", a - b); // it wasn't supposed to be 11 instead …Run Code Online (Sandbox Code Playgroud) 这是来自 linux 源代码 arch/arm64/kernel/head.S 显示内核启动。代码首先调用preserve_boot_args和下一个调用el2_setup使用bl(分支和链接)。我也展示了程序preserve_boot_args。
SYM_CODE_START(primary_entry)
bl preserve_boot_args
bl el2_setup // Drop to EL1, w0=cpu_boot_mode
adrp x23, __PHYS_OFFSET
and x23, x23, MIN_KIMG_ALIGN - 1 // KASLR offset, defaults to 0
bl set_cpu_boot_mode_flag
bl __create_page_tables
/*
* The following calls CPU setup code, see arch/arm64/mm/proc.S for
* details.
* On return, the CPU will be ready for the MMU to be turned on and
* the TCR will have been set.
*/
bl …Run Code Online (Sandbox Code Playgroud) 我正在将代码移植到现代编译器,不幸的是,当从 Rust 调用 FFI 函数到 C++ 时遇到了一个微妙的分段错误。
堆栈跟踪显示,在过渡到 C++ 之后,Rust 提供的第一个参数神奇地消失了,这会误导 C++ 使用错误的参数。
代码有点私密,所以我不能在这里发布,但程序集显示了一些有趣的东西:
在 GCC-7(代码运行没有问题)中,汇编的前几行如下所示:
0x0000000000001119 <+0>: push rbp
0x000000000000111a <+1>: mov rbp,rsp
0x000000000000111d <+4>: push r13
0x000000000000111f <+6>: push r12
0x0000000000001121 <+8>: push rbx
0x0000000000001122 <+9>: sub rsp,0x128
0x0000000000001129 <+16>: mov QWORD PTR [rbp-0x118],rdi
0x0000000000001130 <+23>: mov rax,rsi
0x0000000000001133 <+26>: mov rsi,rdx
0x0000000000001136 <+29>: mov rdx,rsi
0x0000000000001139 <+32>: mov QWORD PTR [rbp-0x130],rax
0x0000000000001140 <+39>: mov QWORD PTR [rbp-0x128],rdx
0x0000000000001147 <+46>: mov QWORD PTR [rbp-0x120],rcx
0x000000000000114e <+53>: mov QWORD …Run Code Online (Sandbox Code Playgroud) 好吧,问题标题是一种钩子.我已经知道没有C++标准ABI.也就是说,我并没有欺骗你渴望过度的收集者.我想知道C++ ABI是否有任何限制.例如,似乎常见的是至少在ABI名称中某个类的名称被修改.
一个更明确的问题
假设我对所有字符串都有一个无冲突的哈希函数.然后我们说GCC在其名称中添加了一个步骤:将当前受损名称的哈希值附加到下划线.这会破坏几乎所有在阳光下的东西,但GCC仍然会像以前那样符合C++标准吗?
编辑:
好吧,显然"明确的问题"位是一个选择不当的小节名称.我真的想了解更多关于人们遵循的常见ABI标准的信息.这是通过我使用Mingw32编译的二进制文件的存在得知的,这些二进制文件与我用MSVC编译的二进制文件成功连接.