cmd/cgo: Support functions in libgcc
minux opened this issue · 15 comments
minux commented
What steps will reproduce the problem?
1. this program gccbuiltin.go
package main
// int f(int x) { return __builtin_popcount(x); }
import "C"
func main() {
println(C.f(100))
}
2. go build gccbuiltin.go
What is the expected output? What do you see instead?
It should compile OK. But I get errors instead:
command-line-arguments
/tmp/go-build285777972/command-line-arguments.a(gccbuiltin.cgo2.)(.text): __popcountdi2:
not defined
__popcountdi2(0): not defined
Notes:
0. Discussion: http://groups.google.com/group/golang-dev/t/bf56f38944524389
1. this happens on Linux, FreeBSD and Windows (It doesn't fail on Mac OS X, because
libSystem includes libgcc.).
2. I use a gcc builtin to test this error, but this bug isn't caused by gcc builtin, it
is
caused by the general problem of gcc static linking libgcc by default.
3. We can fix this on FreeBSD and Linux quite easily, by providing -shared-libgcc to gcc.
But we can't fix this on Wndows this way, because libgcc isn't bundled with Windows.minux commented
A very simple resolution would be to copy all object files in libgcc.a into runtime/cgo.a. Quick debugging shows that this won't fix the bug: 1. cmd/ld disregard all undefined symbols in gcc compiled objects. 2. cmd/ld always link in all objects from an archive. If the above observations are correct, this approach won't work (at least before Go 1).
dsymonds commented
minux commented
Found a way to get the static linked object files names: gcc -Wl,-t popcnt.c (based on gccbuiltin.go) Sample output on Linux: /usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../lib64/crt1.o /usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../lib64/crti.o /usr/lib/gcc/x86_64-redhat-linux/4.1.2/crtbegin.o /tmp/ccybkK4V.o (/usr/lib/gcc/x86_64-redhat-linux/4.1.2/libgcc.a)_popcountsi2.o (/usr/lib/gcc/x86_64-redhat-linux/4.1.2/libgcc.a)_popcount_tab.o -lgcc_s (/usr/lib/gcc/x86_64-redhat-linux/4.1.2/libgcc_s.so) /lib64/libc.so.6 (/usr/lib64/libc_nonshared.a)elf-init.oS /lib64/ld-linux-x86-64.so.2 -lgcc_s (/usr/lib/gcc/x86_64-redhat-linux/4.1.2/libgcc_s.so) /usr/lib/gcc/x86_64-redhat-linux/4.1.2/crtend.o /usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../lib64/crtn.o Sample output on FreeBSD: /usr/bin/ld: mode elf_x86_64_fbsd /usr/lib/crt1.o /usr/lib/crti.o /usr/lib/crtbegin.o /var/tmp//cpXjI9Cv.o (/usr/lib/libgcc.a)popcountdi2.o -lgcc_s (/usr/lib/libgcc_s.so) -lc (/usr/lib/libc.so) -lgcc_s (/usr/lib/libgcc_s.so) /usr/lib/crtend.o /usr/lib/crtn.o Sample output on Windows: c:/mingw/bin/../lib/gcc/mingw32/4.6.2/../../../../mingw32/bin/ld.exe: mode i386pe c:/mingw/bin/../lib/gcc/mingw32/4.6.2/../../../crt2.o c:/mingw/bin/../lib/gcc/mingw32/4.6.2/crtbegin.o C:\Users\minux\AppData\Local\Temp\ccM49pK1.o (c:/mingw/bin/../lib/gcc/mingw32/4.6.2/../../../libmingw32.a)tlssup.o (c:/mingw/bin/../lib/gcc/mingw32/4.6.2/../../../libmingw32.a)CRTglob.o (c:/mingw/bin/../lib/gcc/mingw32/4.6.2/../../../libmingw32.a)CRTfmode.o (c:/mingw/bin/../lib/gcc/mingw32/4.6.2/../../../libmingw32.a)txtmode.o (c:/mingw/bin/../lib/gcc/mingw32/4.6.2/../../../libmingw32.a)cpu_features.o (c:/mingw/bin/../lib/gcc/mingw32/4.6.2/../../../libmingw32.a)CRT_fp10.o (c:/mingw/bin/../lib/gcc/mingw32/4.6.2/../../../libmingw32.a)pseudo-reloc.o (c:/mingw/bin/../lib/gcc/mingw32/4.6.2/../../../libmingw32.a)gccmain.o (c:/mingw/bin/../lib/gcc/mingw32/4.6.2/../../../libmingw32.a)crtst.o (c:/mingw/bin/../lib/gcc/mingw32/4.6.2/../../../libmingw32.a)tlsthrd.o (c:/mingw/bin/../lib/gcc/mingw32/4.6.2/../../../libmingw32.a)pseudo-reloc-list.o (c:/mingw/bin/../lib/gcc/mingw32/4.6.2/libgcc.a)_popcountsi2.o (c:/mingw/bin/../lib/gcc/mingw32/4.6.2/libgcc.a)_ctors.o (c:/mingw/bin/../lib/gcc/mingw32/4.6.2/libgcc.a)_popcount_tab.o (c:/mingw/bin/../lib/gcc/mingw32/4.6.2/../../../libmsvcrt.a)dcfls00266.o [ snip ] (c:/mingw/bin/../lib/gcc/mingw32/4.6.2/../../../libmsvcrt.a)dcflt.o (c:/mingw/bin/../lib/gcc/mingw32/4.6.2/../../../libkernel32.a)dchds01140.o [ snip ] (c:/mingw/bin/../lib/gcc/mingw32/4.6.2/../../../libkernel32.a)dchdt.o c:/mingw/bin/../lib/gcc/mingw32/4.6.2/crtend.o This works on Linux, FreeBSD and Windows (on Mac OS X, libgcc is contained in libSystem, so it worked out of the box). The only complication is, well, how to filter out objects that we don't want, esp. on Windows. I think we can use a library whitelist for now. (although these file are static linked, we require them to be compiled -fPIC, so this limits the generality of this approach. But I think it is OK for now.) Still need to diagnose why after I manually pack the required object files into runtime/cgo.a, the link still fails.
minux commented
minux commented
I've made some progress thanks to iant's suggestion. The new approach is: instead of trying to link all of gcc object files together by cmd/ld itself, we add a new step to cmd/go, which uses gcc to link them into a new relocatable object file, like these: gcc -Wl,-r -o all.o obj0.o obj1.o obj2.o -nostdlib -lgcc (-lmingwex -lmingw32) Any suggestions? I can successfully build & run misc/cgo/life now, but misc/cgo/test failed miserably. (http://golang.org/cl/5822049/)
Owner changed to @minux.
Status changed to Started.
rsc commented
minux commented
With this CL:
On windows/amd64:
misc/cgo/life build & run OK.
misc/cgo/test build OK, but SIGTRAP when run, stacktrace is:
(gdb) thread apply all bt
Thread 2 (Thread 261460.0x3fd70):
#0 0x000000007731fefa in ntdll!ZwWriteVirtualMemory ()
from C:\Windows\system32\ntdll.dll
#1 0x000007fefd3410ac in WaitForSingleObjectEx ()
from C:\Windows\system32\KernelBase.dll
#2 0x0000000000000000 in ?? ()
Thread 1 (Thread 261460.0x3fd20):
#0 runtime.morestack () at C:/go/go64.hg/src/pkg/runtime/asm_amd64.s:177
#1 0x000000000041013a in runtime.newstack ()
at C:/go/go64.hg/src/pkg/runtime/proc.c:1058
#2 0x00000000004192ad in reflect.call ()
at C:/go/go64.hg/src/pkg/runtime/asm_amd64.s:236
#3 0x000000000022ff18 in ?? ()
#4 0x0000000000000000 in ?? ()
On windows/386:
misc/cgo/life and misc/cgo/test all build, but fail to run due to SIGSEGV.
stracktrace of life.exe:
(gdb) thread apply all bt
Thread 2 (Thread 3376.0xd78):
#0 0x0042f49d in ?? ()
#1 0x7c80b713 in KERNEL32!GetModuleFileNameA ()
from C:\WINDOWS\system32\kernel32.dll
#2 0x00000000 in ?? ()
Thread 1 (Thread 3376.0xbe0):
#0 0x7c92e4f4 in ntdll!LdrAccessResource ()
from C:\WINDOWS\system32\ntdll.dll
#1 0x7c92df3c in ntdll!ZwWaitForSingleObject ()
from C:\WINDOWS\system32\ntdll.dll
#2 0x7c8025db in WaitForSingleObjectEx ()
from C:\WINDOWS\system32\kernel32.dll
#3 0x000007b0 in ?? ()
#4 0x00000000 in ?? ()
stacktrace of test.exe:
(gdb) thread apply all bt
Thread 2 (Thread 3200.0xf74):
#0 0x004749db in ?? ()
#1 0x7c80b713 in KERNEL32!GetModuleFileNameA ()
from C:\WINDOWS\system32\kernel32.dll
#2 0x00000000 in ?? ()
Thread 1 (Thread 3200.0xb0c):
#0 0x7c92e4f4 in ntdll!LdrAccessResource ()
from C:\WINDOWS\system32\ntdll.dll
#1 0x7c92df3c in ntdll!ZwWaitForSingleObject ()
from C:\WINDOWS\system32\ntdll.dll
#2 0x7c8025db in WaitForSingleObjectEx ()
from C:\WINDOWS\system32\kernel32.dll
#3 0x000007b0 in ?? ()
#4 0x00000000 in ?? ()
Something is very wrong with this CL, but I don't know what went wrong.
PS: cmd/go works OK on both systems with this CL.minux commented
minux commented
Found the cause for all the above troubles.
runtime/cgo can't use the gcc -Wl,-r approach. Why??
The endless loop is caused by two subsym having the same name (.LC0).
(I guess this is a real bug in cmd/ld, and should be fixed. but how to treat these
.LC0's?)
Updated the CL.
Now, misc/cgo/life build & run on both windows/386 and windows/amd64.
misc/cgo/test failed with these:
--- FAIL: TestHelpers (0.00 seconds)
basic.go:349: GoString: got "C: %#x %#x %#x %#x %#x %#x %#x\n", want "hello, world"
basic.go:349: GoStringN: got "C: %#", want "hello"
basic.go:349: GoBytes: got []byte{0x43, 0x3a, 0x20, 0x25, 0x23}, want []byte{0x68, 0x65, 0x6c, 0x6c, 0x6f}
FAIL
exit status 1
FAIL _/C_/go/go.hg/misc/cgo/test 1.203sianlancetaylor commented
minux commented
ianlancetaylor commented
minux commented
Found the bug mentioned in comment #10, it's a bit unrelated, so I filed issue #3322. I'm sure issue #3322 is causing the problem in comment #8. For the problem in comment #9, it's caused by two local symbol with the same name in one obj file. (they form a circle in sym->sub, and then trigger the endless loop in address().) Ha ha, this issue has provided us with at least 3 different issues to resolve.
rsc commented