Golang反汇编代码问题求助 [Capstone反汇编器]
Golang反汇编代码问题求助 [Capstone反汇编器] 大家好,
这是我的Go程序:
package main
import (
"fmt"
)
func main() {
i := 3
fmt.Println(i)
}
我使用以下命令构建此程序:env GOOS=unix GOARCH=x86 go build main.go
然后我使用这个反汇编器:https://gist.github.com/grantseltzer/3efa8ecc5de1fb566e8091533050d608
在反汇编器代码中,我已指向生成的ELF文件的路径,并使其使用 gapstone.CS_ARCH_X86、gapstone.CS_MODE_64 作为配置值。
输出内容很多,但没有告诉我关于 i:=3 这一行分配了多少内存的信息:
…已截断…
SYMBOL fmt.glob…func1 0x80bf5b0: mov ecx, dword ptr gs:[rip] 0x80bf5b7: mov ecx, dword ptr [rcx - 4] 0x80bf5bd: cmp esp, dword ptr [rcx + 8] 0x80bf5c0: jbe 0x80bf5e9 0x80bf5c2: sub esp, 8 0x80bf5c5: lea eax, [rip + 0x80de5a0] 0x80bf5cb: mov dword ptr [rsp], eax 0x80bf5ce: call 0x8051700 0x80bf5d3: mov eax, dword ptr [rsp + 4] 0x80bf5d7: lea ecx, [rip + 0x80e13e0] 0x80bf5dd: mov dword ptr [rsp + 0xc], ecx 0x80bf5e1: mov dword ptr [rsp + 0x10], eax 0x80bf5e5: add esp, 8 0x80bf5e8: ret 0x80bf5e9: call 0x808fab0 0x80bf5ee: jmp 0x80bf5b0
SYMBOL fmt.init.ializers 0x80bf5f0: mov ecx, dword ptr gs:[rip] 0x80bf5f7: mov ecx, dword ptr [rcx - 4] 0x80bf5fd: cmp esp, dword ptr [rcx + 8] 0x80bf600: jbe 0x80bf693 0x80bf606: sub esp, 0x10 0x80bf609: lea eax, [rip + 0x80eb29c] 0x80bf60f: mov dword ptr [rsp], eax 0x80bf612: mov dword ptr [rsp + 4], 0x24 0x80bf61a: call 0x8095390 0x80bf61f: mov eax, dword ptr [rsp + 8] 0x80bf623: mov ecx, dword ptr [rsp + 0xc] 0x80bf627: mov dword ptr [rip + 0x8170e48], eax 0x80bf62d: mov eax, dword ptr [rip + 0x8181cc0] 0x80bf633: test eax, eax 0x80bf635: jne 0x80bf684 0x80bf637: mov dword ptr [rip + 0x8170e4c], ecx 0x80bf63d: lea eax, [rip + 0x80e9f4b] 0x80bf643: mov dword ptr [rsp], eax 0x80bf646: mov dword ptr [rsp + 4], 0x1d 0x80bf64e: call 0x8095390 0x80bf653: mov eax, dword ptr [rsp + 8] 0x80bf657: mov ecx, dword ptr [rsp + 0xc] 0x80bf65b: mov dword ptr [rip + 0x8170e40], eax 0x80bf661: mov eax, dword ptr [rip + 0x8181cc0] 0x80bf667: test eax, eax 0x80bf669: jne 0x80bf675 0x80bf66b: mov dword ptr [rip + 0x8170e44], ecx 0x80bf671: add esp, 0x10 0x80bf674: ret 0x80bf675: lea edi, [rip + 0x8170e44] 0x80bf67b: mov eax, ecx 0x80bf67d: call 0x8091220 0x80bf682: jmp 0x80bf671 0x80bf684: lea edi, [rip + 0x8170e4c] 0x80bf68a: mov eax, ecx 0x80bf68c: call 0x8091220 0x80bf691: jmp 0x80bf63d 0x80bf693: call 0x808fab0 0x80bf698: jmp 0x80bf5f0
SYMBOL fmt.init 0x80bf6a0: mov ecx, dword ptr gs:[rip] 0x80bf6a7: mov ecx, dword ptr [rcx - 4] 0x80bf6ad: cmp esp, dword ptr [rcx + 8] 0x80bf6b0: jbe 0x80bf6fa 0x80bf6b2: movzx eax, byte ptr [rip + 0x8181b60] 0x80bf6b9: cmp al, 1 0x80bf6bc: jbe 0x80bf6bf 0x80bf6be: ret 0x80bf6bf: jne 0x80bf6c8 0x80bf6c1: call 0x806b350 0x80bf6c6: ud2 0x80bf6c8: mov byte ptr [rip + 0x8181b60], 1 0x80bf6cf: call 0x809bd80 0x80bf6d4: call 0x80b47b0 0x80bf6d9: call 0x80b4a70 0x80bf6de: call 0x80b7a10 0x80bf6e3: call 0x80ad740 0x80bf6e8: call 0x809dfd0 0x80bf6ed: call 0x80bf5f0 0x80bf6f2: mov byte ptr [rip + 0x8181b60], 2 0x80bf6f9: ret 0x80bf6fa: call 0x808fab0 0x80bf6ff: jmp 0x80bf6a0
SYMBOL type…hash.fmt.fmt 0x80bf710: mov ecx, dword ptr gs:[rip] 0x80bf717: mov ecx, dword ptr [rcx - 4] 0x80bf71d: cmp esp, dword ptr [rcx + 8] 0x80bf720: jbe 0x80bf76c 0x80bf722: sub esp, 0x10 0x80bf725: mov eax, dword ptr [rsp + 0x14] 0x80bf729: mov dword ptr [rsp], eax 0x80bf72c: mov ecx, dword ptr [rsp + 0x18] 0x80bf730: mov dword ptr [rsp + 4], ecx 0x80bf734: mov dword ptr [rsp + 8], 0xd 0x80bf73c: call 0x804e530 0x80bf741: mov eax, dword ptr [rsp + 0xc] 0x80bf745: mov ecx, dword ptr [rsp + 0x14] 0x80bf749: add ecx, 0x10 0x80bf74c: mov dword ptr [rsp], ecx 0x80bf74f: mov dword ptr [rsp + 4], eax 0x80bf753: mov dword ptr [rsp + 8], 0x4c 0x80bf75b: call 0x804e530 0x80bf760: mov eax, dword ptr [rsp + 0xc] 0x80bf764: mov dword ptr [rsp + 0x1c], eax 0x80bf768: add esp, 0x10 0x80bf76b: ret 0x80bf76c: call 0x808fab0 0x80bf771: jmp 0x80bf710
SYMBOL type…eq.fmt.fmt 0x80bf780: mov ecx, dword ptr gs:[rip] 0x80bf787: mov ecx, dword ptr [rcx - 4] 0x80bf78d: cmp esp, dword ptr [rcx + 8] 0x80bf790: jbe 0x80bf7fd 0x80bf792: sub esp, 0x10 0x80bf795: mov eax, dword ptr [rsp + 0x18] 0x80bf799: mov ecx, dword ptr [rax] 0x80bf79b: mov edx, dword ptr [rsp + 0x14] 0x80bf79f: cmp dword ptr [rdx], ecx 0x80bf7a1: je 0x80bf7d4 0x80bf7a3: xor ecx, ecx 0x80bf7a5: test cl, cl 0x80bf7a7: jne 0x80bf7b3 0x80bf7a9: xor eax, eax 0x80bf7ab: mov byte ptr [rsp + 0x1c], al 0x80bf7af: add esp, 0x10 0x80bf7b2: ret 0x80bf7b3: lea ecx, [rdx + 0x10] 0x80bf7b6: mov dword ptr [rsp], ecx 0x80bf7b9: add eax, 0x10 0x80bf7bc: mov dword ptr [rsp + 4], eax 0x80bf7c0: mov dword ptr [rsp + 8], 0x4c 0x80bf7c8: call 0x8049e80 0x80bf7cd: movzx eax, byte ptr [rsp + 0xc] 0x80bf7d2: jmp 0x80bf7ab 0x80bf7d4: lea ecx, [rdx + 4] 0x80bf7d7: mov dword ptr [rsp], ecx 0x80bf7da: lea ecx, [rax + 4] 0x80bf7dd: mov dword ptr [rsp + 4], ecx 0x80bf7e1: mov dword ptr [rsp + 8], 9 0x80bf7e9: call 0x8049e80 0x80bf7ee: movzx ecx, byte ptr [rsp + 0xc] 0x80bf7f3: mov eax, dword ptr [rsp + 0x18] 0x80bf7f7: mov edx, dword ptr [rsp + 0x14] 0x80bf7fb: jmp 0x80bf7a5 0x80bf7fd: call 0x808fab0 0x80bf802: jmp 0x80bf780
SYMBOL main.main 0x80bf810: mov ecx, dword ptr gs:[rip] 0x80bf817: mov ecx, dword ptr [rcx - 4] 0x80bf81d: cmp esp, dword ptr [rcx + 8] 0x80bf820: jbe 0x80bf888 0x80bf822: sub esp, 0x28 0x80bf825: mov dword ptr [rsp], 3 0x80bf82c: call 0x804f420 0x80bf831: mov eax, dword ptr [rsp + 4] 0x80bf835: mov dword ptr [rsp + 0x20], 0 0x80bf83d: mov dword ptr [rsp + 0x24], 0 0x80bf845: lea ecx, [rip + 0x80d2220] 0x80bf84b: mov dword ptr [rsp + 0x20], ecx 0x80bf84f: mov dword ptr [rsp + 0x24], eax 0x80bf853: nop 0x80bf854: mov eax, dword ptr [rip + 0x8170db8] 0x80bf85a: lea ecx, [rip + 0x80fc760] 0x80bf860: mov dword ptr [rsp], ecx 0x80bf863: mov dword ptr [rsp + 4], eax 0x80bf867: lea eax, [rsp + 0x20] 0x80bf86b: mov dword ptr [rsp + 8], eax 0x80bf86f: mov dword ptr [rsp + 0xc], 1 0x80bf877: mov dword ptr [rsp + 0x10], 1 0x80bf87f: call 0x80ba2d0 0x80bf884: add esp, 0x28 0x80bf887: ret 0x80bf888: call 0x808fab0 0x80bf88d: jmp 0x80bf810
SYMBOL main.init 0x80bf890: mov ecx, dword ptr gs:[rip] 0x80bf897: mov ecx, dword ptr [rcx - 4] 0x80bf89d: cmp esp, dword ptr [rcx + 8] 0x80bf8a0: jbe 0x80bf8cc 0x80bf8a2: movzx eax, byte ptr [rip + 0x8181b66] 0x80bf8a9: cmp al, 1 0x80bf8ac: jbe 0x80bf8af 0x80bf8ae: ret 0x80bf8af: jne 0x80bf8b8 0x80bf8b1: call 0x806b350 0x80bf8b6: ud2 0x80bf8b8: mov byte ptr [rip + 0x8181b66], 1 0x80bf8bf: call 0x80bf6a0 0x80bf8c4: mov byte ptr [rip + 0x8181b66], 2 0x80bf8cb: ret 0x80bf8cc: call 0x808fab0 0x80bf8d1: jmp 0x80bf890
我如何才能找出在我的主函数中,`i := 3` 这一行分配了多少内存?这个反汇编代码虽然不错,但没有提供任何可读的信息。老实说,我也不懂汇编语言。更多关于Golang反汇编代码问题求助 [Capstone反汇编器]的实战教程也可以访问 https://www.itying.com/category-94-b0.html
并且,给定“rsp”,它位于栈的顶部。因此,本质上没有单独的内存分配。
更多关于Golang反汇编代码问题求助 [Capstone反汇编器]的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
0x80bf825: mov dword ptr [rsp], 3 是将 3 赋值给 i 的地方。
4 字节 包含此类不同大小字的数据结构分别将它们称为 WORD(16 位/2 字节)、DWORD(32 位/4 字节)和 QWORD(64 位/8 字节)。
顺便提一下,如果你不是必须使用Capstone,你可能会发现 Compiler Explorer 很有用。
它在你的浏览器中运行,网址是 https://godbolt.org/,可以在你输入代码时即时显示Go代码的反汇编结果。它允许你选择Go的版本,并且还支持许多其他语言。
如果你想为Go和其他语言使用Intel汇编语法,那么可以看看 PeachPy。它可以生成Go汇编文件以及其他功能。
在Go语言中,i := 3 这样的局部变量通常不会在堆上分配内存,而是直接在栈上分配。从反汇编代码可以看到,main.main函数中确实没有明显的堆内存分配调用。
查看main.main函数的反汇编代码:
SYMBOL main.main
0x80bf810: mov ecx, dword ptr gs:[rip]
0x80bf817: mov ecx, dword ptr [rcx - 4]
0x80bf81d: cmp esp, dword ptr [rcx + 8]
0x80bf820: jbe 0x80bf888
0x80bf822: sub esp, 0x28 ; 在栈上分配40字节空间
0x80bf825: mov dword ptr [rsp], 3 ; 将3存储到栈顶位置
关键的两行:
sub esp, 0x28- 在栈上分配40字节(0x28 = 40)的空间mov dword ptr [rsp], 3- 将值3存储到栈顶位置(rsp寄存器指向栈顶)
变量i被分配在栈上,占用4字节(dword = 32位 = 4字节)。整个函数栈帧分配了40字节,这是为了满足函数调用约定、对齐要求以及为其他临时变量预留空间。
如果你想验证Go编译器如何分配局部变量,可以查看编译器生成的SSA中间表示:
package main
import (
"fmt"
"os"
"os/exec"
)
func main() {
// 生成SSA中间表示
cmd := exec.Command("go", "build", "-gcflags", "-S", "main.go")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Run()
}
或者使用更详细的编译标志:
go build -gcflags="-m -m" main.go
这会输出编译器的优化决策,包括逃逸分析和内存分配信息。对于你的简单程序,输出会显示变量i没有逃逸到堆上,而是在栈上分配。
如果你想在运行时查看内存分配,可以使用runtime.ReadMemStats:
package main
import (
"fmt"
"runtime"
)
func main() {
var m1, m2 runtime.MemStats
runtime.ReadMemStats(&m1)
i := 3
runtime.ReadMemStats(&m2)
fmt.Println("Allocs:", m2.TotalAlloc - m1.TotalAlloc)
fmt.Println("Mallocs:", m2.Mallocs - m1.Mallocs)
fmt.Println("Frees:", m2.Frees - m1.Frees)
fmt.Println("HeapAlloc:", m2.HeapAlloc - m1.HeapAlloc)
fmt.Println(i)
}
对于i := 3,上述程序会显示0次堆分配,因为变量完全在栈上处理。

