2011-11-08 14 views
5

Desidero utilizzare un naked function nel mio programma C++ utilizzando g ++. Sfortunatamente g ++, a differenza di VC++, non supporta le funzioni nude e l'unico modo per gestirlo è scrivere il proprio codice assembly in un file separato e collegarlo con i file C++. Ho provato a trovare qualche buon tutorial per x86 per mixare file assembly e C/C++ ma non ne ho trovato uno valido.Miscelazione di file C e Assembly

Gentilmente fammi sapere se ne sai qualcosa. Si noti che non sto chiedendo informazioni sull'assemblaggio inline ma sul collegamento di file C e assembly e sui modi per dichiarare variabili esterne di C in assembly e viceversa oltre a utilizzarli in C o assembly e anche come collegare i file C e asm usando Makefile .

+0

Provare e rendere questo più specifico - è piuttosto ampio e vago così com'è - altrimenti sarà probabilmente chiuso come "non è una vera domanda". Ricorda anche il precedente consiglio nelle tue precedenti domande sull'uso di 'gcc -S ...' per produrre modelli asm ecc. –

+0

gcc nella stessa vena ha '__attribute __ ((nudo))' ma non per x86 :( –

risposta

16

In C++ File:

extern "C" void foo(); // Stop name mangling games 

int main() { 
    foo(); 
} 

a "nudo" di file asm, per x86:

# modified from http://asm.sourceforge.net/howto/hello.html 

.text     # section declaration 
    .global foo 

foo: 

# write our string to stdout 

    movl $len,%edx # third argument: message length 
    movl $msg,%ecx # second argument: pointer to message to write 
    movl $1,%ebx  # first argument: file handle (stdout) 
    movl $4,%eax  # system call number (sys_write) 
    int $0x80  # call kernel 

# and exit 

    movl $0,%ebx  # first argument: exit code 
    movl $1,%eax  # system call number (sys_exit) 
    int $0x80  # call kernel 

.data     # section declaration 

msg: 
    .ascii "Hello, world!\n" # our dear string 
    len = . - msg   # length of our dear string 

Compile, montaggio e collegamento (con g ++ piuttosto che ld, perché è molto più facile per farlo in questo modo per C++) ed eseguire:

[email protected]:/tmp > g++ -Wall -Wextra test.cc -c -o test.o 
[email protected]:/tmp > as -o asm.o asm.S 
[email protected]:/tmp > g++ test.o asm.o 
[email protected]:/tmp > ./a.out 
Hello, world! 

Chiaramente se si desidera passare argomenti alla funzione o restituire qualcosa y È necessario rispettare le convenzioni di chiamata.

1

Voglio solo aggiungere una cosa al post precedente. Immaginate di voler una funzione, che accetta argomenti: (qualcosa come

int add(int,int);

prototipo)

segment .text 
global add 

    add: 
    enter 0,0 
    mov eax,[ebp+8] ; first argument 
    mov ebx,[ebp+12] ; second argument 
    add eax,ebx 
    leave 
    ret 
+1

sì, eccetto non usare le lenta istruzione 'enter'. http://agner.org/optimize/.Non c'è alcun motivo per costruire qui uno stack frame. Solo 'mov eax, [esp + 4]'/'aggiungi eax, [esp + 8]'/'ret'. Inoltre, non clobber 'ebx'; è un registro conservato in tutte le consuete convenzioni di chiamata. Downvoting per un esempio pericoloso (e inefficiente) e che non hai mostrato come costruire + collegarlo con NASM. –

5

Ecco un esempio di un trucco per ottenere l'effetto "funzione di nudo".

#include <stdio.h> 

extern "C" int naked_func(); 

static void 
dummy() 
{ 
    __asm__ __volatile__ 
    (
    " .global naked_func\n" 
    "naked_func:\n" 
    " movq $3141569, %rax\n" 
    " ret\n" 
    ); 
} 

int 
main() 
{ 
    printf ("%d\n", naked_func()); 
    return 0; 
} 
+2

Non è nemmeno necessaria la funzione dummy come wrapper, poiché l'assembly inline di base può essere posizionato nell'ambito globale. –

0

questo è il mio modo per definire una funzione in assembly, questo non ha bisogno di avere un assemblatore-file separato e non è necessario fuggire ogni nuova riga. Puoi semplicemente copiare il contenuto dei file di assembly nella stringa letterale. Nota:raw multiline string literal è una funzionalità C++ 11 (anche codificata C++). Questo è utile se vuoi compilare tutto in un unico file .c -/.cpp.

extern"C" int rand_byte(void); 
asm (R"(
    .globl rand_byte 
rand_byte: 
    call rand 
    and eax, 255 
    ret 
)"); 

È possibile utilizzare solo una dichiarazione di assieme di base senza parametri aggiuntivi nell'ambito globale. Quando si utilizza GCC o Clang e un processore di braccio, è possibile utilizzare [[gnu::naked]]/__attribute__((naked)).

[[gnu::naked]] 
int rand_byte(void) { 
    asm volatile (R"(
     push {lr} 
     bl rand 
     and r0, #255 
     pop {pc} 
    )"); 
}; 

Il primo modo consente sempre di definire le funzioni nude. Questo aiuta anche a rendere più portatile il codice.

extern"C" int _cdecl rand_byte(void); 
    #if defined __x86__ 
     // NOTE: the names are decorated with a '_' on windows 32-bit 
     // You can use extern"C" int _cdecl rand_byte() asm("rand_byte"); 
     // to make the asm symbol name always be rand_byte, without an _ 
     asm volatile (R"(
      .globl _rand_byte 
     _rand_byte: 
      call rand 
      and eax, 255 
      ret 
     )"); 
    #elif defined __x86_64__ 
     asm volatile (R"(
      .globl rand_byte 
     rand_byte: 
      call rand 
      and rax, 255 # eax works here, too. x86-32 and -64 could share the same source. 
      ret 
     )"); 
    #elif defined __arm__ 
     asm (R"(
      .global rand_byte 
     rand_byte: 
      push {lr} 
      bl rand 
      and r0, #255 
      pop {pc} 
     )"); 
    #else 
     #error There is no code for your platform yet... 
    #endif 
+0

È possibile utilizzare un'istruzione ASM di base nell'ambito globale in GCC/G ++. Non è possibile utilizzare l'assembly inline esteso nell'ambito globale. Una dichiarazione di assemblaggio di base è sempre implicitamente volatile per la documentazione. –

+0

L'esempio x86 rispetto a x86-64 è un po 'sciocco. 'e eax, 255' fa quello che vuoi su entrambi x86-32 e x86-64, ed è un byte più corto di' e rax, 255'. Inoltre, 'movzx eax, al' è leggermente migliore su entrambi, perché è più breve. Sei sicuro che anche questo si assembla? La direttiva gas è '.globl' o' .global', non 'global'. L'uso di 'gcc -masm = intel' utilizza ancora direttive GAS, non NASM. (Compilerà bene, ma non assemblerà. Su Godbolt, usa la modalità "binaria" per assicurarti che assembri e compili.) Inoltre, ARM non ha 'eax', ha' r0'. –

+0

Ovviamente, asm per 'rand_byte' è comunque stupido. È molto meglio rendere 'uint8_t rand_byte' un alias debole per' rand' quando la convenzione di chiamata consente che i valori di restrizione ristretti abbiano un elevato garbage (come su x86 ma non ARM), e lascia che il chiamante incorpori l'estensione zero se ne ha bisogno . È quasi impossibile trovare esempi per in linea asm, dove non sarebbe meglio semplicemente https://gcc.gnu.org/wiki/DontUseInlineAsm, tuttavia, ma potresti almeno menzionarlo. (Tranne forse le istruzioni privilegiate che non hanno wrapper intrinseco/incorporato). –