C / inline asm: problem mit Rückgabewert

Hi
Ich wollte mal ein wenig mit C spielen (benutze aber den g++, da es auch in C++ Programmen funktionieren soll),
Und zwar möchte ich eine Funktion aufrufen, aber ohne das das ebp/esp - gedöns ausgeführt wird. Also ohne das _cdecl - zeugs.

Meine Idee: Die Funktion ganz "normal" schreiben, und einfach ein paar bytes nach dem eigentlichen anfang der Funktion aufrufen.
Als beispiel möchte ich einfach 1000 zurückgeben.

Code:
int fnc()
{
 asm("nop");
 asm("movl $0x3eb, %eax");
 asm("ret");
 //return 1000;
}

int main()
{
 unsigned char *x;
 x  = (unsigned char*)fnc;
 x += 6;

 int (*pfnc)();
 pfnc = (int(*)()) x;

 int y = pfnc();

 return y;
}

wenn ich dieses Programm allerdings ausführe bekomme ich nicht 1000 :(
Code:
$ ./cfnc ; echo $?
235
$

wenn ich mir aber die ausgabe von objectdump ansehe, scheint alles i.o, zu sein:
08048484 <_Z3fncv>:
8048484: 55 push %ebp
8048485: 89 e5 mov %esp,%ebp
8048487: 83 ec 04 sub $0x4,%esp

804848a: 90 nop
804848b: b8 eb 03 00 00 mov $0x3eb,%eax
8048490: c3 ret

8048491: c9 leave
8048492: c3 ret

08048493 <main>:
8048493: 8d 4c 24 04 lea 0x4(%esp),%ecx
8048497: 83 e4 f0 and $0xfffffff0,%esp
804849a: ff 71 fc pushl -0x4(%ecx)
804849d: 55 push %ebp
804849e: 89 e5 mov %esp,%ebp
80484a0: 51 push %ecx
80484a1: 83 ec 14 sub $0x14,%esp
80484a4: c7 45 f0 84 84 04 08 movl $0x8048484,-0x10(%ebp)
80484ab: 83 45 f0 06 addl $0x6,-0x10(%ebp)
80484af: 8b 45 f0 mov -0x10(%ebp),%eax
80484b2: 89 45 f4 mov %eax,-0xc(%ebp)
80484b5: 8b 45 f4 mov -0xc(%ebp),%eax
80484b8: ff d0 call *%eax
80484ba: 89 45 f8 mov %eax,-0x8(%ebp)
80484bd: 8b 45 f8 mov -0x8(%ebp),%eax

80484c0: 83 c4 14 add $0x14,%esp
80484c3: 59 pop %ecx
80484c4: 5d pop %ebp
80484c5: 8d 61 fc lea -0x4(%ecx),%esp
80484c8: c3 ret


(rot: relevante stelle; "teal": wird nicht ausgeführt)

Wo liegt mein Fehler? ich ändere in der Funktion doch nichts, außer eax. ich verlasse die Funktion also genau so, wie es auch in C/C++ üblich ist...
 
Bei mir generiert g++ (4.3.0) sowas:
Code:
004012d0 <__Z3fncv>:
  4012d0:	55                   	push   %ebp
  4012d1:	89 e5                	mov    %esp,%ebp
  4012d3:	90                   	nop    
  4012d4:	b8 eb 03 00 00       	mov    $0x3eb,%eax
  4012d9:	c3                   	ret    
  4012da:	5d                   	pop    %ebp
  4012db:	c3                   	ret

sofern ich dann im Code statt +6 ein "x += 4;" schreibe, klappt es anstandslos.

Was sagt der Debugger ;)?
 
Sehr kurios:
Code:
#include <stdio.h>

int fnc()
{
        asm("nop");
        asm("movl $0x3eb, %eax");
        asm("ret");
}

int main()
{
        unsigned char *x;
        int y;
        int (*pfnc)();

        x=(unsigned char*)fnc;
        x+=4;
        pfnc=(int(*)())x;
        y=pfnc();
        printf("%d\n", y);

        return y;
}

Ausgabe:

Code:
$ ./cfnc ; echo $?
1003
235

Mit asm("movl $0x3e8, %eax"); (0x3eb=1003 , 1000=0x3e8 ;))

Code:
$ ./cfnc ; echo $?
1000
232

Laut GDB gibt main 1003, bzw. 1000 zurück, ändert das Konstrukt um main herum etwa den Rückgabewert?

?(, loose
 
Ohm man...
Wenn man 0x3e8 in ein Byte reinzwengt, hat man ja 0xe8, und ratet mal, was das für eine Dezimalzahl ist: 232 :D

Aber warum wird nur das untere Byte verarbeitet?
 
Habe das Problem gefunden =)

Code:
int main()
{
    return 1000;
}

Rate mal, welche Ausgabe das gibt... 232.
Wahrscheinlich kann der Rückgabewert nur 1 Byte groß sein.
Ist mir noch nie aufgefallen, habe bisher nie Programme geschrieben, die derartige Rückabewerte liefern.

mfg, loose
 
Zurück
Oben