Sys V ABI规范(i386和AMD64)中描述的标准“函数调用序列”是否适用于静态C函数?

时间:2018-12-28 11:42:57

标签: c compiler-construction operating-system abi

  

在计算机软件中,应用程序二进制接口(ABI)是两个二进制程序模块之间的接口;通常,这些模块之一是库或操作系统工具,另一个是用户正在运行的程序。

     

ABI定义了如何以机器代码访问数据结构或计算例程,这是一种低级的,与硬件相关的格式;相反,API在源代码中定义了这种访问,这是一种相对高级,相对独立于硬件的,通常是人类可读的格式。 ABI的一个常见方面是调用约定,它确定如何将数据作为计算例程的输入提供或从计算例程的输出读取。例如x86调用约定。

     

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

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

这里是一个例子:

sendEmail(){

      var headers = new Headers();
    headers.append("Accept", 'application/json');
    headers.append('Content-Type', 'application/json' );
    const requestOptions = new RequestOptions({ headers: headers });

    let postData = {
        fristName: this.fristName,
        lastName: this.lastName,
        email:this.Email,
        phoneNumber:this.phoneNumber,
    }

    this.http.post("http://www.android.transatour.ma/contact_script.php",postData, requestOptions)
      .subscribe(data => {
        console.log(data['_body']);
       }, error => {
        console.log(error);
      });

      //console.log(this.fristName+" "+this.lastName+" "+this.Email+" "+this.phoneNumber);  
  }

当abi_main.c调用api_1和api_2是外部函数时,在Sys V ABI中定义了函数调用序列(包括寄存器使用情况,堆栈帧,参数传递,变量参数...)的详细信息。调用abi.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标准还是属于编译器来决定?

1 个答案:

答案 0 :(得分:0)

是的,它们确实适用。静态函数只是具有翻译单元可见性的普通函数。 ABI是一个编译器生成任务,C标准故意不做任何说明。从代码中删除static单词时,这一点变得很清楚。推理是一样的。使用此方法的 drawback 是,编译器无法在编译时检查链接权(调用方-被调用方),而只能检查其类型(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处有带有正确参数的函数,它也可以工作。如您所见,该函数无法inline d,因为编译器不知道哪个函数定义将在该内存位置结束,