Go compilation
Compile one of the simplest go execution programs
package mainimport "fmt"func main(){ fmt.Println("helloworld")}
Go build-gcflags "-n-l" Test.go
Using Go tool objdump disassembly
Go Tool objdump Test >test.asm
GDB test
Goasm1.png
We see the Assembly's entry address in 0x452100, open test.asm
TEXT _rt0_amd64_linux(SB) /usr/local/go/src/runtime/rt0_linux_amd64.s rt0_linux_amd64.s:8 0x452100 488d742408 LEAQ 0x8(SP), SI rt0_linux_amd64.s:9 0x452105 488b3c24 MOVQ 0(SP), DI rt0_linux_amd64.s:10 0x452109 488d0510000000 LEAQ 0x10(IP), AX rt0_linux_amd64.s:11 0x452110 ffe0 JMP AX
You can see that the entrance is RTO_LINUX_AMD64.S (certainly not the same as the entry file for different platforms),
Rto_linux_amd64.s
#include "textflag.h" TEXT _rt0_amd64_linux (SB), nosplit,$-8 Leaq 8 (SP), SI//argv movq 0 (sp), DI//ARGC MOVQ $main (SB), AX JMP ax//when building with-buildmode=c-shared, this symbol is called when the shared//library is LOA ded.//note:this function calls external C code, which might required 16-byte stack//alignment after Cmd/internal/obj AP Plies its transformations. TEXT _rt0_amd64_linux_lib (SB), nosplit,$0x50 movq sp, AX andq $-16, SP movq BX, 0x10 (sp) movq BP, 0x18 (SP) Movq R12, 0x20 (sp) movq R13, 0x28 (sp) movq R14, 0x30 (sp) movq R15, 0x38 (sp) movq AX, 0x40 (sp) movq DI, _rt0_amd64_linux_lib_argc<> (SB) movq SI, _rt0_amd64_linux_lib_argv<> (SB)//Synchronous Initializat Ion. Movq $runtime libpreinit (SB), ax call AX//Create a new thread to do the runtime initialization and return. Movq _cgo_sys_thread_create (SB), ax TESTQ ax, ax JZ nocgo movq $_rt0_amd64_linux_lib_go (SB), DI movq$, SI call AX JMP restorenocgo:movq $8388608, 0 (SP)//stacksize movq $_rt0_amd64_li Nux_lib_go (SB), Ax Movq ax, 8 (SP)//FN MOVQ $runtime newosproc0 (SB), Ax call Axresto Re:movq 0x10 (SP), BX movq 0x18 (sp), BP movq 0x20 (sp), R12 movq 0x28 (sp), R13 movq 0x30 (sp), R14 MOV Q 0x38 (SP), R15 movq 0x40 (sp), SP Rettext _rt0_amd64_linux_lib_go (SB), nosplit,$0 movq _rt0_amd64_linux_lib_arg C<> (SB), DI movq _rt0_amd64_linux_lib_argv<> (SB), SI movq $runtime rt0_go (SB), AX JMP axdata _rt0 _amd64_linux_lib_argc<> (SB)/8, $0globl _rt0_amd64_linux_lib_argc<> (SB), Noptr, $8data _rt0_amd64_linux_ Lib_argv<> (SB)/8, $0globl _rt0_amd64_linux_lib_argv<> (SB), Noptr, $8text Main (SB), Nosplit,$-8 MOVQ $ Runtime Rt0_go (SB), ax JMP, Microsoft Dynamics AX
Above is the contents of the go1.9.2 rto_linux_amd64.s file.
But I totally half understand the assembly, only half a half to guess, not to mention that the Go assembly instructions some have not seen before. Fortunately there is great Google, in addition gdb inside of the assembly single-step debugging provides a lot of convenience.
TEXT rt0amd64_linux(SB),NOSPLIT,$-8 LEAQ 8(SP), SI // argv MOVQ 0(SP), DI // argc MOVQ $main(SB), AX JMP AX TEXT main(SB),NOSPLIT,$-8 MOVQ $runtime·rt0_go(SB), AX JMP AX
This is the first few lines of RTO_LINUX_ASM64.S, and the 4th line jumps to main (SB) here. Main (SB) has jumped to runtime Rt0_go (SB) but runtime Rt0_go (SB) is there. There are 2 ways to find, one we can search all the assembly files in the runtime directory. Another way is to use GDB's assembler to step through the debugger to see where it jumps
This is the content of single step debugging using GDB, about GDB Assembly single-step debugging on the 2 instruction Ni Si.
Breakpoint 1, _rt0_amd64_linux () at /usr/local/go/src/runtime/rt0_linux_amd64.s:88 LEAQ 8(SP), SI // argv(gdb) ni9 MOVQ 0(SP), DI // argc(gdb) niBreakpoint 2, _rt0_amd64_linux () at /usr/local/go/src/runtime/rt0_linux_amd64.s:1010 MOVQ $main(SB), AX(gdb) ni11 JMP AX(gdb) niStopped due to shared library event(gdb) si74 JMP AX(gdb) siruntime.rt0_go () at /usr/local/go/src/runtime/asm_amd64.s:1212 MOVQ DI, AX // argc(gdb) ni13 MOVQ SI, BX
We see that is jumping to the Asm_amd64.s:12 12 line execution, here's the code we can get through the next note about what to do about it
// create istack out of the given (operating system) stack. // _cgo_init may update stackguard. MOVQ $runtime·g0(SB), DI LEAQ (-64*1024+104)(SP), BX MOVQ BX, g_stackguard0(DI) MOVQ BX, g_stackguard1(DI) MOVQ BX, (g_stack+stack_lo)(DI) MOVQ SP, (g_stack+stack_hi)(DI) // find out information about the processor we're on MOVL $0, AX CPUID MOVL AX, SI CMPL AX, $0 JE nocpuinfo MOVL 16(SP), AX // copy argc MOVL AX, 0(SP) MOVQ 24(SP), AX // copy argv MOVQ AX, 8(SP) CALL runtime·args(SB) CALL runtime·osinit(SB) CALL runtime·schedinit(SB)
The main thing is to get the initialization of some things, including Runtime.osinit runtime.schedinit and so on.
// create a new goroutine to start program MOVQ $runtime·mainPC(SB), AX // entry PUSHQ AX PUSHQ $0 // arg size CALL runtime·newproc(SB) POPQ AX POPQ AX
This puts the main function into the stack and then calls Newproc to create the co-process.
Summary
This article mainly introduces the use of Go tool he gdb simple analysis Golang program start-up boot process, some details such as Newproc and Mstart are described in the following article.