Discussion:
objcopy behavior for --globalize-symbol and --keep-global-symbol (-G)
Jordan Rupprecht via binutils
2018-09-05 18:15:20 UTC
Permalink
As part of work on LLVM binutils, I've been spending time looking at
GNU objcopy. One thing I'm confused by is how --globalize-symbol and
--keep-global-symbol are supposed to work, especially when comparing
their documented effects vs reading the code.

My understanding from documentation is that --globalize-symbol is
supposed to promote a symbol to global visibility, and
--keep-global-symbol is supposed to localize all symbols except those
retained by --keep-global-symbol. However, the way it's written
(simplified for purposes of this thread) looks like this:

for (symbol *sym : symbols) {
flagword flags = sym->flags;
char* name = sym->name;

// If flag is global/weak, and --keep-global-symbol includes it,
// make it local
if ((flags & (GLOBAL | WEAK)) &&
(keep_globals.size() != 0 && !list_contains(keep_globals, name))) {
sym->flags &= ~(GLOBAL | WEAK);
sym->flags |= LOCAL;
}

// If flag is local and --globalize-symbol is set, make it global
// Note: checks flags, not sym->flags
if ((flags & LOCAL) && list_contains(globalize, name)) {
sym->flags &= ~LOCAL;
sym->flags |= GLOBAL;
}
}

The actual snippet I'm talking about is here:
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=blob;f=binutils/objcopy.c;h=6bd933993b39e9f4d3038d3045a1d4096705be3e;hb=HEAD#l1627

The two things I'd like to ask about this:

* Weak symbols are not globalized. --help/man pages never mention
this. Is this intentional?

* Supposing we had an object file with two globals, SomeGlobal and
SomeOtherGlobal, if one were to do "--globalize-symbol SomeGlobal
--keep-global-symbol SomeOtherGlobal", you might expect that both
SomeGlobal and SomeOtherGlobal are global in the output file... but it
isn't. Because --keep-global-symbol is set and doesn't include
SomeGlobal, SomeGlobal will be demoted to a local symbol. And because
the check to see if we should apply the --globalize-symbol flag checks
"flags" (the original flag set), and not "sym->flags", it decides not
to do anything, so SomeGlobal remains a local symbol. Although this is
a weird edge case, should this be changed so that --keep-global-symbol
implicitly keeps anything also specified via --globalize-symbol? (The
code seems technically correct with respect to the documentation, but
IMO the behavior is counter-intuitive).

Note that I haven't (yet) seen anyone actually try to use objcopy in
either of these ways, this is just something I've noticed from reading
documentation and code. I'm wondering if this behavior is intentional,
and if anyone is known to be relying on objcopy working this way.

Thanks -- Jordan
Nick Clifton
2018-09-17 14:56:24 UTC
Permalink
Hi Jordan,
Post by Jordan Rupprecht via binutils
As part of work on LLVM binutils, I've been spending time looking at
GNU objcopy. One thing I'm confused by is how --globalize-symbol and
--keep-global-symbol are supposed to work, especially when comparing
their documented effects vs reading the code.
To be fair, this code was never planned out fully, rather it grew organically...
Post by Jordan Rupprecht via binutils
* Weak symbols are not globalized. --help/man pages never mention
this. Is this intentional?
Yes. There is no such thing as a weak local symbol. (Well there shouldn't
be anyway). So when promoting from LOCAL to GLOBAL there is no need to also
check for WEAK.
Post by Jordan Rupprecht via binutils
* Supposing we had an object file with two globals, SomeGlobal and
SomeOtherGlobal, if one were to do "--globalize-symbol SomeGlobal
--keep-global-symbol SomeOtherGlobal", you might expect that both
SomeGlobal and SomeOtherGlobal are global in the output file... but it
isn't. Because --keep-global-symbol is set and doesn't include
SomeGlobal, SomeGlobal will be demoted to a local symbol. And because
the check to see if we should apply the --globalize-symbol flag checks
"flags" (the original flag set), and not "sym->flags", it decides not
to do anything, so SomeGlobal remains a local symbol.
All true.
Post by Jordan Rupprecht via binutils
Although this is
a weird edge case, should this be changed so that --keep-global-symbol
implicitly keeps anything also specified via --globalize-symbol? (The
code seems technically correct with respect to the documentation, but
IMO the behavior is counter-intuitive).
Actually I think that it should be an error to mix the two options.
However you code it, somebody is going to get confused about the behaviour
when both options are specified. Best to keep things simple and consider
the two options to be mutually exclusive.

Cheers
Nick
Jordan Rupprecht via binutils
2018-09-24 22:24:59 UTC
Permalink
Post by Nick Clifton
Hi Jordan,
Post by Jordan Rupprecht via binutils
As part of work on LLVM binutils, I've been spending time looking at
GNU objcopy. One thing I'm confused by is how --globalize-symbol and
--keep-global-symbol are supposed to work, especially when comparing
their documented effects vs reading the code.
To be fair, this code was never planned out fully, rather it grew organically...
All good software is :)
Post by Nick Clifton
Post by Jordan Rupprecht via binutils
* Weak symbols are not globalized. --help/man pages never mention
this. Is this intentional?
Yes. There is no such thing as a weak local symbol. (Well there shouldn't
be anyway). So when promoting from LOCAL to GLOBAL there is no need to also
check for WEAK.
Technically a weak symbol isn't global either though -- i.e. the
binding type is an enum of STB_LOCAL/STB_GLOBAL/STB_WEAK (plus enum
masks).

Still, I'm not sure why anyone would want to take a weak symbol and
make it global. Maybe someone would want to take an object file with a
weak symbol and make sure it's a link error to also include some other
object file that has that symbol as global? Anyway, it's purely
hypothetical.
Post by Nick Clifton
Post by Jordan Rupprecht via binutils
* Supposing we had an object file with two globals, SomeGlobal and
SomeOtherGlobal, if one were to do "--globalize-symbol SomeGlobal
--keep-global-symbol SomeOtherGlobal", you might expect that both
SomeGlobal and SomeOtherGlobal are global in the output file... but it
isn't. Because --keep-global-symbol is set and doesn't include
SomeGlobal, SomeGlobal will be demoted to a local symbol. And because
the check to see if we should apply the --globalize-symbol flag checks
"flags" (the original flag set), and not "sym->flags", it decides not
to do anything, so SomeGlobal remains a local symbol.
All true.
Post by Jordan Rupprecht via binutils
Although this is
a weird edge case, should this be changed so that --keep-global-symbol
implicitly keeps anything also specified via --globalize-symbol? (The
code seems technically correct with respect to the documentation, but
IMO the behavior is counter-intuitive).
Actually I think that it should be an error to mix the two options.
However you code it, somebody is going to get confused about the behaviour
when both options are specified. Best to keep things simple and consider
the two options to be mutually exclusive.
Agree, probably worth just making it an error (or at least a warning)
to use both flags.
Post by Nick Clifton
Cheers
Nick
Thanks!
-- Jordan
Nick Clifton
2018-10-02 14:32:48 UTC
Permalink
Hi Jordan,
Post by Jordan Rupprecht via binutils
Post by Nick Clifton
Post by Jordan Rupprecht via binutils
GNU objcopy. One thing I'm confused by is how --globalize-symbol and
--keep-global-symbol are supposed to work, especially when comparing
Actually I think that it should be an error to mix the two options.
Agree, probably worth just making it an error (or at least a warning)
to use both flags.
Would you care to create a patch to do this, and then submit it for
review ? (hint hint... :-) I am just very busy right now, so I do
not have time myself, but I do not want this issue to be dropped either.

Cheers
Nick

Loading...