Always define referenced __start_SECNAME/__stop_SECNAME
Currently, linker will define __start_SECNAME and __stop_SECNAME symbols only for orphaned sections. However, during garbage collection, ELF linker marks all sections with references to __start_SECNAME and __stop_SECNAME symbols as used even when section SECNAME isn't an orphaned section and linker won't define __start_SECNAME nor __stop_SECNAME. And ELF linker stores the first input section whose name matches __start_SECNAME or __stop_SECNAME in u.undef.section for garbage collection. If these symbols are provided in linker script, u.undef.section is set to the section where they will defined by linker script, which leads to the incorrect output. This patch changes linker to always define referenced __start_SECNAME and __stop_SECNAME if the input section name is the same as the output section name, which is always true for orphaned sections, and SECNAME is a C identifier. Also __start_SECNAME and __stop_SECNAME symbols are marked as hidden by ELF linker so that __start_SECNAME and __stop_SECNAME symbols for section SECNAME in different modules are unique. For garbage collection, ELF linker stores the first matched input section in the unused vtable field. bfd/ PR ld/20022 PR ld/21557 PR ld/21562 PR ld/21571 * elf-bfd.h (elf_link_hash_entry): Add start_stop. Change the vtable field to a union. (_bfd_elf_is_start_stop): Removed. * elf32-i386.c (elf_i386_convert_load_reloc): Also check for __start_SECNAME and __stop_SECNAME symbols. * elf64-x86-64.c (elf_x86_64_convert_load_reloc): Likewise. * elflink.c (_bfd_elf_is_start_stop): Removed. (_bfd_elf_gc_mark_rsec): Check start_stop instead of calling _bfd_elf_is_start_stop. (elf_gc_propagate_vtable_entries_used): Skip __start_SECNAME and __stop_SECNAME symbols. Updated. (elf_gc_smash_unused_vtentry_relocs): Likewise. (bfd_elf_gc_record_vtinherit): Likewise. (bfd_elf_gc_record_vtentry): Likewise. ld/ PR ld/20022 PR ld/21557 PR ld/21562 PR ld/21571 * ld.texinfo: Update __start_SECNAME/__stop_SECNAME symbols. * ldlang.c (lang_insert_orphan): Move handling of __start_SECNAME and __stop_SECNAME symbols to ... (lang_set_startof): Here. Also define __start_SECNAME and __stop_SECNAME for -Ur. * emultempl/elf32.em (gld${EMULATION_NAME}_after_open): Mark referenced __start_SECNAME and __stop_SECNAME symbols as hidden and set start_stop for garbage collection. * testsuite/ld-elf/pr21562a.d: New file. * testsuite/ld-elf/pr21562a.s: Likewise. * testsuite/ld-elf/pr21562a.t: Likewise. * testsuite/ld-elf/pr21562b.d: Likewise. * testsuite/ld-elf/pr21562b.s: Likewise. * testsuite/ld-elf/pr21562b.t: Likewise. * testsuite/ld-elf/pr21562c.d: Likewise. * testsuite/ld-elf/pr21562c.t: Likewise. * testsuite/ld-elf/pr21562d.d: Likewise. * testsuite/ld-elf/pr21562d.t: Likewise. * testsuite/ld-elf/pr21562e.d: Likewise. * testsuite/ld-elf/pr21562f.d: Likewise. * testsuite/ld-elf/pr21562g.d: Likewise. * testsuite/ld-elf/pr21562h.d: Likewise. * testsuite/ld-elf/pr21562i.d: Likewise. * testsuite/ld-elf/pr21562j.d: Likewise. * testsuite/ld-elf/pr21562k.d: Likewise. * testsuite/ld-elf/pr21562l.d: Likewise. * testsuite/ld-elf/pr21562m.d: Likewise. * testsuite/ld-elf/pr21562n.d: Likewise. * testsuite/ld-gc/pr20022.d: Likewise. * testsuite/ld-gc/pr20022a.s: Likewise. * testsuite/ld-gc/pr20022b.s: Likewise. * testsuite/ld-gc/gc.exp: Run PR ld/20022 tests. * testsuite/ld-gc/pr19161.d: Also accept local __start_SECNAME symbol. * testsuite/ld-gc/start.d: Likewise. * testsuite/ld-x86-64/lea1a.d: Updated. * testsuite/ld-x86-64/lea1b.d: Updated. * testsuite/ld-x86-64/lea1d.d: Updated. * testsuite/ld-x86-64/lea1e.d: Likewise.
This commit is contained in:
parent
6490dc678b
commit
cbd0eecf26
39 changed files with 473 additions and 182 deletions
|
@ -1,3 +1,24 @@
|
||||||
|
2017-06-13 H.J. Lu <hongjiu.lu@intel.com>
|
||||||
|
|
||||||
|
PR ld/20022
|
||||||
|
PR ld/21557
|
||||||
|
PR ld/21562
|
||||||
|
PR ld/21571
|
||||||
|
* elf-bfd.h (elf_link_hash_entry): Add start_stop. Change the
|
||||||
|
vtable field to a union.
|
||||||
|
(_bfd_elf_is_start_stop): Removed.
|
||||||
|
* elf32-i386.c (elf_i386_convert_load_reloc): Also check for
|
||||||
|
__start_SECNAME and __stop_SECNAME symbols.
|
||||||
|
* elf64-x86-64.c (elf_x86_64_convert_load_reloc): Likewise.
|
||||||
|
* elflink.c (_bfd_elf_is_start_stop): Removed.
|
||||||
|
(_bfd_elf_gc_mark_rsec): Check start_stop instead of calling
|
||||||
|
_bfd_elf_is_start_stop.
|
||||||
|
(elf_gc_propagate_vtable_entries_used): Skip __start_SECNAME and
|
||||||
|
__stop_SECNAME symbols. Updated.
|
||||||
|
(elf_gc_smash_unused_vtentry_relocs): Likewise.
|
||||||
|
(bfd_elf_gc_record_vtinherit): Likewise.
|
||||||
|
(bfd_elf_gc_record_vtentry): Likewise.
|
||||||
|
|
||||||
2017-06-13 Nick Clifton <nickc@redhat.com>
|
2017-06-13 Nick Clifton <nickc@redhat.com>
|
||||||
|
|
||||||
PR ld/21524
|
PR ld/21524
|
||||||
|
|
|
@ -213,6 +213,9 @@ struct elf_link_hash_entry
|
||||||
/* Symbol is defined by a shared library with non-default visibility
|
/* Symbol is defined by a shared library with non-default visibility
|
||||||
in a read/write section. */
|
in a read/write section. */
|
||||||
unsigned int protected_def : 1;
|
unsigned int protected_def : 1;
|
||||||
|
/* Symbol is __start_SECNAME or __stop_SECNAME to mark section
|
||||||
|
SECNAME. */
|
||||||
|
unsigned int start_stop : 1;
|
||||||
|
|
||||||
/* String table index in .dynstr if this is a dynamic symbol. */
|
/* String table index in .dynstr if this is a dynamic symbol. */
|
||||||
unsigned long dynstr_index;
|
unsigned long dynstr_index;
|
||||||
|
@ -243,7 +246,15 @@ struct elf_link_hash_entry
|
||||||
struct bfd_elf_version_tree *vertree;
|
struct bfd_elf_version_tree *vertree;
|
||||||
} verinfo;
|
} verinfo;
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
/* For __start_SECNAME and __stop_SECNAME symbols, record the first
|
||||||
|
input section whose section name is SECNAME. */
|
||||||
|
asection *start_stop_section;
|
||||||
|
|
||||||
|
/* Vtable information. */
|
||||||
struct elf_link_virtual_table_entry *vtable;
|
struct elf_link_virtual_table_entry *vtable;
|
||||||
|
} u2;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Will references to this symbol always reference the symbol
|
/* Will references to this symbol always reference the symbol
|
||||||
|
@ -2445,9 +2456,6 @@ extern bfd_boolean bfd_elf_gc_common_finalize_got_offsets
|
||||||
extern bfd_boolean bfd_elf_gc_common_final_link
|
extern bfd_boolean bfd_elf_gc_common_final_link
|
||||||
(bfd *, struct bfd_link_info *);
|
(bfd *, struct bfd_link_info *);
|
||||||
|
|
||||||
extern asection *_bfd_elf_is_start_stop
|
|
||||||
(const struct bfd_link_info *, struct elf_link_hash_entry *);
|
|
||||||
|
|
||||||
extern bfd_boolean bfd_elf_reloc_symbol_deleted_p
|
extern bfd_boolean bfd_elf_reloc_symbol_deleted_p
|
||||||
(bfd_vma, void *);
|
(bfd_vma, void *);
|
||||||
|
|
||||||
|
|
|
@ -1787,11 +1787,13 @@ convert_branch:
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
/* def_regular is set by an assignment in a linker script in
|
/* def_regular is set by an assignment in a linker script in
|
||||||
bfd_elf_record_link_assignment. */
|
bfd_elf_record_link_assignment. start_stop is set on
|
||||||
if ((h->def_regular
|
__start_SECNAME/__stop_SECNAME which mark section SECNAME. */
|
||||||
|
if (h->start_stop
|
||||||
|
|| ((h->def_regular
|
||||||
|| h->root.type == bfd_link_hash_defined
|
|| h->root.type == bfd_link_hash_defined
|
||||||
|| h->root.type == bfd_link_hash_defweak)
|
|| h->root.type == bfd_link_hash_defweak)
|
||||||
&& SYMBOL_REFERENCES_LOCAL (link_info, h))
|
&& SYMBOL_REFERENCES_LOCAL (link_info, h)))
|
||||||
{
|
{
|
||||||
convert_load:
|
convert_load:
|
||||||
if (opcode == 0x8b)
|
if (opcode == 0x8b)
|
||||||
|
|
|
@ -1920,21 +1920,25 @@ elf_x86_64_convert_load_reloc (bfd *abfd, asection *sec,
|
||||||
}
|
}
|
||||||
/* Avoid optimizing GOTPCREL relocations againt _DYNAMIC since
|
/* Avoid optimizing GOTPCREL relocations againt _DYNAMIC since
|
||||||
ld.so may use its link-time address. */
|
ld.so may use its link-time address. */
|
||||||
else if ((h->def_regular
|
else if (h->start_stop
|
||||||
|
|| ((h->def_regular
|
||||||
|| h->root.type == bfd_link_hash_defined
|
|| h->root.type == bfd_link_hash_defined
|
||||||
|| h->root.type == bfd_link_hash_defweak)
|
|| h->root.type == bfd_link_hash_defweak)
|
||||||
&& h != htab->elf.hdynamic
|
&& h != htab->elf.hdynamic
|
||||||
&& SYMBOL_REFERENCES_LOCAL (link_info, h))
|
&& SYMBOL_REFERENCES_LOCAL (link_info, h)))
|
||||||
{
|
{
|
||||||
/* bfd_link_hash_new or bfd_link_hash_undefined is
|
/* bfd_link_hash_new or bfd_link_hash_undefined is
|
||||||
set by an assignment in a linker script in
|
set by an assignment in a linker script in
|
||||||
bfd_elf_record_link_assignment. */
|
bfd_elf_record_link_assignment. start_stop is set
|
||||||
if (h->def_regular
|
on __start_SECNAME/__stop_SECNAME which mark section
|
||||||
|
SECNAME. */
|
||||||
|
if (h->start_stop
|
||||||
|
|| (h->def_regular
|
||||||
&& (h->root.type == bfd_link_hash_new
|
&& (h->root.type == bfd_link_hash_new
|
||||||
|| h->root.type == bfd_link_hash_undefined
|
|| h->root.type == bfd_link_hash_undefined
|
||||||
|| ((h->root.type == bfd_link_hash_defined
|
|| ((h->root.type == bfd_link_hash_defined
|
||||||
|| h->root.type == bfd_link_hash_defweak)
|
|| h->root.type == bfd_link_hash_defweak)
|
||||||
&& h->root.u.def.section == bfd_und_section_ptr)))
|
&& h->root.u.def.section == bfd_und_section_ptr))))
|
||||||
{
|
{
|
||||||
/* Skip since R_X86_64_32/R_X86_64_32S may overflow. */
|
/* Skip since R_X86_64_32/R_X86_64_32S may overflow. */
|
||||||
if (require_reloc_pc32)
|
if (require_reloc_pc32)
|
||||||
|
|
118
bfd/elflink.c
118
bfd/elflink.c
|
@ -12698,55 +12698,6 @@ elf_gc_mark_debug_section (asection *sec ATTRIBUTE_UNUSED,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For undefined __start_<name> and __stop_<name> symbols, return the
|
|
||||||
first input section matching <name>. Return NULL otherwise. */
|
|
||||||
|
|
||||||
asection *
|
|
||||||
_bfd_elf_is_start_stop (const struct bfd_link_info *info,
|
|
||||||
struct elf_link_hash_entry *h)
|
|
||||||
{
|
|
||||||
asection *s;
|
|
||||||
const char *sec_name;
|
|
||||||
|
|
||||||
if (h->root.type != bfd_link_hash_undefined
|
|
||||||
&& h->root.type != bfd_link_hash_undefweak)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
s = h->root.u.undef.section;
|
|
||||||
if (s != NULL)
|
|
||||||
{
|
|
||||||
if (s == (asection *) 0 - 1)
|
|
||||||
return NULL;
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
sec_name = NULL;
|
|
||||||
if (strncmp (h->root.root.string, "__start_", 8) == 0)
|
|
||||||
sec_name = h->root.root.string + 8;
|
|
||||||
else if (strncmp (h->root.root.string, "__stop_", 7) == 0)
|
|
||||||
sec_name = h->root.root.string + 7;
|
|
||||||
|
|
||||||
if (sec_name != NULL && *sec_name != '\0')
|
|
||||||
{
|
|
||||||
bfd *i;
|
|
||||||
|
|
||||||
for (i = info->input_bfds; i != NULL; i = i->link.next)
|
|
||||||
{
|
|
||||||
s = bfd_get_section_by_name (i, sec_name);
|
|
||||||
if (s != NULL)
|
|
||||||
{
|
|
||||||
h->root.u.undef.section = s;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s == NULL)
|
|
||||||
h->root.u.undef.section = (asection *) 0 - 1;
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* COOKIE->rel describes a relocation against section SEC, which is
|
/* COOKIE->rel describes a relocation against section SEC, which is
|
||||||
a section we've decided to keep. Return the section that contains
|
a section we've decided to keep. Return the section that contains
|
||||||
the relocation symbol, or NULL if no section contains it. */
|
the relocation symbol, or NULL if no section contains it. */
|
||||||
|
@ -12792,10 +12743,9 @@ _bfd_elf_gc_mark_rsec (struct bfd_link_info *info, asection *sec,
|
||||||
or __stop_XXX symbols. The linker will later define such
|
or __stop_XXX symbols. The linker will later define such
|
||||||
symbols for orphan input sections that have a name
|
symbols for orphan input sections that have a name
|
||||||
representable as a C identifier. */
|
representable as a C identifier. */
|
||||||
asection *s = _bfd_elf_is_start_stop (info, h);
|
if (h->start_stop)
|
||||||
|
|
||||||
if (s != NULL)
|
|
||||||
{
|
{
|
||||||
|
asection *s = h->u2.start_stop_section;
|
||||||
*start_stop = !s->gc_mark;
|
*start_stop = !s->gc_mark;
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
@ -13136,26 +13086,28 @@ static bfd_boolean
|
||||||
elf_gc_propagate_vtable_entries_used (struct elf_link_hash_entry *h, void *okp)
|
elf_gc_propagate_vtable_entries_used (struct elf_link_hash_entry *h, void *okp)
|
||||||
{
|
{
|
||||||
/* Those that are not vtables. */
|
/* Those that are not vtables. */
|
||||||
if (h->vtable == NULL || h->vtable->parent == NULL)
|
if (h->start_stop
|
||||||
|
|| h->u2.vtable == NULL
|
||||||
|
|| h->u2.vtable->parent == NULL)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
/* Those vtables that do not have parents, we cannot merge. */
|
/* Those vtables that do not have parents, we cannot merge. */
|
||||||
if (h->vtable->parent == (struct elf_link_hash_entry *) -1)
|
if (h->u2.vtable->parent == (struct elf_link_hash_entry *) -1)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
/* If we've already been done, exit. */
|
/* If we've already been done, exit. */
|
||||||
if (h->vtable->used && h->vtable->used[-1])
|
if (h->u2.vtable->used && h->u2.vtable->used[-1])
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
/* Make sure the parent's table is up to date. */
|
/* Make sure the parent's table is up to date. */
|
||||||
elf_gc_propagate_vtable_entries_used (h->vtable->parent, okp);
|
elf_gc_propagate_vtable_entries_used (h->u2.vtable->parent, okp);
|
||||||
|
|
||||||
if (h->vtable->used == NULL)
|
if (h->u2.vtable->used == NULL)
|
||||||
{
|
{
|
||||||
/* None of this table's entries were referenced. Re-use the
|
/* None of this table's entries were referenced. Re-use the
|
||||||
parent's table. */
|
parent's table. */
|
||||||
h->vtable->used = h->vtable->parent->vtable->used;
|
h->u2.vtable->used = h->u2.vtable->parent->u2.vtable->used;
|
||||||
h->vtable->size = h->vtable->parent->vtable->size;
|
h->u2.vtable->size = h->u2.vtable->parent->u2.vtable->size;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -13163,9 +13115,9 @@ elf_gc_propagate_vtable_entries_used (struct elf_link_hash_entry *h, void *okp)
|
||||||
bfd_boolean *cu, *pu;
|
bfd_boolean *cu, *pu;
|
||||||
|
|
||||||
/* Or the parent's entries into ours. */
|
/* Or the parent's entries into ours. */
|
||||||
cu = h->vtable->used;
|
cu = h->u2.vtable->used;
|
||||||
cu[-1] = TRUE;
|
cu[-1] = TRUE;
|
||||||
pu = h->vtable->parent->vtable->used;
|
pu = h->u2.vtable->parent->u2.vtable->used;
|
||||||
if (pu != NULL)
|
if (pu != NULL)
|
||||||
{
|
{
|
||||||
const struct elf_backend_data *bed;
|
const struct elf_backend_data *bed;
|
||||||
|
@ -13173,7 +13125,7 @@ elf_gc_propagate_vtable_entries_used (struct elf_link_hash_entry *h, void *okp)
|
||||||
|
|
||||||
bed = get_elf_backend_data (h->root.u.def.section->owner);
|
bed = get_elf_backend_data (h->root.u.def.section->owner);
|
||||||
log_file_align = bed->s->log_file_align;
|
log_file_align = bed->s->log_file_align;
|
||||||
n = h->vtable->parent->vtable->size >> log_file_align;
|
n = h->u2.vtable->parent->u2.vtable->size >> log_file_align;
|
||||||
while (n--)
|
while (n--)
|
||||||
{
|
{
|
||||||
if (*pu)
|
if (*pu)
|
||||||
|
@ -13198,7 +13150,9 @@ elf_gc_smash_unused_vtentry_relocs (struct elf_link_hash_entry *h, void *okp)
|
||||||
|
|
||||||
/* Take care of both those symbols that do not describe vtables as
|
/* Take care of both those symbols that do not describe vtables as
|
||||||
well as those that are not loaded. */
|
well as those that are not loaded. */
|
||||||
if (h->vtable == NULL || h->vtable->parent == NULL)
|
if (h->start_stop
|
||||||
|
|| h->u2.vtable == NULL
|
||||||
|
|| h->u2.vtable->parent == NULL)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
BFD_ASSERT (h->root.type == bfd_link_hash_defined
|
BFD_ASSERT (h->root.type == bfd_link_hash_defined
|
||||||
|
@ -13220,11 +13174,11 @@ elf_gc_smash_unused_vtentry_relocs (struct elf_link_hash_entry *h, void *okp)
|
||||||
if (rel->r_offset >= hstart && rel->r_offset < hend)
|
if (rel->r_offset >= hstart && rel->r_offset < hend)
|
||||||
{
|
{
|
||||||
/* If the entry is in use, do nothing. */
|
/* If the entry is in use, do nothing. */
|
||||||
if (h->vtable->used
|
if (h->u2.vtable->used
|
||||||
&& (rel->r_offset - hstart) < h->vtable->size)
|
&& (rel->r_offset - hstart) < h->u2.vtable->size)
|
||||||
{
|
{
|
||||||
bfd_vma entry = (rel->r_offset - hstart) >> log_file_align;
|
bfd_vma entry = (rel->r_offset - hstart) >> log_file_align;
|
||||||
if (h->vtable->used[entry])
|
if (h->u2.vtable->used[entry])
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* Otherwise, kill it. */
|
/* Otherwise, kill it. */
|
||||||
|
@ -13448,11 +13402,11 @@ bfd_elf_gc_record_vtinherit (bfd *abfd,
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
win:
|
win:
|
||||||
if (!child->vtable)
|
if (!child->u2.vtable)
|
||||||
{
|
{
|
||||||
child->vtable = ((struct elf_link_virtual_table_entry *)
|
child->u2.vtable = ((struct elf_link_virtual_table_entry *)
|
||||||
bfd_zalloc (abfd, sizeof (*child->vtable)));
|
bfd_zalloc (abfd, sizeof (*child->u2.vtable)));
|
||||||
if (!child->vtable)
|
if (!child->u2.vtable)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
if (!h)
|
if (!h)
|
||||||
|
@ -13462,10 +13416,10 @@ bfd_elf_gc_record_vtinherit (bfd *abfd,
|
||||||
would be bad. It isn't worth paging in the local symbols to be
|
would be bad. It isn't worth paging in the local symbols to be
|
||||||
sure though; that case should simply be handled by the assembler. */
|
sure though; that case should simply be handled by the assembler. */
|
||||||
|
|
||||||
child->vtable->parent = (struct elf_link_hash_entry *) -1;
|
child->u2.vtable->parent = (struct elf_link_hash_entry *) -1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
child->vtable->parent = h;
|
child->u2.vtable->parent = h;
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -13481,18 +13435,18 @@ bfd_elf_gc_record_vtentry (bfd *abfd ATTRIBUTE_UNUSED,
|
||||||
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
|
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
|
||||||
unsigned int log_file_align = bed->s->log_file_align;
|
unsigned int log_file_align = bed->s->log_file_align;
|
||||||
|
|
||||||
if (!h->vtable)
|
if (!h->u2.vtable)
|
||||||
{
|
{
|
||||||
h->vtable = ((struct elf_link_virtual_table_entry *)
|
h->u2.vtable = ((struct elf_link_virtual_table_entry *)
|
||||||
bfd_zalloc (abfd, sizeof (*h->vtable)));
|
bfd_zalloc (abfd, sizeof (*h->u2.vtable)));
|
||||||
if (!h->vtable)
|
if (!h->u2.vtable)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addend >= h->vtable->size)
|
if (addend >= h->u2.vtable->size)
|
||||||
{
|
{
|
||||||
size_t size, bytes, file_align;
|
size_t size, bytes, file_align;
|
||||||
bfd_boolean *ptr = h->vtable->used;
|
bfd_boolean *ptr = h->u2.vtable->used;
|
||||||
|
|
||||||
/* While the symbol is undefined, we have to be prepared to handle
|
/* While the symbol is undefined, we have to be prepared to handle
|
||||||
a zero size. */
|
a zero size. */
|
||||||
|
@ -13523,7 +13477,7 @@ bfd_elf_gc_record_vtentry (bfd *abfd ATTRIBUTE_UNUSED,
|
||||||
{
|
{
|
||||||
size_t oldbytes;
|
size_t oldbytes;
|
||||||
|
|
||||||
oldbytes = (((h->vtable->size >> log_file_align) + 1)
|
oldbytes = (((h->u2.vtable->size >> log_file_align) + 1)
|
||||||
* sizeof (bfd_boolean));
|
* sizeof (bfd_boolean));
|
||||||
memset (((char *) ptr) + oldbytes, 0, bytes - oldbytes);
|
memset (((char *) ptr) + oldbytes, 0, bytes - oldbytes);
|
||||||
}
|
}
|
||||||
|
@ -13535,11 +13489,11 @@ bfd_elf_gc_record_vtentry (bfd *abfd ATTRIBUTE_UNUSED,
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
/* And arrange for that done flag to be at index -1. */
|
/* And arrange for that done flag to be at index -1. */
|
||||||
h->vtable->used = ptr + 1;
|
h->u2.vtable->used = ptr + 1;
|
||||||
h->vtable->size = size;
|
h->u2.vtable->size = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
h->vtable->used[addend >> log_file_align] = TRUE;
|
h->u2.vtable->used[addend >> log_file_align] = TRUE;
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
46
ld/ChangeLog
46
ld/ChangeLog
|
@ -1,3 +1,49 @@
|
||||||
|
2017-06-13 H.J. Lu <hongjiu.lu@intel.com>
|
||||||
|
|
||||||
|
PR ld/20022
|
||||||
|
PR ld/21557
|
||||||
|
PR ld/21562
|
||||||
|
PR ld/21571
|
||||||
|
* ld.texinfo: Update __start_SECNAME/__stop_SECNAME symbols.
|
||||||
|
* ldlang.c (lang_insert_orphan): Move handling of __start_SECNAME
|
||||||
|
and __stop_SECNAME symbols to ...
|
||||||
|
(lang_set_startof): Here. Also define __start_SECNAME and
|
||||||
|
__stop_SECNAME for -Ur.
|
||||||
|
* emultempl/elf32.em (gld${EMULATION_NAME}_after_open): Mark
|
||||||
|
referenced __start_SECNAME and __stop_SECNAME symbols as hidden
|
||||||
|
and set start_stop for garbage collection.
|
||||||
|
* testsuite/ld-elf/pr21562a.d: New file.
|
||||||
|
* testsuite/ld-elf/pr21562a.s: Likewise.
|
||||||
|
* testsuite/ld-elf/pr21562a.t: Likewise.
|
||||||
|
* testsuite/ld-elf/pr21562b.d: Likewise.
|
||||||
|
* testsuite/ld-elf/pr21562b.s: Likewise.
|
||||||
|
* testsuite/ld-elf/pr21562b.t: Likewise.
|
||||||
|
* testsuite/ld-elf/pr21562c.d: Likewise.
|
||||||
|
* testsuite/ld-elf/pr21562c.t: Likewise.
|
||||||
|
* testsuite/ld-elf/pr21562d.d: Likewise.
|
||||||
|
* testsuite/ld-elf/pr21562d.t: Likewise.
|
||||||
|
* testsuite/ld-elf/pr21562e.d: Likewise.
|
||||||
|
* testsuite/ld-elf/pr21562f.d: Likewise.
|
||||||
|
* testsuite/ld-elf/pr21562g.d: Likewise.
|
||||||
|
* testsuite/ld-elf/pr21562h.d: Likewise.
|
||||||
|
* testsuite/ld-elf/pr21562i.d: Likewise.
|
||||||
|
* testsuite/ld-elf/pr21562j.d: Likewise.
|
||||||
|
* testsuite/ld-elf/pr21562k.d: Likewise.
|
||||||
|
* testsuite/ld-elf/pr21562l.d: Likewise.
|
||||||
|
* testsuite/ld-elf/pr21562m.d: Likewise.
|
||||||
|
* testsuite/ld-elf/pr21562n.d: Likewise.
|
||||||
|
* testsuite/ld-gc/pr20022.d: Likewise.
|
||||||
|
* testsuite/ld-gc/pr20022a.s: Likewise.
|
||||||
|
* testsuite/ld-gc/pr20022b.s: Likewise.
|
||||||
|
* testsuite/ld-gc/gc.exp: Run PR ld/20022 tests.
|
||||||
|
* testsuite/ld-gc/pr19161.d: Also accept local __start_SECNAME
|
||||||
|
symbol.
|
||||||
|
* testsuite/ld-gc/start.d: Likewise.
|
||||||
|
* testsuite/ld-x86-64/lea1a.d: Updated.
|
||||||
|
* testsuite/ld-x86-64/lea1b.d: Updated.
|
||||||
|
* testsuite/ld-x86-64/lea1d.d: Updated.
|
||||||
|
* testsuite/ld-x86-64/lea1e.d: Likewise.
|
||||||
|
|
||||||
2017-06-13 H.J. Lu <hongjiu.lu@intel.com>
|
2017-06-13 H.J. Lu <hongjiu.lu@intel.com>
|
||||||
|
|
||||||
* testsuite/ld-elf/sizeof.d: New file.
|
* testsuite/ld-elf/sizeof.d: New file.
|
||||||
|
|
|
@ -1216,6 +1216,9 @@ gld${EMULATION_NAME}_after_open (void)
|
||||||
{
|
{
|
||||||
struct bfd_link_needed_list *needed, *l;
|
struct bfd_link_needed_list *needed, *l;
|
||||||
struct elf_link_hash_table *htab;
|
struct elf_link_hash_table *htab;
|
||||||
|
asection *s;
|
||||||
|
bfd *abfd;
|
||||||
|
char leading_char;
|
||||||
|
|
||||||
after_open_default ();
|
after_open_default ();
|
||||||
|
|
||||||
|
@ -1239,8 +1242,6 @@ gld${EMULATION_NAME}_after_open (void)
|
||||||
|
|
||||||
if (emit_note_gnu_build_id != NULL)
|
if (emit_note_gnu_build_id != NULL)
|
||||||
{
|
{
|
||||||
bfd *abfd;
|
|
||||||
|
|
||||||
/* Find an ELF input. */
|
/* Find an ELF input. */
|
||||||
for (abfd = link_info.input_bfds;
|
for (abfd = link_info.input_bfds;
|
||||||
abfd != (bfd *) NULL; abfd = abfd->link.next)
|
abfd != (bfd *) NULL; abfd = abfd->link.next)
|
||||||
|
@ -1276,11 +1277,66 @@ gld${EMULATION_NAME}_after_open (void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
leading_char = bfd_get_symbol_leading_char (link_info.output_bfd);
|
||||||
|
|
||||||
|
/* Check for input sections whose names match references to
|
||||||
|
__start_SECNAME or __stop_SECNAME symbols. Mark the matched
|
||||||
|
symbols as hidden and set start_stop for garbage collection. */
|
||||||
|
for (abfd = link_info.input_bfds; abfd; abfd = abfd->link.next)
|
||||||
|
for (s = abfd->sections; s; s = s->next)
|
||||||
|
{
|
||||||
|
const char *name = bfd_get_section_name (abfd, s);
|
||||||
|
const char *ps;
|
||||||
|
|
||||||
|
for (ps = name; *ps != '\0'; ps++)
|
||||||
|
if (!ISALNUM ((unsigned char) *ps) && *ps != '_')
|
||||||
|
break;
|
||||||
|
if (*ps == '\0')
|
||||||
|
{
|
||||||
|
struct elf_link_hash_entry *h;
|
||||||
|
char *symbol = (char *) xmalloc (ps - name
|
||||||
|
+ sizeof "__start_" + 1);
|
||||||
|
|
||||||
|
symbol[0] = leading_char;
|
||||||
|
sprintf (symbol + (leading_char != 0), "__start_%s", name);
|
||||||
|
h = elf_link_hash_lookup (elf_hash_table (&link_info),
|
||||||
|
symbol, FALSE, FALSE, TRUE);
|
||||||
|
if (h != NULL
|
||||||
|
&& (h->root.type == bfd_link_hash_undefined
|
||||||
|
|| h->root.type == bfd_link_hash_undefweak)
|
||||||
|
&& h->u2.start_stop_section == NULL)
|
||||||
|
{
|
||||||
|
h->start_stop = 1;
|
||||||
|
h->u2.start_stop_section = s;
|
||||||
|
_bfd_elf_link_hash_hide_symbol (&link_info, h, TRUE);
|
||||||
|
if (ELF_ST_VISIBILITY (h->other) != STV_INTERNAL)
|
||||||
|
h->other = ((h->other & ~ELF_ST_VISIBILITY (-1))
|
||||||
|
| STV_HIDDEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
symbol[0] = leading_char;
|
||||||
|
sprintf (symbol + (leading_char != 0), "__stop_%s", name);
|
||||||
|
h = elf_link_hash_lookup (elf_hash_table (&link_info),
|
||||||
|
symbol, FALSE, FALSE, TRUE);
|
||||||
|
if (h != NULL
|
||||||
|
&& (h->root.type == bfd_link_hash_undefined
|
||||||
|
|| h->root.type == bfd_link_hash_undefweak)
|
||||||
|
&& h->u2.start_stop_section == NULL)
|
||||||
|
{
|
||||||
|
h->start_stop = 1;
|
||||||
|
h->u2.start_stop_section = s;
|
||||||
|
_bfd_elf_link_hash_hide_symbol (&link_info, h, TRUE);
|
||||||
|
if (ELF_ST_VISIBILITY (h->other) != STV_INTERNAL)
|
||||||
|
h->other = ((h->other & ~ELF_ST_VISIBILITY (-1))
|
||||||
|
| STV_HIDDEN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!link_info.traditional_format)
|
if (!link_info.traditional_format)
|
||||||
{
|
{
|
||||||
bfd *abfd, *elfbfd = NULL;
|
bfd *elfbfd = NULL;
|
||||||
bfd_boolean warn_eh_frame = FALSE;
|
bfd_boolean warn_eh_frame = FALSE;
|
||||||
asection *s;
|
|
||||||
int seen_type = 0;
|
int seen_type = 0;
|
||||||
|
|
||||||
for (abfd = link_info.input_bfds; abfd; abfd = abfd->link.next)
|
for (abfd = link_info.input_bfds; abfd; abfd = abfd->link.next)
|
||||||
|
|
|
@ -4657,6 +4657,14 @@ SECTIONS @{
|
||||||
@end group
|
@end group
|
||||||
@end smallexample
|
@end smallexample
|
||||||
|
|
||||||
|
If an output section's name is the same as the input section's name
|
||||||
|
and is representable as a C identifier, then the linker will
|
||||||
|
automatically @pxref{PROVIDE} two symbols: __start_SECNAME and
|
||||||
|
__stop_SECNAME, where SECNAME is the name of the section. These
|
||||||
|
indicate the start address and end address of the output section
|
||||||
|
respectively. Note: most section names are not representable as
|
||||||
|
C identifiers because they contain a @samp{.} character.
|
||||||
|
|
||||||
@node Output Section Data
|
@node Output Section Data
|
||||||
@subsection Output Section Data
|
@subsection Output Section Data
|
||||||
@cindex data
|
@cindex data
|
||||||
|
@ -5841,14 +5849,6 @@ The command line options @samp{--orphan-handling} and @samp{--unique}
|
||||||
(@pxref{Options,,Command Line Options}) can be used to control which
|
(@pxref{Options,,Command Line Options}) can be used to control which
|
||||||
output sections an orphan is placed in.
|
output sections an orphan is placed in.
|
||||||
|
|
||||||
If an orphaned section's name is representable as a C identifier then
|
|
||||||
the linker will automatically @pxref{PROVIDE} two symbols:
|
|
||||||
__start_SECNAME and __stop_SECNAME, where SECNAME is the name of the
|
|
||||||
section. These indicate the start address and end address of the
|
|
||||||
orphaned section respectively. Note: most section names are not
|
|
||||||
representable as C identifiers because they contain a @samp{.}
|
|
||||||
character.
|
|
||||||
|
|
||||||
@node Location Counter
|
@node Location Counter
|
||||||
@subsection The Location Counter
|
@subsection The Location Counter
|
||||||
@kindex .
|
@kindex .
|
||||||
|
|
103
ld/ldlang.c
103
ld/ldlang.c
|
@ -1829,8 +1829,6 @@ lang_insert_orphan (asection *s,
|
||||||
lang_statement_list_type *add_child)
|
lang_statement_list_type *add_child)
|
||||||
{
|
{
|
||||||
lang_statement_list_type add;
|
lang_statement_list_type add;
|
||||||
const char *ps;
|
|
||||||
lang_assignment_statement_type *start_assign;
|
|
||||||
lang_output_section_statement_type *os;
|
lang_output_section_statement_type *os;
|
||||||
lang_output_section_statement_type **os_tail;
|
lang_output_section_statement_type **os_tail;
|
||||||
|
|
||||||
|
@ -1852,29 +1850,6 @@ lang_insert_orphan (asection *s,
|
||||||
os = lang_enter_output_section_statement (secname, address, normal_section,
|
os = lang_enter_output_section_statement (secname, address, normal_section,
|
||||||
NULL, NULL, NULL, constraint, 0);
|
NULL, NULL, NULL, constraint, 0);
|
||||||
|
|
||||||
ps = NULL;
|
|
||||||
start_assign = NULL;
|
|
||||||
if (config.build_constructors && *os_tail == os)
|
|
||||||
{
|
|
||||||
/* If the name of the section is representable in C, then create
|
|
||||||
symbols to mark the start and the end of the section. */
|
|
||||||
for (ps = secname; *ps != '\0'; ps++)
|
|
||||||
if (!ISALNUM ((unsigned char) *ps) && *ps != '_')
|
|
||||||
break;
|
|
||||||
if (*ps == '\0')
|
|
||||||
{
|
|
||||||
char *symname;
|
|
||||||
|
|
||||||
symname = (char *) xmalloc (ps - secname + sizeof "__start_" + 1);
|
|
||||||
symname[0] = bfd_get_symbol_leading_char (link_info.output_bfd);
|
|
||||||
sprintf (symname + (symname[0] != 0), "__start_%s", secname);
|
|
||||||
start_assign
|
|
||||||
= lang_add_assignment (exp_provide (symname,
|
|
||||||
exp_nameop (NAME, "."),
|
|
||||||
FALSE));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (add_child == NULL)
|
if (add_child == NULL)
|
||||||
add_child = &os->children;
|
add_child = &os->children;
|
||||||
lang_add_section (add_child, s, NULL, os);
|
lang_add_section (add_child, s, NULL, os);
|
||||||
|
@ -1894,27 +1869,6 @@ lang_insert_orphan (asection *s,
|
||||||
lang_leave_output_section_statement (NULL, DEFAULT_MEMORY_REGION, NULL,
|
lang_leave_output_section_statement (NULL, DEFAULT_MEMORY_REGION, NULL,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
if (start_assign != NULL)
|
|
||||||
{
|
|
||||||
char *symname;
|
|
||||||
lang_assignment_statement_type *stop_assign;
|
|
||||||
bfd_vma dot;
|
|
||||||
|
|
||||||
symname = (char *) xmalloc (ps - secname + sizeof "__stop_" + 1);
|
|
||||||
symname[0] = bfd_get_symbol_leading_char (link_info.output_bfd);
|
|
||||||
sprintf (symname + (symname[0] != 0), "__stop_%s", secname);
|
|
||||||
stop_assign
|
|
||||||
= lang_add_assignment (exp_provide (symname,
|
|
||||||
exp_nameop (NAME, "."),
|
|
||||||
FALSE));
|
|
||||||
/* Evaluate the expression to define the symbol if referenced,
|
|
||||||
before sizing dynamic sections. */
|
|
||||||
dot = os->bfd_section->vma;
|
|
||||||
exp_fold_tree (start_assign->exp, os->bfd_section, &dot);
|
|
||||||
dot += TO_ADDR (s->size);
|
|
||||||
exp_fold_tree (stop_assign->exp, os->bfd_section, &dot);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Restore the global list pointer. */
|
/* Restore the global list pointer. */
|
||||||
if (after != NULL)
|
if (after != NULL)
|
||||||
pop_stat_ptr ();
|
pop_stat_ptr ();
|
||||||
|
@ -5924,20 +5878,25 @@ section_for_dot (void)
|
||||||
return bfd_abs_section_ptr;
|
return bfd_abs_section_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fix any .startof. or .sizeof. symbols. When the assemblers see the
|
/* Fix any .startof., .sizeof., __start or __stop symbols. When the
|
||||||
operator .startof. (section_name), it produces an undefined symbol
|
assemblers see the operator .startof. (section_name), it produces
|
||||||
.startof.section_name. Similarly, when it sees
|
an undefined symbol .startof.section_name. Similarly, when it sees
|
||||||
.sizeof. (section_name), it produces an undefined symbol
|
.sizeof. (section_name), it produces an undefined symbol
|
||||||
.sizeof.section_name. For all the output sections, we look for
|
.sizeof.section_name. Also for ELF linker, __start_XXX or __stop_XXX
|
||||||
such symbols, and set them to the correct value. */
|
symbols should be resolved to the start and end of section XXX. For
|
||||||
|
all the output sections, we look for such symbols, and set them to
|
||||||
|
the correct value. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
lang_set_startof (void)
|
lang_set_startof (void)
|
||||||
{
|
{
|
||||||
asection *s;
|
asection *s;
|
||||||
|
char leading_char;
|
||||||
|
bfd_boolean is_elf = (bfd_get_flavour (link_info.output_bfd)
|
||||||
|
== bfd_target_elf_flavour);
|
||||||
|
bfd_boolean is_elocatable = bfd_link_relocatable (&link_info);
|
||||||
|
|
||||||
if (bfd_link_relocatable (&link_info))
|
leading_char = bfd_get_symbol_leading_char (link_info.output_bfd);
|
||||||
return;
|
|
||||||
|
|
||||||
for (s = link_info.output_bfd->sections; s != NULL; s = s->next)
|
for (s = link_info.output_bfd->sections; s != NULL; s = s->next)
|
||||||
{
|
{
|
||||||
|
@ -5948,8 +5907,11 @@ lang_set_startof (void)
|
||||||
secname = bfd_get_section_name (link_info.output_bfd, s);
|
secname = bfd_get_section_name (link_info.output_bfd, s);
|
||||||
buf = (char *) xmalloc (10 + strlen (secname));
|
buf = (char *) xmalloc (10 + strlen (secname));
|
||||||
|
|
||||||
|
if (!is_elocatable)
|
||||||
|
{
|
||||||
sprintf (buf, ".startof.%s", secname);
|
sprintf (buf, ".startof.%s", secname);
|
||||||
h = bfd_link_hash_lookup (link_info.hash, buf, FALSE, FALSE, TRUE);
|
h = bfd_link_hash_lookup (link_info.hash, buf, FALSE, FALSE,
|
||||||
|
TRUE);
|
||||||
if (h != NULL && h->type == bfd_link_hash_undefined)
|
if (h != NULL && h->type == bfd_link_hash_undefined)
|
||||||
{
|
{
|
||||||
h->type = bfd_link_hash_defined;
|
h->type = bfd_link_hash_defined;
|
||||||
|
@ -5958,14 +5920,45 @@ lang_set_startof (void)
|
||||||
}
|
}
|
||||||
|
|
||||||
sprintf (buf, ".sizeof.%s", secname);
|
sprintf (buf, ".sizeof.%s", secname);
|
||||||
h = bfd_link_hash_lookup (link_info.hash, buf, FALSE, FALSE, TRUE);
|
h = bfd_link_hash_lookup (link_info.hash, buf, FALSE, FALSE,
|
||||||
|
TRUE);
|
||||||
if (h != NULL && h->type == bfd_link_hash_undefined)
|
if (h != NULL && h->type == bfd_link_hash_undefined)
|
||||||
{
|
{
|
||||||
h->type = bfd_link_hash_defined;
|
h->type = bfd_link_hash_defined;
|
||||||
h->u.def.value = TO_ADDR (s->size);
|
h->u.def.value = TO_ADDR (s->size);
|
||||||
h->u.def.section = bfd_abs_section_ptr;
|
h->u.def.section = bfd_abs_section_ptr;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[0] = leading_char;
|
||||||
|
sprintf (buf + (buf[0] != 0), "__start_%s", secname);
|
||||||
|
h = bfd_link_hash_lookup (link_info.hash, buf, FALSE, FALSE,
|
||||||
|
TRUE);
|
||||||
|
if (h != NULL
|
||||||
|
&& (h->type == bfd_link_hash_undefined
|
||||||
|
|| h->type == bfd_link_hash_undefweak))
|
||||||
|
{
|
||||||
|
h->type = bfd_link_hash_defined;
|
||||||
|
h->u.def.value = 0;
|
||||||
|
h->u.def.section = s;
|
||||||
|
if (is_elf)
|
||||||
|
((struct elf_link_hash_entry *) h)->def_regular = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[0] = leading_char;
|
||||||
|
sprintf (buf + (buf[0] != 0), "__stop_%s", secname);
|
||||||
|
h = bfd_link_hash_lookup (link_info.hash, buf, FALSE, FALSE,
|
||||||
|
TRUE);
|
||||||
|
if (h != NULL
|
||||||
|
&& (h->type == bfd_link_hash_undefined
|
||||||
|
|| h->type == bfd_link_hash_undefweak))
|
||||||
|
{
|
||||||
|
h->type = bfd_link_hash_defined;
|
||||||
|
h->u.def.value = TO_ADDR (s->size);
|
||||||
|
h->u.def.section = s;
|
||||||
|
if (is_elf)
|
||||||
|
((struct elf_link_hash_entry *) h)->def_regular = 1;
|
||||||
|
}
|
||||||
free (buf);
|
free (buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
9
ld/testsuite/ld-elf/pr21562a.d
Normal file
9
ld/testsuite/ld-elf/pr21562a.d
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#ld: -shared -z defs --gc-sections
|
||||||
|
#readelf: -s -S --wide
|
||||||
|
#target: *-*-linux* *-*-gnu*
|
||||||
|
|
||||||
|
#...
|
||||||
|
\[[ 0-9]+\] scnfoo[ \t]+PROGBITS[ \t]+[0-9a-f]+ +[0-9a-f]+ +0*10[ \t]+.*
|
||||||
|
#...
|
||||||
|
+[0-9]+: +[0-9a-f]+ +[0-9a-f]+ +NOTYPE +LOCAL +DEFAULT +[0-9]+ +__start_scnfoo
|
||||||
|
#pass
|
8
ld/testsuite/ld-elf/pr21562a.s
Normal file
8
ld/testsuite/ld-elf/pr21562a.s
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
.section scnfoo,"aw",%progbits
|
||||||
|
.zero 0x10
|
||||||
|
|
||||||
|
.globl bar
|
||||||
|
.data
|
||||||
|
.type bar, %object
|
||||||
|
bar:
|
||||||
|
.dc.a __start_scnfoo
|
3
ld/testsuite/ld-elf/pr21562a.t
Normal file
3
ld/testsuite/ld-elf/pr21562a.t
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
SECTIONS {
|
||||||
|
scnfoo : { *(scnfoo) }
|
||||||
|
}
|
9
ld/testsuite/ld-elf/pr21562b.d
Normal file
9
ld/testsuite/ld-elf/pr21562b.d
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#ld: -shared -z defs --gc-sections
|
||||||
|
#readelf: -s -S --wide
|
||||||
|
#target: *-*-linux* *-*-gnu*
|
||||||
|
|
||||||
|
#...
|
||||||
|
\[[ 0-9]+\] scnfoo[ \t]+PROGBITS[ \t]+[0-9a-f]+ +[0-9a-f]+ +0*10[ \t]+.*
|
||||||
|
#...
|
||||||
|
+[0-9]+: +[0-9a-f]+ +[0-9a-f]+ +NOTYPE +LOCAL +DEFAULT +[0-9]+ +__stop_scnfoo
|
||||||
|
#pass
|
8
ld/testsuite/ld-elf/pr21562b.s
Normal file
8
ld/testsuite/ld-elf/pr21562b.s
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
.section scnfoo,"aw",%progbits
|
||||||
|
.zero 0x10
|
||||||
|
|
||||||
|
.globl bar
|
||||||
|
.data
|
||||||
|
.type bar, %object
|
||||||
|
bar:
|
||||||
|
.dc.a __stop_scnfoo
|
5
ld/testsuite/ld-elf/pr21562b.t
Normal file
5
ld/testsuite/ld-elf/pr21562b.t
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
SECTIONS {
|
||||||
|
PROVIDE (__start_scnfoo = .);
|
||||||
|
scnfoo : { *(scnfoo) }
|
||||||
|
PROVIDE (__stop_scnfoo = .);
|
||||||
|
}
|
10
ld/testsuite/ld-elf/pr21562c.d
Normal file
10
ld/testsuite/ld-elf/pr21562c.d
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#source: pr21562a.s
|
||||||
|
#ld: -shared -z defs --gc-sections -T pr21562a.t
|
||||||
|
#readelf: -s -S --wide
|
||||||
|
#target: *-*-linux* *-*-gnu*
|
||||||
|
|
||||||
|
#...
|
||||||
|
\[[ 0-9]+\] scnfoo[ \t]+PROGBITS[ \t]+[0-9a-f]+ +[0-9a-f]+ +0*10[ \t]+.*
|
||||||
|
#...
|
||||||
|
+[0-9]+: +[0-9a-f]+ +[0-9a-f]+ +NOTYPE +LOCAL +DEFAULT +[0-9]+ +__start_scnfoo
|
||||||
|
#pass
|
7
ld/testsuite/ld-elf/pr21562c.t
Normal file
7
ld/testsuite/ld-elf/pr21562c.t
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
SECTIONS {
|
||||||
|
.foo : {
|
||||||
|
PROVIDE (__start_scnfoo = .);
|
||||||
|
*(scnfoo)
|
||||||
|
PROVIDE (__stop_scnfoo = .);
|
||||||
|
}
|
||||||
|
}
|
10
ld/testsuite/ld-elf/pr21562d.d
Normal file
10
ld/testsuite/ld-elf/pr21562d.d
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#source: pr21562b.s
|
||||||
|
#ld: -shared -z defs --gc-sections -T pr21562a.t
|
||||||
|
#readelf: -s -S --wide
|
||||||
|
#target: *-*-linux* *-*-gnu*
|
||||||
|
|
||||||
|
#...
|
||||||
|
\[[ 0-9]+\] scnfoo[ \t]+PROGBITS[ \t]+[0-9a-f]+ +[0-9a-f]+ +0*10[ \t]+.*
|
||||||
|
#...
|
||||||
|
+[0-9]+: +[0-9a-f]+ +[0-9a-f]+ +NOTYPE +LOCAL +DEFAULT +[0-9]+ +__stop_scnfoo
|
||||||
|
#pass
|
5
ld/testsuite/ld-elf/pr21562d.t
Normal file
5
ld/testsuite/ld-elf/pr21562d.t
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
SECTIONS {
|
||||||
|
PROVIDE (__start_scnfoo = .);
|
||||||
|
.foo : { *(scnfoo) }
|
||||||
|
PROVIDE (__stop_scnfoo = .);
|
||||||
|
}
|
10
ld/testsuite/ld-elf/pr21562e.d
Normal file
10
ld/testsuite/ld-elf/pr21562e.d
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#source: pr21562a.s
|
||||||
|
#ld: -shared -z defs
|
||||||
|
#readelf: -s -S --wide
|
||||||
|
#target: *-*-linux* *-*-gnu*
|
||||||
|
|
||||||
|
#...
|
||||||
|
\[[ 0-9]+\] scnfoo[ \t]+PROGBITS[ \t]+[0-9a-f]+ +[0-9a-f]+ +0*10[ \t]+.*
|
||||||
|
#...
|
||||||
|
+[0-9]+: +[0-9a-f]+ +[0-9a-f]+ +NOTYPE +LOCAL +DEFAULT +[0-9]+ +__start_scnfoo
|
||||||
|
#pass
|
10
ld/testsuite/ld-elf/pr21562f.d
Normal file
10
ld/testsuite/ld-elf/pr21562f.d
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#source: pr21562b.s
|
||||||
|
#ld: -shared -z defs
|
||||||
|
#readelf: -s -S --wide
|
||||||
|
#target: *-*-linux* *-*-gnu*
|
||||||
|
|
||||||
|
#...
|
||||||
|
\[[ 0-9]+\] scnfoo[ \t]+PROGBITS[ \t]+[0-9a-f]+ +[0-9a-f]+ +0*10[ \t]+.*
|
||||||
|
#...
|
||||||
|
+[0-9]+: +[0-9a-f]+ +[0-9a-f]+ +NOTYPE +LOCAL +DEFAULT +[0-9]+ +__stop_scnfoo
|
||||||
|
#pass
|
10
ld/testsuite/ld-elf/pr21562g.d
Normal file
10
ld/testsuite/ld-elf/pr21562g.d
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#source: pr21562a.s
|
||||||
|
#ld: -shared -z defs -T pr21562a.t
|
||||||
|
#readelf: -s -S --wide
|
||||||
|
#target: *-*-linux* *-*-gnu*
|
||||||
|
|
||||||
|
#...
|
||||||
|
\[[ 0-9]+\] scnfoo[ \t]+PROGBITS[ \t]+[0-9a-f]+ +[0-9a-f]+ +0*10[ \t]+.*
|
||||||
|
#...
|
||||||
|
+[0-9]+: +[0-9a-f]+ +[0-9a-f]+ +NOTYPE +LOCAL +DEFAULT +[0-9]+ +__start_scnfoo
|
||||||
|
#pass
|
10
ld/testsuite/ld-elf/pr21562h.d
Normal file
10
ld/testsuite/ld-elf/pr21562h.d
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#source: pr21562b.s
|
||||||
|
#ld: -shared -z defs -T pr21562a.t
|
||||||
|
#readelf: -s -S --wide
|
||||||
|
#target: *-*-linux* *-*-gnu*
|
||||||
|
|
||||||
|
#...
|
||||||
|
\[[ 0-9]+\] scnfoo[ \t]+PROGBITS[ \t]+[0-9a-f]+ +[0-9a-f]+ +0*10[ \t]+.*
|
||||||
|
#...
|
||||||
|
+[0-9]+: +[0-9a-f]+ +[0-9a-f]+ +NOTYPE +LOCAL +DEFAULT +[0-9]+ +__stop_scnfoo
|
||||||
|
#pass
|
10
ld/testsuite/ld-elf/pr21562i.d
Normal file
10
ld/testsuite/ld-elf/pr21562i.d
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#source: pr21562a.s
|
||||||
|
#ld: -shared -z defs --gc-sections -T pr21562b.t
|
||||||
|
#readelf: -s -S --wide
|
||||||
|
#target: *-*-linux* *-*-gnu*
|
||||||
|
|
||||||
|
#...
|
||||||
|
\[[ 0-9]+\] scnfoo[ \t]+PROGBITS[ \t]+[0-9a-f]+ +[0-9a-f]+ +0*10[ \t]+.*
|
||||||
|
#...
|
||||||
|
+[0-9]+: +[0-9a-f]+ +[0-9a-f]+ +NOTYPE +LOCAL +DEFAULT +[0-9]+ +__start_scnfoo
|
||||||
|
#pass
|
10
ld/testsuite/ld-elf/pr21562j.d
Normal file
10
ld/testsuite/ld-elf/pr21562j.d
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#source: pr21562b.s
|
||||||
|
#ld: -shared -z defs --gc-sections -T pr21562b.t
|
||||||
|
#readelf: -s -S --wide
|
||||||
|
#target: *-*-linux* *-*-gnu*
|
||||||
|
|
||||||
|
#...
|
||||||
|
\[[ 0-9]+\] scnfoo[ \t]+PROGBITS[ \t]+[0-9a-f]+ +[0-9a-f]+ +0*10[ \t]+.*
|
||||||
|
#...
|
||||||
|
+[0-9]+: +[0-9a-f]+ +[0-9a-f]+ +NOTYPE +LOCAL +DEFAULT +[0-9]+ +__stop_scnfoo
|
||||||
|
#pass
|
10
ld/testsuite/ld-elf/pr21562k.d
Normal file
10
ld/testsuite/ld-elf/pr21562k.d
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#source: pr21562a.s
|
||||||
|
#ld: -shared -z defs --gc-sections -T pr21562c.t
|
||||||
|
#readelf: -s -S --wide
|
||||||
|
#target: *-*-linux* *-*-gnu*
|
||||||
|
|
||||||
|
#...
|
||||||
|
\[[ 0-9]+\] \.foo[ \t]+PROGBITS[ \t]+[0-9a-f]+ +[0-9a-f]+ +0*10[ \t]+.*
|
||||||
|
#...
|
||||||
|
+[0-9]+: +[0-9a-f]+ +[0-9a-f]+ +NOTYPE +LOCAL +DEFAULT +[0-9]+ +__start_scnfoo
|
||||||
|
#pass
|
10
ld/testsuite/ld-elf/pr21562l.d
Normal file
10
ld/testsuite/ld-elf/pr21562l.d
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#source: pr21562b.s
|
||||||
|
#ld: -shared -z defs --gc-sections -T pr21562c.t
|
||||||
|
#readelf: -s -S --wide
|
||||||
|
#target: *-*-linux* *-*-gnu*
|
||||||
|
|
||||||
|
#...
|
||||||
|
\[[ 0-9]+\] \.foo[ \t]+PROGBITS[ \t]+[0-9a-f]+ +[0-9a-f]+ +0*10[ \t]+.*
|
||||||
|
#...
|
||||||
|
+[0-9]+: +[0-9a-f]+ +[0-9a-f]+ +NOTYPE +LOCAL +DEFAULT +[0-9]+ +__stop_scnfoo
|
||||||
|
#pass
|
10
ld/testsuite/ld-elf/pr21562m.d
Normal file
10
ld/testsuite/ld-elf/pr21562m.d
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#source: pr21562a.s
|
||||||
|
#ld: -shared -z defs --gc-sections -T pr21562d.t
|
||||||
|
#readelf: -s -S --wide
|
||||||
|
#target: *-*-linux* *-*-gnu*
|
||||||
|
|
||||||
|
#...
|
||||||
|
\[[ 0-9]+\] \.foo[ \t]+PROGBITS[ \t]+[0-9a-f]+ +[0-9a-f]+ +0*10[ \t]+.*
|
||||||
|
#...
|
||||||
|
+[0-9]+: +[0-9a-f]+ +[0-9a-f]+ +NOTYPE +LOCAL +DEFAULT +[0-9]+ +__start_scnfoo
|
||||||
|
#pass
|
10
ld/testsuite/ld-elf/pr21562n.d
Normal file
10
ld/testsuite/ld-elf/pr21562n.d
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#source: pr21562b.s
|
||||||
|
#ld: -shared -z defs --gc-sections -T pr21562d.t
|
||||||
|
#readelf: -s -S --wide
|
||||||
|
#target: *-*-linux* *-*-gnu*
|
||||||
|
|
||||||
|
#...
|
||||||
|
\[[ 0-9]+\] \.foo[ \t]+PROGBITS[ \t]+[0-9a-f]+ +[0-9a-f]+ +0*10[ \t]+.*
|
||||||
|
#...
|
||||||
|
+[0-9]+: +[0-9a-f]+ +[0-9a-f]+ +NOTYPE +LOCAL +DEFAULT +[0-9]+ +__stop_scnfoo
|
||||||
|
#pass
|
|
@ -119,6 +119,12 @@ if { [is_elf_format] && [check_shared_lib_support] } then {
|
||||||
run_dump_test "personality"
|
run_dump_test "personality"
|
||||||
}
|
}
|
||||||
run_dump_test "pr18223"
|
run_dump_test "pr18223"
|
||||||
|
if {![ld_assemble_flags $as $gasopt $srcdir/$subdir/pr20022a.s tmpdir/pr20022a.o]
|
||||||
|
|| ![ld_link $ld tmpdir/pr20022.so "-shared --gc-sections tmpdir/pr20022a.o"] } then {
|
||||||
|
fail pr20022
|
||||||
|
} else {
|
||||||
|
run_dump_test "pr20022"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if { [is_remote host] || [which $CC] != 0 } {
|
if { [is_remote host] || [which $CC] != 0 } {
|
||||||
|
|
|
@ -6,5 +6,5 @@
|
||||||
#xfail: mips64vr-*-* msp430-*-* powerpc*-*-eabivle rl78-*-* rx-*-* sh*-*-*
|
#xfail: mips64vr-*-* msp430-*-* powerpc*-*-eabivle rl78-*-* rx-*-* sh*-*-*
|
||||||
|
|
||||||
#...
|
#...
|
||||||
0*[1-9a-f]+[0-9a-f]*[ ](D)[ ]_*__start_my_section
|
0*[1-9a-f]+[0-9a-f]*[ ](d|D)[ ]_*__start_my_section
|
||||||
#...
|
#...
|
||||||
|
|
11
ld/testsuite/ld-gc/pr20022.d
Normal file
11
ld/testsuite/ld-gc/pr20022.d
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#source: pr20022b.s
|
||||||
|
#ld: --gc-sections -e _start tmpdir/pr20022.so
|
||||||
|
#readelf: -SsW
|
||||||
|
#target: *-*-linux* *-*-gnu*
|
||||||
|
#notarget: *-*-*aout *-*-*oldld frv-*-linux* metag-*-linux*
|
||||||
|
|
||||||
|
#...
|
||||||
|
\[[ 0-9]+\] _foo[ \t]+PROGBITS[ \t]+[0-9a-f]+ +[0-9a-f]+ +[0-9a-f]+[ \t]+.*
|
||||||
|
#...
|
||||||
|
+[0-9]+: +[0-9a-f]+ +[0-9a-f]+ +NOTYPE +LOCAL +DEFAULT +[0-9]+ +__start__foo
|
||||||
|
#pass
|
8
ld/testsuite/ld-gc/pr20022a.s
Normal file
8
ld/testsuite/ld-gc/pr20022a.s
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
.data
|
||||||
|
.globl bar
|
||||||
|
.type bar,%object
|
||||||
|
bar:
|
||||||
|
.dc.a __start__foo
|
||||||
|
.section _foo,"aw",%progbits
|
||||||
|
foo:
|
||||||
|
.ascii "This is bar"
|
8
ld/testsuite/ld-gc/pr20022b.s
Normal file
8
ld/testsuite/ld-gc/pr20022b.s
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
.text
|
||||||
|
.globl _start
|
||||||
|
_start:
|
||||||
|
.dc.a __start__foo
|
||||||
|
.dc.a bar
|
||||||
|
.section _foo,"aw",%progbits
|
||||||
|
foo:
|
||||||
|
.ascii "This is foo"
|
|
@ -5,5 +5,5 @@
|
||||||
#notarget: *-*-*aout *-*-*oldld frv-*-linux* metag-*-linux*
|
#notarget: *-*-*aout *-*-*oldld frv-*-linux* metag-*-linux*
|
||||||
|
|
||||||
#...
|
#...
|
||||||
[0-9a-f]+ D +__start__foo
|
[0-9a-f]+ d +__start__foo
|
||||||
#...
|
#...
|
||||||
|
|
|
@ -15,5 +15,5 @@ Disassembly of section .text:
|
||||||
[ ]*[a-f0-9]+: 48 8d 05 ([0-9a-f]{2} ){4} * lea -0x[a-f0-9]+\(%rip\),%rax # [a-f0-9]+ <foo>
|
[ ]*[a-f0-9]+: 48 8d 05 ([0-9a-f]{2} ){4} * lea -0x[a-f0-9]+\(%rip\),%rax # [a-f0-9]+ <foo>
|
||||||
[ ]*[a-f0-9]+: 4c 8d 1d ([0-9a-f]{2} ){4} * lea 0x[a-f0-9]+\(%rip\),%r11 # [a-f0-9]+ <bar>
|
[ ]*[a-f0-9]+: 4c 8d 1d ([0-9a-f]{2} ){4} * lea 0x[a-f0-9]+\(%rip\),%r11 # [a-f0-9]+ <bar>
|
||||||
[ ]*[a-f0-9]+: 48 8d 05 ([0-9a-f]{2} ){4} * lea 0x[a-f0-9]+\(%rip\),%rax # [a-f0-9]+ <__start_my_section>
|
[ ]*[a-f0-9]+: 48 8d 05 ([0-9a-f]{2} ){4} * lea 0x[a-f0-9]+\(%rip\),%rax # [a-f0-9]+ <__start_my_section>
|
||||||
[ ]*[a-f0-9]+: 4c 8d 1d ([0-9a-f]{2} ){4} * lea 0x[a-f0-9]+\(%rip\),%r11 # [a-f0-9]+ <__stop_my_section>
|
[ ]*[a-f0-9]+: 4c 8d 1d ([0-9a-f]{2} ){4} * lea 0x[a-f0-9]+\(%rip\),%r11 # [a-f0-9]+ <.*>
|
||||||
#pass
|
#pass
|
||||||
|
|
|
@ -15,5 +15,5 @@ Disassembly of section .text:
|
||||||
[ ]*[a-f0-9]+: 48 8d 05 ([0-9a-f]{2} ){4} * lea -0x[a-f0-9]+\(%rip\),%rax # [a-f0-9]+ <foo>
|
[ ]*[a-f0-9]+: 48 8d 05 ([0-9a-f]{2} ){4} * lea -0x[a-f0-9]+\(%rip\),%rax # [a-f0-9]+ <foo>
|
||||||
[ ]*[a-f0-9]+: 4c 8d 1d ([0-9a-f]{2} ){4} * lea 0x[a-f0-9]+\(%rip\),%r11 # [a-f0-9]+ <bar>
|
[ ]*[a-f0-9]+: 4c 8d 1d ([0-9a-f]{2} ){4} * lea 0x[a-f0-9]+\(%rip\),%r11 # [a-f0-9]+ <bar>
|
||||||
[ ]*[a-f0-9]+: 48 8d 05 ([0-9a-f]{2} ){4} * lea 0x[a-f0-9]+\(%rip\),%rax # [a-f0-9]+ <__start_my_section>
|
[ ]*[a-f0-9]+: 48 8d 05 ([0-9a-f]{2} ){4} * lea 0x[a-f0-9]+\(%rip\),%rax # [a-f0-9]+ <__start_my_section>
|
||||||
[ ]*[a-f0-9]+: 4c 8d 1d ([0-9a-f]{2} ){4} * lea 0x[a-f0-9]+\(%rip\),%r11 # [a-f0-9]+ <__stop_my_section>
|
[ ]*[a-f0-9]+: 4c 8d 1d ([0-9a-f]{2} ){4} * lea 0x[a-f0-9]+\(%rip\),%r11 # [a-f0-9]+ <.*>
|
||||||
#pass
|
#pass
|
||||||
|
|
|
@ -15,5 +15,5 @@ Disassembly of section .text:
|
||||||
[ ]*[a-f0-9]+: 48 8d 05 ([0-9a-f]{2} ){4} * lea -0x[a-f0-9]+\(%rip\),%rax # [a-f0-9]+ <foo>
|
[ ]*[a-f0-9]+: 48 8d 05 ([0-9a-f]{2} ){4} * lea -0x[a-f0-9]+\(%rip\),%rax # [a-f0-9]+ <foo>
|
||||||
[ ]*[a-f0-9]+: 4c 8d 1d ([0-9a-f]{2} ){4} * lea 0x[a-f0-9]+\(%rip\),%r11 # [a-f0-9]+ <bar>
|
[ ]*[a-f0-9]+: 4c 8d 1d ([0-9a-f]{2} ){4} * lea 0x[a-f0-9]+\(%rip\),%r11 # [a-f0-9]+ <bar>
|
||||||
[ ]*[a-f0-9]+: 48 8d 05 ([0-9a-f]{2} ){4} * lea 0x[a-f0-9]+\(%rip\),%rax # [a-f0-9]+ <__start_my_section>
|
[ ]*[a-f0-9]+: 48 8d 05 ([0-9a-f]{2} ){4} * lea 0x[a-f0-9]+\(%rip\),%rax # [a-f0-9]+ <__start_my_section>
|
||||||
[ ]*[a-f0-9]+: 4c 8d 1d ([0-9a-f]{2} ){4} * lea 0x[a-f0-9]+\(%rip\),%r11 # [a-f0-9]+ <__stop_my_section>
|
[ ]*[a-f0-9]+: 4c 8d 1d ([0-9a-f]{2} ){4} * lea 0x[a-f0-9]+\(%rip\),%r11 # [a-f0-9]+ <.*>
|
||||||
#pass
|
#pass
|
||||||
|
|
|
@ -15,5 +15,5 @@ Disassembly of section .text:
|
||||||
[ ]*[a-f0-9]+: 48 8d 05 ([0-9a-f]{2} ){4} * lea -0x[a-f0-9]+\(%rip\),%rax # [a-f0-9]+ <foo>
|
[ ]*[a-f0-9]+: 48 8d 05 ([0-9a-f]{2} ){4} * lea -0x[a-f0-9]+\(%rip\),%rax # [a-f0-9]+ <foo>
|
||||||
[ ]*[a-f0-9]+: 4c 8d 1d ([0-9a-f]{2} ){4} * lea 0x[a-f0-9]+\(%rip\),%r11 # [a-f0-9]+ <bar>
|
[ ]*[a-f0-9]+: 4c 8d 1d ([0-9a-f]{2} ){4} * lea 0x[a-f0-9]+\(%rip\),%r11 # [a-f0-9]+ <bar>
|
||||||
[ ]*[a-f0-9]+: 48 8d 05 ([0-9a-f]{2} ){4} * lea 0x[a-f0-9]+\(%rip\),%rax # [a-f0-9]+ <__start_my_section>
|
[ ]*[a-f0-9]+: 48 8d 05 ([0-9a-f]{2} ){4} * lea 0x[a-f0-9]+\(%rip\),%rax # [a-f0-9]+ <__start_my_section>
|
||||||
[ ]*[a-f0-9]+: 4c 8d 1d ([0-9a-f]{2} ){4} * lea 0x[a-f0-9]+\(%rip\),%r11 # [a-f0-9]+ <__stop_my_section>
|
[ ]*[a-f0-9]+: 4c 8d 1d ([0-9a-f]{2} ){4} * lea 0x[a-f0-9]+\(%rip\),%r11 # [a-f0-9]+ <.*>
|
||||||
#pass
|
#pass
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue