gpt4 book ai didi

c - 链接器如何将 C 结构和偏移量存储在内存中?

转载 作者:太空宇宙 更新时间:2023-11-04 02:21:11 25 4
gpt4 key购买 nike

我对系统编程很感兴趣,想看看结构是如何在汇编中实现的,以及它们是如何链接的。我写了三个简短的 .c 代码,它们具有相同的命名结构但在不同的文件中并编译和链接在一起,但我无法理解输出。我相信该结构只是汇编中数据段中的一个连续内存块。但是,我无法通过使用指针或让每个函数使用其相应文件的偏移量来访问第一个 int 数据之后的值。有人可以解释输出吗?

我尝试更改数据类型,实现字符以避免填充或字节序问题。我尝试使用 char* 指针来打印整个结构,这令人惊讶地给了我奇怪的值(不是随机的,因为它们在每次执行中都是相同的)

#include <stdio.h>

struct S1
{
int i1;
int i2;
int i3;
int i4;
int i5;
int i6;
};

int main()
{
struct S1 s;
s.i1 = 5;
s.i2 = 10;
s.i3 = 15;
s.i4 = 16;

func1(s); //Implicit calls, no declarations needed
// because linker will know where to find defs
func2(s);
}

#include <stdio.h>

struct S1
{
int i1;
int i2;
float i3;
};


void func1(struct S1 s)
{
printf("In func1 : %d %d %f %lu\n", s.i1, s.i2, s.i3, sizeof(s));
};


#include <stdio.h>

struct S3
{
double i1;
int i2;
};

void func2(struct S3 s)
{
printf("In func2 : %lf %d %lu \n", s.i1, s.i2, sizeof(s));
};

我得到输出:

In func1 : 1 0 0.000000 12

In func2 : 0.000000 1 16

我希望打印出这些值

最佳答案

As GCC 9.2 compiles your file with main ,我们看到了调用 func1 的这些说明:

    mov     rdx, QWORD PTR [rbp-16]
mov rax, QWORD PTR [rbp-8]
mov rdi, rdx
mov rsi, rax
mov eax, 0
call func1

请注意,编译器已将数据加载到通用寄存器——rsirdi 等。将此与 the instructions in func1 进行比较:

    mov     rdx, rdi
movd eax, xmm0
mov QWORD PTR [rbp-16], rdx
mov DWORD PTR [rbp-8], eax
movss xmm0, DWORD PTR [rbp-8]

请特别注意 movss 指令。这是试图从 xmm0 寄存器中检索 float i3 成员。但是,正如我们所见,调用例程并未将任何内容放入 xmm0 寄存器。

编译器对如何在例程之间传递参数有一个规范。这称为应用程序二进制接口(interface)。 (ABI 由旨在在特定平台上兼容的软件共享,并且通常由处理器制造商推荐。)对于小型结构,至少在这种情况下,编译器不会通过在内存中指向它们或复制它们来传递它们确切的布局。相反,成员是单独传递的,就好像它们是单独的参数一样。

因此,您的代码没有研究结构在内存中的布局方式。它正在研究如何在函数调用中传递结构。部分答案是成员有时会单独传递,传递的位置部分取决于它们的类型。因为 main 只传递整数数据,所以它使用寄存器作为整数参数。因为 func1 需要一些 float 据,所以它会在寄存器中查找。结果是 func1 永远不会获取为 i3i4 传递的数据。

关于c - 链接器如何将 C 结构和偏移量存储在内存中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57993048/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com