为了账号安全,请及时绑定邮箱和手机立即绑定

_cgo_topofstack@@Base剥离的二进制文件中

_cgo_topofstack@@Base剥离的二进制文件中

Go
慕慕森 2022-09-12 17:08:49
在来自 Go 的剥离二进制文件中,这意味着什么?_cgo_topofstack@@Base$ cat simple.gopackage mainimport(    "net"    "time"    "strconv")func main() {    tcpAddr, _ := net.ResolveTCPAddr("tcp4", ":7777")    listener, _ := net.ListenTCP("tcp", tcpAddr)    conn, _ := listener.Accept()    daytime := time.Now().String()+strconv.Itoa(0xdeadface)    conn.Write([]byte(daytime))}代码应该被剥离 - 这是什么意思?_cgo_topofstack@@Base$ go build -gcflags=-l -ldflags "-s -w" -o simple_wo_symbols simple.go$ objdump -D -S simple_wo_symbols > simple_wo_symbols.human$ sed -n "198899,198904p" simple_wo_symbols.human  4b9860:   e8 db c1 fb ff          callq  475a40 <_cgo_topofstack@@Base+0xe4c0>  4b9865:   48 8b 44 24 18          mov    0x18(%rsp),%rax  4b986a:   48 89 44 24 70          mov    %rax,0x70(%rsp)  4b986f:   48 8b 4c 24 20          mov    0x20(%rsp),%rcx  4b9874:   48 89 4c 24 40          mov    %rcx,0x40(%rsp)  4b9879:   ba ce fa ad de          mov    $0xdeadface,%edx编辑(更好的问题规范):为什么这个符号存在于一个剥离的二进制文件中?批准 peter-cordes 声明:被调用的函数与 处的函数完全无关,添加此(不相关和多余的)信息是一件(奇怪的?)事情_cgo_topofstack@@Baseobjdump也许与此有关(?):有没有一种脱衣的惯用语?!
查看完整描述

2 回答

?
慕姐8265434

TA贡献1813条经验 获得超2个赞

_cgo_topofstack@@Base是一个符号,由于某种原因在剥离的二进制文件中仍然存在。你的调用是一个超出该地址的地址,无论函数位于该地址之外,与实际代码完全无关。0xe4c0_cgo_topofstack


拆装者将地址描述为符号+偏移量是正常的。


这种样式对于数据数组(例如,如果 符号 for 仍然存在,则将类似的东西编译为 来自 的负载)以及函数内的跳转是有意义的。对于这种情况,除了让你看到附近有什么,并且有较小的数字要查看之外,通常没有帮助。x = global_array[10]global_array+40global_array


与其实现花哨的逻辑来决定是否要打印地址的版本,而不仅仅是数字绝对地址,对于汇编程序来说,总是这样做要容易得多(并且没有出错的风险)。从地址向后搜索,并获取找到的第一个符号。或者,对于节中第一个符号之前的地址,打印为 。这取决于人类使用判断和经验来理解输出,特别是在查看剥离的二进制文件的反汇编时。symbol+offsetfoo - 0x...


(没有一个反汇编者可以查看的标志来检测剥离的二进制文件,检测这将是一个启发式的问题,就像注意到大多数直接目标是没有自己符号的地址一样。call


AFAIK,GNU二进制文件没有不打印符号版本的地址的选项。 做一些不同的事情。objdump--no-addresses


我不确定这是关于什么的。不过,这似乎并不是Go独有的。在我的 x86-64 架构 GNU/Linux 系统上,(这是一个剥离的 PIE 可执行文件)显示了很多地址,例如 .所以这是恰好在程序的大部分代码之前最后一个符号。@@Baseobjdump -d /bin/ls22d60 <_obstack_memory_used@@Base+0xc2a0>


其他情况包括同一二进制文件中的glibc符号ABI版本控制,例如.这个 Arch Linux 二进制文件是在最新的 Arch Linux 系统上编译的,实际上并没有与一个古老的 glibc 2.2.5 相关联,但我认为这意味着 的类型或自 glibc 2.2.5 以来没有改变过。可能不是从更早的时候开始的,但是2.2.5可能是glibc开始以这种方式命名符号的时候。对这一段持怀疑态度,因为我真的不知道如何安排用这些版本化名称来代替符号名称,或者这个的历史。@@23298 <optarg@@GLIBC_2.2.5>optarglibc.soldstderr@@


查看完整回答
反对 回复 2022-09-12
?
繁华开满天机

TA贡献1816条经验 获得超4个赞

关于它是什么,你可以看到它在Go 1.4中以当前的形式引入原始名称cgo_topofstack_cgo_topofstack

(但是,正如彼得·科德斯(Peter Cordes)评论中指出的那样,这并不能解释为什么该符号仍然存在于剥离的二进制文件中。)

// Called from cgo wrappers, this function returns g->m->curg.stack.hi.

// Must obey the gcc calling convention.

TEXT cgo_topofstack(SB),NOSPLIT,$0

    get_tls(CX)

    MOVL    g(CX), AX

    MOVL    g_m(AX), AX

    MOVL    m_curg(AX), AX

    MOVL    (g_stack+stack_hi)(AX), AX

    RET

这是为了修复戈兰/go/问题8771

cmd/cgo:返回值的 C 函数在调用复制堆栈的 Go 回调时失败

Cgo 使用调用 C 代码的包装器函数,传递堆栈帧的地址。
这个包装函数由GCC编译,它调用用户编写的真实函数。

允许用户的函数调用 Go 回调。
这些 Go 回调将在原始调用方的堆栈上运行。
它们可能会导致堆栈复制。

如果在 Go 回调期间复制堆栈,则 GCC 编译的包装器的调用方正在其他位置运行。
GCC 编译的包装器使用的堆栈帧指针不会更新,因为堆栈复制器当然对 GCC 编译的代码一无所知。
我不认为这对函数的参数来说是一个问题;当包装器调用 real 函数时,它们已经被复制出堆栈帧。

但是,对于返回值的 C 函数来说,这是一个问题。
包装器将获取 C 函数返回的值,并使用其指向堆栈帧的指针存储该值。如果发生堆栈复制,则该指针将不会更新。
换句话说,包装器可以将返回值存储在旧堆栈上,而不是新堆栈上。

CL 144130043添加:

cgo:调整返回值位置以考虑堆栈副本。

在 cgo 调用期间,可以复制堆栈。
此副本使 cgo 在返回值区域中具有的指针失效。

要解决此问题,请传递包含堆栈顶部值的位置的地址(位于 G 结构中)。
对于返回值的 cgo 函数,请在 cgo 调用之前和之后读取 stktop,以计算写入返回值所需的调整。

它已使用提交e1364a6进行了修订。


“@@”部分应该是服从选项的结果--symbols

显示文件的符号表部分中的条目(如果有)。
如果符号具有与之关联的版本信息,则也会显示此信息。

版本字符串显示为符号名称的后缀,前面带有一个字符。例如。@foo@VER_1

如果版本是解析对符号的不受版本控制的引用时要使用的默认版本,则它将显示为以两个字符开头的后缀。例如。@foo@@VER_2


查看完整回答
反对 回复 2022-09-12
  • 2 回答
  • 0 关注
  • 121 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号