Go FAQ: Analyze the entry of the Go program from the source code

Source: Internet
Author: User
This is a creation in Article, where the information may have evolved or changed.

Cause

The go language has been learned in recent days, but the information given in the textbook is too small to meet the needs. So on the Internet read a lot of blog posts, which found that there are many conflicts, making people more confused. In order to dispel doubts, I deeply analyzed the go language and small have experience, want to share some of them to everyone, hope to improve everyone's learning efficiency.


The real entrance to the go language

The Runtime.caller method of the Go language provides the function call information on the current Goroutine stack, mainly with the current PC value and the called File and line number. If the information is not available, the fourth value returned is false. When we use this function in Main.main (this function is reproduced):

Func main ()  {    for skip := 0; ; skip++ {         pc, file, line, ok := runtime. Caller (Skip)         if !ok {             break        }         fmt. Printf ("skip = %v, pc = %v, file = %v, line = %v\n",  skip, pc, file, line)     }    // output:     // skip = 0, pc = 4198453, file =  caller.go, line = 10    // skip = 1, pc =  4280066, file = $ (goroot)/src/pkg/runtime/proc.c, line = 220     // skip = 2, pc = 4289712, file = $ (GOROOT)/SRC/PKG/RUNTIME/PROC.C,  line = 1394}

According to the display entrance here are: Runtime.goexit, Runtime.main, Main.main.

This is unreasonable! By parsing the Runtime.goexit code, it is not possible to confirm that it calls Runtime.main. Later, I saw someone talking about the entrance to the go language in src/lib9/main.c. so I think it is necessary to analyze the source code to find out its real entrance, because I am too confused.


Start with the linker source code

A linker is a tool that eventually generates an executable file, and we start with it if we want to see the portal. I'm using the Go installer for the 32bit version of Windows 1.21, so start with the 8l code. First navigate to its main function: Go/src/cmd/8l/obj.c/main, the detail is not table, where it calls the Libinit. The last few lines of Libinit are key:

if (initentry = = nil) {initentry = Mal (strlen (goarch) +strlen (GOOS) +20); if (!flag_shared) {Sprint (Initentry, "_rt0_%s_%s ", Goarch, GOOS);} else {Sprint (Initentry, "_rt0_%s_%s_lib", Goarch, GOOS);}} Lookup (initentry, 0)->type = sxref;

The real entrance to the function is this initentry, which is pointed to go/src/pkg/runtime/rt0-windows_386.s on my version. After this libinit, Initentry is placed in the hash table and then dump to the executable file these details are irrelevant to the subject, and there may be a lot of people interested in it, but I don't watch it here.


Assembly entrance

PLAN9 format of assembly language, GO/SRC/PKG/RUNTIME/RT0_WINDOWS_386.S content as follows:

TEXT _rt0_386_windows (SB), nosplit,$12

movl (SP), AX

LEAL (SP), BX

movl AX, 4 (SP)

movl BX, 8 (SP)

movl $-1, 0 (SP)//return PC for main

JMP Main (SB)//Where is this main? It's down there!


TEXT Main (SB), nosplit,$0

JMP _rt0_go (SB)//Where is this _rt0_go?

Go to Go/src/pkg/runtime/asm_386.s:

TEXT _rt0_go (SB), nosplit,$0

//Copy arguments forward on a even stack

movl argc+0 (FP), AX

movl argv+4 (FP), BX

subl $128, SP //plenty of scratch

Andl $~15, SP

movl AX, (SP) //Save argc, argv away

movl BX, 124 (SP)

//set default stack bounds.

//_cgo_init may update stackguard.

movl $runtime ·g0 (SB), BP

LEAL ( -64*1024+104) (SP), BX

movl BX, G_stackguard (BP)

movl BX, g_stackguard0 (BP)

movl SP, G_stackbase (BP)

//Find out information about the processor we ' re on

movl $, AX

CPUID

Cmpl AX, $

JE nocpuinfo

movl $, AX

CPUID

movl CX, runtime·cpuid_ecx (SB)

movl DX, Runtime·cpuid_edx (SB)

Nocpuinfo:


//If there is a _cgo_init, call it-let it

//Initialize and to set up GS. If not,

//We set up GS ourselves.

movl _cgo_init (SB), AX

testl ax, ax

JZ needtls

movl $setmg _gcc<> (SB), BX

movl BX, 4 (SP)

movl BP, 0 (SP)

call AX

//update stackguard after _cgo_init

movl $runtime &middot;g0 (SB), CX

movl g_stackguard0 (CX), AX

movl AX, G_stackguard (CX)

//Skip Runtime&middot;ldt0setup (SB) and TLS test after _cgo_init for Non-windows

Cmpl runtime&middot;iswindows (SB), $

JEQ OK

NEEDTLS:

//Skip Runtime&middot;ldt0setup (SB) and TLS test on Plan 9 in all cases

Cmpl runtime&middot;isplan9 (SB), $

JEQ OK


//Set up%gs

Call runtime&middot;ldt0setup (SB)


//store through it, to make sure it works

Get_tls (BX)

movl $0x123, g (BX)

movl runtime&middot;tls0 (SB), AX

Cmpl AX, $0x123

JEQ OK

movl AX, 0 //Abort

Ok:

//Set up M and g "registers"

Get_tls (BX)

LEAL runtime&middot;g0 (SB), CX

movl CX, g (BX)

LEAL runtime&middot;m0 (SB), AX

movl AX, M (BX)


//Save m->g0 = G0

movl CX, m_g0 (AX)


Call runtime&middot;emptyfunc (SB) //fault if stack check is wrong


//convention is D are always cleared

CLD


Call Runtime&middot;check (SB)


//Saved argc, argv

movl (SP), AX

movl AX, 0 (SP)

movl 124 (SP), AX

movl AX, 4 (SP)

Call Runtime&middot;args (SB)

Call runtime&middot;osinit (SB)

Call runtime&middot;hashinit (SB)

Call runtime&middot;schedinit (SB)


//Create a new goroutine to start program

pushl $runtime &middot;main&middot;f (SB) //Entry

pushl //ARG size

argsize (8)

Call Runtime&middot;newproc (SB)

Argsize (-1)

popl AX

popl AX


//start this M

Call Runtime&middot;mstart (SB)


INT $

RET


DATA runtime&middot;main&middot;f+0 (SB)/4, $runtime &middot;main (SB)

Globl runtime&middot;main&middot;f (SB), rodata,$4


Disassembly verification

Just compile a Go program and verify with W32asm.

200419560 Sub ESP, 0000000C


: 00419563 mov eax, DWORD pt: [ESP+0C]

: o0419$67 Lea ebx, DWORD ptr [ESP+10]

: 00419$6B mov DWORD pct [ESP+04], eax

: 0041956F MNV DWORD pt: [esp+08], ebx

: 00419S73 mov dword ptr [ESP], FFFFFFFF

: 00419$7a jmp TEST.00419S80

.......

: 00417C90 mov eax, DWORD pt: [ESP+04]

: 0O417C94 mov ebx, DWORD pct [ESP+08]

200417098 Sub ESP, 00000080

: 00417c9e and ESP, FFFFFFFO

: 00417CA1 mov dword ptr [esp+78], eax

: 0O417CA9 mov ebp, 00447300

: 00417CAE Lea EBX, DWORD pt: [Esp-0000ff98]

: 00417CB5 mov DWORD pt: [EBP+40], ebx

: 00417CB8 mov DWORD pt: [ebp+00], ebx

: 0O417CBB mov DWORD pct [EBP+O4], ESP

Above is the RT0_WINDOWS_386.S section, the following is the ASM_386.S section. By contrast, this is the real entrance to the GO program.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.