return _bfd_elf_hash_symbol (h);
}
+/* Write nops to align section. */
+
+static bool
+loongarch_build_align_nops (asection *align_section)
+{
+ bfd_byte *loc = align_section->contents;
+ for (bfd_size_type i = 0; i < (align_section->size / 4); i++)
+ {
+ bfd_putl32 (LARCH_NOP, loc);
+ loc += 4;
+ }
+
+ return true;
+}
+
+/* Emit an align relocation and a related undefined symbol. */
+
+static bool
+loongarch_add_align_relocs (asection *align_sec, bfd* align_bfd)
+{
+ elf_backend_data *bed = get_elf_backend_data (align_bfd);
+
+ if (elf_section_data (align_sec)->relocs == NULL)
+ {
+ align_sec->reloc_count = 1;
+ align_sec->flags |= SEC_RELOC;
+
+ Elf_Internal_Rela *rela = (Elf_Internal_Rela *)
+ bfd_malloc (sizeof (Elf_Internal_Rela));
+ if (rela == NULL)
+ return false;
+
+ rela->r_offset = 0;
+ rela->r_addend = align_sec->size;
+ rela->r_info = ELFNN_R_INFO (0, R_LARCH_ALIGN);
+ elf_section_data (align_sec)->relocs = rela;
+
+ Elf_Internal_Shdr *rela_hdr = (Elf_Internal_Shdr *)
+ bfd_zalloc (align_bfd, sizeof (Elf_Internal_Shdr));
+ if (rela_hdr == NULL)
+ return false;
+
+ rela_hdr->sh_size = sizeof (Elf_Internal_Rela);
+ rela_hdr->sh_entsize = sizeof (Elf_Internal_Rela);
+ rela_hdr->sh_type = SHT_RELA;
+ rela_hdr->sh_addralign = (bfd_vma) 1 << bed->s->log_file_align;
+ elf_section_data (align_sec)->rela.hdr = rela_hdr;
+ }
+
+ /* Used in loongarch_elf_relax_section for align relocations. */
+ Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (align_bfd);
+ if (symtab_hdr->contents == NULL)
+ {
+ Elf_Internal_Sym *sym = (Elf_Internal_Sym *)
+ bfd_zmalloc (sizeof (Elf_Internal_Sym));
+ if (sym == NULL)
+ return false;
+
+ /* Match if (r_symndx < symtab_hdr->sh_info) branch in
+ loongarch_elf_relocate_section to avoid find link failed. */
+ symtab_hdr->sh_info = 1;
+ symtab_hdr->contents = (unsigned char *) sym;
+ }
+
+ return true;
+}
+
+/* Section name for aligns is the associated section name plus this
+ string. */
+#define ALIGN_SUFFIX ".align"
+
+/* Determine and set the size of the align section for a final link. */
+
+bool
+elfNN_loongarch_size_aligns (bfd *output_bfd,
+ bfd *align_bfd,
+ struct bfd_link_info *info,
+ asection * (*add_align_section)
+ (const char *, asection *),
+ void (*layout_sections_again) (void))
+{
+ bool need_laying_out = false;
+ for (bfd *input_bfd = info->input_bfds; input_bfd != NULL;
+ input_bfd = input_bfd->link.next)
+ {
+ asection *sec;
+ asection *align_sec;
+
+ if (!is_loongarch_elf (input_bfd)
+ || (input_bfd->flags & BFD_LINKER_CREATED) != 0)
+ continue;
+
+ for (sec = input_bfd->sections; sec != NULL; sec = sec->next)
+ {
+ /* If this section is not a code section, do nothing. */
+ if ((sec->flags & SEC_CODE) == 0)
+ continue;
+
+ /* If this section is a link-once section that will be
+ discarded, then don't create any stubs. */
+ if (sec->output_section == NULL
+ || sec->output_section->owner != output_bfd)
+ continue;
+
+ if (sec->alignment_power > 2)
+ {
+ char *s_name;
+ size_t namelen;
+ bfd_size_type len;
+ namelen = strlen (sec->name);
+ len = namelen + sizeof (ALIGN_SUFFIX);
+ s_name = bfd_alloc (align_bfd, len);
+ if (s_name == NULL)
+ return false;
+ memcpy (s_name, sec->name, namelen);
+ memcpy (s_name + namelen, ALIGN_SUFFIX, sizeof (ALIGN_SUFFIX));
+
+ align_sec = add_align_section (s_name, sec);
+
+ if (align_sec == NULL)
+ return false;
+
+ if (! loongarch_build_align_nops (align_sec))
+ return false;
+
+ if (! loongarch_add_align_relocs (align_sec, align_bfd))
+ return false;
+
+ /* Change the section alignment to 4 to disable the default
+ behavior of "dot += alignment_needed" in ldlang.c. */
+ bfd_set_section_alignment (sec, 2);
+
+ need_laying_out = true;
+ }
+ }
+ }
+
+ if (need_laying_out)
+ layout_sections_again ();
+
+ return true;
+}
+
#define TARGET_LITTLE_SYM loongarch_elfNN_vec
#define TARGET_LITTLE_NAME "elfNN-loongarch"
#define ELF_ARCH bfd_arch_loongarch
'
fragment <<EOF
+
+/* Fake input file for align. */
+static lang_input_statement_type *align_file;
+
static void
larch_elf_before_allocation (void)
{
link_info.relax_pass = 3;
}
+/* Traverse the linker tree to insert the align section
+ before input section. */
+
+static bool
+hook_in_align (lang_statement_list_type add,
+ asection *input_section,
+ lang_statement_union_type **lp)
+{
+ bool ret;
+ lang_statement_union_type *l;
+
+ for (; (l = *lp) != NULL; lp = &l->header.next)
+ {
+ switch (l->header.type)
+ {
+ case lang_constructors_statement_enum:
+ ret = hook_in_align (add, input_section, &constructor_list.head);
+ if (ret)
+ return ret;
+ break;
+
+ case lang_output_section_statement_enum:
+ ret = hook_in_align (add, input_section,
+ &l->output_section_statement.children.head);
+ if (ret)
+ return ret;
+ break;
+
+ case lang_wild_statement_enum:
+ ret = hook_in_align (add, input_section,
+ &l->wild_statement.children.head);
+ if (ret)
+ return ret;
+ break;
+
+ case lang_group_statement_enum:
+ ret = hook_in_align (add, input_section,
+ &l->group_statement.children.head);
+ if (ret)
+ return ret;
+ break;
+
+ case lang_input_section_enum:
+ if (l->input_section.section == input_section)
+ {
+ /* We've found our section. Insert the align immediately
+ before its associated input section. */
+ *lp = add.head;
+ add.head->header.next = l;
+ return true;
+ }
+ break;
+
+ case lang_data_statement_enum:
+ case lang_reloc_statement_enum:
+ case lang_object_symbols_statement_enum:
+ case lang_output_statement_enum:
+ case lang_target_statement_enum:
+ case lang_input_statement_enum:
+ case lang_assignment_statement_enum:
+ case lang_padding_statement_enum:
+ case lang_address_statement_enum:
+ case lang_fill_statement_enum:
+ break;
+
+ default:
+ FAIL ();
+ break;
+ }
+ }
+
+ return false;
+}
+
+/* Create a new align section, and arrange for it to be linked
+ immediately before INPUT_SECTION. */
+
+static asection *
+elf${ELFSIZE}_loongarch_add_align_section (const char *align_sec_name,
+ asection *input_section)
+{
+ flagword flags;
+ asection *align_sec;
+ asection *output_section;
+ lang_statement_list_type add_child;
+ lang_output_section_statement_type *os;
+
+ flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE
+ | SEC_HAS_CONTENTS | SEC_RELOC | SEC_IN_MEMORY | SEC_KEEP);
+ align_sec = bfd_make_section_anyway_with_flags (align_file->the_bfd,
+ align_sec_name, flags);
+ if (align_sec == NULL)
+ goto err_ret;
+
+ align_sec->veneer = 1;
+ bfd_set_section_alignment (align_sec, 2);
+
+ output_section = input_section->output_section;
+ os = lang_output_section_get (output_section);
+
+ lang_list_init (&add_child);
+ lang_add_section (&add_child, align_sec, NULL, NULL, os);
+
+ if (add_child.head == NULL)
+ goto err_ret;
+
+ align_sec->size = (1 << input_section->alignment_power) - 4;
+ align_sec->contents = bfd_alloc (align_file->the_bfd, align_sec->size);
+ if (align_sec->contents == NULL && align_sec->size != 0)
+ goto err_ret;
+ align_sec->alloced = 1;
+
+ if (hook_in_align (add_child, input_section, &os->children.head))
+ return align_sec;
+
+ err_ret:
+ einfo (_("%X%P: can not make align section: %E\n"));
+ return NULL;
+}
+
+static void
+gldloongarch_layout_sections_again (void)
+{
+ /* If we have changed sizes of the align sections, then we need
+ to recalculate all the section offsets. */
+ ldelf_map_segments (true);
+}
+
static void
gld${EMULATION_NAME}_after_allocation (void)
{
}
}
+ /* If generating a relocatable output file, we have to add align
+ at the start of sections. */
+ if (align_file != NULL && bfd_link_relocatable (&link_info))
+ {
+ if (! elf${ELFSIZE}_loongarch_size_aligns (link_info.output_bfd,
+ align_file->the_bfd,
+ &link_info,
+ &elf${ELFSIZE}_loongarch_add_align_section,
+ &gldloongarch_layout_sections_again))
+ {
+ einfo (_("%X%P: can not size align section: %E\n"));
+ return;
+ }
+ }
+
/* The program header size of executable file may increase. */
if (bfd_get_flavour (link_info.output_bfd) == bfd_target_elf_flavour
&& !bfd_link_relocatable (&link_info))
ldelf_map_segments (need_layout);
}
+/* This is called before the input files are opened. We create a new
+ fake input file to hold the align sections. */
+
+static void
+loongarch_elf_create_output_section_statements (void)
+{
+ if (! bfd_link_relocatable (&link_info))
+ return;
+
+ align_file = lang_add_input_file ("linker aligns",
+ lang_input_file_is_fake_enum,
+ NULL);
+ align_file->the_bfd = bfd_create ("linker aligns",
+ link_info.output_bfd);
+ if (align_file->the_bfd == NULL
+ || ! bfd_set_arch_mach (align_file->the_bfd,
+ bfd_get_arch (link_info.output_bfd),
+ bfd_get_mach (link_info.output_bfd)))
+ {
+ fatal (_("%P: can not create BFD: %E\n"));
+ return;
+ }
+
+ align_file->the_bfd->flags |= BFD_LINKER_CREATED;
+
+ Elf_Internal_Ehdr *ehdr = elf_elfheader (align_file->the_bfd);
+ elf_backend_data *bed = get_elf_backend_data (link_info.output_bfd);
+ ehdr->e_ident[EI_CLASS] = bed->s->elfclass;
+
+ ldlang_add_file (align_file);
+}
+
EOF
LDEMUL_BEFORE_ALLOCATION=larch_elf_before_allocation
LDEMUL_AFTER_ALLOCATION=gld${EMULATION_NAME}_after_allocation
+LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS=loongarch_elf_create_output_section_statements