waitpid在使用单个参数调用而不包含sys / wait.h时的参数值

时间:2013-02-25 08:03:52

标签: c assembly

考虑以下C程序:

int main()
{
    waitpid(1337);
}

正如预期的那样,gcc和clang都警告我有关waitpid的隐式声明但是生成的二进制文件工作正常。当我ltrace时,我看到了

waitpid(1337, 0x7fff86950ec8, -2037051688)

被调用。现在有三个问题:

  1. 为什么上面的C代码甚至可以工作?我应该包含sys/wait.h以便能够调用waitpid。调用printf而不包括stdio.h时会发生同样的事情。输出有效。
  2. 所以gcc仍然会调用waitpid,但是为什么只用一个参数来调用它,即使它有三个?多次调用ltrace暗示其他两个参数是随机值? Gcc在单参数waitpid和三参数waitpid之间做了一些翻译,但是怎么做?
  3. 我如何使用gdb来计算最后两个参数背后的值?其他两个值没有显示在源代码中,所以如何在gcc中访问它们?
  4. 我收集了一些线索:我查看了main函数的汇编输出:

    0x000000000040050c <+0>:    push   %rbp
    0x000000000040050d <+1>:    mov    %rsp,%rbp
    0x0000000000400510 <+4>:    mov    $0x539,%edi
    0x0000000000400515 <+9>:    mov    $0x0,%eax
    0x000000000040051a <+14>:   callq  0x4003f0 <waitpid@plt>
    0x000000000040051f <+19>:   pop    %rbp
    0x0000000000400520 <+20>:   retq   
    

    所以我猜这不是gcc做的事情,因为确实有一个waitpid函数只需要一个参数(1337)?

2 个答案:

答案 0 :(得分:3)

  

为什么上面的C代码甚至可以工作?

它“偶然”起作用。 C允许您在不指定原型的情况下调用函数,即不包括其标题。当你这样做时,对参数的数量和类型做出假设并试图调用它。显然,使用错误数量的参数调用函数是未定义的行为。

  

6.5.2.2-3

     

如果表示被调用函数的表达式具有类型   不包括原型,执行整数促销   每个参数和类型为float的参数都被提升为   双。这些被称为默认参数促销。 如果   参数个数不等于参数个数,   行为未定义。

至于你的第三个问题,我怀疑你看到的垃圾只是堆栈上的残羹剩饭。要查明是否属实,请在waitpid之前设置一个断点,然后单步执行它,看看会传递什么。

答案 1 :(得分:0)

通过在c程序中包含头文件,您基本上可以提供该函数的原型。如果没有给出,那么它假设cnicutar告诉的参数数量和参数类型。如果未定义原型,它还假定函数的返回类型为int。