首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >x86_64调用函数时调用约定不正确

x86_64调用函数时调用约定不正确
EN

Stack Overflow用户
提问于 2021-11-12 21:27:33
回答 1查看 46关注 0票数 0

我对LLVM比较陌生,我正在尝试生成调用C函数(growDictionary)的LLVM。这是在x86_64 Linux上,使用llvm 12:

代码语言:javascript
复制
$ llc-12 --version
Ubuntu LLVM version 12.0.1

  Optimized build.
  Default target: x86_64-pc-linux-gnu
  Host CPU: broadwell

函数(在C++中定义为extern "C",用clang 12编译):

代码语言:javascript
复制
struct StringDictionary {
    uint32_t* base;
    uint32_t elementSize;
    uint32_t rowCount;
    uint32_t wordsCapacity;
};

extern "C" {
StringDictionary growStringDictionary(StringDictionary dict,
                                      uint32_t neededWordsCapacity);
}

该函数通过值获取StringDictionary对象,但是,根据x86_64 ABI (https://github.com/hjl-tools/x86-psABI/wiki/x86-64-psABI-1.0.pdf,3.2.3节,“参数传递”),应该将其传递到堆栈上。(该对象的大小大于2个8字节,并且这8个字节都不在SSE或SSEUP类中,因此根据“合并后清理”部分,它将转换为类内存。)粗略地看一下反汇编,就会确认确实是这样的:

代码语言:javascript
复制
Dump of assembler code for function growStringDictionary(rockset::jit::StringDictionary, uint32_t):
   0x00007ffff7f98f70 <+0>: push   %rbp
   0x00007ffff7f98f71 <+1>: mov    %rsp,%rbp
   0x00007ffff7f98f74 <+4>: push   %rbx
   0x00007ffff7f98f75 <+5>: and    $0xffffffffffffffe0,%rsp
   0x00007ffff7f98f79 <+9>: sub    $0x1c0,%rsp
   0x00007ffff7f98f80 <+16>:    mov    %rsp,%rbx
   0x00007ffff7f98f83 <+19>:    mov    %esi,0x15c(%rbx)
   0x00007ffff7f98f89 <+25>:    mov    %rdi,0x160(%rbx)
[...]

%rdi是将写入返回值的地址,%esi是uint32_t neededWordsCapacity参数,不使用其他参数传递寄存器。

到目前为止一切都还好,但是我现在正在尝试从我生成的IR中调用这个函数,并且它试图传递寄存器中的所有参数。以下是代码的相关部分:

代码语言:javascript
复制
  %83 = call { i32*, i32, i32, i32 } @growStringDictionary({ i32*, i32, i32, i32 } %70, i32 %73)
[...]
declare { i32*, i32, i32, i32 } @growStringDictionary({ i32*, i32, i32, i32 }, i32)

请注意,调用约定是默认的(不会更改为fastcc之类的内容)。

生成的代码(我尝试使用的JIT和llc都会产生相同的结果) os试图在寄存器中传递参数,下面是来自llc -O0的输出;-O3类似于:

代码语言:javascript
复制
        movl    148(%rsp), %r9d                 # 4-byte Reload
        movl    140(%rsp), %r8d                 # 4-byte Reload
        movl    136(%rsp), %ecx                 # 4-byte Reload
        movl    132(%rsp), %edx                 # 4-byte Reload
        movq    120(%rsp), %rsi                 # 8-byte Reload
        leaq    376(%rsp), %rdi
        callq   growStringDictionary@PLT

不出所料,我的代码出现了分段错误。

我很惊讶llc生成的代码与ABI不匹配。有没有什么属性我需要放在函数声明上,或者放在类型定义上,或者我还遗漏了什么?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-11-12 22:01:58

事实证明,调用约定的这一部分是由前端处理的(我假设还有类似“这是一个非常重要的C++对象”之类的东西)。

以这个示例文件为例:

代码语言:javascript
复制
#include <stdint.h>

struct A {
  uint32_t* p;
  uint32_t a;
  uint32_t b;
};

struct B {
  uint32_t* p;
  uint32_t a;
  uint32_t b;
  uint32_t c;
};

uint32_t addA(struct A x) {
  return x.a + x.b;
}

uint32_t addB(struct B x) {
  return x.a + x.b + x.c;
}

clang -S -emit-llvm说:

代码语言:javascript
复制
%struct.A = type { i32*, i32, i32 }
%struct.B = type { i32*, i32, i32, i32 }

; Function Attrs: noinline nounwind optnone uwtable
define dso_local i32 @addA(i32* %0, i64 %1) #0 {
  %3 = alloca %struct.A, align 8
  %4 = bitcast %struct.A* %3 to { i32*, i64 }*
  %5 = getelementptr inbounds { i32*, i64 }, { i32*, i64 }* %4, i32 0, i32 0
  store i32* %0, i32** %5, align 8
  %6 = getelementptr inbounds { i32*, i64 }, { i32*, i64 }* %4, i32 0, i32 1
  store i64 %1, i64* %6, align 8
  %7 = getelementptr inbounds %struct.A, %struct.A* %3, i32 0, i32 1
  %8 = load i32, i32* %7, align 8
  %9 = getelementptr inbounds %struct.A, %struct.A* %3, i32 0, i32 2
  %10 = load i32, i32* %9, align 4
  %11 = add i32 %8, %10
  ret i32 %11
}

; Function Attrs: noinline nounwind optnone uwtable
define dso_local i32 @addB(%struct.B* byval(%struct.B) align 8 %0) #0 {
  %2 = getelementptr inbounds %struct.B, %struct.B* %0, i32 0, i32 1
  %3 = load i32, i32* %2, align 8
  %4 = getelementptr inbounds %struct.B, %struct.B* %0, i32 0, i32 2
  %5 = load i32, i32* %4, align 4
  %6 = add i32 %3, %5
  %7 = getelementptr inbounds %struct.B, %struct.B* %0, i32 0, i32 3
  %8 = load i32, i32* %7, align 8
  %9 = add i32 %6, %8
  ret i32 %9
}

请注意,addB的参数已变为%struct.B* byval(%struct.B),表明这是在堆栈上传递的。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69949247

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档