使用gcc编译32位结构的C程序出现意外退出代码

4

我写了一个简单的C程序,并为32位架构编译它。

但是当我运行它时,发现得到了意想不到的结果。

#include <stdio.h>

int foo(int n) {
    int sum=0;
    int i;
    if (n <= 1 || n >= 0x1000)
        return n;
    for (i=0; i<= n; i++) {
        sum = sum + i;
    }
    return foo(sum);
}

int main(int argc, char** argv) {
    int n;
    n = foo(200);
    printf("\n\n main about to return %d \n\n", n);
    return n;
}

➜  wbench  gcc -o test.elf test.c -m32 -fno-stack-protector -mpreferred-stack-boundary=2 -Wall
➜  wbench  ./test.elf 

 main about to return 20100


➜  wbench  echo $?
132

我期望的返回值是20100,就像主函数打印的那样。

但是,我得到了退出码为132

我使用GDB验证了,在主函数即将返回时,eax寄存器中的值为20100

➜  wbench  gdb -q test.elf
gdb-peda$ b *main+44
Breakpoint 1 at 0x8048492
gdb-peda$ r

 main about to return 20100 

Breakpoint 1, 0x08048492 in main ()

   0x8048489 <main+35>: call   0x80482f0 <printf@plt>
   0x804848e <main+40>: mov    eax,DWORD PTR [ebp-0x4]
   0x8048491 <main+43>: leave  
=> 0x8048492 <main+44>: ret    
   0x8048493:   xchg   ax,ax



gdb-peda$ p/d $eax
$1 = 20100
gdb-peda$ c
[Inferior 1 (process 32172) exited with code 0204]
Warning: not running or target is remote
gdb-peda$ p/d 0204
$2 = 132

我甚至验证了当控制权返回到__libc_start_main并调用exit函数时,20100被推送为exit()的参数。

gdb-peda$ r
 main returning 20100 
Breakpoint 1, 0x08048492 in main ()

gdb-peda$ finish
=> 0xf7e1ca83 <__libc_start_main+243>:  mov    DWORD PTR [esp],eax
   0xf7e1ca86 <__libc_start_main+246>:  call   0xf7e361e0 <exit>
   0xf7e1ca8b <__libc_start_main+251>:  xor    ecx,ecx
gdb-peda$ si
=> 0xf7e1ca86 <__libc_start_main+246>:  call   0xf7e361e0 <exit>
   0xf7e1ca8b <__libc_start_main+251>:  xor    ecx,ecx
gdb-peda$ x/wd $esp
0xffffd5c0: 20100

这是什么原因呢? 我认为这里的退出码132与SIGILL无关,因为当我将硬编码的参数从200更改为foo()时,退出码变为172,而期望的退出码是26796。请注意,保留HTML标记。

还要注意,标准C仅支持0(EXIT_SUCCESS的同义词)和EXIT_FAILURE作为main函数的返回值。 - jxh
3个回答

3

看起来您所做的是无效的,因为您只有8位比特可以返回给操作系统。

假设您正在链接libc

当程序退出时,它可以使用退出状态向父进程返回有关终止原因的少量信息。这是一个在0到255之间的值,退出进程将其作为参数传递给exit。

如其文档中所示(这里)。还有一行相关的内容:

警告:不要尝试将错误数量用作退出状态。这实际上并不是非常有用;父进程通常不会关心发生了多少个错误。更糟糕的是,它不起作用,因为状态值被截断为8位。因此,如果程序尝试报告256个错误,父进程将收到0个错误的报告,即成功。


1
只有8位用于退出代码的原因是从waitpid获取的status中的其他位用于其他信息:低8位是否为有效的退出状态,或者是否发生了其他情况。以及导致其退出的信号和一些其他标志。 - Peter Cordes

2

20100 十进制是 4E84 十六进制。
132 十进制是 84 十六进制。
你的 shell 只接收 8 位返回值。


1

虽然你的程序可能返回20100,但系统仅获取最低字节,例如return % 256

因此,20100 % 256 = 132


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接