c - Sys V ABI 规范(i386 和 AMD64)中描述的标准 "Function Calling Sequence"是否适用于静态 C 函数?

标签 c compiler-construction operating-system abi

In computer software, an application binary interface (ABI) is an interface between two binary program modules; often, one of these modules is a library or operating system facility, and the other is a program that is being run by a user.

An ABI defines how data structures or computational routines are accessed in machine code, which is a low-level, hardware-dependent format; in contrast, an API defines this access in source code, which is a relatively high-level, relatively hardware-independent, often human-readable format. A common aspect of an ABI is the calling convention, which determines how data is provided as input to or read as output from computational routines; examples are the x86 calling conventions.

-- https://en.wikipedia.org/wiki/Application_binary_interface

我确信 Sys V ABI 规范(i386 和 AMD64)中描述的标准“函数调用序列”限制了 C 库中那些外部函数的调用,但它是否也限制了那些静态函数的调用?

这是一个例子:

$cat abi.c

#include<stdio.h>
typedef void (*ret_function_t)(int,int);
ret_function_t gl_fp = NULL;
static void prnt(int i, int j){
    printf("hi from static prnt:%d:%d\n", i, j);
}
void api_1(int i){
    gl_fp = prnt;
    printf("hi from extern api_1:%d\n", i);
}
ret_function_t api_2(void){
    return gl_fp;
}

$cat abi_main.c

#include<stdio.h>
typedef void (*ret_function_t)(int,int);
extern void api_1(int i);
extern ret_function_t api_2(void);

int main(){
    api_1(1111);
    api_2()(2222, 3333);
}

$gcc abi_main.c abi.c -o abi_test

$./abi_test
hi from extern api_1:1111
hi from static prnt:2222:3333

当 abi_main.c 调用 api_1 和 api_2 时,函数调用序列(包括寄存器使用、堆栈框架、参数传递、变量参数...)详细信息在 Sys V ABI 中定义,因为它们是外部的,但是调用在abi.c 中定义的静态函数prnt?是属于ABI标准还是由编译器来决定?

最佳答案

是的,它们确实适用。静态函数只是具有翻译单元可见性的普通函数。 ABI 是编译器生成任务,C 标准故意对此只字未提。从您的代码中删除 static 词时,它会变得清晰。道理是一样的。这种方法的缺点是编译器无法检查链接正确性(调用者-被调用者),而只能检查其类型(void (*ret_function_t)(int,int);)在编译时,因为您是在运行时链接的人。所以,不推荐。

发生的情况是您的编译器将为任何调用函数生成代码,遵循一些 ABI,我们称之为 ABI-a。它将生成代码 根据其他一些 ABI 调用的函数,比方说 ABI-b。如果 ABI-a == ABI-b,那总是有效的,如果您使用相同的 ABI 编译两个文件,就会出现这种情况。

例如,如果 prnt 函数位于地址 0x12345678,则此方法有效:

ret_function_t gl_fp = (ret_function_t)0x12345678;

只要在 0x12345678 处有一个带有正确参数的函数,它也可以工作。如您所见,该函数不能内联d,因为编译器不知道哪个函数定义将在该内存点结束,可能有很多。

关于c - Sys V ABI 规范(i386 和 AMD64)中描述的标准 "Function Calling Sequence"是否适用于静态 C 函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53958062/

相关文章:

c - 如何配置 git 以忽略文件?

c - 如何通过linux内核中的c指针覆盖x86 `movq`指令的操作数值

c - 使用递归函数反转字符串

c# - C# 编译器如何检测 COM 类型?

c - 我可以从 pic 18f4550 的 PORTBbits.RB7 看哪个值

c++ - 即使 CPU 数量增加,执行时间也会增加,为什么?

operating-system - 页表如何处理堆栈和堆内存地址?

c - 关于系统例程: OPEN of the unix file system

css - 优化 css 编译器

embedded - 基于轮询或中断的方法