流程的退出状态如何取决于它是否是静态构建的?

时间:2012-09-27 17:17:03

标签: c gcc static-linking dynamic-linking libc

现代系统:

% pacman -Q glibc gcc
glibc 2.16.0-4
gcc 4.7.1-6
% uname -sr
Linux 3.5.4-1-ARCH

一个简单的程序:

% < wtf.c   
void main(){}

让我们做静态和动态构建:

% gcc -o wtfs wtf.c -static                               
% gcc -o wtfd wtf.c

一切都很好看:

% file wtf?                                             
wtfd: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=0x4b421af13d6b3ccb6213b8580e4a7b072b6c7c3e, not stripped
wtfs: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=0x1f2a9beebc0025026b89a06525eec5623315c267, not stripped

有人可以向我解释一下吗?

% for n in $(seq 1 10); do ./wtfd; echo $?; done | xargs
0 0 0 0 0 0 0 0 0 0
% for n in $(seq 1 10); do ./wtfs; echo $?; done | xargs
128 240 48 128 128 32 64 224 160 48

当然,可以使用int main()-Wmain会发出警告(return type of ‘main’ is not ‘int’)。

我只想了解那里发生了什么。

2 个答案:

答案 0 :(得分:6)

这完全是重点。

没有“void main()”。总有一个结果值,如果你没有返回一个并且在你的程序中没有做任何事情,那么返回值就是在程序启动时恰好在适当的寄存器中发生的事情(或者具体地说,无论什么时候发生在那里) main从启动代码调用)。这当然可以取决于程序在main之前正在做什么,例如处理共享库。

编辑:想知道如何发生这种情况,试试这个:

int foo(void)
{
    return 55;
}

void main(void)
{
    foo();
}

当然没有保证,但是这个程序很可能会有55的退出代码,因为这是某个函数返回的最后一个值。试想一下,调用发生在main之前。

答案 1 :(得分:2)

进一步说明基督徒所说的话。即使您声明void main(),您的进程也将返回eax中之前的任何值(因为您使用的是linux x86 arch)。

void main() {
    asm("movl $55, %eax");
}

所以现在它总是返回55 b / c,上面的代码显式初始化eax

$ cc rval.c 
$ ./a.out 
$ echo $?
55

此示例仅适用于当前主要操作系统,因为我假设调用约定。没有理由操作系统不能有不同的调用约定,返回值可能在其他地方(RAM,寄存器,等等)。