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: misgenerated offsets when passing C-side arguments to winapi functions on windows/386 #8092

Closed
andlabs opened this issue May 24, 2014 · 15 comments
Milestone

Comments

@andlabs
Copy link
Contributor

andlabs commented May 24, 2014

package main
// #cgo LDFLAGS: -luser32
// #include <windows.h>
// CHAR *title = "Hi";
// CHAR *text = "There";
import "C"
func main() {
C.MessageBox(nil, C.title, C.text, C.MB_OK)
}

Windows XP shows a generic "this program has stopped working" dialog. In wine,
this results in

wine: Unhandled page fault on read access to 0x140d8b6c at address 0xf73f99c6 (thread
0009), starting debugger...

Disassembling wintest.exe as produced by cross-compiling on linux/amd64 in IDA reveals
that our main() function gets compiled to

.text:0040101C                 sub     esp, 14h
.text:0040101F                 mov     [esp+14h+var_14], 0
.text:00401026                 mov     ebx, off_45A090       ; correctly points to
another pointer which points to the "Hi" string
.text:0040102C                 mov     ebp, [ebx]
.text:0040102E                 mov     [esp+14h+var_10], ebp
.text:00401032                 mov     ebx, off_45A08C       ; incorrectly points to
0x401000, which is the address of main.main()!
.text:00401038                 mov     ebp, [ebx]
.text:0040103A                 mov     [esp+14h+var_C], ebp
.text:0040103E                 mov     [esp+14h+var_8], 0
.text:00401046                 call    sub_4010A0            ; main.main() in this case
was found and labelled manually; this is the __Cfunc_MessageBoxA the above produced

and the data:

.data:0045A08C off_45A08C      dd offset main_main     ; DATA XREF: main_main+32�r
.data:0045A090 off_45A090      dd offset off_45A0DC    ; DATA XREF: main_main+26�r

.data:0045A0DC off_45A0DC      dd offset aHi           ; DATA XREF: .data:off_45A090�o

What's more, the "There" string is still there, before the "Hi"
string:

.text:00440878                 db  54h ; T
.text:00440879                 db  68h ; h
.text:0044087A                 db  65h ; e
.text:0044087B                 db  72h ; r
.text:0044087C                 db  65h ; e
.text:0044087D                 db    0
.text:0044087E aHi             db 'Hi',0               ; DATA XREF: .data:off_45A0DC�o

Switching to calling MessageBoxA() directly doesn't fix this; it still fails to run. So
does switching to wide strings and MessageBoxW().

The same happens both on native Windows and when cross-compiling with wine. I also
disassembled a native Windows build; it has the same code (though the "Hi"
string seems to be missing; I'm probably doing something wrong and will re-evaluate when
this issue is fixed).

Windows cgo works fine; a simple program (println(C.WM_ACTIVATE)) works...

>rem windows
>go version
go version go1.3beta2 +aecdc70c44ac Fri May 23 17:39:58 2014 -0700 windows/386
>gcc --version
gcc (i686-win32-sjlj, Built by MinGW-W64 project) 4.8.2
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ # linux
$ go version
go version go1.3beta2 +aecdc70c44ac Fri May 23 17:39:58 2014 -0700 linux/amd64
$ i686-w64-mingw32-gcc --version
i686-w64-mingw32-gcc (GCC) 4.8.2
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Thanks.
@ianlancetaylor
Copy link
Contributor

Comment 1:

Labels changed: added repo-main, release-go1.3maybe, os-windows.

@andlabs
Copy link
Contributor Author

andlabs commented May 26, 2014

Comment 2:

Oh I think I get it: the main.main() is a red herring: the problem is /something/ is
taking text and using it to mean "the start of the text segment".
package main
// #include <stdio.h>
// char *data = "hello, ", *text = "world\n";
// void c(void) { printf("0x%p 0x%p\n", text, data); }
import "C"
func main() { println(C.text, C.data); C.c() }
pietro@pietro-laptop:/tmp/datatext$ GOOS=windows GOARCH=386 CGO_ENABLED=1 go run x.go 
fixme:process:SetProcessPriorityBoost (0xffffffff,1): stub
0x140d8b64 0x1
0x0044089B 0x004408A2
pietro@pietro-laptop:/tmp/datatext$ GOOS=linux GOARCH=amd64 CGO_ENABLED=1 go run x.go 
0xfffff0250c8b4864 0xffffffff00000001
0x0x42680f 0x0x426816
It looks like cgo is doing it. I don't know if it can be changed... or if it should be.
(The fixme: line is from wine and is a separate issue.)

@rsc
Copy link
Contributor

rsc commented May 27, 2014

Comment 3:

Labels changed: added release-go1.4, removed release-go1.3maybe.

Status changed to Accepted.

@alexbrainman
Copy link
Member

Comment 4:

Yes, I believe we have symbols named "data" and "text" that point to correspondent pe
sections during linking. I don't know, if these interfere with your C variables. I don't
know what cgo does with your variables - it must rename them to something. You could use
-x and -work flags when you build executable, then you will be able to have the exact
source that gets compiled. I would look at Go linker (cmd/ld/ldpe.c) to see what happens
to all those symbols. Perhaps some can be renamed so we don't get clashes.
Alex

@alexbrainman
Copy link
Member

Comment 5:

This is not windows specific problem. I can see the same issue on linux-386:
# cat main.go
package main
/*
#include <stdio.h>
char *data = "data", *text = "text", *alex = "alex";
void c(void) {
        printf("text=%s data=%s alex=%s\n", text, data, alex);
        printf("text=%p data=%p alex=%p\n", text, data, alex);
}
*/
import "C"
import "fmt"
func main() {
        C.c()
        fmt.Printf("text=%v data=%v alex=%v\n", C.text, C.data, C.alex)
}
# go run main.go
text=text data=data alex=alex
text=0x80c121f data=0x80c121a alex=0x80c1224
text=0xd8b65 data=0x29690001 alex=0x80c1224
Alex

Labels changed: removed os-windows.

@mdempsky
Copy link
Member

mdempsky commented Aug 7, 2014

Comment 6:

Looks like a collision between the symbols provided by cmd/ld/data.c:^address for use by
the "runtime" package and external C symbols we're trying to use.
The quick fix for the immediate issue would be to rename those symbols to
"runtime.text", "runtime.data", etc. and update the "runtime" package to use the new
names.  (Might be helpful in converting runtime C code to Go too?)
Beyond that, there's only a handful of global symbols in package runtime that are
unnamespaced (dropg, getprofile, and mheap_alloc_m), and it looks like they could all be
easily marked "static".

@mdempsky
Copy link
Member

mdempsky commented Aug 7, 2014

Comment 7:

I've prepared https://golang.org/cl/126790043/ that moves all linker defined
symbols (e.g., text, etext, data, ...) into package runtime (i.e., runtime.text,
runtime.etext, runtime.data, ...) to avoid conflicts with cgo symbols.  It also marks
the couple of C runtime functions mentioned as static, and it fixes the test case from
comment #5.
However, I'm running into an issue that regenerating the cmd/link/testdata files on
Linux causes the cmd/link tests to fail (even without my patch).  I want to investigate
what's going on there before mailing out the above CL.
Lastly, although it's a pretty straight forward change, it's still rather large.  So I
wonder if it's worth breaking into steps.  E.g., first just change ld to emit both
"text" and "runtime.text", then switch package runtime to use the "runtime.*" symbols,
then stop defining the old symbols.

@gopherbot
Copy link

Comment 8:

CL https://golang.org/cl/122250043 mentions this issue.

@alexbrainman
Copy link
Member

Comment 9:

SGTM re #7. CL 126790043 looks biggish to me. But I would wait for Go Team to confirm
your plan. Maybe even discuss it on go-dev. This change might affect many gophers.
Alex

@mdempsky
Copy link
Member

mdempsky commented Aug 8, 2014

Comment 10:

Thanks, I'll bring it up on golang-dev then.
And in case anyone's interested, I'm tracking the cmd/link/testdata issue in issue #8494.

@dvyukov
Copy link
Member

dvyukov commented Aug 8, 2014

Comment 11:

This issue was updated by revision 28cf62e.

LGTM=dvyukov
R=golang-codereviews, minux, dvyukov
CC=golang-codereviews
https://golang.org/cl/122250043
Committer: Dmitriy Vyukov 

@gopherbot
Copy link

Comment 12:

CL https://golang.org/cl/126790043 mentions this issue.

@rsc
Copy link
Contributor

rsc commented Aug 28, 2014

Comment 13:

This issue was closed by revision 2c110a1.

Status changed to Fixed.

@gopherbot
Copy link

Comment 14:

CL https://golang.org/cl/138770043 mentions this issue.

@ianlancetaylor
Copy link
Contributor

Comment 15:

This issue was updated by revision 43d4f93.

LGTM=iant, alex.brainman
R=rsc, iant, alex.brainman
CC=golang-codereviews
https://golang.org/cl/138770043
Committer: Ian Lance Taylor 

@rsc rsc added this to the Go1.4 milestone Apr 14, 2015
@rsc rsc removed the release-go1.4 label Apr 14, 2015
@golang golang locked and limited conversation to collaborators Jun 25, 2016
wheatman pushed a commit to wheatman/go-akaros that referenced this issue Jun 25, 2018
…ols into runtime package

Fixes golang#8092.

LGTM=rsc
R=iant, rsc
CC=golang-codereviews
https://golang.org/cl/126790043
wheatman pushed a commit to wheatman/go-akaros that referenced this issue Jul 9, 2018
…ols into runtime package

Fixes golang#8092.

LGTM=rsc
R=iant, rsc
CC=golang-codereviews
https://golang.org/cl/126790043
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

7 participants