Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd/cgo: Support functions in libgcc #3261

Closed
minux opened this issue Mar 9, 2012 · 15 comments
Closed

cmd/cgo: Support functions in libgcc #3261

minux opened this issue Mar 9, 2012 · 15 comments

Comments

@minux
Copy link
Member

minux commented Mar 9, 2012

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
Copy link
Member Author

minux commented Mar 9, 2012

Comment 1:

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
Copy link
Contributor

Comment 2:

Labels changed: added priority-go1, removed priority-triage.

@minux
Copy link
Member Author

minux commented Mar 10, 2012

Comment 3:

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
Copy link
Member Author

minux commented Mar 11, 2012

Comment 4:

Found the bug in cmd/ld/ldelf.c, this is caused by all functions symbols in objects in
libgcc has
visibility of hidden.
This has a trivial fix, and I guess it can be merged before Go 1, so I will continue
working on the
aforementioned approach.

@minux
Copy link
Member Author

minux commented Mar 14, 2012

Comment 5:

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
Copy link
Contributor

rsc commented Mar 14, 2012

Comment 6:

How did misc/cgo/test fail?

@minux
Copy link
Member Author

minux commented Mar 14, 2012

Comment 8:

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
Copy link
Member Author

minux commented Mar 14, 2012

Comment 9:

Update: this CL triggered a endless loop in cmd/6l when linking cmd/go and cmd/godoc on
Linux/amd64.
But it passed all tests on Mac OS X.
Why??

@minux
Copy link
Member Author

minux commented Mar 14, 2012

Comment 10:

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.203s

@ianlancetaylor
Copy link
Contributor

Comment 11:

A symbol named ".LC0" is normally a local symbol.  Each local symbol is specific to a
single object file, and should be used to resolve relocations in that file only.

@minux
Copy link
Member Author

minux commented Mar 14, 2012

Comment 12:

But how to deal with a object file with two .LC0 symbols?

@ianlancetaylor
Copy link
Contributor

Comment 13:

Ah, I see, generated by ld -r, presumably.  ELF relocations refer to symbol by index,
not name.  So there is nothing preventing the correct handling of a file with two local
symbols with the same name.  The name of a local symbol is irrelevant to the linker.

@minux
Copy link
Member Author

minux commented Mar 14, 2012

Comment 14:

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
Copy link
Contributor

rsc commented Mar 26, 2012

Comment 15:

I believe it is too late to make linker changes.
The libgcc support will have to wait until after Go 1.

Labels changed: added priority-later, removed priority-go1.

@minux
Copy link
Member Author

minux commented Aug 16, 2012

Comment 16:

This issue was closed by revision 551d8b9.

Status changed to Fixed.

This issue was closed.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants