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

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

cmd/compile: compiler variable folding can break linker's -X option #24890

simonklb opened this issue Apr 17, 2018 · 7 comments
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Milestone

Comments

@simonklb
Copy link

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

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 LDFLAG -X doesn't work when variable is folded into constant cmd/link: LDFLAG -X doesn't work when variable is folded into constant Apr 17, 2018
@andybons
Copy link
Member

@ianlancetaylor

@andybons andybons added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Apr 17, 2018
@andybons andybons added this to the Unplanned milestone Apr 17, 2018
@ianlancetaylor ianlancetaylor changed the title cmd/link: LDFLAG -X doesn't work when variable is folded into constant cmd/compile: compiler variable folding can break linker's -X option Apr 17, 2018
@ianlancetaylor
Copy link
Contributor

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

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

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

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

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

@gopherbot gopherbot added the compiler/runtime Issues related to the Go compiler and/or runtime. label Jul 13, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler/runtime Issues related to the Go compiler and/or runtime. NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Projects
None yet
Development

No branches or pull requests

6 participants