Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Moments before main()

Oleg Kovalov
September 15, 2021

Moments before main()

GopherCon Poland 2021

Oleg Kovalov

September 15, 2021

Transcript

150 slides
  1. - Open source addicted gopher - Fan of linters (co-author

    go-critic) - Father of a labrador Me 4
  2. - Open source addicted gopher - Fan of linters (co-author

    go-critic) - Father of a labrador - Also Twitter/Telegram @go_perf - ... Me 5
  3. - Open source addicted gopher - Fan of linters (co-author

    go-critic) - Father of a labrador - Also Twitter/Telegram @go_perf - ... olegk.dev Me 6
  4. - Why??? - We have *.exe - Let’s get code

    from binary - Let’s scroll the code Agenda 10
  5. - Why??? - We have *.exe - Let’s get code

    from binary - Let’s scroll the code - Let’s scroll the code - Let’s scroll the code - Let’s scroll the code - Let’s scroll the code - Let’s scroll the code - Let’s scroll the code Agenda 11
  6. - Why??? - We have *.exe - Let’s get code

    from binary - Let’s scroll the code - Let’s scroll the code - Let’s scroll the code - Let’s scroll the code - Let’s scroll the code - Let’s scroll the code - Let’s scroll the code - Inside stdlib Go 1.17.1, OS Darwin (macOS Big Sur), YMMV Agenda 12
  7. - Looks like there is a problem - But the

    problem is not so bad So what I’m trying to say 27
  8. - Looks like there is a problem - But the

    problem is not so bad - Docker image is more important - if your base image is Ubuntu/Debian So what I’m trying to say 28
  9. - Looks like there is a problem - But the

    problem is not so bad - Docker image is more important - if your base image is Ubuntu/Debian - also there is UPX So what I’m trying to say 29
  10. So what I’m trying to say 30 - Looks like

    there is a problem - But the problem is not so bad - Docker image is more important - if your base image is Ubuntu/Debian - also there is UPX - But what is inside?
  11. So what I’m trying to say 31 - Looks like

    there is a problem - But the problem is not so bad - Docker image is more important - if your base image is Ubuntu/Debian - also there is UPX - But what is inside? - Let’s talk about that
  12. ❯ cat main.go package main func main() { // ʕ◔ϖ◔ʔ

    } ❯ go build -o main.exe main.go Simplest program 34
  13. ❯ cat main.go package main func main() { // ʕ◔ϖ◔ʔ

    } ❯ go build -o main.exe main.go ❯ du -sh main.exe 1.1M main.exe Simplest program 35
  14. ❯ cat main.go package main func main() { // ʕ◔ϖ◔ʔ

    } ❯ go build -o main.exe main.go ❯ du -sh main.exe 1.1M main.exe ❯ 👀 Simplest program 36
  15. ❯ go build -o main.exe main.go ❯ go list -json

    . > main.json What is inside *.exe? /2 39
  16. go list -json 40 { "Dir": "/Users/olegkovalov/go/src/github.com/cristaloleg/funf", "ImportPath": "github.com/cristaloleg/funf", "Name":

    "main", "Module": {...}, "GoFiles": [ "main.go" ], "Deps": [ "internal/bytealg", "internal/cpu", "runtime", "runtime/internal/atomic", "runtime/internal/math", "runtime/internal/sys", "unsafe" ] }
  17. ❯ go build -o main.exe main.go ❯ go tool objdump

    -S main.exe > main.dump What is inside *.exe? /3 41
  18. - Disassembles executable files var printCode = flag.Bool("S", false, "print

    Go code alongside assembly") - Also symregexp flag flag.String("s", "", "only dump symbols matching this regexp") ❯ go tool objdump -S -s runtime.makech main.exe go tool objdump 44
  19. ❯ go build -o main.exe main.go ❯ go tool objdump

    -S main.exe > main.dump ❯ du -sh main.dump 4.5M main.dump So objdump 46
  20. ❯ go build -o main.exe main.go ❯ go tool objdump

    -S main.exe > main.dump ❯ du -sh main.dump 4.5M main.dump ❯ rg "TEXT runtime." -c main.dump 945 So objdump 47
  21. ❯ go build -o main.exe main.go ❯ go tool objdump

    -S main.exe > main.dump ❯ du -sh main.dump 4.5M main.dump ❯ rg "TEXT runtime." -c main.dump 945 ❯ 🔥🔥🔥 So objdump 48
  22. Close look at main.dump 52 - Just a text file

    - With all possible definitions - Useful if you are doing low-level optimisations
  23. Close look at main.dump 53 - Just a text file

    - With all possible definitions - Useful if you are doing low-level optimisations - or a conference talk :)
  24. ...124k lines later 0x1054bde cc INT $0x3 0x1054bdf cc INT

    $0x3 TEXT main.main(SB) /Users/olegkovalov/code/funf/main.go func main() {} 0x1054be0 c3 RET 0x1054be1 cc INT $0x3 0x1054be2 cc INT $0x3 0x1054be3 cc INT $0x3 Lovely main() 55
  25. ...124k lines later 0x1054bde cc INT $0x3 0x1054bdf cc INT

    $0x3 TEXT main.main(SB) /Users/olegkovalov/code/funf/main.go func main() {} 0x1054be0 c3 RET 0x1054be1 cc INT $0x3 0x1054be2 cc INT $0x3 0x1054be3 cc INT $0x3 Hm...main.main ? 56
  26. Real main 57 ...60k lines 0x102d7cd e8eebeffff CALL runtime.deferreturn(SB) 0x102d7d2

    488b6c2450 MOVQ 0x50(SP), BP 0x102d7d7 4883c458 ADDQ $0x58, SP 0x102d7db c3 RET func main() { 0x102d7dc 0f1f4000 NOPL 0(AX) 0x102d7e0 e8bb440200 CALL runtime.morestack_noctxt.abi0(SB) 0x102d7e5 e9b6fcffff JMP runtime.main(SB) 0x102d7ea cc INT $0x3 ...60k lines
  27. Real main...is closer ...60k lines 0x102d7cd e8eebeffff CALL runtime.deferreturn(SB) 0x102d7d2

    488b6c2450 MOVQ 0x50(SP), BP 0x102d7d7 4883c458 ADDQ $0x58, SP 0x102d7db c3 RET func main() { 0x102d7dc 0f1f4000 NOPL 0(AX) 0x102d7e0 e8bb440200 CALL runtime.morestack_noctxt.abi0(SB) 0x102d7e5 e9b6fcffff JMP runtime.main(SB) 0x102d7ea cc INT $0x3 ...60k lines 58
  28. runtime.main TEXT runtime.main(SB) /usr/local/Cellar/go/1.17/libexec/src/runtime/proc.go func main() { 0x102d4a0 493b6610 CMPQ

    0x10(R14), SP 0x102d4a4 0f8632030000 JBE 0x102d7dc 0x102d4aa 4883ec58 SUBQ $0x58, SP 0x102d4ae 48896c2450 MOVQ BP, 0x50(SP) 0x102d4b3 488d6c2450 LEAQ 0x50(SP), BP 0x102d4b8 49c7c500000000 MOVQ $0x0, R13 0x102d4bf 4c896c2448 MOVQ R13, 0x48(SP) 0x102d4c4 c644242700 MOVB $0x0, 0x27(SP) g := getg() 0x102d4c9 4c89742430 MOVQ R14, 0x30(SP) g.m.g0.racectx = 0 0x102d4ce 498b4630 MOVQ 0x30(R14), AX 0x102d4d2 488b00 MOVQ 0(AX), AX 0x102d4d5 48c7804001000000000000 MOVQ $0x0, 0x140(AX) maxstacksize = 1000000000 59
  29. Inside runtime/proc.go 60 //go:linkname main_main main.main func main_main() // ...

    // The main goroutine. func main() { g := getg() // ... fn := main_main // make an indirect call, // as the linker doesn't know the address // of the main package when laying down the runtime fn() // ...
  30. To sum up /1 61 - ... - runtime.main() -

    main_main ~ main.main // linker’s magic - main.main // that’s us!
  31. - There are strange runtime/asm_<arch>.s files - arch is some

    CPU architecture (amd64, arm64, mips, …) - *.s - Assembler But that's not all 64
  32. - There are strange runtime/asm_<arch>.s files - arch is some

    CPU architecture (amd64, arm64, mips, …) - *.s - Assembler - 👀 But that's not all 65
  33. - There are strange runtime/asm_<arch>.s files - arch is some

    CPU architecture (amd64, arm64, mips, …) - *.s - Assembler - 👀 - Let’s check asm_amd64.s - just 2k lines But that's not all 66
  34. - There are strange runtime/asm_<arch>.s files - arch is some

    CPU architecture (amd64, arm64, mips, …) - *.s - Assembler - 👀 - Let’s check asm_amd64.s - just 2k lines - others are + - 1k - arm64.s is also heavy But that's not all 67
  35. - FP: Frame pointer: arguments and locals. - PC: Program

    counter: jumps and branches. - SB: Static base pointer: global symbols. - SP: Stack pointer: top of stack. Go assembler cheat sheet 68
  36. - FP: Frame pointer: arguments and locals. - PC: Program

    counter: jumps and branches. - SB: Static base pointer: global symbols. - SP: Stack pointer: top of stack. - JMP: jump - LEA: load effective address - MOV dst, src: move src to dst - CALL: invoke function - DATA(+GLOBL): data symbols (global) Go assembler cheat sheet 69
  37. // _rt0_amd64 is common startup code for most amd64 systems

    when using // internal linking. This is the entry point for the program from the // kernel for an ordinary -buildmode=exe program. The stack holds the // number of arguments and the C-style argv. TEXT _rt0_amd64(SB),NOSPLIT,$-8 MOVQ 0(SP), DI // argc LEAQ 8(SP), SI // argv JMP runtime·rt0_go(SB) Ah, that the trick 70
  38. // Defined as ABIInternal since it does not use the

    stack-based Go ABI (and // in addition there are no calls to this entry point from Go code). TEXT runtime·rt0_go(SB),NOSPLIT|TOPFRAME,$0 // copy arguments forward on an even stack MOVQ DI, AX // argc MOVQ SI, BX // argv // ... // create istack out of the given (operating system) stack. MOVQ $runtime·g0(SB), DI // ... // find out information about the processor we're on MOVL $0, AX CPUID // ... Scroll further 71
  39. Scroll further 72 TEXT runtime·rt0_go(SB),NOSPLIT|TOPFRAME,$0 // ... ok: // set

    the per-goroutine and per-mach "registers" get_tls(BX) LEAQ runtime·g0(SB), CX MOVQ CX, g(BX) LEAQ runtime·m0(SB), AX // save m->g0 = g0 MOVQ CX, m_g0(AX) // save m0 to g0->m MOVQ AX, g_m(CX)
  40. Scroll further 73 TEXT runtime·rt0_go(SB),NOSPLIT|TOPFRAME,$0 // ... CALL runtime·check(SB) 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)
  41. - Platform dependent things - Signal handlers - Timers -

    Random - Thread sizes and other consts - Envs and cmd params - I mean environment variables и argc & argv runtime/os_<os>.go 76
  42. - Platform dependent things - Signal handlers - Timers -

    Random - Thread sizes and other consts - Envs and cmd params - I mean environment variables и argc & argv - Machine sanity checks - Oh, interesting! runtime/os_<os>.go 77
  43. - In runtime1.go there is an interesting function - check()

    - checks primitive type sizes - d uint16 - if unsafe.Sizeof(d) != 2 { throw("bad d") } Machine sanity checks 79
  44. - In runtime1.go there is an interesting function - check()

    - checks primitive type sizes - d uint16 - if unsafe.Sizeof(d) != 2 { throw("bad d") } - check() calls testAtomic64() Machine sanity checks 80
  45. - In runtime1.go there is an interesting function - check()

    - checks primitive type sizes - d uint16 - if unsafe.Sizeof(d) != 2 { throw("bad d") } - check() calls testAtomic64() - As you can guess testAtomic64 is about atomics - test_z64 = 42, test_x64 = 0 - if atomic.Cas64(&test_z64, test_x64, 1) { throw("cas64 failed") } Machine sanity checks 81
  46. Scroll further 82 TEXT runtime·rt0_go(SB),NOSPLIT|TOPFRAME,$0 // ... CALL runtime·check(SB) 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) // with some magic and linker this will be os.Args
  47. Scroll further 84 /Users/olegkovalov/go/src/golang/go/src/runtime/runtime1.go func args(c int32, v **byte) {

    argc = c argv = v sysargs(c, v) } // os_darwin.go func sysargs(argc int32, argv **byte) { // skip over argv, envv and the first string will be the path n := argc + 1 for argv_index(argv, n) != nil { n++ } executablePath = gostringnocopy(argv_index(argv, n+1)) // ... }
  48. Scroll further 85 TEXT runtime·rt0_go<ABIInternal>(SB),NOSPLIT,$0 // ... CALL runtime·check(SB) 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)
  49. Scroll further 86 // os_darwin.go // BSD interface for threading.

    func osinit() { // pthread_create delayed until end of goenvs so that we // can look at the environment first. ncpu = getncpu() physPageSize = getPageSize() }
  50. Scroll further 87 TEXT runtime·rt0_go<ABIInternal>(SB),NOSPLIT,$0 // ... CALL runtime·check(SB) 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)
  51. To sum up /2 88 - runtime·_rt0_amd64 // or which

    architecture you have - runtime·rt0_go - <creating universe> - check - args - osinit - schedinit - runtime.main() - main_main ~ main.main // linker’s magic - main.main // that’s us!
  52. Scroll further 89 // The bootstrap sequence is: // //

    call osinit // call schedinit // make & queue new G // call runtime·mstart // // The new G calls runtime·main. func schedinit() { // ...
  53. - G - goroutine - M - worker thread, or

    machine. - P - processor, a resource that is required to execute Go code. - getg() - returns the pointer to the current g - _g_ := getg() - p := getg().m.p.ptr() - tls - thread-local storage Everything else is if’s, atomics & unclear algorithms. Ez. Go runtime cheat sheet 90
  54. func schedinit() { // ... _g_ := getg() sched.maxmcount =

    10000 // maximum number of m's allowed (or die) // The world starts stopped. worldStopped() moduledataverify() // pclntab is correct stackinit() // mallocinit() fastrandinit() // must run before mcommoninit mcommoninit(_g_.m, -1) schedinit /1 91
  55. func schedinit() { // ... _g_ := getg() sched.maxmcount =

    10000 // maximum number of m's allowed (or die) // The world starts stopped. worldStopped() moduledataverify() // pclntab is correct stackinit() // mallocinit() fastrandinit() // must run before mcommoninit mcommoninit(_g_.m, -1) cpuinit() // must run before alginit alginit() // maps must not be used before this call modulesinit() // provides activeModules typelinksinit() // uses maps, activeModules itabsinit() // uses activeModules schedinit /1 92
  56. func schedinit() { // ... goargs() goenvs() parsedebugvars() gcinit() lock(&sched.lock)

    // ... if procresize(procs) != nil { throw("unknown runnable goroutine during bootstrap") } unlock(&sched.lock) // World is effectively started now, as P's can run. worldStarted() // ... } schedinit /2 93
  57. TEXT runtime·rt0_go(SB),NOSPLIT|TOPFRAME,$0 // ... // 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 ... // mainPC is a function value for runtime.main, to be passed to newproc. // The reference to runtime.main is made via ABIInternal, since the // actual function (not the ABI0 wrapper) is needed by newproc. DATA runtime·mainPC+0(SB)/8,$runtime·main<ABIInternal>(SB) GLOBL runtime·mainPC(SB),RODATA,$8 A bit of assembler 94
  58. One more bit of assembler 95 TEXT runtime·rt0_go(SB),NOSPLIT|TOPFRAME,$0 // ...

    // 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 // start this M CALL runtime·mstart(SB) CALL runtime·abort(SB)// mstart should never return RET TEXT runtime·mstart(SB),NOSPLIT|TOPFRAME,$0 CALL runtime·mstart0(SB) RET // not reached
  59. newproc // Create a new g running fn. // Put

    it on the queue of g's waiting to run. // The compiler turns a go statement into a call to this. func newproc(fn *funcval) { gp := getg() pc := getcallerpc() systemstack(func() { newg := newproc1(fn, gp, pc) _p_ := getg().m.p.ptr() runqput(_p_, newg, true) if mainStarted { wakep() } }) } 96
  60. // Create a new g running fn. // Put it

    on the queue of g's waiting to run. // The compiler turns a go statement into a call to this. func newproc(fn *funcval) { gp := getg() pc := getcallerpc() systemstack(func() { newg := newproc1(fn, gp, pc) _p_ := getg().m.p.ptr() runqput(_p_, newg, true) if mainStarted { wakep() } }) } newproc 97
  61. newproc 98 // Create a new g running fn. //

    Put it on the queue of g's waiting to run. // The compiler turns a go statement into a call to this. func newproc(fn *funcval) { gp := getg() pc := getcallerpc() systemstack(func() { newg := newproc1(fn, gp, pc) _p_ := getg().m.p.ptr() runqput(_p_, newg, true) if mainStarted { wakep() } }) }
  62. systemstack 99 // systemstack runs fn on a system stack.

    // If systemstack is called from the per-OS-thread (g0) stack, or // if systemstack is called from the signal handling (gsignal) stack, // systemstack calls fn directly and returns. // // Otherwise, systemstack is being called from the limited stack // of an ordinary goroutine. In this case, systemstack switches // to the per-OS-thread stack, calls fn, and switches back. // //go:noescape func systemstack(fn func())
  63. Finally scheduler // mstart is the entry-point for new Ms.

    func mstart() // mstart0 is the Go entry-point for new Ms. func mstart0() { _g_ := getg() // ... mstart1() } func mstart1() { _g_ := getg() // ... schedule() } 100
  64. schedule 101 // One round of scheduler: find a runnable

    goroutine and execute it. // Never returns. func schedule() { _g_ := getg() top: pp := _g_.m.p.ptr() pp.preempt = false var gp *g // get some gp execute(gp, inheritTime) }
  65. To sum up /3 102 - runtime·_rt0_amd64 // or which

    architecture you have - runtime·rt0_go - check - args - osinit - schedinit - ... - newproc // will create goroutine for runtime.main - mstart // to start goroutine above - mstart0 -> mstart1 - schedule - runtime.main() - main_main ~ main.main // linker’s magic - main.main // that’s us!
  66. - Everything discussed is ~250 lines - Everything else is

    runtime things (obvious) Ok, but why 2k lines? 105
  67. - Everything discussed is ~250 lines - Everything else is

    runtime things (obvious) - stack handling - defer’s - different panics Ok, but why 2k lines? 106
  68. - Everything discussed is ~250 lines - Everything else is

    runtime things (obvious) - stack handling - defer’s - different panics - debug helpers - lovely cgo - gc barriers Ok, but why 2k lines? 107
  69. - Everything discussed is ~250 lines - Everything else is

    runtime things (obvious) - stack handling - defer’s - different panics - debug helpers - lovely cgo - gc barriers - timers - signals - hashes Ok, but why 2k lines? 108
  70. Popular pattern // func memhash(p unsafe.Pointer, h, s uintptr) uintptr

    // hash function using AES hardware instructions TEXT runtime·memhash<ABIInternal>(SB),NOSPLIT,$0-32 // AX = ptr to data // BX = seed // CX = size CMPB runtime·useAeshash(SB), $0 JEQ noaes JMP aeshashbody<>(SB) noaes: JMP runtime·memhashFallback<ABIInternal>(SB) /Users/olegkovalov/go/src/golang/go/src/runtime/hash64.go func memhashFallback(p unsafe.Pointer, seed, s uintptr) uintptr { 109
  71. - add GOAMD64 architecture variants #25489 - https://github.com/golang/go/issues/25489 - Now

    you can easily find such lines - x86HasSSE41 = cpu.X86.HasSSE41 - to be honest a lot of them - Wasting our CPU on nothing - every nanosecond counts :( GOAMD64 proposal 110
  72. - Runtime packages has a lot inits - Most of

    them are OS/machine checks - type size - available CPU flags - But there is one interesting (then we will scroll through other stdlib packages) What about init()’s ?? 112
  73. /Users/olegkovalov/go/src/golang/go/src/runtime/proc.go // start forcegc helper goroutine func init() { go

    forcegchelper() } // 5k lines later... Popular claim regarding Go GC 114
  74. Popular claim regarding Go GC 115 /Users/olegkovalov/go/src/golang/go/src/runtime/proc.go // start forcegc

    helper goroutine func init() { go forcegchelper() } // 5k lines later... // forcegcperiod is the maximum time in nanoseconds between garbage // collections. If we go this long without a garbage collection, one // is forced to run. // // This is a variable for testing purposes. It normally doesn't change. var forcegcperiod int64 = 2 * 60 * 1e9
  75. func init() { crypto.RegisterHash(crypto.MD5, New) } // do THIS with

    crypto packages: import ( _ "crypto/sha256" // to register a sha256 _ "crypto/sha512" // to register a sha384/512 ) Inside crypto/* 118
  76. func init() { crypto.RegisterHash(crypto.MD5, New) } // do THIS with

    crypto packages: import ( _ "crypto/sha256" // to register a sha256 _ "crypto/sha512" // to register a sha384/512 ) // and NOT this: import ( _ "crypto/sha256" //nolint "crypto/sha512" ) var _ = sha512.<Something_Just_To_Import> Inside crypto/* 119
  77. func init() { // ... registerBasics() // ... } func

    registerBasics() { Register(int(0)) Register(int8(0)) Register(int16(0)) Register(int32(0)) Register(int64(0)) // ... Inside encoding/gob 121
  78. Inside net 122 // net/conf_netcgo.go //go:build netcgo // +build netcgo

    package net // The build tag "netcgo" forces use of the cgo DNS resolver. // It is the opposite of "netgo". func init() { netCgo = true } // net/conf.go netGo bool // go DNS resolution forced netCgo bool // cgo DNS resolution forced
  79. Inside net 123 // net/conf_netcgo.go //go:build netcgo // +build netcgo

    package net // The build tag "netcgo" forces use of the cgo DNS resolver. // It is the opposite of "netgo". func init() { netCgo = true } // net/conf.go netGo bool // go DNS resolution forced netCgo bool // cgo DNS resolution forced
  80. // When debugging a particular http server-based test, // this

    flag lets you run // go test -run=BrokenTest -httptest.serve=127.0.0.1:8000 // to start the broken server so you can interact with it manually. // ... // isn't really part of our API. Don't depend on this. var serveFlag string func init() { if has(os.Args, "-httptest.serve=") { flag.StringVar(&serveFlag, "httptest.serve", "", "...") } } Inside net/http/httptest 124
  81. // mime/type_freebsd.go func init() { typeFiles = append(typeFiles, "/usr/local/etc/mime.types") }

    // mime/type_openbsd.go func init() { typeFiles = append(typeFiles, "/usr/share/misc/mime.types") } ... Inside mime 126 MIME == Multipurpose Internet Mail Extensions
  82. func init() { runtime_registerPoolCleanup(poolCleanup) } func poolCleanup() { for _,

    p := range oldPools { // ... } for _, p := range allPools { // ... } // The pools with non-empty primary caches now have non-empty // victim caches and no pools have primary caches. oldPools, allPools = allPools, nil } Inside sync 127
  83. Inside sync /2 // sync/runtime.go // Ensure that sync and

    runtime agree on size of notifyList. func runtime_notifyListCheck(size uintptr) func init() { var n notifyList runtime_notifyListCheck(unsafe.Sizeof(n)) } // runtime/sema.go //go:linkname notifyListCheck sync.runtime_notifyListCheck func notifyListCheck(sz uintptr) { if sz != unsafe.Sizeof(notifyList{}) { print("runtime: bad notifyList") throw("bad notifyList size") } } 128
  84. // Package tzdata provides an embedded copy of the timezone

    database. // If this package is imported anywhere in the program, then if // the time package cannot find tzdata files on the system, // it will use this embedded information. // // Importing this package will increase the size of a program by about // 450 KB. // Inside time/tzdata 130
  85. // Package tzdata provides an embedded copy of the timezone

    database. // If this package is imported anywhere in the program, then if // the time package cannot find tzdata files on the system, // it will use this embedded information. // // Importing this package will increase the size of a program by about // 450 KB. // Inside time/tzdata 131
  86. Inside time/tzdata 132 // Package tzdata provides an embedded copy

    of the timezone database. // If this package is imported anywhere in the program, then if // the time package cannot find tzdata files on the system, // it will use this embedded information. // // Importing this package will increase the size of a program by about // 450 KB. // // This package should normally be imported by a program's main package, // not by a library. Libraries normally shouldn't decide whether to // include the timezone database in a program. // // This package will be automatically imported if you build with // -tags timetzdata. package tzdata
  87. Inside time/tzdata 133 // Package tzdata provides an embedded copy

    of the timezone database. // If this package is imported anywhere in the program, then if // the time package cannot find tzdata files on the system, // it will use this embedded information. // // Importing this package will increase the size of a program by about // 450 KB. // // This package should normally be imported by a program's main package, // not by a library. Libraries normally shouldn't decide whether to // include the timezone database in a program. // // This package will be automatically imported if you build with // -tags timetzdata. package tzdata
  88. - Function definition before usage - do you remember that

    first versions of Go compiler was in C ? :) 1 slide notes 135
  89. - Function definition before usage - do you remember that

    first versions of Go compiler was in C ? :) - Many underscores in var and func names - again the C legacy 1 slide notes 136
  90. - Function definition before usage - do you remember that

    first versions of Go compiler was in C ? :) - Many underscores in var and func names - again the C legacy - Windows, NetBSD, Wasm, JS & Plan9 are special - often requires special treatment 1 slide notes 137
  91. - Function definition before usage - do you remember that

    first versions of Go compiler was in C ? :) - Many underscores in var and func names - again the C legacy - Windows, NetBSD, Wasm, JS & Plan9 are special - often requires special treatment - Cgo is not Go, as Rob Pike said - basically explains everything 1 slide notes 138
  92. - Function definition before usage - do you remember that

    first versions of Go compiler was in C ? :) - Many underscores in var and func names - again the C legacy - Windows, NetBSD, Wasm, JS & Plan9 are special - often requires special treatment - Cgo is not Go, as Rob Pike said - basically explains everything - Runtime is all about corner cases - that’s my IMHO 1 slide notes 139
  93. Conclusions 144 - Meeting a machine - Creating goroutine -

    Creating thread to run it - Running and looking for another to run
  94. Conclusions 145 - Meeting a machine - Creating goroutine -

    Creating thread to run it - Running and looking for another to run - That’s all
  95. - A Quick Guide to Go's Assembler - https://golang.org/doc/asm -

    The Go Memory Model - https://golang.org/ref/mem - Go 1.2 Runtime Symbol Information (2013) - https://docs.google.com/document/d/1lyPIbmsYbXnpNj57a261hgOYVpNRcgydurVQIyZO z_o/pub - runtime/HACKING.md - https://github.com/golang/go/blob/master/src/runtime/HACKING.md References 146
  96. - Anton Repushko - Bogdan Storozhuk - Iskander Sharipov -

    and you GopherCon Poland team 👌 Thanks 149

More Decks by Oleg Kovalov

Other Decks in Programming