从.NET9看Golang

文摘   2024-08-08 14:55   湖北  

点击上方蓝字 江湖评谈设为关注/星标




前言

NET9在Linux入口是Glibc,偶然看到Go的main入口不是Glibc,这难道是GO的性能和体积都具有优势的地方,本篇看下Glibc。

Go操作

#apt install golang-go 安装#go verison 查看版本号#which gdb查看调试器#go run godemo.go 运行#go build 生成可执行文件

例子:

# filename gofirstproj.go 可执行文件名 gofirstprojpackage mainimport "fmt"func main() {    fmt.Printf("Welcome to golang World\n")}

GDB

#readelf gofirstproj 查看下go可执行文件头ELF Header:  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00   Class:                             ELF64  Data:                              2's complement, little endian  Version:                           1 (current)  OS/ABI:                            UNIX - System V  ABI Version:                       0  Type:                              EXEC (Executable file)  Machine:                           Advanced Micro Devices X86-64  Version:                           0x1  Entry point address:               0x45bfa0  Start of program headers:          64 (bytes into file)  Start of section headers:          456 (bytes into file)  Flags:                             0x0  Size of this header:               64 (bytes)  Size of program headers:           56 (bytes)  Number of program headers:         7  Size of section headers:           64 (bytes)  Number of section headers:         23  Section header string table index: 3#gdb gofirstproj(gdb)b main.main 两个main注意了(gdb)r(gdb)n 下一步(gdb)bt#0  runtime.sigtramp () at /usr/lib/go-1.18/src/runtime/sys_linux_amd64.s:353#1  0x000000000045c5e0 in ?? ()#2  0x0000000000000007 in ?? ()#3  0x0000000000000000 in ?? ()

看到GO的这个main入口是在文件sys_linux_amd64.s里,具体代码如下(实际GO main调用是在353行PUSH_REGS_HOST_TO_ABI0):

337 TEXT runtime·sigfwd(SB),NOSPLIT,$0-32338         MOVQ    fn+0(FP),    AX339         MOVL    sig+8(FP),   DI340         MOVQ    info+16(FP), SI341         MOVQ    ctx+24(FP),  DX342         PUSHQ   BP343         MOVQ    SP, BP344         ANDQ    $~15, SP     // alignment for x86_64 ABI345         CALL    AX346         MOVQ    BP, SP347         POPQ    BP348         RET349 350 // Called using C ABI.351 TEXT runtime·sigtramp(SB),NOSPLIT,$0352         // Transition from C ABI to Go ABI.353         PUSH_REGS_HOST_TO_ABI0()354 355         // Call into the Go signal handler356         NOP     SP              // disable vet stack checking357         ADJSP   $24358         MOVQ    DI, 0(SP)       // sig359         MOVQ    SI, 8(SP)       // info360         MOVQ    DX, 16(SP)      // ctx361         CALL    ·sigtrampgo(SB)362         ADJSP   $-24

可以看到main确实不是glibc里面被调用的,而是go1.18版本自己用汇编代码实现的main调用。把CGO_ENABLED关闭和开启分别试下:

#go env 查看go环境变量,CGO_ENABLED默认为1#CGO_ENABLED=0 go build -o no_cgo gofirstproj.go #CGO_ENABLED=1 go build -o yes_cgo gofirstproj.go#ldd no_cgo yes_cgo no_cgo:  not a dynamic executableyes_cgo:  not a dynamic executable

看到无论CGO_ENABLED开启或者是关闭都没有动态依赖,难道go1.18都是静态链接了?

.NET9

用lldb看下.NET9的corerun-Main的Linux下面是被谁调用的

#lldb corerun ConsoleApp1.dll(lldbb main(lldb)r  (lldb)bt* thread #1, name = 'corerun', stop reason = breakpoint 1.1  * frame #0: 0x000055555556c420 corerun`main(argc=<unavailable>, argv=<unavailable>) at corerun.cpp:616    frame #1: 0x00007ffff7829d90 libc.so.6`__libc_start_call_main(main=(corerun`main at corerun.cpp:616), argc=2, argv=0x00007fffffffdef8) at libc_start_call_main.h:58:16    frame #2: 0x00007ffff7829e40 libc.so.6`__libc_start_main_impl(main=(corerun`main at corerun.cpp:616), argc=2, argv=0x00007fffffffdef8, init=0x00007ffff7ffd040, fini=<unavailable>, rtld_fini=<unavailable>, stack_end=0x00007fffffffdee8) at libc-start.c:392:3    frame #3: 0x000055555556bf45 corerun`_start + 37

很清晰的看到了libc-start.c,它即 是 GNU C 库(Glibc)的一部分。

结尾

Go能直接避开Glibc用自己的汇编代码调用Main入口,确实属于非常独立的可执行文件,可以避免很多的依赖纠缠,各种发行版的特性阻碍。.NET目前似乎尚未实现此功能,.NET9 PreView2里面的AOT自举来看,以后不排除也会这样搞。至于性能和体积方面的优势,需要更多深入了解GO才能下结论。

往期精彩回顾

.NET9现代化编程长啥样?

推荐两个.NET JIT顶级安全加密工具


江湖评谈
记录,分享,自由。
 最新文章