What does _cgo_topofstack@@Base
mean in the context of a stripped binary coming from Go?
$ cat simple.go
package main
import
(
"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))
}
The code is supposed to be stripped - what does _cgo_topofstack@@Base
mean?
$ 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
EDIT (better specification of the question):
_cgo_topofstack@@Base
, and it is an objdump
(weird?) thing to add this (irrelevant and redundant) info_cgo_topofstack@@Base
is a symbol that does still exist for some reason in your stripped binary. Your call is to an address 0xe4c0
beyond that, whatever function lives there, completely unrelated to the actual _cgo_topofstack
code.
It's normal for disassemblers to describe addresses as symbol+offset.
That style makes sense for data arrays (e.g. compiling something like x = global_array[10]
into a load from global_array+40
, if the symbol for global_array
is still around), and for jumps within functions. It's usually not helpful for cases like this, other than to let you see what's nearby, and to have smaller numbers to look at.
Instead of implementing fancy logic to decide whether or not to bother printing a symbol+offset
version of an address, instead of just the numeric absolute address, it's much easier (and no risk of being wrong) for assemblers to just always do it. Search backward from the address and take the first symbol found. Or for addresses before the first symbol in a section, print as foo - 0x...
. It's up to humans to use judgement and experience to make sense of the output, especially when looking at disassembly of stripped binaries.
(There isn't a flag a disassembler can look at to detect a stripped binary or not; detecting this would be a matter of a heuristic like noticing that most direct call
targets are to addresses without their own symbol.)
AFAIK, GNU Binutils objdump
doesn't have an option not to print symbolic versions of addresses. --no-addresses
does something different.
I'm not sure what the @@Base
is about. It doesn't seem to be unique to Go, though. On my x86-64 Arch GNU/Linux system, objdump -d /bin/ls
(which is a stripped PIE executable) shows a lot of addresses as things like 22d60 <_obstack_memory_used@@Base+0xc2a0>
. So that's the symbol that happened to be last before the bulk of the code for that program.
Other cases of @@
include glibc symbol ABI versioning in that same binary, e.g. 23298 <optarg@@GLIBC_2.2.5>
. This Arch Linux binary was compiled on an up-to-date Arch Linux system, not actually linked against an ancient glibc 2.2.5, but I think that means optarg
's type or something hasn't changed since glibc 2.2.5. And probably not since earlier, but 2.2.5 might have been when glibc started naming symbols this way. Take this paragraph with a big grain of salt because I don't really know how libc.so
arranges for ld
to substitute symbol names like stderr
with these @@
versioned names, or the history of this.