2016-03-27 17 views
0

Ich habe vor kurzem in GCC Inline-Assembly und mit grundlegenden Assembly-Kenntnisse, ich verstand, wie syscalls ziemlich gut, bis ich versuchte, eine einfache sys_execve mit einem oder mehreren Argumenten zu machen. Der Systemaufruf execve funktioniert einwandfrei, wenn ich keine zusätzlichen Parameter übergebe, und führe die ausführbare Datei ohne Parameter aus, wenn ich versuche, eine zu übergeben.Execve Inline-Assembly

#include <stdio.h> 

char *argv[]={"/bin/echo","parameter test", NULL}; 

int main(){ 
    __asm__ volatile ("int $0x80" 
      : 
      :"a"(11), // syscall number (execve) 
      "b"(argv[0]), // filename 
      "c"(argv), // arguments 
      "d"(0)); // env 
    return 0; 
} 

Ich habe keine Ahnung, was schief gehen könnte, wie ich diese getestet haben mit

execve(argv[0], argv, NULL); 

und es funktionierte wie erwartet.

+2

Wenn ich auf die API für [sys_execve] (http://docs.cs.up.ac.za/programming/asm/derick_tut/syscalls.html) schaue, bin ich mir nicht sicher, ob die Parameter korrekt sind. Außerdem kompilieren Sie für x64? Wenn ja, sollten Sie Int 0x80 nicht verwenden. –

+0

Ich kompiliere für x64, und mit meinem aktuellen Fortschritt ist der Dateiname Teil korrekt, da jede ausführbare Datei, die ich ausführen möchte, funktioniert. Der Teil, an dem ich festhalte, gibt ihm irgendwelche Parameter. Ich benutze [diese] (http://syscalls.kernelgrok.com/), um zu bestimmen, was ich passieren musste. – LazyShpee

Antwort

4

Dies ist ein 32-Bit-Code, der 32-Bit-Konventionen verwendet. Kompilieren Sie mit gcc -m32 und es wird funktionieren. Alternativ wechseln Sie auf die richtigen 64-Bit-Version wie:

#include <stdio.h> 

char *argv[]={"/bin/echo","parameter test", NULL}; 

int main(){ 
    int ret; 
    __asm__ volatile ("syscall" 
      :"=a" (ret) 
      :"a"(59), // syscall number (execve) 
      "D"(argv[0]), // filename 
      "S"(argv), // arguments 
      "d"(0) // env 
      :"rcx","r11","cc"); 
    return 0; 
} 

Das eigentliche Problem ist, dass Sie 64-Bit-Zeiger in der Anordnung, aber die 32-Bit-Kompatibilität unterbrechen, dass Sie natürlich nutzen erwartet 32-Bit-Poiters.

+2

Das '= a' ist es wert, explizit darauf hinzuweisen: Der Systemaufruf gibt einen Wert im' eax' (oder 'rax') Register zurück, so dass der Compiler wissen muss, dass dies geschieht. Andernfalls wird angenommen, dass der Asm-Code 'eax' unverändert belässt, und wenn er später im Code den Wert 59 benötigt, könnte er versuchen, ihn von 'eax' zu laden. Das wird zu Problemen führen, weil 'eax' tatsächlich mit dem Rückgabewert des Systemaufrufs überschrieben wurde. Wahrscheinlich unwahrscheinlich, tatsächlich ein Problem in diesem Code zu verursachen, aber wichtig, im Allgemeinen zu beachten. –

+2

Übrigens, von dem was ich in der amd64 abi gelesen habe, kann ein Systemaufruf sowohl 'r11' als auch' rcx' klobbeln. –

+1

@NateEldredge: Das stimmt, das Design von 'syscall' /' sysret' garantiert, dass ein 'syscall' immer rcx und r11 (mit RIP und RFLAGS) überstürzt. Den Kernel sogar sehen zu lassen, was in diesen Regs enthalten war, würde eine Benutzerraum-Kooperation erfordern (z. B. sie auf den Stapel zu legen). Linux Syscalls schauen nicht auf den User-Space-Stack, so dass der ABI es einfach hält und Systemaufrufe diese beiden regs auf amd64 im Gegensatz zu 32bit 'int 0x80', wo nur' eax' modifiziert wird, zurückgibt. –