Неочакван изходен код за C програма, компилирана за 32-битова архитектура с помощта на gcc

Написах проста 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, че 20100 е стойността в регистъра eax, когато main е на път да се върне.

➜  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, защото когато промених твърдо кодирания аргумент на foo() от 200 на 2, кодът за изход се промени на 172, където очакваният код за изход е 26796.


person Akshay Krishnan R    schedule 04.08.2015    source източник
comment
Също така имайте предвид, че стандартният C поддържа само 0 (синоним на EXIT_SUCCESS) и EXIT_FAILURE като връщани стойности от main.   -  person jxh    schedule 04.08.2015


Отговори (3)


Изглежда, че това, което правите, е невалидно, тъй като имате само 8 бита за връщане към операционната система.

Ако приемем, че се свързвате срещу libc:

Когато програмата излезе, тя може да върне на родителския процес малко количество информация за причината за прекратяване, използвайки състоянието на изход. Това е стойност между 0 и 255, която излизащият процес предава като аргумент за излизане.

Както е посочено в неговата документация тук. Уместен е и този ред:

Предупреждение: Не се опитвайте да използвате броя на грешките като състояние на изход. Това всъщност не е много полезно; родителският процес обикновено не би се интересувал колко грешки са възникнали. По-лошото е, че не работи, защото стойността на състоянието е съкратена до осем бита. По този начин, ако програмата се опита да докладва 256 грешки, родителят ще получи доклад за 0 грешки - тоест успех.

person dsolimano    schedule 04.08.2015
comment
Причината да има само 8 бита за кода за изход е, че другите битове в status, които получавате от waitpid, се използват за друга информация: дали ниските 8 бита са валиден статус на изход, или ако се случва нещо друго. И какъв сигнал го е накарал да излезе, и някои други флагове. - person Peter Cordes; 04.08.2015

20100 десетичният знак е 4E84 шестнадесетичен.
132 десетичният знак е 84 шестнадесетичен.
Вашата обвивка получава върнатата стойност само като 8 бита.

person mah    schedule 04.08.2015

Докато вашата програма може да връща 20100, системата извлича само най-малкия байт, напр. return % 256

So 20100 % 256 = 132

person Glenn Teitelbaum    schedule 04.08.2015