2016-03-17 17 views
7

Stavo eseguendo il debug di un problema irrilevante nel kernel di Linux e ho visto che il processo etcd, gestito dal supervisore, stava ripetutamente colpendo l'eccezione di errore di pagina e ricevendo SIGSEGV.Qual è questo schema nel codice assembly generato dal compilatore go?

ho ottenuto curioso e usato objdump di smontare il programma, e ho trovato le istruzioni amd64 ha provocato l'errore di essere:

89 04 25 00 00 00 00 mov %eax,0x0 

Poi ho guardato lo smontaggio di un programma ciao mondo. Ho visto uno schema molto comune nel codice generato dal compilatore go, che si trova alla fine di una funzione, subito dopo lo ret, c'è un mov seguito da un jmp nella funzione. Ad esempio,

0000000000400c00 <main.main>: 
    400c00:  64 48 8b 0c 25 f0 ff mov %fs:0xfffffffffffffff0,%rcx 
    400c07:  ff ff 
     ... 
    400c4b:  48 83 7c 24 48 00  cmpq $0x0,0x48(%rsp) 
    400c51:  74 59     je  400cac <main.main+0xac> 
    400c53:  48 c7 04 24 c0 fc 47 movq $0x47fcc0,(%rsp) 
    400c5a:  00 

     ... 
    400cab:  c3      retq 
    400cac:  89 04 25 00 00 00 00 mov %eax,0x0 
    400cb3:  eb 9e     jmp 400c53 <main.main+0x53> 

È questo qualche trucco giocato da go? Se sì, come funziona? Sto indovinando a 0x400c51 salta a 0x400cac, innesca un SIGSEGV, che viene gestito e quindi l'istruzione successiva salta a 0x400c53.

+2

'mov% eax, 0x0' non sposta un registro su un immediato. Sposta un registro per l'indirizzo 0 (a meno che non sia stata eseguita una correzione a un certo punto che ha sostituito 0 con qualcos'altro). Se volessi tentare di spostare 'eax' nell'immediato 0 (che non sarebbe stato assemblato) avresti scritto' mov% eax, $ 0' (con un segno di dollaro). – Michael

+0

@ Michael, grazie per la correzione. Mi sono confuso. –

+0

nessun compilatore imposterà un registro a 0 da mov in modalità ottimizzata. Useranno ['xor reg, reg'] (http://stackoverflow.com/q/33666617/995714) –

risposta

1

ho avuto alcune risposte da parte degli sviluppatori Go: https://groups.google.com/forum/#!topic/golang-nuts/_7yio3ZfVBE

Fondamentalmente, questo modello è l'nullo il check-in l'implementazione obsolete. Citato è la risposta di Keith Randall.

Se il puntatore è nullo, passa a un'istruzione che genera un errore . Questo errore è usato per iniziare un panico nullo.

È una sequenza di codice piuttosto inefficiente. I jmps non sembrano mai essere usati da . Esegui l'upgrade a una versione Go più recente e vedrai che è stata migliorata .

+1

gcc spesso mette brevi blocchi di codice dopo il primo 'ret' in una funzione per il corpo di un'istruzione' if' in C. Quindi quando la condizione è vera, salta laggiù e fa qualcosa, quindi salta indietro. Questo rende il caso non vero più efficiente, perché non c'è nessuna filiale condizionata e nessun ramo incondizionato. Sembra che il compilatore Go abbia utilizzato la stessa struttura per il codice che si intende arrestare, non restituire. Questa è la mia ipotesi sul motivo per cui quel pattern esisteva in primo luogo: era naturale che gcc producesse un codice come quello per il panico 'if (null pointer) ' –