aboutsummaryrefslogtreecommitdiff
path: root/bfd
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2021-06-17 14:11:28 -0700
committerH.J. Lu <hjl.tools@gmail.com>2021-07-08 18:14:31 -0700
commit6f365fda85a2e2682b197540d14adf66c4261b19 (patch)
treef746621b46e022fabe3662b04da4d5c2a36f2e1b /bfd
parent6320fd00dc374f74658c7e4b7dffbe1d71723284 (diff)
downloadgdb-6f365fda85a2e2682b197540d14adf66c4261b19.zip
gdb-6f365fda85a2e2682b197540d14adf66c4261b19.tar.gz
gdb-6f365fda85a2e2682b197540d14adf66c4261b19.tar.bz2
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.
Diffstat (limited to 'bfd')
-rw-r--r--bfd/elf-bfd.h6
-rw-r--r--bfd/elf-properties.c129
-rw-r--r--bfd/elf32-i386.c3
-rw-r--r--bfd/elf64-x86-64.c6
-rw-r--r--bfd/elflink.c4
-rw-r--r--bfd/elfxx-x86.c19
-rw-r--r--bfd/elfxx-x86.h4
7 files changed, 152 insertions, 19 deletions
diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 65c08ca..b3f56b8 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -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 *);
diff --git a/bfd/elf-properties.c b/bfd/elf-properties.c
index 56ee91d..aae0288 100644
--- a/bfd/elf-properties.c
+++ b/bfd/elf-properties.c
@@ -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;
}
diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c
index 1898ba3..9a9e48b 100644
--- a/bfd/elf32-i386.c
+++ b/bfd/elf32-i386.c
@@ -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. */
diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
index 8deb62d..dc416a7 100644
--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -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. */
diff --git a/bfd/elflink.c b/bfd/elflink.c
index 003c954..c9d5da2 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -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
diff --git a/bfd/elfxx-x86.c b/bfd/elfxx-x86.c
index 088f6e5..fe4a822 100644
--- a/bfd/elfxx-x86.c
+++ b/bfd/elfxx-x86.c
@@ -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)
{
diff --git a/bfd/elfxx-x86.h b/bfd/elfxx-x86.h
index db11327..8251f64 100644
--- a/bfd/elfxx-x86.h
+++ b/bfd/elfxx-x86.h
@@ -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;