elf: Add GNU_PROPERTY_1_NEEDED check

If GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS is set on any input
relocatable files:

1. Don't generate copy relocations.
2. Turn off extern_protected_data since it implies
GNU_PROPERTY_NO_COPY_ON_PROTECTED.
3. Treate reference to protected symbols with indirect external access
as local.
4. Set GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS on output.
5. When generating executable, clear this bit when there are non-GOT or
non-PLT relocations in input relocatable files without the bit set.
6. Add -z [no]indirect-extern-access to control indirect external access.

bfd/

	* elf-bfd (elf_obj_tdata): Add has_indirect_extern_access.
	(elf_has_indirect_extern_access): New.
	* elf-properties.c (_bfd_elf_parse_gnu_properties): Set
	elf_has_indirect_extern_access and elf_has_no_copy_on_protected
	when seeing GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS.
	(elf_write_gnu_propertie): Add an argument to pass link_info.
	Set needed_1_p for GNU_PROPERTY_1_NEEDED in memory.
	(_bfd_elf_link_setup_gnu_properties): Handle
	GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS for
	-z indirect-extern-access.  Set nocopyreloc to true and
	extern_protected_data to false for indirect external access.
	(_bfd_elf_convert_gnu_properties): Updated.
	* elf32-i386.c (elf_i386_check_relocs): Set
	non_got_ref_without_indirect_extern_access on legacy non-GOT or
	non-PLT references.
	* elf64-x86-64.c (elf_x86_64_check_relocs): Likewise.
	* elflink.c (_bfd_elf_symbol_refs_local_p): Return true for
	STV_PROTECTED symbols with indirect external access.
	* elfxx-x86.c (_bfd_x86_elf_adjust_dynamic_symbol): Clear
	indirect_extern_access for legacy non-GOT/non-PLT references.
	* elfxx-x86.h (elf_x86_link_hash_entry): Add
	non_got_ref_without_indirect_extern_access.

include/

	* bfdlink.h (bfd_link_info): Add indirect_extern_access and
	needed_1_p.  Change nocopyreloc to int.

ld/

	* NEWS: Mention -z [no]indirect-extern-access
	* ld.texi: Document -z [no]indirect-extern-access
	* ldmain.c (main): Initialize link_info.indirect_extern_access
	to -1.
	* emulparams/extern_protected_data.sh: Support
	-z [no]indirect-extern-access.
	* testsuite/ld-elf/indirect-extern-access-1.rd: New file
	* testsuite/ld-elf/indirect-extern-access-1a.c: Likewise.
	* testsuite/ld-elf/indirect-extern-access-1b.c: Likewise.
	* testsuite/ld-elf/indirect-extern-access-2.rd: Likewise.
	* testsuite/ld-elf/indirect-extern-access-2a.c: Likewise.
	* testsuite/ld-elf/indirect-extern-access-2b.c: Likewise.
	* testsuite/ld-elf/indirect-extern-access-3.rd: Likewise.
	* testsuite/ld-elf/indirect-extern-access.S: Likewise.
	* testsuite/ld-elf/property-1_needed-1b.d: Likewise.
	* testsuite/ld-elf/property-1_needed-1c.d: Likewise.
	* testsuite/ld-x86-64/indirect-extern-access.rd: Likewise.
	* testsuite/ld-x86-64/protected-data-1.h: Likewise.
	* testsuite/ld-x86-64/protected-data-1a.c: Likewise.
	* testsuite/ld-x86-64/protected-data-1b.c: Likewise.
	* testsuite/ld-x86-64/protected-data-2a.S: Likewise.
	* testsuite/ld-x86-64/protected-data-2b.S: Likewise.
	* testsuite/ld-x86-64/protected-func-2a.S: Likewise.
	* testsuite/ld-x86-64/protected-func-2b.S: Likewise.
	* testsuite/ld-x86-64/protected-func-2c.c: Likewise.
	* testsuite/ld-elf/linux-x86.exp: Run test with
	GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS.
	* testsuite/ld-x86-64/x86-64.exp: Run tests for protected
	function and data with indirect external access.
This commit is contained in:
H.J. Lu 2021-06-17 14:11:28 -07:00
parent 6320fd00dc
commit 6f365fda85
33 changed files with 1078 additions and 23 deletions

View File

@ -2073,6 +2073,10 @@ struct elf_obj_tdata
property. */
unsigned int has_no_copy_on_protected : 1;
/* Whether if the bfd contains the
GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS property. */
unsigned int has_indirect_extern_access : 1;
/* Irix 5 often screws up the symbol table, sorting local symbols
after global symbols. This flag is set if the symbol table in
this BFD appears to be screwed up. If it is, we ignore the
@ -2138,6 +2142,8 @@ struct elf_obj_tdata
#define elf_properties(bfd) (elf_tdata (bfd) -> properties)
#define elf_has_no_copy_on_protected(bfd) \
(elf_tdata(bfd) -> has_no_copy_on_protected)
#define elf_has_indirect_extern_access(bfd) \
(elf_tdata(bfd) -> has_indirect_extern_access)
extern void _bfd_elf_swap_verdef_in
(bfd *, const Elf_External_Verdef *, Elf_Internal_Verdef *);

View File

@ -195,6 +195,18 @@ _bfd_elf_parse_gnu_properties (bfd *abfd, Elf_Internal_Note *note)
prop = _bfd_elf_get_property (abfd, type, datasz);
prop->u.number |= bfd_h_get_32 (abfd, ptr);
prop->pr_kind = property_number;
if ((abfd->flags & DYNAMIC) == 0
&& type == GNU_PROPERTY_1_NEEDED
&& ((prop->u.number
& GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS)
!= 0))
{
/* NB: Skip the shared library since it may not be
the same at run-time. */
elf_has_indirect_extern_access (abfd) = true;
/* GNU_PROPERTY_NO_COPY_ON_PROTECTED is implied. */
elf_has_no_copy_on_protected (abfd) = true;
}
goto next;
}
break;
@ -525,7 +537,8 @@ elf_get_gnu_property_section_size (elf_property_list *list,
/* Write GNU properties. */
static void
elf_write_gnu_properties (bfd *abfd, bfd_byte *contents,
elf_write_gnu_properties (struct bfd_link_info *info,
bfd *abfd, bfd_byte *contents,
elf_property_list *list, unsigned int size,
unsigned int align_size)
{
@ -570,6 +583,11 @@ elf_write_gnu_properties (bfd *abfd, bfd_byte *contents,
break;
case 4:
/* Save the pointer to GNU_PROPERTY_1_NEEDED so that it
can be updated later if needed. */
if (info != NULL
&& list->property.pr_type == GNU_PROPERTY_1_NEEDED)
info->needed_1_p = contents + size;
bfd_h_put_32 (abfd, list->property.u.number,
contents + size);
break;
@ -598,7 +616,7 @@ elf_write_gnu_properties (bfd *abfd, bfd_byte *contents,
bfd *
_bfd_elf_link_setup_gnu_properties (struct bfd_link_info *info)
{
bfd *abfd, *first_pbfd = NULL;
bfd *abfd, *first_pbfd = NULL, *elf_bfd = NULL;
elf_property_list *list;
asection *sec;
bool has_properties = false;
@ -606,32 +624,75 @@ _bfd_elf_link_setup_gnu_properties (struct bfd_link_info *info)
= get_elf_backend_data (info->output_bfd);
unsigned int elfclass = bed->s->elfclass;
int elf_machine_code = bed->elf_machine_code;
elf_property *p;
/* Find the first relocatable ELF input with GNU properties. */
for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link.next)
if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
&& (abfd->flags & DYNAMIC) == 0
&& elf_properties (abfd) != NULL)
&& (elf_machine_code
== get_elf_backend_data (abfd)->elf_machine_code)
&& (elfclass == get_elf_backend_data (abfd)->s->elfclass))
{
has_properties = true;
/* Ignore GNU properties from ELF objects with different machine
code or class. Also skip objects without a GNU_PROPERTY note
section. */
if ((elf_machine_code
== get_elf_backend_data (abfd)->elf_machine_code)
&& (elfclass
== get_elf_backend_data (abfd)->s->elfclass)
&& bfd_get_section_by_name (abfd,
NOTE_GNU_PROPERTY_SECTION_NAME) != NULL
)
elf_bfd = abfd;
if (elf_properties (abfd) != NULL)
{
/* Keep .note.gnu.property section in FIRST_PBFD. */
first_pbfd = abfd;
break;
has_properties = true;
if (bfd_get_section_by_name (abfd,
NOTE_GNU_PROPERTY_SECTION_NAME)
!= NULL)
{
/* Keep .note.gnu.property section in FIRST_PBFD. */
first_pbfd = abfd;
break;
}
}
}
if (info->indirect_extern_access > 0 && elf_bfd != NULL)
{
/* Support -z indirect-extern-access. */
if (first_pbfd == NULL)
{
sec = bfd_make_section_with_flags (elf_bfd,
NOTE_GNU_PROPERTY_SECTION_NAME,
(SEC_ALLOC
| SEC_LOAD
| SEC_IN_MEMORY
| SEC_READONLY
| SEC_HAS_CONTENTS
| SEC_DATA));
if (sec == NULL)
info->callbacks->einfo (_("%F%P: failed to create GNU property section\n"));
if (!bfd_set_section_alignment (sec,
elfclass == ELFCLASS64 ? 3 : 2))
info->callbacks->einfo (_("%F%pA: failed to align section\n"),
sec);
elf_section_type (sec) = SHT_NOTE;
first_pbfd = elf_bfd;
has_properties = true;
}
p = _bfd_elf_get_property (first_pbfd, GNU_PROPERTY_1_NEEDED, 4);
if (p->pr_kind == property_unknown)
{
/* Create GNU_PROPERTY_1_NEEDED. */
p->u.number
= GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS;
p->pr_kind = property_number;
}
else
p->u.number
|= GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS;
}
/* Do nothing if there is no .note.gnu.property section. */
if (!has_properties)
return NULL;
@ -695,7 +756,6 @@ _bfd_elf_link_setup_gnu_properties (struct bfd_link_info *info)
if N > 0. */
if (info->stacksize > 0)
{
elf_property *p;
bfd_vma stacksize = info->stacksize;
p = _bfd_elf_get_property (first_pbfd, GNU_PROPERTY_STACK_SIZE,
@ -737,7 +797,30 @@ _bfd_elf_link_setup_gnu_properties (struct bfd_link_info *info)
sec->size = size;
contents = (bfd_byte *) bfd_zalloc (first_pbfd, size);
elf_write_gnu_properties (first_pbfd, contents, list, size,
if (info->indirect_extern_access <= 0)
{
/* Get GNU_PROPERTY_1_NEEDED properties. */
p = elf_find_and_remove_property (&elf_properties (first_pbfd),
GNU_PROPERTY_1_NEEDED, false);
if (p != NULL)
{
if (info->indirect_extern_access < 0)
{
/* Set indirect_extern_access to 1 to indicate that
it is turned on by input properties. */
if ((p->u.number
& GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS)
!= 0)
info->indirect_extern_access = 1;
}
else
/* Turn off indirect external access. */
p->u.number
&= ~GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS;
}
}
elf_write_gnu_properties (info, first_pbfd, contents, list, size,
align_size);
/* Cache the section contents for elf_link_input_bfd. */
@ -747,6 +830,15 @@ _bfd_elf_link_setup_gnu_properties (struct bfd_link_info *info)
symbol is defined in the shared object. */
if (elf_has_no_copy_on_protected (first_pbfd))
info->extern_protected_data = false;
if (info->indirect_extern_access > 0)
{
/* For indirect external access, don't generate copy
relocations. NB: Set to nocopyreloc to 2 to indicate
that it is implied by indirect_extern_access. */
info->nocopyreloc = 2;
info->extern_protected_data = false;
}
}
return first_pbfd;
@ -804,7 +896,8 @@ _bfd_elf_convert_gnu_properties (bfd *ibfd, asection *isec,
*ptr_size = size;
/* Generate the output .note.gnu.property section. */
elf_write_gnu_properties (ibfd, contents, list, size, 1 << align_shift);
elf_write_gnu_properties (NULL, ibfd, contents, list, size,
1 << align_shift);
return true;
}

View File

@ -1815,6 +1815,9 @@ elf_i386_check_relocs (bfd *abfd,
adjust_dynamic_symbol. */
h->non_got_ref = 1;
if (!elf_has_indirect_extern_access (sec->owner))
eh->non_got_ref_without_indirect_extern_access = 1;
/* We may need a .plt entry if the symbol is a function
defined in a shared lib or is a function referenced
from the code or read-only section. */

View File

@ -1972,6 +1972,8 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
break;
}
eh = (struct elf_x86_link_hash_entry *) h;
if (h != NULL)
{
/* It is referenced by a non-shared object. */
@ -2008,7 +2010,6 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
if (h == htab->elf.hgot)
htab->got_referenced = true;
eh = (struct elf_x86_link_hash_entry *) h;
switch (r_type)
{
case R_X86_64_TLSLD:
@ -2263,6 +2264,9 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
adjust_dynamic_symbol. */
h->non_got_ref = 1;
if (!elf_has_indirect_extern_access (sec->owner))
eh->non_got_ref_without_indirect_extern_access = 1;
/* We may need a .plt entry if the symbol is a function
defined in a shared lib or is a function referenced
from the code or read-only section. */

View File

@ -3353,6 +3353,10 @@ _bfd_elf_symbol_refs_local_p (struct elf_link_hash_entry *h,
if (!is_elf_hash_table (&hash_table->root))
return true;
/* STV_PROTECTED symbols with indirect external access are local. */
if (info->indirect_extern_access > 0)
return true;
bed = get_elf_backend_data (hash_table->dynobj);
/* If extern_protected_data is false, STV_PROTECTED non-function

View File

@ -1824,6 +1824,25 @@ _bfd_x86_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
eh = (struct elf_x86_link_hash_entry *) h;
/* Clear GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS if it is turned
on by an input relocatable file and there is a non-GOT/non-PLT
reference from another relocatable file without it.
NB: There can be non-GOT reference in data sections in input with
GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS. */
if (eh->non_got_ref_without_indirect_extern_access
&& info->indirect_extern_access == 1
&& bfd_link_executable (info))
{
unsigned int needed_1;
info->indirect_extern_access = 0;
/* Turn off nocopyreloc if implied by indirect_extern_access. */
if (info->nocopyreloc == 2)
info->nocopyreloc = 0;
needed_1 = bfd_h_get_32 (info->output_bfd, info->needed_1_p);
needed_1 &= ~GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS;
bfd_h_put_32 (info->output_bfd, needed_1, info->needed_1_p);
}
/* STT_GNU_IFUNC symbol must go through PLT. */
if (h->type == STT_GNU_IFUNC)
{

View File

@ -279,6 +279,10 @@ struct elf_x86_link_hash_entry
/* TRUE if symbol is defined by linker. */
unsigned int linker_def : 1;
/* TRUE if symbol is referenced by a non-GOT/non-PLT relocation in a
relocatable object file without indirect external access marker. */
unsigned int non_got_ref_without_indirect_extern_access : 1;
/* TRUE if symbol is referenced by R_386_GOTOFF relocation. This is
only used by i386. */
unsigned int gotoff_ref : 1;

View File

@ -335,10 +335,6 @@ struct bfd_link_info
/* TRUE if BFD should pre-bind symbols in a shared object. */
unsigned int symbolic: 1;
/* TRUE if executable should not contain copy relocs.
Setting this true may result in a non-sharable text segment. */
unsigned int nocopyreloc: 1;
/* TRUE if BFD should export all symbols in the dynamic symbol table
of an executable, rather than only those used. */
unsigned int export_dynamic: 1;
@ -652,6 +648,25 @@ struct bfd_link_info
/* How many spare .dynamic DT_NULL entries should be added? */
unsigned int spare_dynamic_tags;
/* GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS control:
> 1: Turn on by -z indirect-extern-access or by backend.
== 1: Turn on by an input.
0: Turn off.
< 0: Turn on if it is set on any inputs or let backend to
decide. */
int indirect_extern_access;
/* Non-zero if executable should not contain copy relocs.
> 1: Implied by indirect_extern_access.
== 1: Turn on by -z nocopyreloc.
0: Turn off.
Setting this to non-zero may result in a non-sharable text
segment. */
int nocopyreloc;
/* Pointer to the GNU_PROPERTY_1_NEEDED property in memory. */
bfd_byte *needed_1_p;
/* May be used to set DT_FLAGS for ELF. */
bfd_vma flags;

View File

@ -1,5 +1,8 @@
-*- text -*-
* Add -z indirect-extern-access/-z noindirect-extern-access to control
canonical function pointers and copy relocation.
* Add --max-cache-size=SIZE to set the the maximum cache size to SIZE
bytes.

View File

@ -1,11 +1,21 @@
PARSE_AND_LIST_OPTIONS_NOEXTEN_PROTECTED_DATA='
fprintf (file, _("\
-z noextern-protected-data Do not treat protected data symbol as external\n"));
fprintf (file, _("\
-z indirect-extern-access Enable indirect external access\n"));
fprintf (file, _("\
-z noindirect-extern-access Disable indirect external access (default)\n"));
'
# Set link_info.indirect_extern_access to 2 to indicate that it is set
# by "-z indirect-extern-access".
PARSE_AND_LIST_ARGS_CASE_Z_NOEXTEN_PROTECTED_DATA='
else if (strcmp (optarg, "noextern-protected-data") == 0)
link_info.extern_protected_data = false;
else if (strcmp (optarg, "indirect-extern-access") == 0)
link_info.indirect_extern_access = 2;
else if (strcmp (optarg, "noindirect-extern-access") == 0)
link_info.indirect_extern_access = 0;
'

View File

@ -1293,6 +1293,18 @@ Generate GNU_PROPERTY_X86_FEATURE_1_IBT in .note.gnu.property section
to indicate compatibility with IBT. This also implies @option{ibtplt}.
Supported for Linux/i386 and Linux/x86_64.
@item indirect-extern-access
@itemx noindirect-extern-access
Generate GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS in
.note.gnu.property section to indicate that object file requires
canonical function pointers and cannot be used with copy relocation.
This option also implies @option{noextern-protected-data} and
@option{nocopyreloc}. Supported for i386 and x86-64.
@option{noindirect-extern-access} removes
GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS from .note.gnu.property
section.
@item initfirst
This option is only meaningful when building a shared object.
It marks the object so that its runtime initialization will occur

View File

@ -347,6 +347,7 @@ main (int argc, char **argv)
link_info.relax_pass = 1;
link_info.extern_protected_data = -1;
link_info.dynamic_undefined_weak = -1;
link_info.indirect_extern_access = -1;
link_info.pei386_auto_import = -1;
link_info.spare_dynamic_tags = 5;
link_info.path_separator = ':';

View File

@ -0,0 +1,8 @@
#...
[a-f0-9]+ +[0-9a-f]+ +R_.*_COPY +[a-f0-9]+ +indirect_extern_access( \+ 0|)
#...
Displaying notes found in: .note.gnu.property
[ ]+Owner[ ]+Data size[ ]+Description
GNU 0x[0-9a-f]+ NT_GNU_PROPERTY_TYPE_0
Properties: 1_needed:
#pass

View File

@ -0,0 +1 @@
int indirect_extern_access = 1;

View File

@ -0,0 +1,12 @@
#include <stdio.h>
extern int indirect_extern_access;
int
main (void)
{
if (indirect_extern_access == 1)
puts ("PASS");
return 0;
}

View File

@ -0,0 +1,8 @@
#...
[a-f0-9]+ +[0-9a-f]+ +R_.*_JUMP_SLO(T|) +[a-f0-9]+ +indirect_extern_access( \+ 0|)
#...
Displaying notes found in: .note.gnu.property
[ ]+Owner[ ]+Data size[ ]+Description
GNU 0x[0-9a-f]+ NT_GNU_PROPERTY_TYPE_0
Properties: 1_needed:
#pass

View File

@ -0,0 +1,10 @@
void
indirect_extern_access (void)
{
}
void *
indirect_extern_access_p (void)
{
return indirect_extern_access;
}

View File

@ -0,0 +1,13 @@
#include <stdio.h>
extern void indirect_extern_access (void);
extern void *indirect_extern_access_p (void);
int
main (void)
{
if (&indirect_extern_access == indirect_extern_access_p ())
puts ("PASS");
return 0;
}

View File

@ -0,0 +1,8 @@
#...
[a-f0-9]+ +[0-9a-f]+ +R_.*_GLOB_DAT +[a-f0-9]+ +indirect_extern_access( \+ 0|)
#...
Displaying notes found in: .note.gnu.property
[ ]+Owner[ ]+Data size[ ]+Description
GNU 0x[0-9a-f]+ NT_GNU_PROPERTY_TYPE_0
Properties: 1_needed: indirect external access
#pass

View File

@ -0,0 +1,20 @@
# ifdef __LP64__
# define ALIGN 3
# else
# define ALIGN 2
# endif
.section ".note.gnu.property", "a"
.p2align ALIGN
.long 1f - 0f /* name length */
.long 5f - 2f /* data length */
.long 5 /* note type */
0: .asciz "GNU" /* vendor name */
1:
.p2align ALIGN
2: .long 0xb0008000 /* pr_type. */
.long 4f - 3f /* pr_datasz. */
3:
.long 0x1
4:
.p2align ALIGN
5:

View File

@ -73,6 +73,103 @@ run_ld_link_tests [list \
] \
]
run_cc_link_tests [list \
[list \
"Build indirect-extern-access-1.so" \
"-shared" \
"-fPIC" \
{ indirect-extern-access-1a.c } \
{} \
"indirect-extern-access-1.so" \
] \
[list \
"Build indirect-extern-access-1a without PIE" \
"$NOPIE_LDFLAGS -Wl,--no-as-needed \
tmpdir/indirect-extern-access-1.so" \
"$NOPIE_CFLAGS" \
{ indirect-extern-access.S indirect-extern-access-1b.c } \
{{readelf -rn indirect-extern-access-1.rd}} \
"indirect-extern-access-1a" \
] \
[list \
"Build indirect-extern-access-2.so" \
"-shared" \
"-fPIC" \
{ indirect-extern-access-2a.c } \
{} \
"indirect-extern-access-2.so" \
] \
[list \
"Build indirect-extern-access-2a without PIE" \
"$NOPIE_LDFLAGS -Wl,--no-as-needed \
tmpdir/indirect-extern-access-2.so" \
"$NOPIE_CFLAGS" \
{ indirect-extern-access.S indirect-extern-access-1b.c } \
{{readelf -rn indirect-extern-access-2.rd}} \
"indirect-extern-access-2a" \
] \
[list \
"Build indirect-extern-access-2b with PIE" \
"-pie -Wl,--no-as-needed \
tmpdir/indirect-extern-access-2.so" \
"-fpie" \
{ indirect-extern-access.S indirect-extern-access-2b.c } \
{{readelf -rn indirect-extern-access-3.rd}} \
"indirect-extern-access-2b" \
] \
]
run_ld_link_exec_tests [list \
[list \
"Run indirect-extern-access-1a without PIE" \
"$NOPIE_LDFLAGS" \
"" \
{ indirect-extern-access.S indirect-extern-access-1b.c } \
"indirect-extern-access-1a" \
"pass.out" \
"$NOPIE_CFLAGS" \
"" \
"" \
"tmpdir/indirect-extern-access-1.so" \
] \
[list \
"Run indirect-extern-access-1b with PIE" \
"-pie" \
"" \
{ indirect-extern-access.S indirect-extern-access-1b.c } \
"indirect-extern-access-1b" \
"pass.out" \
"-fpie" \
"" \
"" \
"tmpdir/indirect-extern-access-1.so" \
] \
[list \
"Run indirect-extern-access-2a without PIE" \
"$NOPIE_LDFLAGS" \
"" \
{ indirect-extern-access.S indirect-extern-access-2b.c } \
"indirect-extern-access-2a" \
"pass.out" \
"$NOPIE_CFLAGS" \
"" \
"" \
"tmpdir/indirect-extern-access-2.so" \
] \
[list \
"Run indirect-extern-access-2b with PIE" \
"-pie" \
"" \
{ indirect-extern-access.S indirect-extern-access-2b.c } \
"indirect-extern-access-2b" \
"pass.out" \
"-fpie" \
"" \
"" \
"tmpdir/indirect-extern-access-2.so" \
] \
]
proc elfedit_test { options test output } {
global ELFEDIT
global READELF

View File

@ -0,0 +1,16 @@
#source: empty.s
#as:
#ld: -shared -z indirect-extern-access
#readelf: -n
#xfail: ![check_shared_lib_support]
#notarget: am33_2.0-*-* hppa*-*-hpux* mn10300-*-*
# Assembly source file for the HPPA assembler is renamed and modifed by
# sed. mn10300 has relocations in .note.gnu.property section which
# elf_parse_notes doesn't support.
#...
Displaying notes found in: .note.gnu.property
[ ]+Owner[ ]+Data size[ ]+Description
GNU 0x[0-9a-f]+ NT_GNU_PROPERTY_TYPE_0
Properties: 1_needed: indirect external access
#pass

View File

@ -0,0 +1,17 @@
#source: empty.s
#source: property-1_needed-1.s
#as:
#ld: -shared -z noindirect-extern-access
#readelf: -n
#xfail: ![check_shared_lib_support]
#notarget: am33_2.0-*-* hppa*-*-hpux* mn10300-*-*
# Assembly source file for the HPPA assembler is renamed and modifed by
# sed. mn10300 has relocations in .note.gnu.property section which
# elf_parse_notes doesn't support.
#...
Displaying notes found in: .note.gnu.property
[ ]+Owner[ ]+Data size[ ]+Description
GNU 0x[0-9a-f]+ NT_GNU_PROPERTY_TYPE_0
Properties: 1_needed: <unknown: 2>
#pass

View File

@ -0,0 +1,6 @@
#...
Displaying notes found in: .note.gnu.property
[ ]+Owner[ ]+Data size[ ]+Description
GNU 0x[0-9a-f]+ NT_GNU_PROPERTY_TYPE_0
Properties: 1_needed: indirect external access
#pass

View File

@ -0,0 +1,11 @@
extern int protected_data_1a;
extern int protected_data_1b;
extern int *protected_data_1a_p ();
extern int *protected_data_1b_p ();
extern void set_protected_data_1a (int);
extern void set_protected_data_1b (int);
extern int check_protected_data_1a (int);
extern int check_protected_data_1b (int);

View File

@ -0,0 +1,40 @@
#include "protected-data-1.h"
int protected_data_1a __attribute__ ((visibility("protected"))) = 1;
int protected_data_1b __attribute__ ((visibility("protected"))) = 2;
int *
protected_data_1a_p (void)
{
return &protected_data_1a;
}
int *
protected_data_1b_p (void)
{
return &protected_data_1b;
}
void
set_protected_data_1a (int i)
{
protected_data_1a = i;
}
void
set_protected_data_1b (int i)
{
protected_data_1b = i;
}
int
check_protected_data_1a (int i)
{
return protected_data_1a == i ? 0 : 1;
}
int
check_protected_data_1b (int i)
{
return protected_data_1b == i ? 0 : 1;
}

View File

@ -0,0 +1,59 @@
#include <stdio.h>
#include "protected-data-1.h"
int protected_data_1b = 3;
int
main (void)
{
int res = 0;
/* Check if we get the same address for the protected data symbol. */
if (&protected_data_1a != protected_data_1a_p ())
{
puts ("'protected_data_1a' in main and shared library doesn't have same address");
res = 1;
}
protected_data_1a = -1;
if (check_protected_data_1a (-1))
{
puts ("'protected_data_1a' in main and shared library doesn't have same value");
res = 1;
}
set_protected_data_1a (-3);
if (protected_data_1a != -3)
{
puts ("'protected_data_1a' in main and shared library doesn't have same value");
res = 1;
}
/* Check if we get the different addresses for the protected data
symbol. */
if (&protected_data_1b == protected_data_1b_p ())
{
puts ("'protected_data_1b' in main and shared library has same address");
res = 1;
}
protected_data_1b = -10;
if (check_protected_data_1b (2))
{
puts ("'protected_data_1b' in main and shared library has same address");
res = 1;
}
set_protected_data_1b (-30);
if (protected_data_1b != -10)
{
puts ("'protected_data_1b' in main and shared library has same address");
res = 1;
}
if (!res)
puts ("PASS");
return res;
}

View File

@ -0,0 +1,109 @@
.text
.p2align 4
.protected protected_data_1a
.globl protected_data_1a_p
.type protected_data_1a_p, @function
protected_data_1a_p:
.LFB0:
.cfi_startproc
leaq protected_data_1a(%rip), %rax
ret
.cfi_endproc
.LFE0:
.size protected_data_1a_p, .-protected_data_1a_p
.p2align 4
.protected protected_data_1b
.globl protected_data_1b_p
.type protected_data_1b_p, @function
protected_data_1b_p:
.LFB1:
.cfi_startproc
leaq protected_data_1b(%rip), %rax
ret
.cfi_endproc
.LFE1:
.size protected_data_1b_p, .-protected_data_1b_p
.p2align 4
.globl set_protected_data_1a
.type set_protected_data_1a, @function
set_protected_data_1a:
.LFB2:
.cfi_startproc
movl %edi, protected_data_1a(%rip)
ret
.cfi_endproc
.LFE2:
.size set_protected_data_1a, .-set_protected_data_1a
.p2align 4
.globl set_protected_data_1b
.type set_protected_data_1b, @function
set_protected_data_1b:
.LFB3:
.cfi_startproc
movl %edi, protected_data_1b(%rip)
ret
.cfi_endproc
.LFE3:
.size set_protected_data_1b, .-set_protected_data_1b
.p2align 4
.globl check_protected_data_1a
.type check_protected_data_1a, @function
check_protected_data_1a:
.LFB4:
.cfi_startproc
xorl %eax, %eax
cmpl %edi, protected_data_1a(%rip)
setne %al
ret
.cfi_endproc
.LFE4:
.size check_protected_data_1a, .-check_protected_data_1a
.p2align 4
.globl check_protected_data_1b
.type check_protected_data_1b, @function
check_protected_data_1b:
.LFB5:
.cfi_startproc
xorl %eax, %eax
cmpl %edi, protected_data_1b(%rip)
setne %al
ret
.cfi_endproc
.LFE5:
.size check_protected_data_1b, .-check_protected_data_1b
.globl protected_data_1b
.data
.align 4
.type protected_data_1b, @object
.size protected_data_1b, 4
protected_data_1b:
.long 2
.globl protected_data_1a
.align 4
.type protected_data_1a, @object
.size protected_data_1a, 4
protected_data_1a:
.long 1
.section .note.GNU-stack,"",@progbits
#ifdef USE_GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS
# ifdef __LP64__
# define ALIGN 3
# else
# define ALIGN 2
# endif
.section ".note.gnu.property", "a"
.p2align ALIGN
.long 1f - 0f /* name length */
.long 5f - 2f /* data length */
.long 5 /* note type */
0: .asciz "GNU" /* vendor name */
1:
.p2align ALIGN
2: .long 0xb0008000 /* pr_type. */
.long 4f - 3f /* pr_datasz. */
3:
.long 0x1
4:
.p2align ALIGN
5:
#endif

View File

@ -0,0 +1,119 @@
.section .rodata.str1.8,"aMS",@progbits,1
.align 8
.LC0:
.string "'protected_data_1a' in main and shared library doesn't have same address"
.align 8
.LC1:
.string "'protected_data_1a' in main and shared library doesn't have same value"
.align 8
.LC2:
.string "'protected_data_1b' in main and shared library has same address"
.section .rodata.str1.1,"aMS",@progbits,1
.LC3:
.string "PASS"
.section .text.startup,"ax",@progbits
.p2align 4,,15
.globl main
.type main, @function
main:
.LFB11:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
xorl %eax, %eax
pushq %rbx
.cfi_def_cfa_offset 24
.cfi_offset 3, -24
xorl %ebx, %ebx
subq $8, %rsp
.cfi_def_cfa_offset 32
call protected_data_1a_p
movq protected_data_1a@GOTPCREL(%rip), %rbp
cmpq %rbp, %rax
je .L2
leaq .LC0(%rip), %rdi
movb $1, %bl
call puts
.L2:
movl $-1, %edi
movl $-1, 0(%rbp)
call check_protected_data_1a
testl %eax, %eax
jne .L17
.L3:
movl $-3, %edi
call set_protected_data_1a
cmpl $-3, 0(%rbp)
je .L4
leaq .LC1(%rip), %rdi
movl $1, %ebx
call puts
.L4:
xorl %eax, %eax
call protected_data_1b_p
leaq protected_data_1b(%rip), %rdx
cmpq %rdx, %rax
je .L18
.L5:
movl $2, %edi
movl $-10, protected_data_1b(%rip)
call check_protected_data_1b
testl %eax, %eax
jne .L19
movl $-30, %edi
call set_protected_data_1b
cmpl $-10, protected_data_1b(%rip)
je .L9
.L7:
leaq .LC2(%rip), %rdi
movl $1, %ebx
call puts
.L8:
addq $8, %rsp
.cfi_remember_state
.cfi_def_cfa_offset 24
movl %ebx, %eax
popq %rbx
.cfi_def_cfa_offset 16
popq %rbp
.cfi_def_cfa_offset 8
ret
.L9:
.cfi_restore_state
testl %ebx, %ebx
jne .L11
leaq .LC3(%rip), %rdi
call puts
jmp .L8
.L19:
leaq .LC2(%rip), %rdi
call puts
movl $-30, %edi
call set_protected_data_1b
cmpl $-10, protected_data_1b(%rip)
jne .L7
.L11:
movl $1, %ebx
jmp .L8
.L17:
leaq .LC1(%rip), %rdi
movl $1, %ebx
call puts
jmp .L3
.L18:
leaq .LC2(%rip), %rdi
movl $1, %ebx
call puts
jmp .L5
.cfi_endproc
.LFE11:
.size main, .-main
.globl protected_data_1b
.data
.align 4
.type protected_data_1b, @object
.size protected_data_1b, 4
protected_data_1b:
.long 3
.section .note.GNU-stack,"",@progbits

View File

@ -0,0 +1,68 @@
.text
.p2align 4
.protected protected_func_1a
.globl protected_func_1a
.type protected_func_1a, @function
protected_func_1a:
.LFB0:
.cfi_startproc
movl $1, %eax
ret
.cfi_endproc
.LFE0:
.size protected_func_1a, .-protected_func_1a
.p2align 4
.protected protected_func_1b
.globl protected_func_1b
.type protected_func_1b, @function
protected_func_1b:
.LFB1:
.cfi_startproc
movl $2, %eax
ret
.cfi_endproc
.LFE1:
.size protected_func_1b, .-protected_func_1b
.p2align 4
.globl protected_func_1a_p
.type protected_func_1a_p, @function
protected_func_1a_p:
.LFB2:
.cfi_startproc
leaq protected_func_1a(%rip), %rax
ret
.cfi_endproc
.LFE2:
.size protected_func_1a_p, .-protected_func_1a_p
.p2align 4
.globl protected_func_1b_p
.type protected_func_1b_p, @function
protected_func_1b_p:
.LFB3:
.cfi_startproc
leaq protected_func_1b(%rip), %rax
ret
.cfi_endproc
.LFE3:
.size protected_func_1b_p, .-protected_func_1b_p
.section .note.GNU-stack,"",@progbits
#ifdef __LP64__
# define ALIGN 3
#else
# define ALIGN 2
#endif
.section ".note.gnu.property", "a"
.p2align ALIGN
.long 1f - 0f /* name length */
.long 5f - 2f /* data length */
.long 5 /* note type */
0: .asciz "GNU" /* vendor name */
1:
.p2align ALIGN
2: .long 0xb0008000 /* pr_type. */
.long 4f - 3f /* pr_datasz. */
3:
.long 0x1
4:
.p2align ALIGN
5:

View File

@ -0,0 +1,83 @@
.text
.p2align 4
.globl protected_func_1b
.type protected_func_1b, @function
protected_func_1b:
.LFB11:
.cfi_startproc
movl $3, %eax
ret
.cfi_endproc
.LFE11:
.size protected_func_1b, .-protected_func_1b
.section .rodata.str1.8,"aMS",@progbits,1
.align 8
.LC0:
.string "'protected_func_1a' in main and shared library doesn't have same address"
.align 8
.LC1:
.string "'protected_func_1a' doesn't return the correct value"
.align 8
.LC2:
.string "'protected_func_1b' in main and shared library has same address"
.section .rodata.str1.1,"aMS",@progbits,1
.LC3:
.string "PASS"
.section .text.startup,"ax",@progbits
.p2align 4
.globl main
.type main, @function
main:
.LFB12:
.cfi_startproc
pushq %r12
.cfi_def_cfa_offset 16
.cfi_offset 12, -16
xorl %r12d, %r12d
call protected_func_1a_p
cmpq protected_func_1a@GOTPCREL(%rip), %rax
je .L4
leaq .LC0(%rip), %rdi
movl $1, %r12d
call puts
.L4:
call protected_func_1a
cmpl $1, %eax
jne .L13
call protected_func_1b_p
leaq protected_func_1b(%rip), %rdx
cmpq %rax, %rdx
je .L6
testl %r12d, %r12d
jne .L12
leaq .LC3(%rip), %rdi
call puts
movl %r12d, %eax
popq %r12
.cfi_remember_state
.cfi_def_cfa_offset 8
ret
.L13:
.cfi_restore_state
leaq .LC1(%rip), %rdi
call puts
call protected_func_1b_p
leaq protected_func_1b(%rip), %rdx
cmpq %rax, %rdx
je .L6
.L12:
movl $1, %r12d
movl %r12d, %eax
popq %r12
.cfi_remember_state
.cfi_def_cfa_offset 8
ret
.L6:
.cfi_restore_state
leaq .LC2(%rip), %rdi
call puts
jmp .L12
.cfi_endproc
.LFE12:
.size main, .-main
.section .note.GNU-stack,"",@progbits

View File

@ -0,0 +1,29 @@
#include "protected-func-1.h"
protected_func_type protected_func_1a_ptr = protected_func_1a;
__attribute__ ((visibility("protected")))
int
protected_func_1a (void)
{
return 1;
}
__attribute__ ((visibility("protected")))
int
protected_func_1b (void)
{
return 2;
}
protected_func_type
protected_func_1a_p (void)
{
return protected_func_1a;
}
protected_func_type
protected_func_1b_p (void)
{
return protected_func_1b;
}

View File

@ -1334,6 +1334,63 @@ if { [isnative] && [check_compiler_available] } {
{} \
"libprotected-func-1.so" \
] \
[list \
"Build libprotected-func-2a.so" \
"-shared" \
"-fPIC -Wa,-mx86-used-note=yes" \
{ protected-func-2a.S } \
{{readelf -n indirect-extern-access.rd}} \
"libprotected-func-2a.so" \
] \
[list \
"Build libprotected-func-2b.so" \
"-shared -z indirect-extern-access" \
"-fPIC -Wa,-mx86-used-note=yes" \
{ protected-func-2c.c } \
{{readelf -n indirect-extern-access.rd}} \
"libprotected-func-2b.so" \
] \
[list \
"Build libprotected-data-1a.so" \
"-shared -z noindirect-extern-access" \
"-fPIC -Wa,-mx86-used-note=yes" \
{ protected-data-1a.c } \
{} \
"libprotected-data-1a.so" \
] \
[list \
"Build libprotected-data-1b.so" \
"-shared -z indirect-extern-access" \
"-fPIC -Wa,-mx86-used-note=yes" \
{ protected-data-1a.c } \
{} \
"libprotected-data-1b.so" \
] \
[list \
"Build protected-data-1 without PIE" \
"$NOPIE_LDFLAGS -Wl,--no-as-needed tmpdir/libprotected-data-1b.so" \
"$NOPIE_CFLAGS -Wa,-mx86-used-note=yes" \
{ protected-data-1b.c } \
{} \
"protected-data-1" \
] \
[list \
"Build libprotected-data-2a.so" \
"-shared" \
"-fPIC -Wa,-mx86-used-note=yes \
-DUSE_GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS" \
{ protected-data-2a.S } \
{{readelf -n indirect-extern-access.rd}} \
"libprotected-data-2a.so" \
] \
[list \
"Build libprotected-data-2b.so" \
"-shared -z indirect-extern-access" \
"-fPIC -Wa,-mx86-used-note=yes" \
{ protected-data-2a.S } \
{{readelf -n indirect-extern-access.rd}} \
"libprotected-data-2b.so" \
] \
]
if {[istarget "x86_64-*-linux*-gnux32"]} {
@ -1761,6 +1818,96 @@ if { [isnative] && [check_compiler_available] } {
"pass.out" \
"-fPIE" \
] \
[list \
"Run protected-func-2a without PIE" \
"$NOPIE_LDFLAGS -Wl,--no-as-needed tmpdir/libprotected-func-2a.so" \
"-Wa,-mx86-used-note=yes" \
{ protected-func-2b.S } \
"protected-func-2a" \
"pass.out" \
"$NOPIE_CFLAGS" \
] \
[list \
"Run protected-func-2b with PIE" \
"-Wl,--no-as-needed -pie tmpdir/libprotected-func-2a.so" \
"-Wa,-mx86-used-note=yes" \
{ protected-func-2b.S } \
"protected-func-2b" \
"pass.out" \
"-fPIE" \
] \
[list \
"Run protected-func-2c without PIE" \
"$NOPIE_LDFLAGS -Wl,--no-as-needed tmpdir/libprotected-func-2b.so" \
"-Wa,-mx86-used-note=yes" \
{ protected-func-2b.S } \
"protected-func-2c" \
"pass.out" \
"$NOPIE_CFLAGS" \
] \
[list \
"Run protected-func-2d with PIE" \
"-Wl,--no-as-needed -pie tmpdir/libprotected-func-2b.so" \
"-Wa,-mx86-used-note=yes" \
{ protected-func-2b.S } \
"protected-func-2d" \
"pass.out" \
"-fPIE" \
] \
[list \
"Run protected-data-1a without PIE" \
"$NOPIE_LDFLAGS -Wl,--no-as-needed tmpdir/libprotected-data-1a.so" \
"-Wa,-mx86-used-note=yes" \
{ protected-data-1b.c } \
"protected-data-1a" \
"pass.out" \
"$NOPIE_CFLAGS" \
] \
[list \
"Run protected-data-1b with PIE" \
"-Wl,--no-as-needed -pie tmpdir/libprotected-data-1a.so" \
"-Wa,-mx86-used-note=yes" \
{ protected-data-1b.c } \
"protected-data-1b" \
"pass.out" \
"-fPIE" \
] \
[list \
"Run protected-data-2a without PIE" \
"$NOPIE_LDFLAGS -Wl,--no-as-needed tmpdir/libprotected-data-2a.so" \
"-Wa,-mx86-used-note=yes" \
{ protected-data-2b.S } \
"protected-data-2a" \
"pass.out" \
"$NOPIE_CFLAGS" \
] \
[list \
"Run protected-data-2b with PIE" \
"-Wl,--no-as-needed -pie tmpdir/libprotected-data-2a.so" \
"-Wa,-mx86-used-note=yes" \
{ protected-data-2b.S } \
"protected-data-2b" \
"pass.out" \
"-fPIE" \
] \
[list \
"Run protected-data-2c without PIE" \
"$NOPIE_LDFLAGS -Wl,--no-as-needed tmpdir/libprotected-data-2b.so" \
"-Wa,-mx86-used-note=yes" \
{ protected-data-2b.S } \
"protected-data-2c" \
"pass.out" \
"$NOPIE_CFLAGS" \
] \
[list \
"Run protected-data-2d with PIE" \
"-Wl,--no-as-needed -pie tmpdir/libprotected-data-2b.so" \
"-Wa,-mx86-used-note=yes" \
{ protected-data-2b.S } \
"protected-data-2d" \
"pass.out" \
"-fPIE" \
] \
]
# Run-time tests which require working ifunc attribute support.