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/compile: compiler variable folding can break linker's -X option #24890

Open
simonklb opened this Issue Apr 17, 2018 · 7 comments

Comments

Projects
None yet
5 participants
@simonklb

simonklb commented Apr 17, 2018

I'm facing a problem when I'm trying to set a variable at build time using the LDFLAG -X. The issue seem to occur because the compiler optimizes the variable into a constant since it's not being used in the package.

Here's a very simplfied code snippet that shows the issue:

package main

import "fmt"

var foo = "A"
var bar = foo

func main() {
	fmt.Println(bar)
}
% go build -ldflags "-X main.foo=B" test.go && ./test
A

If you change the bar variable initialization line to: var bar = foo + "" the output is as expected:

% go build -ldflags "-X main.foo=B" test.go && ./test
B

go version go1.10.1 linux/amd64

@tv42

This comment has been minimized.

tv42 commented Apr 17, 2018

As far as I can tell, a big part of the confusion is that -X will blindly succeed, whether such a variable exists or not. If it errored out, diagnosing things might be confusing, but at least you'd know..

Longer term, I feel like we'd be better off with a way of overriding constants not variables (and likely at package build time, not at link time).

@andybons andybons changed the title from LDFLAG -X doesn't work when variable is folded into constant to cmd/link: LDFLAG -X doesn't work when variable is folded into constant Apr 17, 2018

@andybons

This comment has been minimized.

Member

andybons commented Apr 17, 2018

@andybons andybons added this to the Unplanned milestone Apr 17, 2018

@ianlancetaylor ianlancetaylor changed the title from cmd/link: LDFLAG -X doesn't work when variable is folded into constant to cmd/compile: compiler variable folding can break linker's -X option Apr 17, 2018

@ianlancetaylor

This comment has been minimized.

Contributor

ianlancetaylor commented Apr 17, 2018

At least at first glance this does look like a compiler optimization. I'm not sure what to do about this. It seems a shame to disable a useful compiler optimization for the extremely rare case of using the linker's -X option.

CC @randall77 @josharian

@randall77

This comment has been minimized.

Contributor

randall77 commented Apr 17, 2018

In the original example the initialization of bar happens at compile time. When you add + "", then the initialization of bar happens at runtime. That is the cause of the effect you are seeing, as -X happens after compiling but before runtime.
The optimization involved isn't very important speed-wise, as it only affects init code. It may be pretty useful code-size-wise, though, there'd be a whole lot more init code if we disabled it.
The only real fix I see is to do this optimization in the linker. That sounds like a big change.

@randall77

This comment has been minimized.

Contributor

randall77 commented Apr 17, 2018

-X is a very weird beast anyway. How about this code:

package main

import "fmt"

func a() string {
	return "A"
}

var foo = a()
var bar = foo

func main() {
	fmt.Println(bar)
}

-X doesn't work on foo, as anything written to foo by -X will get overwritten by the runtime init code.

The reasonable workaround to the OP's problem is to wrap any use of a variable which might be -Xed in an identity function, like this:

package main

import "fmt"

func id(s string) string {
	return s
}

var foo = "A"
var bar = id(foo)

func main() {
	fmt.Println(bar)
}
@simonklb

This comment has been minimized.

simonklb commented Apr 17, 2018

Here's a version of the issue that is closer to the actual truth:

package main

import "github.com/spf13/cobra"

var version = "dev"

var cmd = &cobra.Command{
	Version: version,
}

func main() {
	cmd.Execute()
}
% go build -ldflags "-X main.version=1.0" test.go && ./test --version 
version dev

The way I worked around the issue now was to move the command initialization into the body of a function. For example this will yield the correct result:

package main

import "github.com/spf13/cobra"

var version = "dev"

func main() {
	var cmd = &cobra.Command{
		Version: version,
	}

	cmd.Execute()
}
% go build -ldflags "-X main.version=1.0" test.go && ./test --version
version 1.0

Perhaps you know of a more suitable way of setting the version other than using -X though?

@randall77

This comment has been minimized.

Contributor

randall77 commented Apr 18, 2018

You could use build tags.
I'd use a command-line flag for this, but it sounds like you want something build time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment