STV_PROTECTED clarification / corrections

285 views
Skip to first unread message

joerg.son...@googlemail.com

unread,
Apr 10, 2016, 2:43:45 PM4/10/16
to Generic System V Application Binary Interface
Hello all,
the recent changes in GNU binutils to x86 relocation handling for STV_PROTECTED made me investigate the GCC bug reports by H.J. and the associated changes. After investigating and trying similar changes for LLVM, I've found that the gABI rules seem to be oddly inconsistent. It is my understanding that the goal of STV_PROTECTED is to provide externally visible symbols which are still fully resolved locally, i.e. can't be interposed by other objects. In this regard, it behaves like a per-symbol version of DT_SYMBOLIC.

The implication here is that copy relocations must be not be created against protected symbols, so code generators and link editors have to be aware of protected symbols, especially when creating non-PIC output. If they have such awareness, they can create access via the GOT and associated relocations. This brings me to the first issue. In the paragraph after STV_INTERNAL's definition in chapter 4, the following is found:

First, all of the non-default visibility attributes,
when applied to a symbol reference, imply that a definition
to satisfy that reference must be provided within the current
executable or shared object.

This restriction is currently enforced by GNU binutils and seems to be artificial and unnecessary. As written above, a code generator has to know whether a symbol is defined as protected or not to create correct references.
With this restriction, it would be forced to forget this knowledge if no definition exists, making it harder to check for consistent declarations in output. The restriction seems wrong as protected symbol definitions are still publically visible and therefore usable from other objects. I believe the original intention is better served by restriction this to "hidden or internal" visibility.

This brings me to the next enumeration item:

If different visibility attributes are specified for
distinct references to or definitions of a symbol,
the most constraining visibility attribute must be
propagated to the resolving symbol in the linked object.
The attributes, ordered from least to most constraining,
are: STV_PROTECTED, STV_HIDDEN and STV_INTERNAL.

It is perfectly sensible for an object to have a protected definition of a symbol and hidden references. Since all references to that symbol are resolved locally, hidden is perfectly sensible as access mode as it can allow more efficient code generation on architectures with complex addressing modes. While I don't know what exactly the behavior of STV_INTERNAL should be, for the rest is seems to be better to distinguish between definitions and references. References should never override definitions. This gives the following combinations:
- default definition, non-default reference: error
- (local) protected definition: any reference is valid, result is protected
- mix of default and protected references to undefined symbol: result could be either protected or default.
I'm not sure which case is better for the last point, I would certainly consider erroring out valid as well.

Summary: it should be valid to create hidden references, even if the object contains no definition. Hidden references to a protected definition should not change the visibility in the resulting object.

Regards,
Joerg Sonnenberger

Cary Coutant

unread,
Apr 11, 2016, 3:17:18 AM4/11/16
to gener...@googlegroups.com
> The implication here is that copy relocations must be not be
> created against protected symbols, so code generators and link
> editors have to be aware of protected symbols, especially when
> creating non-PIC output. If they have such awareness, they can
> create access via the GOT and associated relocations. This brings
> me to the first issue. In the paragraph after STV_INTERNAL's
> definition in chapter 4, the following is found:
>
> First, all of the non-default visibility attributes,
> when applied to a symbol reference, imply that a definition
> to satisfy that reference must be provided within the current
> executable or shared object.
>
> This restriction is currently enforced by GNU binutils and seems
> to be artificial and unnecessary. As written above, a code
> generator has to know whether a symbol is defined as protected or
> not to create correct references. With this restriction, it would
> be forced to forget this knowledge if no definition exists,
> making it harder to check for consistent declarations in output.
> The restriction seems wrong as protected symbol definitions are
> still publically visible and therefore usable from other objects.
> I believe the original intention is better served by restriction
> this to "hidden or internal" visibility.

I'm not sure I understand your reasoning here; I think you might be
misreading what the gABI says. Certainly, if we have a reference to a
protected or hidden symbol, by definition, we must have a definition
of that symbol somewhere within the same load module (what the gABI
refers to as a "component" -- i.e., an executable or a shared object).
It does not say that the definition must be provided within the same
translation unit (i.e., a relocatable object).

> This brings me to the next enumeration item:
>
> If different visibility attributes are specified for
> distinct references to or definitions of a symbol,
> the most constraining visibility attribute must be
> propagated to the resolving symbol in the linked object.
> The attributes, ordered from least to most constraining,
> are: STV_PROTECTED, STV_HIDDEN and STV_INTERNAL.
>
> It is perfectly sensible for an object to have a protected
> definition of a symbol and hidden references. Since all
> references to that symbol are resolved locally, hidden is
> perfectly sensible as access mode as it can allow more efficient
> code generation on architectures with complex addressing modes.
> While I don't know what exactly the behavior of STV_INTERNAL
> should be, for the rest is seems to be better to distinguish
> between definitions and references. References should never
> override definitions. This gives the following combinations:
> - default definition, non-default reference: error
> - (local) protected definition: any reference is valid, result is protected
> - mix of default and protected references to undefined symbol: result could be either protected or default.
> I'm not sure which case is better for the last point, I would
> certainly consider erroring out valid as well.

You may have a reasonable suggestion here, but I think it's going to
take some compelling arguments to change the rules now. In my opinion,
good programming practices would ensure that each symbol is declared
consistently across all uses, and I'd be happy to require exact
matches, but that's probably unrealistic. I'd like to think we had
some good reasons to pick the rules we did, but I really don't
remember that far back -- I'll have to dig through some really old
email (unfortunately, most of the gABI discussions at the time were
conference calls, so all I have to dig through are notes and follow-up
discussions from those calls). Maybe someone else on this list
remembers better than I do. Maybe we didn't really consider
alternatives, but just adopted existing SGI behavior (which is where
the idea of visibility came from).

After some further thought, I'm thinking it may have something to do
with the SGI treatment of STV_INTERNAL, where it really did matter
that a reference marked internal would force a definition to also be
marked internal.

I'll try to find some time to dig through that old email and come up
with a better answer for you, if no one else does first.

It's funny to me that after more than 15 years, suddenly protected
symbols and pre-emption seem to be such a hot topic. I'm curious why
-- what's going on that has brought this tiny little corner case to
such a head?

-cary

joerg.son...@googlemail.com

unread,
Apr 11, 2016, 2:24:02 PM4/11/16
to Generic System V Application Binary Interface


On Monday, April 11, 2016 at 9:17:18 AM UTC+2, Cary wrote:
I'm not sure I understand your reasoning here; I think you might be
misreading what the gABI says. Certainly, if we have a reference to a
protected or hidden symbol, by definition, we must have a definition
of that symbol somewhere within the same load module (what the gABI
refers to as a "component" -- i.e., an executable or a shared object).
It does not say that the definition must be provided within the same
translation unit (i.e., a relocatable object).

I'm talking about the component, not the translation unit. Why must a protected symbol be defined in the same component? It is exported after all. It seems quite strange that a code generator or assembler has to drop the visibility knowledge when creating a reference to something outside the current component, which it normally has no chance of knowing.
 

Well, without the first point about not requiring definitions, the point is mood. I still think never changing the visibility of a declaration is important and being able to mix normal and hidden references can be useful.

It's funny to me that after more than 15 years, suddenly protected
symbols and pre-emption seem to be such a hot topic. I'm curious why
-- what's going on that has brought this tiny little corner case to
such a head?

One side are functions using global locales that can simplify a lot when getting the hidden threatment. Another side are larger C++ programs, where the reduction in relocations is significant. Qt5 recentish got a somewhat hackish option to build with -Bsymbolic for a similar gain. Better handling of protected symbols would allow the same advantage in a much more controlled manor. Given the work on a proper module system in C++ in general, it is likely to become more useful in the near future from that perspective as  well.

Joerg

Suprateeka R Hegde

unread,
Apr 11, 2016, 3:44:22 PM4/11/16
to gener...@googlegroups.com
On 11-Apr-2016 11:54 PM, joerg.sonnenberger via Generic System V
Application Binary Interface wrote:
>
>
> On Monday, April 11, 2016 at 9:17:18 AM UTC+2, Cary wrote:
>
> I'm not sure I understand your reasoning here; I think you might be
> misreading what the gABI says. Certainly, if we have a reference to a
> protected or hidden symbol, by definition, we must have a definition
> of that symbol somewhere within the same load module (what the gABI
> refers to as a "component" -- i.e., an executable or a shared object).
> It does not say that the definition must be provided within the same
> translation unit (i.e., a relocatable object).
>
>
> I'm talking about the component, not the translation unit. Why must a
> protected symbol be defined in the same component?

Because the protection should not interfere with other components (load
modules). For instance, a shared library might have its own
implementation of a memory allocator, and not use libc. Another shared
library linked to the same exe may need the libc allocator. In this
case, protection (and hence preemption) cannot be at the global exe
level. Unless you use techniques like RTLD_GROUP or shared library load
groups, which are non-standard (AFAIK).

> It is exported after
> all.

Its a side effect in a way. If you dont want, use STV_HIDDEN that would
eventually become STB_LOCAL.

> It seems quite strange that a code generator or assembler has to
> drop the visibility knowledge when creating a reference to something
> outside the current component, which it normally has no chance of knowing.

LTO should be able to handle this?

Based on the discussion, I tend to understand your requirement is to get
the optimizations of hidden references, but still get the visibility
outside so that other load modules can use the definition. Am I right?

To me it looks like a very corner case and falls under the category of
peep hole optimizations that compilers can handle through LTOs.

I cant think of any other use case as STV_HIDDEN and STV_PROTECTED have
well defined semantics and a good developer should know when to use what.

If you think my understanding is wrong, please consider explaining the
concerns with some simple code snippets? That would be very good and
helpful.

For instances,
1. I am not clear about your point "(local) protected..." because
"local" is a binding (STB) and protected is a visibility (STV). And
local to translation unit? load module? etc.
2. You say "...valid to create hidden references, even if the object
contains no definition...". What is object here? Relocatable or load
module? If relocatable, is it from a single translation unit? Or a "ld
-r" (link multiple relocatable to create a single relocatable) kind of link?
3. The usage of word "interpose" in the beginning. I assumed you meant
preemption.
4. And more...

This is a very core area and has been quite stable for decades now ( at
least as I see on HP-UX, Solaris and AIX). Any change would need a very
clear test-case based explanation.

--
Supra
> --
> You received this message because you are subscribed to the Google
> Groups "Generic System V Application Binary Interface" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to generic-abi...@googlegroups.com
> <mailto:generic-abi...@googlegroups.com>.
> To post to this group, send email to gener...@googlegroups.com
> <mailto:gener...@googlegroups.com>.
> Visit this group at https://groups.google.com/group/generic-abi.
> For more options, visit https://groups.google.com/d/optout.

Cary Coutant

unread,
Apr 11, 2016, 5:22:02 PM4/11/16
to gener...@googlegroups.com
>> I'm not sure I understand your reasoning here; I think you might be
>> misreading what the gABI says. Certainly, if we have a reference to a
>> protected or hidden symbol, by definition, we must have a definition
>> of that symbol somewhere within the same load module (what the gABI
>> refers to as a "component" -- i.e., an executable or a shared object).
>> It does not say that the definition must be provided within the same
>> translation unit (i.e., a relocatable object).
>
> I'm talking about the component, not the translation unit. Why must a
> protected symbol be defined in the same component? It is exported after all.

I guess I still don't understand what you're getting at. It must be
defined in the same component because that's the *definition* of
"protected". If you drop that requirement, protected visibility means
nothing.

> It seems quite strange that a code generator or assembler has to drop the
> visibility knowledge when creating a reference to something outside the
> current component, which it normally has no chance of knowing.

Again, I don't understand. What do you mean by "drop the visibility knowledge"?

-cary

joerg.son...@googlemail.com

unread,
Apr 11, 2016, 6:17:36 PM4/11/16
to Generic System V Application Binary Interface
On Monday, April 11, 2016 at 11:22:02 PM UTC+2, Cary wrote:
>> I'm not sure I understand your reasoning here; I think you might be
>> misreading what the gABI says. Certainly, if we have a reference to a
>> protected or hidden symbol, by definition, we must have a definition
>> of that symbol somewhere within the same load module (what the gABI
>> refers to as a "component" -- i.e., an executable or a shared object).
>> It does not say that the definition must be provided within the same
>> translation unit (i.e., a relocatable object).
>
> I'm talking about the component, not the translation unit. Why must a
> protected symbol be defined in the same component? It is exported after all.

I guess I still don't understand what you're getting at. It must be
defined in the same component because that's the *definition* of
"protected". If you drop that requirement, protected visibility means
nothing.

If you just take the definition of STV_PROTECTED, it only talks about defined symbols. That part is fine. In the newer versions of GABI it even mentions how to SHN_UNDEF. The real problem for me is the enumeration afterwards. The first part seems to directly contradict the definition, since if SHN_UNDEF is not possible, what's the point of changing STV_PROTECTED to STV_DEFAULT for undefined symbol table entries?

Joerg

joerg.son...@googlemail.com

unread,
Apr 11, 2016, 6:58:50 PM4/11/16
to Generic System V Application Binary Interface, hegdes...@gmail.com


On Monday, April 11, 2016 at 9:44:22 PM UTC+2, Supra wrote:
On 11-Apr-2016 11:54 PM, joerg.sonnenberger via Generic System V
> I'm talking about the component, not the translation unit. Why must a
> protected symbol be defined in the same component?

Because the protection should not interfere with other components (load
modules). For instance, a shared library might have its own
implementation of a memory allocator, and not use libc. Another shared
library linked to the same exe may need the libc allocator. In this
case, protection (and hence preemption) cannot be at the global exe
level. Unless you use techniques like RTLD_GROUP or shared library load
groups, which are non-standard (AFAIK).

Sorry, but none of this seems to be relevant to the case of STV_PROTECTED. It doesn't stop another component from using a hidden implementation. It does require that another component wanting to use the protected symbol to:
(1) Not copy data with copy relocations.
(2) Not refer to the PLT as canonical address when function address identity has to be preserved.
 
This is normally the case for position independent code, but not necessarily the case for the main executable.


> It is exported after
> all.

Its a side effect in a way. If you dont want, use STV_HIDDEN that would
eventually become STB_LOCAL.

The export is intended and the half of the point of the whole exercise in first place.
 

> It seems quite strange that a code generator or assembler has to
> drop the visibility knowledge when creating a reference to something
> outside the current component, which it normally has no chance of knowing.

LTO should be able to handle this?

Not really, it is only handled in the sense that the behavior is explicitly specified for the linker. It's arguable still a loss of information, but mostly harmless.
 

Based on the discussion, I tend to understand your requirement is to get
the optimizations of hidden references, but still get the visibility
outside so that other load modules can use the definition. Am I right?

Correct.
 

To me it looks like a very corner case and falls under the category of
peep hole optimizations that compilers can handle through LTOs.

I don't see how LTO is at all relevant here. At best it can automatically decide what symbols must be handled as external, it can't automatically handle the reverse.
 

I cant think of any other use case as STV_HIDDEN and STV_PROTECTED have
well defined semantics and a good developer should know when to use what.

The problem is that the side constraints for non-default visibility for references to undefined symbols seem to be inconsistent and/or contradictory.
 

If you think my understanding is wrong, please consider explaining the
concerns with some simple code snippets? That would be very good and
helpful.

The example that triggered this is the explicit locale support in NetBSD. For functions like isalpha_l, it is highly useful to provide a constant reference to the C locale. Let's say this is done by the LC_C_LOCALE symbol. It is exported from libc, so it must have either default or protected visibility. It is highly useful for this symbol to have protected visibility:
(1) Copy relocations would leak the size of the underlaying storage into the ABI contract.
(2) It allows libc consumers more efficient access.
Similar constraints exist for the current global process locale, which is even more performance sensitive.

Let's now look at the main executable. One source file contains a reference to this symbol. The compiler knows (i.e. due to visibility attribute) that it is referencing a protected symbol. It can generate the appropriate code with GOT reference. It does not know if the main binary will contain the definition of the symbol or if it is supplied externally. At the moment, it would have to emit the symbol table entry with default visibility (and therefore hide its own knowledge) because the symbol references with non-default visibility must be provided in the executable.

This directly brings me to the second enumeration item: in libc, a mix of protected (the definition) and default (all other references) symbol table entries exist for the same symbol. Now it would be useful to be able to declare the symbol with hidden visibility internally, so that direct references can be created. But that doesn't play with the propagation of "most restrictive" visibility, since it would override the definition. So deal with that, yet another internal visibility for the code generator would have to be invented (protected, but defined in the component), when the mix of hidden reference to protected definition already clearly expresses the meaning.

Joerg

Jim Dehnert

unread,
Apr 12, 2016, 3:05:33 AM4/12/16
to gener...@googlegroups.com
On Mon, Apr 11, 2016 at 2:22 PM, Cary Coutant <ccou...@gmail.com> wrote:
>> I'm not sure I understand your reasoning here; I think you might be
>> misreading what the gABI says. Certainly, if we have a reference to a
>> protected or hidden symbol, by definition, we must have a definition
>> of that symbol somewhere within the same load module (what the gABI
>> refers to as a "component" -- i.e., an executable or a shared object).
>> It does not say that the definition must be provided within the same
>> translation unit (i.e., a relocatable object).
>
> I'm talking about the component, not the translation unit. Why must a
> protected symbol be defined in the same component? It is exported after all.

I guess I still don't understand what you're getting at. It must be
defined in the same component because that's the *definition* of
"protected". If you drop that requirement, protected visibility means
nothing.

That's correct.  The intent of protected symbols (and hidden/internal symbols)  is to allow the code generator to generate code or relocations that can assume a definition in the same component.  There were at least two cases that I recall motivating this at the time:
  • The ability to emit a data object (often constant after initialization) with values depended upon inside the component, with a guarantee that the internal definition would be the one resolving the internal references, even though it might also be usefully referenced outside the component.  The locale example given later is typical.
  • The ability to emit code with a guarantee that it references an internal object, perhaps to do something like a position-dependent reference that doesn't need to be relocated at runtime.
If you allow the definition to be preempted outside the component, you no longer have the guarantee that was the purpose of the definition.

> It seems quite strange that a code generator or assembler has to drop the
> visibility knowledge when creating a reference to something outside the
> current component, which it normally has no chance of knowing.

Again, I don't understand. What do you mean by "drop the visibility knowledge"?

I think Joerg is thinking in terms of a reference occurring outside the defining component, that happens to "know" that the ultimate resolving definition was defined as protected.  If such a reference were declared protected, that would imply that the symbol being referenced be defined inside its own component.

So, that's the wrong way to use (or think about) this feature.  In general, the intent was that symbol definitions would be marked protected if the component needs them to be so, or else specific references that require protection would do so.  In general, references to a symbol should never be marked with these attributes unless they require them.  The attributes should not propagate to other references, only to the resolving definition _in the same component_.  (The original SGI implementation of this feature used pragmas to mark particular symbol instances in particular translation units, not symbol attributes appearing in global header files.  The latter approach might be what is causing Joerg grief here.)

If you think about this feature in terms of  the attributes specifying requirements that internal references depend on, then the progression rule that says to use the most restrictive requirement that occurs in a component should make more sense (default < protected < hidden < internal).  You only get one choice for the attribute in a component, and you need the strongest restriction that any internal reference depends upon.  It might make some sense to forbid some combinations, but we decided at the time to instead specify a simple resolution rule and leave it up to implementations to use it as they liked.  A language translator or linker would be within its rights IMO to reject some combinations, but it is simply broken if it allows preemption of a protected symbol outside the defining component.

These attributes are all about within-component requirements, so the needs of references outside the component don't count -- they shouldn't be specifying any of them unless they intend to refer to a symbol definition within their own component.

Jim

-cary

--
You received this message because you are subscribed to the Google Groups "Generic System V Application Binary Interface" group.
To unsubscribe from this group and stop receiving emails from it, send an email to generic-abi...@googlegroups.com.
To post to this group, send email to gener...@googlegroups.com.



--
--
             Jim Dehnert
             deh...@gmail.com
             dehn...@acm.org

Cary Coutant

unread,
Apr 13, 2016, 12:20:20 PM4/13/16
to gener...@googlegroups.com, Suprateeka R Hegde
> The example that triggered this is the explicit locale support in NetBSD.
> For functions like isalpha_l, it is highly useful to provide a constant
> reference to the C locale. Let's say this is done by the LC_C_LOCALE symbol.
> It is exported from libc, so it must have either default or protected
> visibility. It is highly useful for this symbol to have protected
> visibility:
> (1) Copy relocations would leak the size of the underlaying storage into the
> ABI contract.
> (2) It allows libc consumers more efficient access.
> Similar constraints exist for the current global process locale, which is
> even more performance sensitive.
>
> Let's now look at the main executable. One source file contains a reference
> to this symbol. The compiler knows (i.e. due to visibility attribute) that
> it is referencing a protected symbol. It can generate the appropriate code
> with GOT reference. It does not know if the main binary will contain the
> definition of the symbol or if it is supplied externally. At the moment, it
> would have to emit the symbol table entry with default visibility (and
> therefore hide its own knowledge) because the symbol references with
> non-default visibility must be provided in the executable.

Ah, here is the fundamental point that you're misunderstanding, and
it's exactly what Jim suspected. If a symbol is known to be defined in
libc, it should be declared protected only when compiling code for
libc. When you're compiling for the main executable, you cannot use
protected visibility because the symbol is not defined in the main
program. (An alternate attribute, one that says the symbol is known to
be external to the component, would be useful here. Sun proposed an
extension, STV_EXTERNAL, a few years ago, but it doesn't really need
to be recorded in the symbol table. Microsoft uses declspec(dllimport)
and HP uses #pragma external for this purpose. Those tell the compiler
that it should generate a PIC reference even when otherwise generating
non-PIC code.)

Typically, a library will add the protected visibility attributes only
in internal header files that are used when building the library, so
that code using the public header files will not see that attribute.
Alternatively, the attribute might be conditionally defined by an
ifdef like this:

#ifdef BUILDING_LIBC
#define VISIBILITY_PROTECTED __attribute__ ((visibility ("protected")))
#else
#define VISIBILITY_PROTECTED /* maybe: __attribute__ ((dllimport)) */
#endif

and you would set -DBUILDING_LIBC when compiling code for the shared library.

> This directly brings me to the second enumeration item: in libc, a mix of
> protected (the definition) and default (all other references) symbol table
> entries exist for the same symbol. Now it would be useful to be able to
> declare the symbol with hidden visibility internally, so that direct
> references can be created. But that doesn't play with the propagation of
> "most restrictive" visibility, since it would override the definition. So
> deal with that, yet another internal visibility for the code generator would
> have to be invented (protected, but defined in the component), when the mix
> of hidden reference to protected definition already clearly expresses the
> meaning.

You don't need hidden for that, nor do you need a new visibility.
"Protected" means exactly that -- defined in the component, and
protected from pre-emption.

-cary

Rod Evans

unread,
Apr 13, 2016, 2:07:45 PM4/13/16
to gener...@googlegroups.com, Suprateeka R Hegde
As a side note, as this thread has talked about copy relocations,
we diagnose that they might be compromised. If I create two data
items in a shared object:

   % elfdump -sN.dynsym libfoo.so.1 | grep _str
       [4] 0x105e0   0x13 OBJT GLOB  D   0  .data      writable_str
       [7] 0x588       0x14 OBJT GLOB  D   0  .rodata   readonly_str

And reference these when building an executable, I get the normal
copy relocations:

   % cc -o main.1 main.o -R. libfoo.so.1
   % elfdump -r main.1 | grep _str
       [0] R_386_COPY  0x8060d5c  0 .bss    writable_str
       [1] R_386_COPY  0x8060d6f   0 .bss    readonly_str

Now if I define the data items in the shared object as protected,
note the 'P':

   % elfdump -sN.dynsym libfoo.so.2 | grep _str
       [4] 0x105e0   0x13 OBJT GLOB  P    0  .data      writable_str
       [7] 0x588       0x14 OBJT GLOB  P    0  .rodata     readonly_str

And reference these when building an executable, I get the normal
copy relocations, but also a warning:

   % cc -o main.2 main.o -R. libfoo.so.2
   ld: warning: relocation warning: R_386_COPY: file libfoo.so.2: \
       symbol readonly_str: relocation bound to a symbol with \
       STV_PROTECTED visibility
   ld: warning: relocation warning: R_386_COPY: file libfoo.so.2: \
       symbol writable_str: relocation bound to a symbol with \
       STV_PROTECTED visibility
   % elfdump -r main.2 | grep _str
      [0] R_386_COPY  0x8060d5c   0   .bss    writable_str
      [1] R_386_COPY  0x8060d6f    0   .bss    readonly_str

I guess it could be argued that the read only data (.rodata) in
the shared object doesn't need a diagnostic, as the library can't
write to it, and potentially get out-of-sync with the a.out. But
we've not made that refinement, and of course the copy is in .bss
and could be corrupted by the a.out regardless.

We also make some noise at runtime. Folks don't generally like
warnings from the runtime linker (they ask for ways to shut them
off), so we advertise things through ldd(1):

   % ldd -r ./main.2
         libfoo.so.2 => ./libfoo.so.2
         libc.so.1 => /lib/libc.so.1
         relocation R_386_COPY symbol: writable_str: \
             file ./libfoo.so.2: relocation bound to a symbol with \
             STV_PROTECTED visibility
         relocation R_386_COPY symbol: readonly_str: \
             file ./libfoo.so.2: relocation bound to a symbol with \
             STV_PROTECTED visibility

FWIW.

--
You received this message because you are subscribed to the Google Groups "Generic System V Application Binary Interface" group.
To unsubscribe from this group and stop receiving emails from it, send an email to generic-abi...@googlegroups.com.
To post to this group, send email to gener...@googlegroups.com.



--
----
Rod.

H.J. Lu

unread,
Apr 13, 2016, 3:18:24 PM4/13/16
to Generic System V Application Binary Interface, Suprateeka R Hegde
I made a proposal to add a .note.gnu.property section to GNU ABI:

https://github.com/hjl-tools/linux-abi/wiki/Linux-Extensions-to-gABI

with NT_GNU_PROPERTY_NO_COPY_ON_PROTECTED:

This indicates that there should be no copy relocations against protected
data symbols. If a relocatable object contains this property, linker
should treat protected data symbol as defined locally at run-time and copy
this property to the output share object. Run-time loader should disallow
copy relocations against protected data symbols defined in share objects
with NT_GNU_PROPERTIES_NO_COPY_ON_PROTECTED property.


--
H.J.

Rod Evans

unread,
Apr 13, 2016, 3:19:51 PM4/13/16
to gener...@googlegroups.com
And to Cary's point:

> Sun proposed an extension, STV_EXTERNAL, a few years ago, ...

We do define, and use STV_EXPORTED, which I assume is the same/equivalent.

On Wed, Apr 13, 2016 at 11:07 AM, Rod Evans <rod.i...@gmail.com> wrote:



--
----
Rod.

Cary Coutant

unread,
Apr 13, 2016, 4:03:27 PM4/13/16
to gener...@googlegroups.com
> And to Cary's point:
>
>> Sun proposed an extension, STV_EXTERNAL, a few years ago, ...
>
> We do define, and use STV_EXPORTED, which I assume is the same/equivalent.

Sorry, that's what I meant -- just mistyped the name.

-cary

Rod Evans

unread,
Apr 13, 2016, 5:04:59 PM4/13/16
to gener...@googlegroups.com
Regarding NT_GNU_PROPERTY_NO_COPY_ON_PROTECTED, yes I saw this
fly by, but wasn't sure how it would be used. It sounds like you have a bit set that
would turn our warnings into fatal conditions.  But who has the knowledge to set
the bit in the first place? the compiler, because its created a protected data item
that "might" get copied?

I found a lot of copies are against constant strings or data.  In this case the copy
is overhead, but probably nothing bad would ever happen.  Would these be tagged
as NO_COPY_ON_PROTECTED?  I could imagine a number of working applications
failing to load.


--
You received this message because you are subscribed to the Google Groups "Generic System V Application Binary Interface" group.
To unsubscribe from this group and stop receiving emails from it, send an email to generic-abi...@googlegroups.com.
To post to this group, send email to gener...@googlegroups.com.
Visit this group at https://groups.google.com/group/generic-abi.
For more options, visit https://groups.google.com/d/optout.



--
----
Rod.

H.J. Lu

unread,
Apr 13, 2016, 5:12:15 PM4/13/16
to Generic System V Application Binary Interface
On Wed, Apr 13, 2016 at 2:04 PM, Rod Evans <rod.i...@gmail.com> wrote:
> Regarding NT_GNU_PROPERTY_NO_COPY_ON_PROTECTED, yes I saw this
> fly by, but wasn't sure how it would be used. It sounds like you have a bit
> set that
> would turn our warnings into fatal conditions. But who has the knowledge to
> set
> the bit in the first place? the compiler, because its created a protected
> data item
> that "might" get copied?

When compiler generates non-GOT relocation against protected symbol
in PIC mode, it should set NT_GNU_PROPERTY_NO_COPY_ON_PROTECTED
in the output relocatable file.

> I found a lot of copies are against constant strings or data. In this case
> the copy
> is overhead, but probably nothing bad would ever happen. Would these be
> tagged
> as NO_COPY_ON_PROTECTED? I could imagine a number of working applications
> failing to load.

Yes, if read-only strings or data are protected and non-GOT relocations
are used to access them in PIC mode, NT_GNU_PROPERTY_NO_COPY_ON_PROTECTED
should be set. Otherwise, pointer won't work correctly. The same applies
to pointer of protected function.

H.J.
H.J.

Rod Evans

unread,
Apr 14, 2016, 1:10:29 PM4/14/16
to gener...@googlegroups.com
I'm still confused by how this is being used:


> When compiler generates non-GOT relocation against protected symbol
> in PIC mode, it should set NT_GNU_PROPERTY_NO_COPY_ON_PROTECTED
> in the output relocatable file.

If I take:

  const char __attribute__ ((visibility ("protected"))) \
       readonly_str[] = "a read-only string";
  char __attribute__ ((visibility ("protected"))) \
       writable_str[] = "a writable string";

  const char *foo() { return (readonly_str); }
  char *bar() { return (writable_str); }

and compile this, I see GOT relocations:

   % gcc -m32 -fPIC -c bar.c
   % elfdump -r bar.o | fgrep _str
     [1]  R_386_GOT32     0xf    0  .text   readonly_str
     [3]  R_386_GOT32   0x24   0  .text   writable_str

These still exist in the final shared object, although they are
expressed as RELATIVE relocations given the offset of the
protected symbols are known:

   % gcc -m32 -G -o libbar.so.1 bar.o
   % elfdump -G libbar.so.1
   ...
   [17]   0x10e3c      0xac0   R_386_RELATIVE
   [18]   0x10e40  0x10e74    R_386_RELATIVE

And if the strings are referenced by an application,  copy relocations result:

  % gcc -m32 -o main.3 main.o -R. libbar.so.1
  ld: warning: relocation warning: R_386_COPY: file libbar.so.1: symbol readonly_str: \

    relocation bound to a symbol with STV_PROTECTED visibility
  ld: warning: relocation warning: R_386_COPY: file libbar.so.1: symbol writable_str: \

    relocation bound to a symbol with STV_PROTECTED visibility

   % elfdump -r main.3 | fgrep _str
   [0]  R_386_COPY  0x8060e50   0   .bss  writable_str
   [1]  R_386_COPY  0x8060e64   0   .bss   readonly_str

So, this type of relocation is allowed, even though the two components
see different instances of the strings, but a non-GOT relocation against
a protected symbol in PIC mode, would be "stopped" because the shared
object was tagged with NT_GNU_PROPERTY_NO_COPY_ON_PROTECTED?

Also, is this no-copy property associated with specific symbols, or simply a
global flag?  If I created the above scenario, and also managed to create a
non-GOT relocation and your tagging, would all copy relocations be prevented
from the shared object?  Some applications can only use some of the data
exported from a shared object - perhaps only the items that were deemed
OK to copy - would these applications fail their copies?

H.J. Lu

unread,
Apr 14, 2016, 1:41:01 PM4/14/16
to Generic System V Application Binary Interface
Since readonly_str and writable_str are expected to be defined
locally at run-time, linker should set
NT_GNU_PROPERTY_NO_COPY_ON_PROTECTED on the
output shared obect. I updated the spec with

---
NT_GNU_PROPERTY_NO_COPY_ON_PROTECTED This indicates that
there should be no copy relocations against protected data symbols.
If a relocatable object contains this property, linker should treat pro-
tected data symbol as defined locally at run-time and copy this prop-
erty to the output share object. Linker should add this property to
the output share object if any protected symbol is expected to be
defined locally at run-time. Run-time loader should disallow copy
relocations against protected data symbols defined in share objects
with NT_GNU_PROPERTY_NO_COPY_ON_PROTECTED property. Its
PR_DATASZ should be 0.
---

> And if the strings are referenced by an application, copy relocations
> result:
>
> % gcc -m32 -o main.3 main.o -R. libbar.so.1
> ld: warning: relocation warning: R_386_COPY: file libbar.so.1: symbol
> readonly_str: \
> relocation bound to a symbol with STV_PROTECTED visibility
> ld: warning: relocation warning: R_386_COPY: file libbar.so.1: symbol
> writable_str: \
> relocation bound to a symbol with STV_PROTECTED visibility
>
> % elfdump -r main.3 | fgrep _str
> [0] R_386_COPY 0x8060e50 0 .bss writable_str
> [1] R_386_COPY 0x8060e64 0 .bss readonly_str
>
> So, this type of relocation is allowed, even though the two components
> see different instances of the strings, but a non-GOT relocation against
> a protected symbol in PIC mode, would be "stopped" because the shared
> object was tagged with NT_GNU_PROPERTY_NO_COPY_ON_PROTECTED?

Run-time loader should disallow it.

> Also, is this no-copy property associated with specific symbols, or simply a
> global flag? If I created the above scenario, and also managed to create a
> non-GOT relocation and your tagging, would all copy relocations be prevented
> from the shared object? Some applications can only use some of the data
> exported from a shared object - perhaps only the items that were deemed
> OK to copy - would these applications fail their copies?

NT_GNU_PROPERTY_NO_COPY_ON_PROTECTED applies to all
protected symbols. If copy relocation is allowed on a symbol, it
shouldn't be made protected.

Rod Evans

unread,
Apr 17, 2016, 8:53:46 PM4/17/16
to gener...@googlegroups.com
On Thu, Apr 14, 2016 at 10:41 AM, H.J. Lu <hjl....@gmail.com> wrote:
Since readonly_str and writable_str are expected to be defined
locally at run-time,  linker should set
NT_GNU_PROPERTY_NO_COPY_ON_PROTECTED on the
output shared obect....

Ok, so the relocation types applied to these symbols from within the shared
object have no bearing on the issue, right?  The triggers are simply a visible
data object with protected binding. 
 
NT_GNU_PROPERTY_NO_COPY_ON_PROTECTED applies to all
protected symbols.

You say ld(1) sets this flag, or can inherit it from a relocatable object.  Can
ld(1) be instructed to *not* to set this flag?  If not, then I still don't see the
point of the flag.  The runtime linker has all the information it needs from
being asked to perform a copy and identifying that the definition is protected.
If the runtime linker wants to make this a fatal condition, it can do so.

We use the same information, but at present have chosen to let ldd(1)
issue a diagnostic, rather than have ld.so.1() set a fatal error.

If ld(1) can be instructed *not* to set this flag, then I question who would
have the smarts to know whether to do this.

If copy relocation is allowed on a symbol, it
shouldn't be made protected.

Yeah.  The problem is that the handful of folks who know what a copy relocation
is are probably on this thread, and the rest of humanity don't have a clue what
they are, the implications of their use, or how they can be 'compromised'
by a protected definition.  The scenario is probably "ohh, this protected flag
looks good, and I'm sure it'll make my shared object perform better, I'll use it",
without regard to the restrictions caused by the underlying implementation.

If you really want to improve things, tell folks not to export data items in
the first place - hide data behind function interfaces.

Now that PIE (position-independent executables) are on the horizon, perhaps
we'll get lucky with their use and protected symbols.  Future users might never
have to know what a copy relocation was :-)

----
Rod.

H.J. Lu

unread,
Apr 18, 2016, 9:20:32 AM4/18/16
to Generic System V Application Binary Interface
On Sun, Apr 17, 2016 at 5:53 PM, Rod Evans <rod.i...@gmail.com> wrote:
> On Thu, Apr 14, 2016 at 10:41 AM, H.J. Lu <hjl....@gmail.com> wrote:
>>
>> Since readonly_str and writable_str are expected to be defined
>> locally at run-time, linker should set
>> NT_GNU_PROPERTY_NO_COPY_ON_PROTECTED on the
>> output shared obect....
>
>
> Ok, so the relocation types applied to these symbols from within the shared
> object have no bearing on the issue, right? The triggers are simply a
> visible
> data object with protected binding.

Yes.

>>
>> NT_GNU_PROPERTY_NO_COPY_ON_PROTECTED applies to all
>> protected symbols.
>
>
> You say ld(1) sets this flag, or can inherit it from a relocatable object.
> Can
> ld(1) be instructed to *not* to set this flag? If not, then I still don't
> see the

Yes, ld can.

> point of the flag. The runtime linker has all the information it needs from
> being asked to perform a copy and identifying that the definition is
> protected.
> If the runtime linker wants to make this a fatal condition, it can do so.

That is correct. This flag asks ld.so to make it a fatal condition
and tells ld that

1. Don't generate copy relocation against protected symbol when
creating executable.
2. Protected symbol is defined locally in shared object when creating
shared object.

> We use the same information, but at present have chosen to let ldd(1)
> issue a diagnostic, rather than have ld.so.1() set a fatal error.
> If ld(1) can be instructed *not* to set this flag, then I question who would
> have the smarts to know whether to do this.

When this flag is set by compiler, there is no choice. If it isn't
set in input relocatable object files, ld has a choice. By default,
ld won't set it unless it is instructed otherwise at command line.

>> If copy relocation is allowed on a symbol, it
>> shouldn't be made protected.
>
>
> Yeah. The problem is that the handful of folks who know what a copy
> relocation
> is are probably on this thread, and the rest of humanity don't have a clue
> what
> they are, the implications of their use, or how they can be 'compromised'
> by a protected definition. The scenario is probably "ohh, this protected
> flag
> looks good, and I'm sure it'll make my shared object perform better, I'll
> use it",
> without regard to the restrictions caused by the underlying implementation.

That is what happened.

> If you really want to improve things, tell folks not to export data items in
> the first place - hide data behind function interfaces.

Or use GNU_PROPERTY_NO_COPY_ON_PROTECTED, which
I have updated to remove the "NT_" prefix.

> Now that PIE (position-independent executables) are on the horizon, perhaps
> we'll get lucky with their use and protected symbols. Future users might
> never
> have to know what a copy relocation was :-)
>

Well, GCC and binutils have been changed to generate copy relocation
in PIE :-).

--
H.J.

Michael Matz

unread,
Apr 18, 2016, 9:29:58 AM4/18/16
to Generic System V Application Binary Interface
Hi,

On Mon, 18 Apr 2016, H.J. Lu wrote:

> > Now that PIE (position-independent executables) are on the horizon,
> > perhaps we'll get lucky with their use and protected symbols. Future
> > users might never have to know what a copy relocation was :-)
>
> Well, GCC and binutils have been changed to generate copy relocation in
> PIE :-).

Uhm, why? IMHO copy relocs are the problem, not protected visibility, so
if anything the use of copy relocs should be reduced instead of increased
at the expense of sensible optimizations that are the whole point of that
visibility.


Ciao,
Michael.

H.J. Lu

unread,
Apr 18, 2016, 10:48:47 AM4/18/16
to Generic System V Application Binary Interface
Copy relocation is generated to access external symbols from PIE
as an optimization. The external symbol may or may not protected
visibility, which is only known to ld or even ld.so.

--
H.J.

Michael Matz

unread,
Apr 18, 2016, 11:08:10 AM4/18/16
to Generic System V Application Binary Interface
Well, I think that's premature optimization (resolving the incompatibility
of protected vs. copyreloc into the wrong direction). I think most
optimizations for PIE accessing external symbols can also be done by
emitting proper GOT indirections in GCC and rewriting to direct-access
with copy relocs, _if_ the symbol turns out to be non-protected at link
edit time.


Ciao,
Michael.

H.J. Lu

unread,
Apr 18, 2016, 11:41:09 AM4/18/16
to Generic System V Application Binary Interface
That is certainly possible with the new relaxable GOT relocations in
the current x86 psABIs and binutils 2.26, which were implemented
AFTER copy relocation was introduced to PIE.

--
H.J.

Rod Evans

unread,
Apr 18, 2016, 12:08:07 PM4/18/16
to gener...@googlegroups.com
On Mon, Apr 18, 2016 at 6:20 AM, H.J. Lu <hjl....@gmail.com> wrote:
> We use the same information, but at present have chosen to let ldd(1)
> issue a diagnostic, rather than have ld.so.1() set a fatal error.
> If ld(1) can be instructed *not* to set this flag, then I question who would
> have the smarts to know whether to do this.

When this flag is set by compiler, there is no choice.  If it isn't
set in input relocatable object files, ld has a choice.  By default,
ld won't set it unless it is instructed otherwise at command line.

I still don't know what user would know to flag ld(1) in this manner, but I'll
assume that most of this is driven off the compiler adding the flag.  And,
if one protected data item results in this flag, all protected data items
offered by the shared object can't be copied - even if some, to .rodata
items, might be "harmless".
 
> If you really want to improve things, tell folks not to export data items in
> the first place - hide data behind function interfaces.

Or use GNU_PROPERTY_NO_COPY_ON_PROTECTED, which
I have updated to remove the "NT_" prefix.

So, I could reference data through function interfaces, have no copy
relocations, and have a working program.  Or, I could reference data
items directly, which might be protected, and enable this flag, which
would kill my program at startup.  I prefer the former.
 
> Now that PIE (position-independent executables) are on the horizon, perhaps
> we'll get lucky with their use and protected symbols.  Future users might
> never
> have to know what a copy relocation was :-)
>

Well, GCC and binutils have been changed to generate copy relocation
in PIE :-).

Among the deficiencies of copy relocations is that a .rodata item in a
shared object can be copied to .bss the an executable, and this data
could be accidentally/maliciously altered. With PIE, where no copy is
required, the executable directly references the shared object data,
and the .rodata protection the shared object desires is realized.

Why you'd want copy relocations with PIE seems odd.

I'm still not convinced this flag is useful/necessary.  But, I think  I've said
enough now.

--
----
Rod.

H.J. Lu

unread,
Apr 18, 2016, 12:22:58 PM4/18/16
to Generic System V Application Binary Interface
On Mon, Apr 18, 2016 at 9:08 AM, Rod Evans <rod.i...@gmail.com> wrote:
> On Mon, Apr 18, 2016 at 6:20 AM, H.J. Lu <hjl....@gmail.com> wrote:
>>
>> > We use the same information, but at present have chosen to let ldd(1)
>> > issue a diagnostic, rather than have ld.so.1() set a fatal error.
>> > If ld(1) can be instructed *not* to set this flag, then I question who
>> > would
>> > have the smarts to know whether to do this.
>>
>> When this flag is set by compiler, there is no choice. If it isn't
>> set in input relocatable object files, ld has a choice. By default,
>> ld won't set it unless it is instructed otherwise at command line.
>
>
> I still don't know what user would know to flag ld(1) in this manner, but
> I'll

The ld option should be used as the last resort.

> assume that most of this is driven off the compiler adding the flag. And,
> if one protected data item results in this flag, all protected data items
> offered by the shared object can't be copied - even if some, to .rodata
> items, might be "harmless".

That is correct.

>>
>> > If you really want to improve things, tell folks not to export data
>> > items in
>> > the first place - hide data behind function interfaces.
>>
>> Or use GNU_PROPERTY_NO_COPY_ON_PROTECTED, which
>> I have updated to remove the "NT_" prefix.
>
>
> So, I could reference data through function interfaces, have no copy
> relocations, and have a working program. Or, I could reference data
> items directly, which might be protected, and enable this flag, which
> would kill my program at startup. I prefer the former.

At last, you won't get a surprise at run-time later.

>>
>> > Now that PIE (position-independent executables) are on the horizon,
>> > perhaps
>> > we'll get lucky with their use and protected symbols. Future users
>> > might
>> > never
>> > have to know what a copy relocation was :-)
>> >
>>
>> Well, GCC and binutils have been changed to generate copy relocation
>> in PIE :-).
>
>
> Among the deficiencies of copy relocations is that a .rodata item in a
> shared object can be copied to .bss the an executable, and this data
> could be accidentally/maliciously altered. With PIE, where no copy is

Yes, that is true, which is orthogonal to protected visibility.

> required, the executable directly references the shared object data,
> and the .rodata protection the shared object desires is realized.
>
> Why you'd want copy relocations with PIE seems odd.

Copy relocation can improve performance. Google enabled copy
relocations for PIE in ld/gold and GCC to improve prefomance by
up to 5%:

https://gcc.gnu.org/ml/gcc-patches/2014-05/msg01215.html


H.J.

Rod Evans

unread,
Apr 18, 2016, 1:05:15 PM4/18/16
to gener...@googlegroups.com
On Mon, Apr 18, 2016 at 9:22 AM, H.J. Lu <hjl....@gmail.com> wrote:
Copy relocation can improve performance.  Google enabled copy
relocations for PIE in ld/gold and GCC to improve prefomance by
up to 5%:

https://gcc.gnu.org/ml/gcc-patches/2014-05/msg01215.html

I'm all for performance improvements, but not a fan of using awful implementation
techniques to get them.  Sigh.

--
----
Rod.

Michael Matz

unread,
Apr 18, 2016, 1:05:29 PM4/18/16
to Generic System V Application Binary Interface
Hi,

On Mon, 18 Apr 2016, H.J. Lu wrote:

> >> > Now that PIE (position-independent executables) are on the horizon,
> >> > perhaps we'll get lucky with their use and protected symbols.
> >> > Future users might never have to know what a copy relocation was
> >> > :-)
> >>
> >> Well, GCC and binutils have been changed to generate copy relocation
> >> in PIE :-).
> >
> >
> > Among the deficiencies of copy relocations is that a .rodata item in a
> > shared object can be copied to .bss the an executable, and this data
> > could be accidentally/maliciously altered. With PIE, where no copy is
>
> Yes, that is true, which is orthogonal to protected visibility.
>
> > required, the executable directly references the shared object data,
> > and the .rodata protection the shared object desires is realized.
> >
> > Why you'd want copy relocations with PIE seems odd.
>
> Copy relocation can improve performance. Google enabled copy
> relocations for PIE in ld/gold and GCC to improve prefomance by
> up to 5%:
>
> https://gcc.gnu.org/ml/gcc-patches/2014-05/msg01215.html

Sure sure. But that doesn't touch the topic of copy relocs vs. protected.
The above argument can't be used to support the "copy-relocs should take
precedence over protected" stance. See the detailed answer from Cary on
that particular change at
https://sourceware.org/ml/binutils/2016-03/msg00409.html
. I'll cite the paragraph:

"There was another change to GCC at r218397, in Dec. 2014, to make data
access in PIE mode work more like non-PIC mode. This required linker
changes to enable the use of COPY relocations when generating PIE
output. This patch was originally developed by Sriraman Tallam on the
Google branch, but was checked on trunk in by HJ after considerable
discussion. As far as I'm concerned (and I advised Sri during the
development of this patch), this change was fine -- it simply
recognizes that a position-independent executable does not need to use
PIC-style references to data when a pc-relative or got-relative access
is possible. As in non-PIC mode, these accesses work fine for data
defined in the main program, but result in occasional COPY relocations
if the data happens to be defined in a shared library. Unfortunately,
I think this was the patch that set the rest in motion -- when
developing test cases, HJ noted that COPY relocations to protected
symbols were not allowed, and set out to fix that."

Additionally, generating copy relocs shouldn't be default anywhere
if alternatives exist (like with PIE) because of the annoying side effects
of them, it should be an opt-in for those who know and accept the
implications.

So, let's please leave out that whole "binutils generates copy relocs also
for PIE" line in this protected vs copy-reloc discussion.

I think we're meanwhile only discussing what the failure mode of
using copy-reloc plus protected should be, right? I think a hard error in
ld and ld.so is quite appropriate, and inventing ways to selectively turn
this off via ELF properties or ld(1) flags seems overengineering.
Basically: who do you envision would _not_ want to be informed of the
incompatibility they are about to be trapped in?


Ciao,
Michael.

Cary Coutant

unread,
Apr 18, 2016, 1:22:29 PM4/18/16
to gener...@googlegroups.com
>> Among the deficiencies of copy relocations is that a .rodata item in a
>> shared object can be copied to .bss the an executable, and this data
>> could be accidentally/maliciously altered. With PIE, where no copy is
>
> Yes, that is true, which is orthogonal to protected visibility.
>
>> required, the executable directly references the shared object data,
>> and the .rodata protection the shared object desires is realized.
>>
>> Why you'd want copy relocations with PIE seems odd.
>
> Copy relocation can improve performance. Google enabled copy
> relocations for PIE in ld/gold and GCC to improve prefomance by
> up to 5%:
>
> https://gcc.gnu.org/ml/gcc-patches/2014-05/msg01215.html

I've tried to set the record straight on this before...

Copy relocations aren't what improved the performance -- it was the
GCC change to generate non-PIC references to global variables with
-fPIE. The difference between a normal executable and a PIE executable
is simply that the PIE executable can be relocated at load time;
references to globals can be assumed to be non-preemptable in either
case, so it's perfectly reasonable for the compiler to take advantage
of that and generate direct references. That doesn't affect the
position-independence of the resulting executable.

Just as in non-PIE executables, an occasional reference to a shared
library data symbol is possible, and just like non-PIE executables,
can be solved with copy relocations. But for an arbitrary (and
groundless) restriction in the linkers that prevented the generation
of copy relocations for PIE executables, the GCC change wouldn't have
needed any linker changes.

The Google changes didn't require copy relocations for anything that
wasn't already using copy relocations in non-PIE mode, so PIE was a
big misdirection, and copy relocations for PIE don't bring up any
issues that hadn't already been with us for 15+ years.

-cary

Cary Coutant

unread,
Apr 18, 2016, 1:37:38 PM4/18/16
to gener...@googlegroups.com
>> If copy relocation is allowed on a symbol, it
>> shouldn't be made protected.
>
> Yeah. The problem is that the handful of folks who know what a copy
> relocation
> is are probably on this thread, and the rest of humanity don't have a clue
> what
> they are, the implications of their use, or how they can be 'compromised'
> by a protected definition. The scenario is probably "ohh, this protected
> flag
> looks good, and I'm sure it'll make my shared object perform better, I'll
> use it",
> without regard to the restrictions caused by the underlying implementation.

As long as we can give a reasonable error message when they do try to
use a protected symbol incorrectly, it shouldn't be a problem. Part of
the problem is that we weren't actually giving the error messages.

> If you really want to improve things, tell folks not to export data items in
> the first place - hide data behind function interfaces.

This. Exactly.

We generally only see copy relocations for things like stdin, where
the size and layout of the data object is already completely exposed
by macro implementations like putc(). And since these symbols are most
definitely not protected visibility, it's pretty rare to see a copy
relocation against a protected symbol.

> Now that PIE (position-independent executables) are on the horizon, perhaps
> we'll get lucky with their use and protected symbols. Future users might
> never
> have to know what a copy relocation was :-)

Since there's really no reason for PIE to use the GOT for a
non-preemptable symbol, that's not really going to change things.

The best way to eliminate copy relocations without hurting non-PIC
performance significantly is to generate an indirect code sequence
that can be rewritten at link time when the symbol is local, using the
dllimport attribute to mark symbols that may not be local.

-cary

H.J. Lu

unread,
Apr 18, 2016, 1:40:53 PM4/18/16
to Generic System V Application Binary Interface
On Mon, Apr 18, 2016 at 10:37 AM, Cary Coutant <ccou...@gmail.com> wrote:
>
> Since there's really no reason for PIE to use the GOT for a
> non-preemptable symbol, that's not really going to change things.
>
> The best way to eliminate copy relocations without hurting non-PIC
> performance significantly is to generate an indirect code sequence
> that can be rewritten at link time when the symbol is local, using the
> dllimport attribute to mark symbols that may not be local.
>

This is one way to move forward and linkers in binutils 26 can
optimize load from memory to load immediate.

--
H.J.

Cary Coutant

unread,
Apr 18, 2016, 1:41:17 PM4/18/16
to gener...@googlegroups.com
> I think we're meanwhile only discussing what the failure mode of
> using copy-reloc plus protected should be, right? I think a hard error in
> ld and ld.so is quite appropriate, and inventing ways to selectively turn
> this off via ELF properties or ld(1) flags seems overengineering.
> Basically: who do you envision would _not_ want to be informed of the
> incompatibility they are about to be trapped in?

I agree. There's only one reason to make a data symbol protected, and
that's to take advantage of its non-preemptability. There's really no
practical case where we would have a protected symbol that could be
the target of a copy relocation.

-cary
Reply all
Reply to author
Forward
0 new messages