From patchwork Mon Mar 16 09:31:42 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yoshinori Sato X-Patchwork-Id: 131783 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id C12F14BC7EFE for ; Mon, 16 Mar 2026 09:42:02 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org C12F14BC7EFE Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=nifty.com header.i=@nifty.com header.a=rsa-sha256 header.s=default-1th84yt82rvi header.b=LXthAFlL X-Original-To: binutils@sourceware.org Delivered-To: binutils@sourceware.org Received: from mta-snd-w05.mail.nifty.com (mta-snd-w05.mail.nifty.com [IPv6:2001:268:fa30:831:6a:99:e3:25]) by sourceware.org (Postfix) with ESMTPS id 9BD3E4BA2E14 for ; Mon, 16 Mar 2026 09:41:08 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 9BD3E4BA2E14 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=nifty.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=nifty.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 9BD3E4BA2E14 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2001:268:fa30:831:6a:99:e3:25 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1773654069; cv=none; b=I1TRL2F5i2g34hLJCm47xoHAipxClXZG76jiLIfUTbG8xFE4DtRzS118SRlsZcG2mLNrNCh+ung57Pkbp55FJQXoIEtu+RMOWCGuNR0rrKdsmRKi+x1sDTL2cU+JdlOjL+N3M9o0KcCi347Kbw3fJQTeLCiLqDiwvfVOqme70V0= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1773654069; c=relaxed/simple; bh=AuCfyA7xLQKpJqFWzs05mdZfR4rT9Hu8tKb9kxdLe3k=; h=From:To:Subject:Date:Message-ID:MIME-Version:DKIM-Signature; b=JffVelJdd2eIYvPM4Dy0yHZZ+a9LNz0ioy9aAyt/bky0aU2bk31cheYRhbvGMqJz11rx7zGZBcxkZP4NEwrfF6cMiS9TPdrD3EN6rXpRm7lmUKcn+wKxlf9O4jAiQm2O9Tzj1VDxqS9Odtp3jbl1rVJ5zCvJVBWCwsx8HosRews= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 9BD3E4BA2E14 Received: from sakura.ysato.name by mta-snd-w05.mail.nifty.com with ESMTP id <20260316094106385.KZKS.127398.sakura.ysato.name@nifty.com>; Mon, 16 Mar 2026 18:41:06 +0900 Received: from SIOS1075.constellations.internal (ZM005235.ppp.dion.ne.jp [222.8.5.235]) by sakura.ysato.name (Postfix) with ESMTPSA id D40A51C0177; Mon, 16 Mar 2026 18:31:55 +0900 (JST) From: Yoshinori Sato To: binutils@sourceware.org Cc: Yoshinori Sato Subject: [RFC PATCH v2 1/4] RX: bfd rx-linux FDPIC support Date: Mon, 16 Mar 2026 18:31:42 +0900 Message-ID: <20260316093151.360635-2-yoshinori.sato@nifty.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260316093151.360635-1-yoshinori.sato@nifty.com> References: <20260316093151.360635-1-yoshinori.sato@nifty.com> MIME-Version: 1.0 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=default-1th84yt82rvi; t=1773654066; bh=V9Wh7w34MQlCnUeDdqfYAtG0YVQZxzUOB7ppkx6zSmM=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=LXthAFlLzB+vMpr6luGRc9yzHV22KybD7HSbWdBRnfy1rHuA+OMYCFTCNw84HD8FZCIReZQ+ Rj1iUoPFBzhHQIzHKr7p3exm7ssT3lkYsle+AhTudiessnHlWRJvUIYe2n7tD3/y6mRDX84dQa El64RN6II1t4Prn+d5OBlSpfIApoc+DyUl1Q1Qust2hyoEdtJXMnD01C+0HY0PVfTccwVeNijY FzmUcS/xow0TZlpFurBY+HqkaxCb0C7joiw/ZxzaC1RQj/5b/KC1MHYVVjE1+J5wCOOt2XNOcg YTMgQ65H3tspRsAUngBhbkrM3T/4uVkUjsd3V/v67GdZeSbA== X-Spam-Status: No, score=-10.6 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_STOCKGEN, POISEN_SPAM_PILL, POISEN_SPAM_PILL_1, RCVD_IN_DNSWL_BLOCKED, SPF_HELO_PASS, SPF_PASS, TXREP, URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: binutils@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Binutils mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: binutils-bounces~patchwork=sourceware.org@sourceware.org * elf-bfd.h (elf_target_id): Add RX_ELF_DATA. * elf32-rx.c (rx_get_reloc): Add const. (rx_elf_howto_table): DIR24S and DIR24S_PCREL have 3byte value. Add FDPIC relocation type. (rx_reloc_map): Add FDPIC relocation type. (elf_rx_link_hash_table): New. (rx_elf_hash_table): New. (MINUS_ONE): New. (gotoff): New. (elf_rx_link_hash_entry): New. (rx_elf_hash_entry): New. (rx_elf_obj_tdata): New. (rx_elf_tdata): New. (rx_elf_local_got_type): New. (rx_elf_local_funcdesc): New. (SYMBOL_FUNCDESC_LOCAL): New. (rx_reloc_type_lookup): Set error in invalid code. (rx_elf_relocate_section): Add FDPIC relocation. (rx_set_section_contents): remove unused 'i'. (rx_elf_reloc_type_class): New. (fdpic_elf_rx_plt_entry): New. (elf_rx_pcrel_relocs_copied): New. (is_rx_elf): New. (fdpic_object_p): New. (rx_elf_mkobject): New. (install_plt_field): New. (rx_elf_link_hash_newfunc): New. (rx_elf_link_hash_table_create): New. (rx_elf_omit_section_dynsym): New. (create_got_section): New. (rx_elf_create_dynamic_sections): New. (rx_elf_adjust_dynamic_symbol): New. (allocate_dynrelocs): New. (rx_elf_early_size_sections): New. (rx_elf_late_size_sections): New. (rx_elf_add_dyn_reloc): New. (rx_elf_add_rofixup): New. (rx_elf_osec_to_segment): New. (rx_elf_osec_readonly_p): New. (rx_elf_initialize_funcdesc): New. (rx_elf_finish_dynamic_symbol): New. (rx_elf_finish_dynamic_sections): New. (rx_elf_copy_indirect_symbol): New. (allocate_local_got_refcounts): New. (rx_elf_check_relocs): New. * reloc.c: Add RX FDPIC relocation. * libbfd.h: Regenerate. * bfd-in2.h: Likewise. * libbfd.h: Likewise. Signed-off-by: Yoshinori Sato --- bfd/bfd-in2.h | 11 + bfd/elf-bfd.h | 1 + bfd/elf32-rx.c | 2315 +++++++++++++++++++++++++++++++++++++++++++++++- bfd/libbfd.h | 11 + bfd/reloc.c | 22 + 5 files changed, 2343 insertions(+), 17 deletions(-) diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index bcec515e8be..f4cd1caa328 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -5481,6 +5481,17 @@ enum bfd_reloc_code_real BFD_RELOC_RX_ABS16UW, BFD_RELOC_RX_ABS16UL, BFD_RELOC_RX_RELAX, + BFD_RELOC_RX_COPY, + BFD_RELOC_RX_GLOB_DAT, + BFD_RELOC_RX_JMP_SLOT, + BFD_RELOC_RX_RELATIVE, + BFD_RELOC_RX_GOT, + BFD_RELOC_RX_GOTOFF, + BFD_RELOC_RX_PLT, + BFD_RELOC_RX_GOTFUNCDESC, + BFD_RELOC_RX_GOTOFFFUNCDESC, + BFD_RELOC_RX_FUNCDESC, + BFD_RELOC_RX_FUNCDESC_VALUE, /* Direct 12 bit. */ BFD_RELOC_390_12, diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h index 837fbefa6a2..99dc46a4224 100644 --- a/bfd/elf-bfd.h +++ b/bfd/elf-bfd.h @@ -580,6 +580,7 @@ enum elf_target_id PPC64_ELF_DATA, PRU_ELF_DATA, RISCV_ELF_DATA, + RX_ELF_DATA, S390_ELF_DATA, SCORE_ELF_DATA, SH_ELF_DATA, diff --git a/bfd/elf32-rx.c b/bfd/elf32-rx.c index 5aadc167709..ace669bbbac 100644 --- a/bfd/elf32-rx.c +++ b/bfd/elf32-rx.c @@ -35,7 +35,7 @@ const bfd_target rx_elf32_be_ns_vec; const bfd_target rx_elf32_be_vec; #ifdef DEBUG -char * rx_get_reloc (long); +const char * rx_get_reloc (long); void rx_dump_symtab (bfd *, void *, void *); #endif @@ -51,14 +51,14 @@ static reloc_howto_type rx_elf_howto_table [] = { RXREL (NONE, 0, 0, 0, dont, false), RXREL (DIR32, 4, 32, 0, signed, false), - RXREL (DIR24S, 4, 24, 0, signed, false), + RXREL (DIR24S, 3, 24, 0, signed, false), RXREL (DIR16, 2, 16, 0, dont, false), RXREL (DIR16U, 2, 16, 0, unsigned, false), RXREL (DIR16S, 2, 16, 0, signed, false), RXREL (DIR8, 1, 8, 0, dont, false), RXREL (DIR8U, 1, 8, 0, unsigned, false), RXREL (DIR8S, 1, 8, 0, signed, false), - RXREL (DIR24S_PCREL, 4, 24, 0, signed, true), + RXREL (DIR24S_PCREL, 3, 24, 0, signed, true), RXREL (DIR16S_PCREL, 2, 16, 0, signed, true), RXREL (DIR8S_PCREL, 1, 8, 0, signed, true), RXREL (DIR16UL, 2, 16, 2, unsigned, false), @@ -69,17 +69,18 @@ static reloc_howto_type rx_elf_howto_table [] = RXREL (DIR16_REV, 2, 16, 0, dont, false), RXREL (DIR3U_PCREL, 1, 3, 0, dont, true), - EMPTY_HOWTO (0x13), - EMPTY_HOWTO (0x14), - EMPTY_HOWTO (0x15), - EMPTY_HOWTO (0x16), - EMPTY_HOWTO (0x17), - EMPTY_HOWTO (0x18), - EMPTY_HOWTO (0x19), - EMPTY_HOWTO (0x1a), - EMPTY_HOWTO (0x1b), - EMPTY_HOWTO (0x1c), - EMPTY_HOWTO (0x1d), + RXREL (GOT, 2, 16, 0, dont, false), + RXREL (PLT, 2, 32, 0, dont, true), + RXREL (COPY, 2, 32, 0, dont, false), + RXREL (GLOB_DAT, 2, 32, 0, dont, false), + RXREL (JMP_SLOT, 2, 32, 0, dont, false), + RXREL (RELATIVE, 2, 32, 0, dont, false), + RXREL (GOTOFF, 2, 32, 0, dont, false), + RXREL (GOTFUNCDESC, 2, 16, 0, dont, false), + RXREL (GOTOFFFUNCDESC, 2, 32, 0, dont, false), + RXREL (FUNCDESC, 2, 32, 0, dont, false), + RXREL (FUNCDESC_VALUE, 2, 64, 0, dont, false), + EMPTY_HOWTO (0x1e), EMPTY_HOWTO (0x1f), @@ -253,6 +254,16 @@ static const struct rx_reloc_map rx_reloc_map [] = { BFD_RELOC_24_PCREL, R_RX_DIR24S_PCREL }, { BFD_RELOC_RX_8U, R_RX_DIR8U }, { BFD_RELOC_RX_16U, R_RX_DIR16U }, + { BFD_RELOC_RX_COPY, R_RX_COPY }, + { BFD_RELOC_RX_GLOB_DAT, R_RX_GLOB_DAT }, + { BFD_RELOC_RX_JMP_SLOT, R_RX_JMP_SLOT }, + { BFD_RELOC_RX_RELATIVE, R_RX_RELATIVE }, + { BFD_RELOC_RX_GOT, R_RX_GOT }, + { BFD_RELOC_32_GOTOFF, R_RX_GOTOFF }, + { BFD_RELOC_32_PLT_PCREL, R_RX_PLT }, + { BFD_RELOC_RX_GOTFUNCDESC, R_RX_GOTFUNCDESC }, + { BFD_RELOC_RX_GOTOFFFUNCDESC, R_RX_GOTOFFFUNCDESC }, + { BFD_RELOC_RX_FUNCDESC, R_RX_FUNCDESC }, { BFD_RELOC_RX_24U, R_RX_RH_24_UNS }, { BFD_RELOC_RX_NEG8, R_RX_RH_8_NEG }, { BFD_RELOC_RX_NEG16, R_RX_RH_16_NEG }, @@ -278,6 +289,104 @@ static const struct rx_reloc_map rx_reloc_map [] = #define BIGE(abfd) ((abfd)->xvec->byteorder == BFD_ENDIAN_BIG) +/* RX ELF linker hash table. */ +struct elf_rx_link_hash_table +{ + struct elf_link_hash_table root; + asection *sfuncdesc; + asection *srelfuncdesc; + asection *srofixup; + + /* True if the target system uses FDPIC. */ + bool fdpic_p; +}; + +/* Get the sh ELF linker hash table from a link_info structure. */ + +#define rx_elf_hash_table(p) \ + ((is_elf_hash_table ((p)->hash) \ + && elf_hash_table_id (elf_hash_table (p)) == RX_ELF_DATA) \ + ? (struct elf_rx_link_hash_table *) (p)->hash : NULL) +#define MINUS_ONE ((bfd_vma) 0 - 1) + +union gotref { + bfd_signed_vma refcount; + bfd_vma offset; +}; + +/* RX ELF linker hash entry. */ + +struct elf_rx_link_hash_entry +{ + struct elf_link_hash_entry root; + + bfd_signed_vma gotplt_refcount; + + /* A local function descriptor, for FDPIC. The refcount counts + R_RX_FUNCDESC, and R_RX_GOTOFFFUNCDESC relocations; + the PLT and GOT entry are accounted for separately. + After adjust_dynamic_symbol, the offset is + MINUS_ONE if there is no local descriptor (dynamic linker + managed and no PLT entry, or undefined weak non-dynamic). + During check_relocs we do not yet know whether the local + descriptor will be canonical. */ + union gotref funcdesc; + + /* How many of the above refcounted relocations were R_RX_FUNCDESC, + and thus require fixups or relocations. */ + bfd_signed_vma abs_funcdesc_refcount; + + enum got_type { + GOT_UNKNOWN = 0, + GOT_NORMAL = 1, + GOT_FUNCDESC = 2, + } got_type; +}; + +#define rx_elf_hash_entry(ent) ((struct elf_rx_link_hash_entry *)(ent)) + +struct rx_elf_obj_tdata +{ + struct elf_obj_tdata root; + + /* got_type for each local got entry. */ + char *local_got_type; + + /* Function descriptor refcount and offset for each local symbol. */ + union gotref *local_funcdesc; +}; + +#define rx_elf_tdata(abfd) \ + ((struct rx_elf_obj_tdata *) (abfd)->tdata.any) + +#define rx_elf_local_got_type(abfd) \ + (rx_elf_tdata (abfd)->local_got_type) + +#define rx_elf_local_funcdesc(abfd) \ + (rx_elf_tdata (abfd)->local_funcdesc) + +/* Decide whether a reference to a symbol can be resolved locally or + not. If the symbol is protected, we want the local address, but + its function descriptor must be assigned by the dynamic linker. */ +#define SYMBOL_FUNCDESC_LOCAL(INFO, H) \ + (SYMBOL_REFERENCES_LOCAL (INFO, H) \ + || ! elf_hash_table (INFO)->dynamic_sections_created) + +/* FDPIC stuff */ +static bool +rx_elf_osec_readonly_p (bfd *output_bfd, asection *osec); + +static void +rx_elf_add_rofixup (bfd *output_bfd, asection *srofixup, bfd_vma offset); + +static bool +rx_elf_initialize_funcdesc (bfd *output_bfd, + struct bfd_link_info *info, + struct elf_link_hash_entry *h, + bfd_vma offset, + asection *section, + bfd_vma value); + static reloc_howto_type * rx_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED, bfd_reloc_code_real_type code) @@ -291,6 +400,7 @@ rx_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED, if (rx_reloc_map [i].bfd_reloc_val == code) return rx_elf_howto_table + rx_reloc_map[i].rx_reloc_val; + bfd_set_error (bfd_error_bad_value); return NULL; } @@ -503,6 +613,7 @@ rx_elf_relocate_section Elf_Internal_Sym * local_syms, asection ** local_sections) { + struct elf_rx_link_hash_table *htab; Elf_Internal_Shdr *symtab_hdr; struct elf_link_hash_entry **sym_hashes; Elf_Internal_Rela *rel; @@ -512,15 +623,32 @@ rx_elf_relocate_section const char *table_default_cache = NULL; bfd_vma table_start_cache = 0; bfd_vma table_end_cache = 0; + asection *sgot = NULL; + asection *sgotplt = NULL; + asection *splt = NULL; + asection *srelgot = NULL; + asection *sfuncdesc = NULL; + bfd_vma *local_got_offsets; if (elf_elfheader (output_bfd)->e_flags & E_FLAG_RX_PID) pid_mode = true; else pid_mode = false; + htab = rx_elf_hash_table (info); + if (htab != NULL) + { + sgot = htab->root.sgot; + sgotplt = htab->root.sgotplt; + srelgot = htab->root.srelgot; + splt = htab->root.splt; + sfuncdesc = htab->sfuncdesc; + } symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr; sym_hashes = elf_sym_hashes (input_bfd); relend = relocs + input_section->reloc_count; + local_got_offsets = elf_local_got_offsets (input_bfd); + for (rel = relocs; rel < relend; rel ++) { reloc_howto_type *howto; @@ -533,11 +661,13 @@ rx_elf_relocate_section const char * name = NULL; bool unresolved_reloc = true; int r_type; + bfd_vma off; + bool resolved_to_zero = false; r_type = ELF32_R_TYPE (rel->r_info); r_symndx = ELF32_R_SYM (rel->r_info); - howto = rx_elf_howto_table + ELF32_R_TYPE (rel->r_info); + howto = rx_elf_howto_table + r_type; h = NULL; sym = NULL; sec = NULL; @@ -567,7 +697,13 @@ rx_elf_relocate_section name = h->root.root.string; } + if (sec != NULL && discarded_section (sec)) + RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, + rel, 1, relend, R_RX_NONE, + howto, 0, contents); + if (bfd_link_relocatable (info)) + continue; if (startswith (name, "$tableentry$default$")) { bfd_vma entry_vma; @@ -856,6 +992,7 @@ rx_elf_relocate_section relocation = - relocation; /* Fall through. */ case R_RX_DIR24S_PCREL: + local_plt: RANGE (-0x800000, 0x7fffff); #if RX_OPCODE_BIG_ENDIAN OP (2) = relocation; @@ -866,6 +1003,9 @@ rx_elf_relocate_section OP (1) = relocation >> 8; OP (2) = relocation >> 16; #endif + if (_bfd_elf_section_offset (output_bfd, info, input_section, + rel->r_offset) != (bfd_vma) -1) + unresolved_reloc = false; break; case R_RX_RH_24_OP: @@ -963,6 +1103,22 @@ rx_elf_relocate_section OP (2) = relocation >> 16; OP (3) = relocation >> 24; } + + if (bfd_link_pic(info) && h == NULL && + (input_section->flags & SEC_ALLOC)) + { + Elf_Internal_Rela outrel; + bfd_byte *loc; + + outrel.r_offset = (input_section->output_section->vma + + input_section->output_offset + + rel->r_offset); + outrel.r_addend = relocation; + outrel.r_info = ELF32_R_INFO (0, R_RX_GLOB_DAT); + loc = srelgot->contents; + loc += srelgot->reloc_count++ * sizeof (Elf32_External_Rela); + bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); + } break; case R_RX_DIR32_REV: @@ -1453,12 +1609,455 @@ rx_elf_relocate_section case R_RX_OPramtop: RX_STACK_PUSH (get_ramstart (info, input_bfd, input_section, rel->r_offset)); break; + case R_RX_GOT: + /* Relocation is to the entry for this symbol in the global + offset table. */ + + BFD_ASSERT (htab); + BFD_ASSERT (sgot != NULL); + + if (h != NULL) + { + bool dyn; + + off = h->got.offset; + BFD_ASSERT (off != (bfd_vma) -1); + + dyn = htab->root.dynamic_sections_created; + if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, + bfd_link_pic (info), + h) + || (bfd_link_pic (info) + && SYMBOL_REFERENCES_LOCAL (info, h)) + || ((ELF_ST_VISIBILITY (h->other) + || resolved_to_zero) + && h->root.type == bfd_link_hash_undefweak)) + { + /* This is actually a static link, or it is a + -Bsymbolic link and the symbol is defined + locally, or the symbol was forced to be local + because of a version file. We must initialize + this entry in the global offset table. Since the + offset must always be a multiple of 4, we use the + least significant bit to record whether we have + initialized it already. + + When doing a dynamic link, we create a .rela.got + relocation entry to initialize the value. This + is done in the finish_dynamic_symbol routine. */ + if ((off & 1) != 0) + off &= ~1; + else + { + bfd_put_32 (output_bfd, relocation, + sgot->contents + off); + h->got.offset |= 1; + } + } + relocation = off; + unresolved_reloc = false; + } + else + { + BFD_ASSERT (local_got_offsets != NULL + && local_got_offsets[r_symndx] != MINUS_ONE); + + off = local_got_offsets[r_symndx]; + + /* The offset must always be a multiple of 4. We use + the least significant bit to record whether we have + already generated the necessary reloc. */ + if ((off & 1) != 0) + off &= ~1; + else + { + bfd_put_32 (output_bfd, relocation, sgot->contents + off); + + if (bfd_link_pic (info)) + { + Elf_Internal_Rela outrel; + bfd_byte *loc; + + outrel.r_offset = (sgot->output_section->vma + + sgot->output_offset + + off); + outrel.r_info = ELF32_R_INFO (0, R_RX_RELATIVE); + outrel.r_addend = relocation; + loc = srelgot->contents; + loc += srelgot->reloc_count++ * sizeof (Elf32_External_Rela); + bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); + } + + local_got_offsets[r_symndx] |= 1; + } + + relocation = off; + unresolved_reloc = false; + } + +#ifdef GOT_BIAS + relocation -= GOT_BIAS; +#endif + RANGE(0, 0x3fffc); + ALIGN(3); + relocation >>= 2; + OP (0) = relocation; + OP (1) = relocation >> 8; + break; + + case R_RX_GOTOFF: + BFD_ASSERT (htab); + BFD_ASSERT (sgotplt != NULL); + if (h && h->root.type == bfd_link_hash_undefweak) + { + _bfd_error_handler + /* xgettext:c-format */ + (_("%pB(%pA+%#" PRIx64 "): " + "%s relocation against external symbol \"%s\""), + input_bfd, input_section, (uint64_t) rel->r_offset, + howto->name, h->root.root.string); + return false; + } + else + { + relocation -= sgot->output_section->vma; + } +#ifdef GOT_BIAS + relocation -= GOT_BIAS; +#endif + OP (0) = relocation; + OP (1) = relocation >> 8; + OP (2) = relocation >> 16; + OP (3) = relocation >> 24; + + break; + + case R_RX_PLT: + /* Relocation is to the entry for this symbol in the + procedure linkage table. */ + + /* Resolve a PLT reloc against a local symbol directly, + without using the procedure linkage table. */ + if (h == NULL || h->plt.refcount == -1) + goto local_plt; + + if (splt && h->plt.offset != (bfd_vma) -1) + { + relocation = splt->output_section->vma + h->plt.offset; + relocation -= (input_section->output_section->vma + + input_section->output_offset + + rel->r_offset) - 1; + OP (0) = relocation; + OP (1) = relocation >> 8; + OP (2) = relocation >> 16; + unresolved_reloc = false; + } + + break; + /* Relocation is to the canonical function descriptor for this + symbol, possibly via the GOT. Initialize the GOT + entry and function descriptor if necessary. */ + case R_RX_GOTFUNCDESC: + { + asection *reloc_section; + bfd_vma reloc_offset; + + reloc_section = htab->root.sgot; + + if (h != NULL) + reloc_offset = rx_elf_hash_entry (h)->funcdesc.offset; + else + { + union gotref *local_funcdesc; + local_funcdesc = rx_elf_local_funcdesc (input_bfd); + BFD_ASSERT (local_funcdesc != NULL); + reloc_offset = local_funcdesc[r_symndx].offset; + } + BFD_ASSERT (reloc_offset != MINUS_ONE); + reloc_offset += sgot->size; + + if (reloc_offset & 1) + { + reloc_offset &= ~1; + relocation = h->got.offset & ~1; + goto funcdesc_done_got; + } + + if (h && h->root.type == bfd_link_hash_undefweak + && (SYMBOL_CALLS_LOCAL (info, h) + || !htab->root.dynamic_sections_created)) + /* Undefined weak symbol which will not be dynamically + resolved later; leave it at zero. */ + goto funcdesc_leave_zero; + else if ( h && SYMBOL_CALLS_LOCAL (info, h) + && ! SYMBOL_FUNCDESC_LOCAL (info, h)) + { + /* If the symbol needs a non-local function descriptor + but binds locally (i.e., its visibility is + protected), emit a dynamic relocation decayed to + section+offset. This is an optimization; the dynamic + linker would resolve our function descriptor request + to our copy of the function anyway. */ + /*dynindx = elf_section_data (h->root.u.def.section + ->output_section)->dynindx;*/ + relocation += h->root.u.def.section->output_offset + + h->root.u.def.value; + } + else + { + bfd_vma offset; + + /* Otherwise, we know we have a private function + descriptor, so reference it directly. */ + + if (h) + { + bool dyn; + + offset = rx_elf_hash_entry (h)->funcdesc.offset; + BFD_ASSERT (offset != MINUS_ONE); + if ((offset & 1) == 0) + { + bfd_vma value; + if (h->dynindx == -1) + { + value = relocation; + value -= h->root.u.def.section->output_section->vma; + } + else + { + value = h->root.u.def.value; + value += h->root.u.def.section->output_offset; + } + if (!rx_elf_initialize_funcdesc (output_bfd, info, h, + offset, NULL, value)) + return false; + rx_elf_hash_entry (h)-> funcdesc.offset |= 1; + } + relocation = offset & ~1; + off = h->got.offset; + BFD_ASSERT (off != (bfd_vma) -1); + dyn = htab->root.dynamic_sections_created; + if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, + bfd_link_pic (info), + h) + || (bfd_link_pic (info) + && SYMBOL_REFERENCES_LOCAL (info, h)) + || ((ELF_ST_VISIBILITY (h->other) + || resolved_to_zero) + && h->root.type == bfd_link_hash_undefweak)) + { + if ((off & 1) != 0) + off &= ~1; + else + { + bfd_put_32 (output_bfd, relocation, + sgot->contents + off); + h->got.offset |= 1; + } + } + relocation = off; + } + else + { + union gotref *local_funcdesc; + + local_funcdesc = rx_elf_local_funcdesc (input_bfd); + offset = local_funcdesc[r_symndx].offset; + BFD_ASSERT (offset != MINUS_ONE); + if ((offset & 1) == 0) + { + if (!rx_elf_initialize_funcdesc (output_bfd, info, NULL, + offset, sec, + sec->vma + sym->st_value)) + return false; + local_funcdesc[r_symndx].offset |= 1; + } + BFD_ASSERT (local_got_offsets != NULL + && local_got_offsets[r_symndx] != MINUS_ONE); + + off = local_got_offsets[r_symndx]; + relocation = htab->sfuncdesc->output_offset + (off & ~1); + unresolved_reloc = false; + } + } + + if (!bfd_link_pic(info) && SYMBOL_FUNCDESC_LOCAL (info, h)) + { + bfd_vma offset; + BFD_ASSERT (htab); + + if (rx_elf_osec_readonly_p (output_bfd, + input_section->output_section)) + { + _bfd_error_handler + /* xgettext:c-format */ + (_("%pB(%pA+%#" PRIx64 "): " + "cannot emit fixup to `%s' in read-only section"), + input_bfd, + input_section, + (uint64_t) rel->r_offset, + name); + return false; + } + + offset = _bfd_elf_section_offset (output_bfd, info, + reloc_section, reloc_offset); + + if (offset != (bfd_vma)-1) + rx_elf_add_rofixup (output_bfd, htab->srofixup, + offset + + reloc_section->output_section->vma + + reloc_section->output_offset); + } + else if ((reloc_section->output_section->flags + & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD)) + { + if (rx_elf_osec_readonly_p (output_bfd, + reloc_section->output_section)) + { + info->callbacks->warning + (info, + _("cannot emit dynamic relocations in read-only section"), + name, input_bfd, reloc_section, reloc_offset); + return false; + } + } + funcdesc_leave_zero: + bfd_put_32 (output_bfd, relocation, + reloc_section->contents + reloc_offset); + if (h != NULL) + h->got.offset |= 1; + else + local_got_offsets[r_symndx] |= 1; + + funcdesc_done_got: + unresolved_reloc = false; +#ifdef GOT_BIAS + relocation -= GOT_BIAS; +#endif + RANGE(0, 0x3fffc); + ALIGN(3); + relocation >>= 2; + OP (0) = relocation; + OP (1) = relocation >> 8; + break; + } + case R_RX_FUNCDESC: + case R_RX_GOTOFFFUNCDESC: + + relocation = 0; + + if (h && (h->root.type == bfd_link_hash_undefweak + || !SYMBOL_FUNCDESC_LOCAL (info, h))) + { + _bfd_error_handler + /* xgettext:c-format */ + (_("%pB(%pA+%#" PRIx64 "): " + "%s relocation against external symbol \"%s\""), + input_bfd, input_section, (uint64_t) rel->r_offset, + howto->name, h->root.root.string); + return false; + } + else + { + bfd_vma offset; + + /* Otherwise, we know we have a private function + descriptor, so reference it directly. */ + if (h) + { + offset = rx_elf_hash_entry (h)->funcdesc.offset; + BFD_ASSERT (offset != MINUS_ONE); + if ((offset & 1) == 0) + { + bfd_vma value; + if (h->dynindx == -1) + { + value = relocation; + } + else + { + value = h->root.u.def.value; + value += h->root.u.def.section->output_offset; + } + if (!rx_elf_initialize_funcdesc (output_bfd, info, h, + offset, NULL, value)) + return false; + rx_elf_hash_entry (h)->funcdesc.offset |= 1; + } + relocation = offset & ~1; + } + else + { + union gotref *local_funcdesc; + + local_funcdesc = rx_elf_local_funcdesc (input_bfd); + offset = local_funcdesc[r_symndx].offset; + BFD_ASSERT (offset != MINUS_ONE); + if ((offset & 1) == 0) + { + if (!rx_elf_initialize_funcdesc (output_bfd, info, NULL, + offset, sec, + sec->output_offset + + sym->st_value)) + return false; + local_funcdesc[r_symndx].offset |= 1; + } + } + relocation = htab->sfuncdesc->output_offset + (offset & ~1); + unresolved_reloc = false; + if (r_type == R_RX_FUNCDESC) + { + Elf_Internal_Rela outrel; + bfd_byte *loc; + + outrel.r_offset = (input_section->output_section->vma + + input_section->output_offset + + rel->r_offset); + outrel.r_addend = sfuncdesc->output_section->vma + relocation; + outrel.r_info = ELF32_R_INFO (0, R_RX_GLOB_DAT); + loc = srelgot->contents; + loc += srelgot->reloc_count++ * sizeof (Elf32_External_Rela); + bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); + } + } + +#ifdef GOT_BIAS + relocation -= GOT_BIAS; +#endif + OP (0) = relocation; + OP (1) = relocation >> 8; + OP (2) = relocation >> 16; + OP (3) = relocation >> 24; + break; default: r = bfd_reloc_notsupported; break; } + /* Dynamic relocs are not propagated for SEC_DEBUGGING sections + because such sections are not SEC_ALLOC and thus ld.so will + not process them. */ + if (unresolved_reloc && h != NULL + && !((input_section->flags & SEC_DEBUGGING) != 0 + && h->def_dynamic) + && _bfd_elf_section_offset (output_bfd, info, input_section, + rel->r_offset) != (bfd_vma) -1) + { + _bfd_error_handler + /* xgettext:c-format */ + (_("%pB(%pA+%#" PRIx64 "): " + "unresolvable %s relocation against symbol `%s'"), + input_bfd, + input_section, + (uint64_t) rel->r_offset, + howto->name, + name); + return false; + } + if (r != bfd_reloc_ok) { const char * msg = NULL; @@ -3414,7 +4013,7 @@ rx_dump_symtab (bfd * abfd, void * internal_syms, void * external_syms) } } -char * +const char * rx_get_reloc (long reloc) { if (0 <= reloc && reloc < R_RX_max) @@ -3565,7 +4164,6 @@ rx_set_section_contents (bfd * abfd, bfd_size_type scount; #ifdef DJDEBUG - bfd_size_type i; fprintf (stderr, "\ndj: set %ld %ld to %s %s e%d sc%d\n", (long) offset, (long) count, section->name, @@ -4048,6 +4646,1634 @@ rx_additional_link_map_text (bfd *obfd, struct bfd_link_info *info, FILE *mapfil bfd_hash_traverse (&(info->hash->table), rx_table_map, &stuff); } +static enum elf_reloc_type_class +rx_elf_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED, + const asection *rel_sec ATTRIBUTE_UNUSED, + const Elf_Internal_Rela *rela) +{ + switch ((int) ELF32_R_TYPE (rela->r_info)) + { + case R_RX_RELATIVE: + return reloc_class_relative; + case R_RX_JMP_SLOT: + return reloc_class_plt; + case R_RX_COPY: + return reloc_class_copy; + default: + return reloc_class_normal; + } +} + +/* FDPIC binaries have a default 128K stack. */ +#define DEFAULT_STACK_SIZE 0x20000 + +/* The name of the dynamic interpreter. This is put in the .interp + section. */ +#define ELF_DYNAMIC_INTERPRETER "/lib/ld-uClibc.so.1" + +#define FDPIC_PLT_ENTRY_SIZE 30 +#define FDPIC_PLT_FUNC 2 +#define FDPIC_PLT_LAZY 14 +#define FDPIC_PLT_REL 24 + +/* First entry in an absolute procedure linkage table look like this. */ +static const bfd_byte fdpic_elf_rx_plt_entry[FDPIC_PLT_ENTRY_SIZE] = +{ + 0x70, 0xd5, /* 0: add #func@GOTOFFUNCDESC, r13, r5 */ + 0, 0, 0, 0, /* 2: */ + 0xec, 0x5e, /* 6: mov.l [r5], r14 */ + 0xed, 0x5d, 0x01, /* 8: mov.l 4[r5], r13 */ + 0x7f, 0x0e, /* b: jmp r14 */ + 0x03, /* d: nop */ + 0xec, 0xde, /* e: mov.l [r13], r14 */ + 0xfd, 0x26, 0x0e, /* 10: mov.l r14, [-r0] */ + 0xed, 0xde, 0x01, /* 13: mov.l 4[r13], r14 */ + 0xfb, 0x52, /* 16: mov.l #rel.plt offset, r5 */ + 0, 0, 0, 0, /* 18: */ + 0x02, /* 1c: rts (jmp [r13]) */ + 0x03, /* 1d: nop */ +}; + +struct elf_rx_pcrel_relocs_copied +{ + /* Next section. */ + struct elf_rx_pcrel_relocs_copied *next; + /* A section in dynobj. */ + asection *section; + /* Number of relocs copied in this section. */ + bfd_size_type count; +}; + +#define is_rx_elf(bfd) \ + (bfd_get_flavour (bfd) == bfd_target_elf_flavour \ + && elf_tdata (bfd) != NULL \ + && elf_object_id (bfd) == RX_ELF_DATA) + +/* Return true if OUTPUT_BFD is an FDPIC object. */ +static bool +fdpic_object_p (bfd *abfd) +{ + extern const bfd_target rx_elf32_linux_le_vec; + + return (abfd->xvec == &rx_elf32_linux_le_vec); +} + +/* Override the generic function because we need to store rx_elf_obj_tdata + as the specific tdata. */ + +inline static bool +rx_elf_mkobject (bfd *abfd) +{ + return bfd_elf_allocate_object (abfd, sizeof (struct rx_elf_obj_tdata)); +} + +/* Install a 32-bit PLT field starting at ADDR, which occurs in OUTPUT_BFD. + VALUE is the field's value and CODE_P is true if VALUE refers to code, + not data. */ + +inline static void +install_plt_field (bfd *output_bfd, bool code_p ATTRIBUTE_UNUSED, + unsigned long value, bfd_byte *addr) +{ + bfd_put_32 (output_bfd, value, addr); +} + +/* Create an entry in an RX ELF linker hash table. */ + +static struct bfd_hash_entry * +rx_elf_link_hash_newfunc (struct bfd_hash_entry *entry, + struct bfd_hash_table *table, + const char *string) +{ + struct elf_rx_link_hash_entry *ret = + (struct elf_rx_link_hash_entry *) entry; + + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (ret == (struct elf_rx_link_hash_entry *) NULL) + ret = ((struct elf_rx_link_hash_entry *) + bfd_hash_allocate (table, + sizeof (struct elf_rx_link_hash_entry))); + if (ret == (struct elf_rx_link_hash_entry *) NULL) + return (struct bfd_hash_entry *) ret; + + /* Call the allocation method of the superclass. */ + ret = ((struct elf_rx_link_hash_entry *) + _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret, + table, string)); + if (ret != (struct elf_rx_link_hash_entry *) NULL) + { + ret->gotplt_refcount = 0; + ret->funcdesc.refcount = 0; + ret->abs_funcdesc_refcount = 0; + ret->got_type = GOT_UNKNOWN; + } + + return (struct bfd_hash_entry *) ret; +} + +/* Create an RX ELF linker hash table. */ + +static struct bfd_link_hash_table * +rx_elf_link_hash_table_create (bfd *abfd) +{ + struct elf_rx_link_hash_table *ret; + size_t amt = sizeof (struct elf_rx_link_hash_table); + + ret = (struct elf_rx_link_hash_table *) bfd_zmalloc (amt); + if (ret == (struct elf_rx_link_hash_table *) NULL) + return NULL; + + if (!_bfd_elf_link_hash_table_init (&ret->root, abfd, + rx_elf_link_hash_newfunc, + sizeof (struct elf_rx_link_hash_entry))) + { + free (ret); + return NULL; + } + + if (fdpic_object_p (abfd)) + { + ret->root.dt_pltgot_required = true; + ret->fdpic_p = true; + } + return &ret->root.root; +} + +static bool +rx_elf_omit_section_dynsym (bfd *output_bfd ATTRIBUTE_UNUSED, + struct bfd_link_info *info, asection *p) +{ + struct elf_rx_link_hash_table *htab = rx_elf_hash_table (info); + + /* Non-FDPIC binaries do not need dynamic symbols for sections. */ + if (!htab->fdpic_p) + return true; + + /* We need dynamic symbols for every section, since segments can + relocate independently. */ + switch (elf_section_data (p)->this_hdr.sh_type) + { + case SHT_PROGBITS: + case SHT_NOBITS: + /* If sh_type is yet undecided, assume it could be + SHT_PROGBITS/SHT_NOBITS. */ + case SHT_NULL: + return false; + + /* There shouldn't be section relative relocations + against any other section. */ + default: + return true; + } +} + +/* Create .got, .gotplt, and .rela.got sections in DYNOBJ, and set up + shortcuts to them in our hash table. */ + +static bool +create_got_section (bfd *dynobj, struct bfd_link_info *info) +{ + struct elf_rx_link_hash_table *htab; + + if (! _bfd_elf_create_got_section (dynobj, info)) + return false; + + htab = rx_elf_hash_table (info); + if (htab == NULL) + return false; + + htab->sfuncdesc = bfd_make_section_anyway_with_flags (dynobj, ".got.funcdesc", + (SEC_ALLOC | SEC_LOAD + | SEC_HAS_CONTENTS + | SEC_IN_MEMORY + | SEC_LINKER_CREATED + | SEC_READONLY)); + if (htab->sfuncdesc == NULL + || !bfd_set_section_alignment (htab->sfuncdesc, 2)) + return false; + + htab->srelfuncdesc = bfd_make_section_anyway_with_flags (dynobj, + ".rela.got.funcdesc", + (SEC_ALLOC | SEC_LOAD + | SEC_HAS_CONTENTS + | SEC_IN_MEMORY + | SEC_LINKER_CREATED + | SEC_READONLY)); + if (htab->srelfuncdesc == NULL + || !bfd_set_section_alignment (htab->srelfuncdesc, 2)) + return false; + + /* Also create .rofixup. */ + htab->srofixup = bfd_make_section_anyway_with_flags (dynobj, ".rofixup", + (SEC_ALLOC | SEC_LOAD + | SEC_HAS_CONTENTS + | SEC_IN_MEMORY + | SEC_LINKER_CREATED + | SEC_READONLY)); + if (htab->srofixup == NULL + || !bfd_set_section_alignment (htab->srofixup, 2)) + return false; + + return true; +} + +/* Create dynamic sections when linking against a dynamic object. */ + +static bool +rx_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) +{ + struct elf_rx_link_hash_table *htab; + flagword flags, pltflags; + asection *s; + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + + htab = rx_elf_hash_table (info); + if (htab == NULL) + return false; + + if (htab->root.dynamic_sections_created) + return true; + + /* We need to create .plt, .rel[a].plt, .got, .got.plt, .dynbss, and + .rel[a].bss sections. */ + + flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY + | SEC_LINKER_CREATED); + + pltflags = flags; + pltflags |= SEC_CODE; + if (bed->plt_not_loaded) + pltflags &= ~ (SEC_LOAD | SEC_HAS_CONTENTS); + if (bed->plt_readonly) + pltflags |= SEC_READONLY; + + s = bfd_make_section_anyway_with_flags (abfd, ".plt", pltflags); + htab->root.splt = s; + if (s == NULL + || !bfd_set_section_alignment (s, bed->plt_alignment)) + return false; + + if (bed->want_plt_sym) + { + /* Define the symbol _PROCEDURE_LINKAGE_TABLE_ at the start of the + .plt section. */ + struct elf_link_hash_entry *h; + struct bfd_link_hash_entry *bh = NULL; + + if (! (_bfd_generic_link_add_one_symbol + (info, abfd, "_PROCEDURE_LINKAGE_TABLE_", BSF_GLOBAL, s, + (bfd_vma) 0, (const char *) NULL, false, + get_elf_backend_data (abfd)->collect, &bh))) + return false; + + h = (struct elf_link_hash_entry *) bh; + h->def_regular = 1; + h->type = STT_OBJECT; + htab->root.hplt = h; + + if (bfd_link_pic (info) + && ! bfd_elf_link_record_dynamic_symbol (info, h)) + return false; + } + + s = bfd_make_section_anyway_with_flags (abfd, + bed->default_use_rela_p + ? ".rela.plt" : ".rel.plt", + flags | SEC_READONLY); + htab->root.srelplt = s; + if (s == NULL + || !bfd_set_section_alignment (s, 2)) + return false; + + if (htab->root.sgot == NULL + && !create_got_section (abfd, info)) + return false; + + if (bed->want_dynbss) + { + /* The .dynbss section is a place to put symbols which are defined + by dynamic objects, are referenced by regular objects, and are + not functions. We must allocate space for them in the process + image and use a R_*_COPY reloc to tell the dynamic linker to + initialize them at run time. The linker script puts the .dynbss + section into the .bss section of the final image. */ + s = bfd_make_section_anyway_with_flags (abfd, ".dynbss", + SEC_ALLOC | SEC_LINKER_CREATED); + htab->root.sdynbss = s; + if (s == NULL) + return false; + + /* The .rel[a].bss section holds copy relocs. This section is not + normally needed. We need to create it here, though, so that the + linker will map it to an output section. We can't just create it + only if we need it, because we will not know whether we need it + until we have seen all the input files, and the first time the + main linker code calls BFD after examining all the input files + (size_dynamic_sections) the input sections have already been + mapped to the output sections. If the section turns out not to + be needed, we can discard it later. We will never need this + section when generating a shared object, since they do not use + copy relocs. */ + if (! bfd_link_pic (info)) + { + s = bfd_make_section_anyway_with_flags (abfd, + (bed->default_use_rela_p + ? ".rela.bss" : ".rel.bss"), + flags | SEC_READONLY); + htab->root.srelbss = s; + if (s == NULL + || !bfd_set_section_alignment (s, 2)) + return false; + } + } + + return true; +} + +/* Adjust a symbol defined by a dynamic object and referenced by a + regular object. The current definition is in some section of the + dynamic object, but we're not including those sections. We have to + change the definition to something the rest of the link can + understand. */ + +static bool +rx_elf_adjust_dynamic_symbol (struct bfd_link_info *info, + struct elf_link_hash_entry *h) +{ + struct elf_rx_link_hash_table *htab; + asection *s; + + htab = rx_elf_hash_table (info); + if (htab == NULL) + return false; + + /* Make sure we know what is going on here. */ + BFD_ASSERT (htab->root.dynobj != NULL + && (h->needs_plt + || h->is_weakalias + || (h->def_dynamic + && h->ref_regular + && !h->def_regular))); + + /* If this is a function, put it in the procedure linkage table. We + will fill in the contents of the procedure linkage table later, + when we know the address of the .got section. */ + if (h->type == STT_FUNC + || h->needs_plt) + { + if (h->plt.refcount <= 0 + || SYMBOL_CALLS_LOCAL (info, h) + || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT + && h->root.type == bfd_link_hash_undefweak)) + { + /* This case can occur if we saw a PLT reloc in an input + file, but the symbol was never referred to by a dynamic + object. In such a case, we don't actually need to build + a procedure linkage table, and we can just do a REL32 + reloc instead. */ + h->plt.offset = (bfd_vma) -1; + h->needs_plt = 0; + } + + return true; + } + else + h->plt.offset = (bfd_vma) -1; + + /* If this is a weak symbol, and there is a real definition, the + processor independent code will have arranged for us to see the + real definition first, and we can just use the same value. */ + if (h->is_weakalias) + { + struct elf_link_hash_entry *def = weakdef (h); + BFD_ASSERT (def->root.type == bfd_link_hash_defined); + h->root.u.def.section = def->root.u.def.section; + h->root.u.def.value = def->root.u.def.value; + if (info->nocopyreloc) + h->non_got_ref = def->non_got_ref; + return true; + } + + /* This is a reference to a symbol defined by a dynamic object which + is not a function. */ + + /* If we are creating a shared library, we must presume that the + only references to the symbol are via the global offset table. + For such cases we need not do anything here; the relocations will + be handled correctly by relocate_section. */ + if (bfd_link_pic (info)) + return true; + + /* If there are no references to this symbol that do not use the + GOT, we don't need to generate a copy reloc. */ + if (!h->non_got_ref) + return true; + + /* If -z nocopyreloc was given, we won't generate them either. */ + if (0 && info->nocopyreloc) + { + h->non_got_ref = 0; + return true; + } + + /* If we don't find any dynamic relocs in read-only sections, then + we'll be keeping the dynamic relocs and avoiding the copy reloc. */ + if (0 && !_bfd_elf_readonly_dynrelocs (h)) + { + h->non_got_ref = 0; + return true; + } + + /* We must allocate the symbol in our .dynbss section, which will + become part of the .bss section of the executable. There will be + an entry for this symbol in the .dynsym section. The dynamic + object will contain position independent code, so all references + from the dynamic object to this symbol will go through the global + offset table. The dynamic linker will use the .dynsym entry to + determine the address it must put in the global offset table, so + both the dynamic object and the regular object will refer to the + same memory location for the variable. */ + + s = htab->root.sdynbss; + BFD_ASSERT (s != NULL); + + /* We must generate a R_RX_COPY reloc to tell the dynamic linker to + copy the initial value out of the dynamic object and into the + runtime process image. We need to remember the offset into the + .rela.bss section we are going to use. */ + if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0) + { + asection *srel; + + srel = htab->root.srelbss; + BFD_ASSERT (srel != NULL); + srel->size += sizeof (Elf32_External_Rela); + h->needs_copy = 1; + } + + return _bfd_elf_adjust_dynamic_copy (info, h, s); +} + +/* Allocate space in .plt, .got and associated reloc sections for + dynamic relocs. */ + +static bool +allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) +{ + struct bfd_link_info *info; + struct elf_rx_link_hash_table *htab; + struct elf_rx_link_hash_entry *eh; + struct elf_dyn_relocs *p; + + if (h->root.type == bfd_link_hash_indirect) + return true; + + info = (struct bfd_link_info *) inf; + htab = rx_elf_hash_table (info); + if (htab == NULL) + return false; + + eh = (struct elf_rx_link_hash_entry *) h; + if ((h->got.refcount > 0 + || h->forced_local) + && eh->gotplt_refcount > 0) + { + /* The symbol has been forced local, or we have some direct got refs, + so treat all the gotplt refs as got refs. */ + h->got.refcount += eh->gotplt_refcount; + if (h->plt.refcount >= eh->gotplt_refcount) + h->plt.refcount -= eh->gotplt_refcount; + } + + if (htab->root.dynamic_sections_created + && h->plt.refcount > 0 + && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT + || h->root.type != bfd_link_hash_undefweak)) + { + /* Make sure this symbol is output as a dynamic symbol. + Undefined weak syms won't yet be marked as dynamic. */ + if (h->dynindx == -1 + && !h->forced_local) + { + if (! bfd_elf_link_record_dynamic_symbol (info, h)) + return false; + } + + if (bfd_link_pic (info) + || WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, 0, h)) + { + asection *s = htab->root.splt; + + h->plt.offset = s->size; + + /* If this symbol is not defined in a regular file, and we are + not generating a shared library, then set the symbol to this + location in the .plt. This is required to make function + pointers compare as equal between the normal executable and + the shared library. Skip this for FDPIC, since the + function's address will be the address of the canonical + function descriptor. */ + if (!htab->fdpic_p && !bfd_link_pic (info) && !h->def_regular) + { + h->root.u.def.section = s; + h->root.u.def.value = h->plt.offset; + } + + /* Make room for this entry. */ + s->size += sizeof(fdpic_elf_rx_plt_entry); + + /* We also need to make an entry in the .got.plt section, which + will be placed in the .got section by the linker script. */ + if (!htab->fdpic_p) + htab->root.sgotplt->size += 4; + else + htab->root.sgotplt->size += 8; + + /* We also need to make an entry in the .rel.plt section. */ + htab->root.srelplt->size += sizeof (Elf32_External_Rela); + + } + else + { + h->plt.offset = (bfd_vma) -1; + h->needs_plt = 0; + } + } + else + { + h->plt.offset = (bfd_vma) -1; + h->needs_plt = 0; + } + + if ((h->got.refcount > 0) || (h->non_got_ref && h->plt.refcount > 0)) + { + asection *sgot; + bool dyn; + enum got_type got_type = rx_elf_hash_entry (h)->got_type; + + /* Make sure this symbol is output as a dynamic symbol. + Undefined weak syms won't yet be marked as dynamic. */ + if (h->dynindx == -1 + && !h->forced_local) + { + if (! bfd_elf_link_record_dynamic_symbol (info, h)) + return false; + } + + sgot = htab->root.sgot; + if (sgot->size == 0) + sgot->size += 12; + + h->got.offset = sgot->size; + sgot->size += 4; + dyn = htab->root.dynamic_sections_created; + if (!dyn) + { + /* No dynamic relocations required. */ + if (htab->fdpic_p && !bfd_link_pic (info) + && h->root.type != bfd_link_hash_undefweak + && (got_type == GOT_NORMAL || got_type == GOT_FUNCDESC)) + htab->srofixup->size += 4; + } + else if ((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT + || h->root.type != bfd_link_hash_undefweak) + && (bfd_link_pic (info))) { + htab->root.srelgot->size += sizeof (Elf32_External_Rela); + } + else if (htab->fdpic_p + && !bfd_link_pic (info) + && got_type == GOT_NORMAL + && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT + || h->root.type != bfd_link_hash_undefweak)) + htab->srofixup->size += 4; + } + else + h->got.offset = MINUS_ONE; + + /* Allocate space for any dynamic relocations to function + descriptors, canonical or otherwise. We need to relocate the + reference unless it resolves to zero, which only happens for + undefined weak symbols (either non-default visibility, or when + static linking). Any GOT slot is accounted for elsewhere. */ + if (eh->abs_funcdesc_refcount > 0 + && (h->root.type != bfd_link_hash_undefweak + || (htab->root.dynamic_sections_created + && ! SYMBOL_CALLS_LOCAL (info, h)))) + { + if (!bfd_link_pic (info) && SYMBOL_FUNCDESC_LOCAL (info, h)) + htab->srofixup->size += eh->abs_funcdesc_refcount * 4; + else + htab->root.srelgot->size + += eh->abs_funcdesc_refcount * sizeof (Elf32_External_Rela); + } + + /* We must allocate a function descriptor if there are references to + a canonical descriptor (R_RX_GOTFUNCDESC or R_RX_FUNCDESC) and + the dynamic linker isn't going to allocate it. None of this + applies if we already created one in .got.plt, but if the + canonical function descriptor can be in this object, there + won't be a PLT entry at all. */ + if ((eh->funcdesc.refcount > 0 + || (h->got.offset != MINUS_ONE && eh->got_type == GOT_FUNCDESC)) + && h->root.type != bfd_link_hash_undefweak) + { + /* Make room for this function descriptor. */ + eh->funcdesc.offset = htab->sfuncdesc->size; + htab->sfuncdesc->size += 8; + + /* We will need a relocation or two fixups to initialize the + function descriptor, so allocate those too. */ + if (!bfd_link_pic(info) && SYMBOL_CALLS_LOCAL (info, h)) + htab->srofixup->size += 8; + else + htab->srelfuncdesc->size += sizeof (Elf32_External_Rela); + } + + if (h->dyn_relocs == NULL) + return true; + + /* In the shared -Bsymbolic case, discard space allocated for + dynamic pc-relative relocs against symbols which turn out to be + defined in regular objects. For the normal shared case, discard + space for pc-relative relocs that have become local due to symbol + visibility changes. */ + + if (bfd_link_pic (info)) + { + if (SYMBOL_CALLS_LOCAL (info, h)) + { + struct elf_dyn_relocs **pp; + + for (pp = &h->dyn_relocs; (p = *pp) != NULL; ) + { + p->count -= p->pc_count; + p->pc_count = 0; + if (p->count == 0) + *pp = p->next; + else + pp = &p->next; + } + } + + /* Also discard relocs on undefined weak syms with non-default + visibility. */ + if (h->dyn_relocs != NULL + && h->root.type == bfd_link_hash_undefweak) + { + if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT + || UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)) + h->dyn_relocs = NULL; + + /* Make sure undefined weak symbols are output as a dynamic + symbol in PIEs. */ + else if (h->dynindx == -1 + && !h->forced_local) + { + if (! bfd_elf_link_record_dynamic_symbol (info, h)) + return false; + } + } + } + else + { + /* For the non-shared case, discard space for relocs against + symbols which turn out to need copy relocs or are not + dynamic. */ + + if (!h->non_got_ref + && ((h->def_dynamic + && !h->def_regular) + || (htab->root.dynamic_sections_created + && (h->root.type == bfd_link_hash_undefweak + || h->root.type == bfd_link_hash_undefined)))) + { + /* Make sure this symbol is output as a dynamic symbol. + Undefined weak syms won't yet be marked as dynamic. */ + if (h->dynindx == -1 + && !h->forced_local) + { + if (! bfd_elf_link_record_dynamic_symbol (info, h)) + return false; + } + + /* If that succeeded, we know we'll be keeping all the + relocs. */ + if (h->dynindx != -1) + goto keep; + } + + h->dyn_relocs = NULL; + + keep: ; + } + + /* Finally, allocate space. */ + for (p = h->dyn_relocs; p != NULL; p = p->next) + { + asection *sreloc = elf_section_data (p->sec)->sreloc; + sreloc->size += p->count * sizeof (Elf32_External_Rela); + /* If we need relocations, we do not need fixups. */ + if (htab->fdpic_p && !bfd_link_pic(info)) + htab->srofixup->size -= 4 * (p->count - p->pc_count); + } + return true; +} + +/* This function is called after all the input files have been read, + and the input sections have been assigned to output sections. + It's a convenient place to determine the PLT style. */ + +static bool +rx_elf_early_size_sections (bfd *output_bfd, struct bfd_link_info *info) +{ + if (rx_elf_hash_table (info)->fdpic_p && !bfd_link_relocatable (info) + && !bfd_elf_stack_segment_size (output_bfd, info, + "__stacksize", DEFAULT_STACK_SIZE)) + return false; + return true; +} + +/* Reserve space for COUNT dynamic relocations in relocation selection + SRELOC. */ + +static bool +rx_elf_late_size_sections (bfd *output_bfd ATTRIBUTE_UNUSED, + struct bfd_link_info *info) +{ + struct elf_rx_link_hash_table *htab; + bfd *dynobj; + asection *s; + bool relocs; + bfd *ibfd; + + htab = rx_elf_hash_table (info); + if (htab == NULL) + return false; + + dynobj = htab->root.dynobj; + if (dynobj == NULL) + return true; + + + if (htab->root.dynamic_sections_created) + { + /* Set the contents of the .interp section to the interpreter. */ + if (bfd_link_executable (info) && !info->nointerp) + { + s = bfd_get_linker_section (dynobj, ".interp"); + BFD_ASSERT (s != NULL); + s->size = sizeof ELF_DYNAMIC_INTERPRETER; + s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; + s->alloced = 1; + } + } + + /* Set up .got offsets for local syms, and space for local dynamic + relocs. */ + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) + { + bfd_signed_vma *local_got; + bfd_signed_vma *end_local_got; + bfd_size_type locsymcount; + Elf_Internal_Shdr *symtab_hdr; + asection *srel; + union gotref *local_funcdesc, *end_local_funcdesc; + char *local_got_type; + + if (! is_rx_elf (ibfd)) + continue; + + symtab_hdr = & elf_symtab_hdr (ibfd); + locsymcount = symtab_hdr->sh_info; + for (s = ibfd->sections; s != NULL; s = s->next) + { + struct elf_dyn_relocs *p; + + for (p = ((struct elf_dyn_relocs *) + elf_section_data (s)->local_dynrel); + p != NULL; + p = p->next) + { + if (! bfd_is_abs_section (p->sec) + && bfd_is_abs_section (p->sec->output_section)) + { + /* Input section has been discarded, either because + it is a copy of a linkonce section or due to + linker script /DISCARD/, so we'll be discarding + the relocs too. */ + } + else if (p->count != 0) + { + srel = elf_section_data (p->sec)->sreloc; + srel->size += p->count * sizeof (Elf32_External_Rela); + if ((p->sec->output_section->flags & SEC_READONLY) != 0) + { + info->flags |= DF_TEXTREL; + info->callbacks->minfo (_("%pB: dynamic relocation in read-only section `%pA'\n"), + p->sec->owner, p->sec); + + /* If we need relocations, we do not need fixups. */ + if (htab->fdpic_p && !bfd_link_pic(info)) + htab->srofixup->size -= 4 * (p->count - p->pc_count); + } + } + } + if (s->flags & SEC_ALLOC && s->reloc_count > 0) + { + Elf_Internal_Rela *rel = elf_section_data (s)->relocs; + unsigned long r_symndx; + unsigned int r; + + srel = htab->root.srelgot; + for (r = 0; r < s->reloc_count; r++, rel++) + { + r_symndx = ELF32_R_SYM (rel->r_info); + if ((bfd_link_pic(info) && + ELF32_R_TYPE(rel->r_info) == R_RX_DIR32 && + r_symndx < locsymcount) || + ELF32_R_TYPE(rel->r_info) == R_RX_FUNCDESC) + srel->size += sizeof (Elf32_External_Rela); + } + } + } + + s = htab->root.sgot; + srel = htab->root.srelgot; + local_got = elf_local_got_refcounts (ibfd); + if (local_got) + { + int r_indx; + end_local_got = local_got + locsymcount; + local_got_type = rx_elf_local_got_type (ibfd); + local_funcdesc = rx_elf_local_funcdesc (ibfd); + for (r_indx = 0; local_got < end_local_got; ++local_got, ++local_got_type, r_indx++) + { + if (*local_got > 0) + { + if (s->size == 0) + s->size += 12; + *local_got = s->size; + s->size += 4; + + switch (*local_got_type) + { + case GOT_FUNCDESC: + if (local_funcdesc == NULL) + { + bfd_size_type size; + + size = locsymcount * sizeof (union gotref); + local_funcdesc = (union gotref *) bfd_zalloc (ibfd, + size); + if (local_funcdesc == NULL) + return false; + rx_elf_local_funcdesc (ibfd) = local_funcdesc; + local_funcdesc += (local_got + - elf_local_got_refcounts (ibfd)); + } + local_funcdesc->refcount++; + break; + case GOT_NORMAL: + if (bfd_link_pic(info)) + srel->size += sizeof (Elf32_External_Rela); + else + htab->srofixup->size += 4; + break; + } + } + if (local_funcdesc) + local_funcdesc++; + } + } + local_funcdesc = rx_elf_local_funcdesc (ibfd); + if (local_funcdesc) + { + int r_indx = 0; + end_local_funcdesc = local_funcdesc + locsymcount; + + for (; local_funcdesc < end_local_funcdesc; ++local_funcdesc) + { + if (local_funcdesc->refcount > 0) + { + local_funcdesc->offset = htab->sfuncdesc->size; + htab->sfuncdesc->size += 8; + if (!bfd_link_pic (info)) + htab->srofixup->size += 8; + else + htab->srelfuncdesc->size += sizeof (Elf32_External_Rela); + } + else + local_funcdesc->offset = MINUS_ONE; + r_indx++; + } + } + } + /* Only the reserved entries should be present. For FDPIC, they go at + the end of .got.plt. */ + if (htab->fdpic_p) + { + BFD_ASSERT (htab->root.sgotplt && htab->root.sgotplt->size == 12); + htab->root.sgotplt->size = 0; + } + + /* Allocate global sym .plt and .got entries, and space for global + sym dynamic relocs. */ + elf_link_hash_traverse (&htab->root, allocate_dynrelocs, info); + + if (htab->fdpic_p) + { + htab->root.hgot->root.u.def.value = htab->root.sgotplt->size; + htab->root.sgotplt->size += 12; + } + + /* At the very end of the .rofixup section is a pointer to the GOT. */ + if (htab->fdpic_p && htab->srofixup != NULL) + htab->srofixup->size += 4; + + /* We now have determined the sizes of the various dynamic sections. + Allocate memory for them. */ + relocs = false; + for (s = dynobj->sections; s != NULL; s = s->next) + { + if ((s->flags & SEC_LINKER_CREATED) == 0) + continue; + + if (s == htab->root.splt + || s == htab->root.sgot + || s == htab->root.srelgot + || s == htab->root.srelplt + || s == htab->root.sgotplt + || s == htab->sfuncdesc + || s == htab->srofixup + || s == htab->root.sdynbss) + { + /* Strip this section if we don't need it; see the + comment below. */ + } + else if (startswith (bfd_section_name (s), ".rela")) + { + if (s->size != 0 && s != htab->root.srelplt ) + relocs = true; + + /* We use the reloc_count field as a counter if we need + to copy relocs into the output file. */ + s->reloc_count = 0; + } + else + { + /* It's not one of our sections, so don't allocate space. */ + continue; + } + + if (s->size == 0) + { + /* If we don't need this section, strip it from the + output file. This is mostly to handle .rela.bss and + .rela.plt. We must create both sections in + create_dynamic_sections, because they must be created + before the linker maps input sections to output + sections. The linker does that before + adjust_dynamic_symbol is called, and it is that + function which decides whether anything needs to go + into these sections. */ + + s->flags |= SEC_EXCLUDE; + continue; + } + + if ((s->flags & SEC_HAS_CONTENTS) == 0) + continue; + + s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->size); + if (s->contents == NULL) + return false; + s->alloced = 1; + } + + return _bfd_elf_add_dynamic_tags (output_bfd, info, relocs); +} + +/* Add a dynamic relocation to the SRELOC section. */ + +inline static bfd_vma +rx_elf_add_dyn_reloc (bfd *output_bfd, asection *sreloc, bfd_vma offset, + int reloc_type, long dynindx, bfd_vma addend) +{ + Elf_Internal_Rela outrel; + bfd_vma reloc_offset; + + outrel.r_offset = offset; + outrel.r_info = ELF32_R_INFO (dynindx, reloc_type); + outrel.r_addend = addend; + + reloc_offset = sreloc->reloc_count * sizeof (Elf32_External_Rela); + + BFD_ASSERT (reloc_offset < sreloc->size); + bfd_elf32_swap_reloca_out (output_bfd, &outrel, + sreloc->contents + reloc_offset); + sreloc->reloc_count++; + + return reloc_offset; +} + +/* Add an FDPIC read-only fixup. */ +inline static void +rx_elf_add_rofixup (bfd *output_bfd, asection *srofixup, bfd_vma offset) +{ + bfd_vma fixup_offset; + + fixup_offset = srofixup->reloc_count++ * 4; + BFD_ASSERT (fixup_offset < srofixup->size); + bfd_put_32 (output_bfd, offset, srofixup->contents + fixup_offset); +} + +/* Find the segment number in which OSEC, and output section, is + located. */ + +static unsigned +rx_elf_osec_to_segment (bfd *output_bfd, asection *osec) +{ + Elf_Internal_Phdr *p = NULL; + + if (output_bfd->xvec->flavour == bfd_target_elf_flavour + && output_bfd->direction != read_direction) + p = _bfd_elf_find_segment_containing_section (output_bfd, osec); + + return (p != NULL) ? p - elf_tdata (output_bfd)->phdr : -1; +} + +static bool +rx_elf_osec_readonly_p (bfd *output_bfd, asection *osec) +{ + unsigned seg = rx_elf_osec_to_segment (output_bfd, osec); + + return (seg != (unsigned) -1 + && ! (elf_tdata (output_bfd)->phdr[seg].p_flags & PF_W)); +} + +/* Generate the initial contents of a local function descriptor, along + with any relocations or fixups required. */ +static bool +rx_elf_initialize_funcdesc (bfd *output_bfd, + struct bfd_link_info *info, + struct elf_link_hash_entry *h, + bfd_vma offset, + asection *section, + bfd_vma value) +{ + struct elf_rx_link_hash_table *htab; + int dynindx; + bfd_vma addr, seg; + + htab = rx_elf_hash_table (info); + + if (h != NULL && SYMBOL_CALLS_LOCAL (info, h)) + section = h->root.u.def.section; + + if (h == NULL || SYMBOL_CALLS_LOCAL (info, h)) + { + dynindx = elf_section_data (section->output_section)->dynindx; + addr = value + section->output_offset; + seg = rx_elf_osec_to_segment (output_bfd, section->output_section); + } + else + { + dynindx = h->dynindx; + addr = seg = 0; + } + + if (!bfd_link_pic (info) && SYMBOL_CALLS_LOCAL (info, h)) + { + if (h == NULL || h->root.type != bfd_link_hash_undefweak) + { + rx_elf_add_rofixup (output_bfd, htab->srofixup, + offset + + htab->sfuncdesc->output_section->vma + + htab->sfuncdesc->output_offset); + rx_elf_add_rofixup (output_bfd, htab->srofixup, + offset + 4 + + htab->sfuncdesc->output_section->vma + + htab->sfuncdesc->output_offset); + } + + /* There are no dynamic relocations so fill in the final + address and gp value (barring fixups). */ + addr += section->output_section->vma; + seg = htab->root.hgot->root.u.def.value + + htab->root.hgot->root.u.def.section->output_section->vma + + htab->root.hgot->root.u.def.section->output_offset; + } + else + { + rx_elf_add_dyn_reloc (output_bfd, htab->srelfuncdesc, + offset + + htab->sfuncdesc->output_section->vma + + htab->sfuncdesc->output_offset, + R_RX_FUNCDESC_VALUE, dynindx, value); + } + bfd_put_32 (output_bfd, addr, htab->sfuncdesc->contents + offset); + bfd_put_32 (output_bfd, seg, htab->sfuncdesc->contents + offset + 4); + + return true; +} + +/* Finish up dynamic symbol handling. We set the contents of various + dynamic sections here. */ + +static bool +rx_elf_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info, + struct elf_link_hash_entry *h, + Elf_Internal_Sym *sym) +{ + struct elf_rx_link_hash_table *htab; + + htab = rx_elf_hash_table (info); + if (htab == NULL) + return false; + + if (h->plt.offset != MINUS_ONE) + { + asection *splt; + asection *sgotplt; + asection *srelplt; + + bfd_vma plt_index; + bfd_vma got_offset; + bfd_vma gotplt_base; + Elf_Internal_Rela rel; + bfd_byte *loc; + + /* This symbol has an entry in the procedure linkage table. Set + it up. */ + + BFD_ASSERT (h->dynindx != -1); + + splt = htab->root.splt; + sgotplt = htab->root.sgotplt; + srelplt = htab->root.srelplt; + gotplt_base = htab->root.sgot->size + htab->sfuncdesc->size; + BFD_ASSERT (splt != NULL && sgotplt != NULL && srelplt != NULL); + + /* Get the index in the procedure linkage table which + corresponds to this symbol. This is the index of this symbol + in all the symbols for which we are making plt entries. The + first entry in the procedure linkage table is reserved. */ + plt_index = h->plt.offset / sizeof(fdpic_elf_rx_plt_entry); + + /* Get the offset into the .got table of the entry that + corresponds to this function. */ + if (htab->fdpic_p) + got_offset = plt_index * 8 + gotplt_base; + else + /* Each .got entry is 4 bytes. The first three are + reserved. */ + got_offset = (plt_index + 3) * 4; +#ifdef GOT_BIAS + if (bfd_link_pic (info)) + got_offset -= GOT_BIAS; +#endif + /* Fill in the entry in the procedure linkage table. */ + memcpy (splt->contents + h->plt.offset, + fdpic_elf_rx_plt_entry, sizeof(fdpic_elf_rx_plt_entry)); + if (bfd_link_pic (info) || htab->fdpic_p) + { + install_plt_field (output_bfd, false, got_offset, + (splt->contents + + h->plt.offset + + FDPIC_PLT_FUNC)); + if (!(info->flags & DF_BIND_NOW)) + install_plt_field (output_bfd, false, + srelplt->reloc_count * sizeof (Elf32_External_Rela), + (splt->contents + + h->plt.offset + + FDPIC_PLT_REL)); + } + + /* Make got_offset relative to the start of .got.plt. */ +#ifdef GOT_BIAS + if (bfd_link_pic (info)) + got_offset += GOT_BIAS; +#endif + if (htab->fdpic_p) + got_offset = plt_index * 8; + + /* Fill in the entry in the global offset table. */ + bfd_put_32 (output_bfd, + splt->output_section->vma + h->plt.offset + FDPIC_PLT_LAZY, + sgotplt->contents + got_offset); + + if (htab->fdpic_p) + bfd_put_32 (output_bfd, + rx_elf_osec_to_segment (output_bfd, splt->output_section), + sgotplt->contents + got_offset + 4); + + /* Fill in the entry in the .rela.plt section. */ + rel.r_offset = (sgotplt->output_section->vma + + sgotplt->output_offset + got_offset); + rel.r_info = ELF32_R_INFO (h->dynindx, R_RX_FUNCDESC_VALUE); + rel.r_addend = 0; +#ifdef GOT_BIAS + rel.r_addend = GOT_BIAS; +#endif + loc = srelplt->contents + plt_index * sizeof (Elf32_External_Rela); + srelplt->reloc_count++; + bfd_elf32_swap_reloca_out (output_bfd, &rel, loc); + + if (!h->def_regular) + { + /* Mark the symbol as undefined, rather than as defined in + the .plt section. Leave the value alone. */ + sym->st_shndx = SHN_UNDEF; + } + } + + if (h->got.offset != MINUS_ONE) { + asection *sgot; + asection *srelgot; + asection *sfuncdesc; + Elf_Internal_Rela rel; + bfd_byte *loc; + + /* This symbol has an entry in the global offset table. Set it + up. */ + + sgot = htab->root.sgot; + srelgot = htab->root.srelgot; + sfuncdesc = htab->sfuncdesc; + BFD_ASSERT (sgot != NULL && srelgot != NULL); + + rel.r_offset = (sgot->output_section->vma + + sgot->output_offset + + (h->got.offset &~ (bfd_vma) 1)); + if (h->root.u.def.section->output_section) + { + if (rx_elf_hash_entry (h)->got_type != GOT_FUNCDESC) + { + rel.r_info = ELF32_R_INFO (0, R_RX_RELATIVE); + rel.r_addend = h->root.u.def.value + + h->root.u.def.section->output_section->vma + + h->root.u.def.section->output_offset; + } + else + { + rel.r_info = ELF32_R_INFO (0, R_RX_RELATIVE); + rel.r_addend = (rx_elf_hash_entry (h)->funcdesc.offset & ~1) + + sfuncdesc->output_section->vma + + sfuncdesc->output_offset; + } + } + else + { + rel.r_info = ELF32_R_INFO (h->dynindx, R_RX_GLOB_DAT); + rel.r_addend = 0; + } + loc = srelgot->contents; + loc += srelgot->reloc_count++ * sizeof (Elf32_External_Rela); + bfd_elf32_swap_reloca_out (output_bfd, &rel, loc); + } + + if (h->needs_copy) + { + asection *s; + Elf_Internal_Rela rel; + bfd_byte *loc; + + /* This symbol needs a copy reloc. Set it up. */ + + BFD_ASSERT (h->dynindx != -1 + && (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak)); + + s = bfd_get_linker_section (htab->root.dynobj, ".rela.bss"); + BFD_ASSERT (s != NULL); + + rel.r_offset = (h->root.u.def.value + + h->root.u.def.section->output_section->vma + + h->root.u.def.section->output_offset); + rel.r_info = ELF32_R_INFO (h->dynindx, R_RX_COPY); + rel.r_addend = 0; + loc = s->contents + s->reloc_count++ * sizeof (Elf32_External_Rela); + bfd_elf32_swap_reloca_out (output_bfd, &rel, loc); + } + + if (h == htab->root.hdynamic + || h == htab->root.hgot) + sym->st_shndx = SHN_ABS; + + return true; +} + +/* Finish up the dynamic sections. */ + +static bool +rx_elf_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info, + bfd_byte *buf ATTRIBUTE_UNUSED) +{ + struct elf_rx_link_hash_table *htab; + asection *sgotplt; + asection *sdyn; + + htab = rx_elf_hash_table (info); + if (htab == NULL) + return false; + + sgotplt = htab->root.sgotplt; + sdyn = bfd_get_linker_section (htab->root.dynobj, ".dynamic"); + + if (htab->root.dynamic_sections_created) + { + Elf32_External_Dyn *dyncon, *dynconend; + + BFD_ASSERT (sgotplt != NULL && sdyn != NULL); + + dyncon = (Elf32_External_Dyn *) sdyn->contents; + dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size); + for (; dyncon < dynconend; dyncon++) + { + Elf_Internal_Dyn dyn; + asection *s; + + bfd_elf32_swap_dyn_in (htab->root.dynobj, dyncon, &dyn); + + switch (dyn.d_tag) + { + + case DT_PLTGOT: + s = htab->root.sgot; + BFD_ASSERT (s != NULL); + dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; + bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); + break; + + case DT_JMPREL: + s = htab->root.srelplt->output_section; + BFD_ASSERT (s != NULL); + dyn.d_un.d_ptr = s->vma; + bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); + break; + + case DT_PLTRELSZ: + s = htab->root.srelplt->output_section; + BFD_ASSERT (s != NULL); + dyn.d_un.d_val = s->size; + bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); + break; + } + } + } + + /* At the very end of the .rofixup section is a pointer to the GOT. */ + if (htab->fdpic_p && htab->srofixup != NULL) + { + struct elf_link_hash_entry *hgot = htab->root.hgot; + bfd_vma got_value = hgot->root.u.def.value + + hgot->root.u.def.section->output_section->vma; + rx_elf_add_rofixup (output_bfd, htab->srofixup, got_value); + + /* Make sure we allocated and generated the same number of fixups. */ + BFD_ASSERT (htab->srofixup->reloc_count * 4 == htab->srofixup->size); + } + + if (htab->srelfuncdesc) + BFD_ASSERT (htab->srelfuncdesc->reloc_count * sizeof (Elf32_External_Rela) + == htab->srelfuncdesc->size); + + if (htab->root.srelgot) + BFD_ASSERT (htab->root.srelgot->reloc_count * sizeof (Elf32_External_Rela) + == htab->root.srelgot->size); + return true; +} + +/* Copy the extra info we tack onto an elf_link_hash_entry. */ + +static void +rx_elf_copy_indirect_symbol (struct bfd_link_info *info, + struct elf_link_hash_entry *dir, + struct elf_link_hash_entry *ind) +{ + struct elf_rx_link_hash_entry *edir, *eind; + + edir = (struct elf_rx_link_hash_entry *) dir; + eind = (struct elf_rx_link_hash_entry *) ind; + + edir->gotplt_refcount = eind->gotplt_refcount; + eind->gotplt_refcount = 0; + edir->funcdesc.refcount += eind->funcdesc.refcount; + eind->funcdesc.refcount = 0; + edir->abs_funcdesc_refcount += eind->abs_funcdesc_refcount; + eind->abs_funcdesc_refcount = 0; + + if (ind->root.type == bfd_link_hash_indirect + && dir->got.refcount <= 0) + { + edir->got_type = eind->got_type; + eind->got_type = GOT_UNKNOWN; + } + + if (ind->root.type != bfd_link_hash_indirect + && dir->dynamic_adjusted) + { + /* If called to transfer flags for a weakdef during processing + of elf_adjust_dynamic_symbol, don't copy non_got_ref. + We clear it ourselves for ELIMINATE_COPY_RELOCS. */ + if (dir->versioned != versioned_hidden) + dir->ref_dynamic |= ind->ref_dynamic; + dir->ref_regular |= ind->ref_regular; + dir->ref_regular_nonweak |= ind->ref_regular_nonweak; + dir->needs_plt |= ind->needs_plt; + } + else + _bfd_elf_link_hash_copy_indirect (info, dir, ind); +} + +static bfd_signed_vma *allocate_local_got_refcounts(bfd *abfd) +{ + bfd_signed_vma *local_got_refcounts; + Elf_Internal_Shdr *symtab_hdr; + + symtab_hdr = &elf_symtab_hdr (abfd); + + local_got_refcounts = elf_local_got_refcounts (abfd); + if (local_got_refcounts == NULL) + { + bfd_size_type size; + + size = symtab_hdr->sh_info; + size *= sizeof (bfd_signed_vma); + size += symtab_hdr->sh_info; + local_got_refcounts = ((bfd_signed_vma *) + bfd_zalloc (abfd, size)); + if (local_got_refcounts == NULL) + return NULL; + + elf_local_got_refcounts (abfd) = local_got_refcounts; + rx_elf_local_got_type (abfd) + = (char *) (local_got_refcounts + symtab_hdr->sh_info); + } + return local_got_refcounts; +} + +/* Look through the relocs for a section during the first phase. + Since we don't do .gots or .plts, we just need to consider the + virtual table relocs for gc. */ + +static bool +rx_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec, + const Elf_Internal_Rela *relocs) +{ + Elf_Internal_Shdr *symtab_hdr; + struct elf_link_hash_entry **sym_hashes; + struct elf_rx_link_hash_table *htab; + const Elf_Internal_Rela *rel; + const Elf_Internal_Rela *rel_end; + unsigned int r_type; + enum got_type got_type, old_got_type; + + if (bfd_link_relocatable (info)) + return true; + + BFD_ASSERT (is_rx_elf (abfd)); + + symtab_hdr = &elf_symtab_hdr (abfd); + sym_hashes = elf_sym_hashes (abfd); + + htab = rx_elf_hash_table (info); + if (htab == NULL) + return false; + + rel_end = relocs + sec->reloc_count; + for (rel = relocs; rel < rel_end; rel++) + { + struct elf_link_hash_entry *h; + unsigned long r_symndx; + + r_symndx = ELF32_R_SYM (rel->r_info); + r_type = ELF32_R_TYPE (rel->r_info); + + if (r_symndx < symtab_hdr->sh_info) + h = NULL; + else + { + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + while (h->root.type == bfd_link_hash_indirect + || h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + } + + /* Some relocs require a global offset table. */ + if (htab->root.sgot == NULL) + { + switch (r_type) + { + case R_RX_DIR32: + /* This may require an rofixup. */ + if (!htab->fdpic_p) + break; + /* Fall through. */ + case R_RX_GOT: + case R_RX_GOTOFF: + case R_RX_FUNCDESC: + case R_RX_GOTFUNCDESC: + case R_RX_GOTOFFFUNCDESC: + if (htab->root.dynobj == NULL) + htab->root.dynobj = abfd; + if (!create_got_section (htab->root.dynobj, info)) + return false; + break; + + default: + break; + } + } + switch (r_type) + { + case R_RX_GOT: + got_type = GOT_NORMAL; + if (h != NULL) + { + h->got.refcount++; + old_got_type = rx_elf_hash_entry (h)->got_type; + } + else + { + bfd_signed_vma *local_got_refcounts; + + local_got_refcounts = allocate_local_got_refcounts (abfd); + if (local_got_refcounts == NULL) + return false; + + local_got_refcounts[r_symndx] += 1; + old_got_type = rx_elf_local_got_type (abfd) [r_symndx]; + } + + if (old_got_type != got_type) + { + if (h != NULL) + rx_elf_hash_entry (h)->got_type = got_type; + else + rx_elf_local_got_type (abfd) [r_symndx] = got_type; + } + break; + + case R_RX_PLT: + /* This symbol requires a procedure linkage table entry. We + actually build the entry in adjust_dynamic_symbol, + because this might be a case of linking PIC code which is + never referenced by a dynamic object, in which case we + don't need to generate a procedure linkage table entry + after all. */ + + /* If this is a local symbol, we resolve it directly without + creating a procedure linkage table entry. */ + if (h == NULL) + continue; + + if (h->forced_local) + break; + + h->needs_plt = 1; + h->plt.refcount++; + break; + + case R_RX_FUNCDESC: + case R_RX_GOTFUNCDESC: + case R_RX_GOTOFFFUNCDESC: + if (h != NULL) { + if (! bfd_link_pic (info)) + { + h->non_got_ref = 1; + h->plt.refcount += 1; + } + else + { + h->got.refcount += 1; + } + } + if (htab->fdpic_p && !bfd_link_pic (info) + && (sec->flags & SEC_ALLOC) != 0) + htab->srofixup->size += 4; + if (h != NULL) + rx_elf_hash_entry (h)->got_type = GOT_FUNCDESC; + else { + bfd_signed_vma *local_got_refcounts; + + local_got_refcounts = allocate_local_got_refcounts (abfd); + if (local_got_refcounts == NULL) + return false; + + local_got_refcounts[r_symndx] += 1; + rx_elf_local_got_type (abfd) [r_symndx] = GOT_FUNCDESC; + } + break; + + default: + break; + } + } + return true; +} + #define ELF_ARCH bfd_arch_rx #define ELF_MACHINE_CODE EM_RX @@ -4111,5 +6337,60 @@ rx_additional_link_map_text (bfd *obfd, struct bfd_link_info *info, FILE *mapfil #undef elf_symbol_leading_char #undef elf32_bed #define elf32_bed elf32_rx_le_linux_bed +#undef ELF_TARGET_ID +#define ELF_TARGET_ID RX_ELF_DATA + +#undef bfd_elf32_mkobject +#define bfd_elf32_mkobject rx_elf_mkobject + +#undef elf_backend_omit_section_dynsym +#define elf_backend_omit_section_dynsym rx_elf_omit_section_dynsym +#undef elf_backend_create_dynamic_sections +#define elf_backend_create_dynamic_sections \ + rx_elf_create_dynamic_sections +#undef bfd_elf32_bfd_link_hash_table_create +#define bfd_elf32_bfd_link_hash_table_create \ + rx_elf_link_hash_table_create +#undef elf_backend_adjust_dynamic_symbol +#define elf_backend_adjust_dynamic_symbol \ + rx_elf_adjust_dynamic_symbol +#undef elf_backend_early_size_sections +#define elf_backend_early_size_sections rx_elf_early_size_sections +#undef elf_backend_late_size_sections +#define elf_backend_late_size_sections rx_elf_late_size_sections +#undef elf_backend_finish_dynamic_symbol +#define elf_backend_finish_dynamic_symbol \ + rx_elf_finish_dynamic_symbol +#undef elf_backend_finish_dynamic_sections +#define elf_backend_finish_dynamic_sections \ + rx_elf_finish_dynamic_sections +#undef elf_backend_check_relocs +#define elf_backend_check_relocs rx_elf_check_relocs + +#undef elf_backend_modify_program_headers +#define elf_backend_modify_program_headers \ + rx_elf_modify_program_headers +#undef elf_backend_copy_indirect_symbol +#define elf_backend_copy_indirect_symbol \ + rx_elf_copy_indirect_symbol +#undef elf_backend_reloc_type_class +#define elf_backend_reloc_type_class rx_elf_reloc_type_class + +#undef elf_backend_want_got_plt +#define elf_backend_want_got_plt 1 +#undef elf_backend_plt_readonly +#define elf_backend_plt_readonly 1 +#undef elf_backend_want_plt_sym +#define elf_backend_want_plt_sym 0 +#undef elf_backend_got_header_size +#define elf_backend_got_header_size 12 +#undef elf_backend_plt_header_size +#define elf_backend_plt_header_size PLT_ENTRY_SIZE +#undef elf_backend_can_refcount +#define elf_backend_can_refcount 1 +#undef elf_backend_special_sections +#define elf_backend_special_sections NULL +#undef elf_backend_dtrel_excludes_plt +#define elf_backend_dtrel_excludes_plt 1 #include "elf32-target.h" diff --git a/bfd/libbfd.h b/bfd/libbfd.h index 74c0fe026f0..a0899d45d97 100644 --- a/bfd/libbfd.h +++ b/bfd/libbfd.h @@ -2476,6 +2476,17 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_RX_ABS16UW", "BFD_RELOC_RX_ABS16UL", "BFD_RELOC_RX_RELAX", + "BFD_RELOC_RX_COPY", + "BFD_RELOC_RX_GLOB_DAT", + "BFD_RELOC_RX_JMP_SLOT", + "BFD_RELOC_RX_RELATIVE", + "BFD_RELOC_RX_GOT", + "BFD_RELOC_RX_GOTOFF", + "BFD_RELOC_RX_PLT", + "BFD_RELOC_RX_GOTFUNCDESC", + "BFD_RELOC_RX_GOTOFFFUNCDESC", + "BFD_RELOC_RX_FUNCDESC", + "BFD_RELOC_RX_FUNCDESC_VALUE", "BFD_RELOC_390_12", "BFD_RELOC_390_GOT12", "BFD_RELOC_390_GOTPC", diff --git a/bfd/reloc.c b/bfd/reloc.c index 98343696a33..d8a45dfeff7 100644 --- a/bfd/reloc.c +++ b/bfd/reloc.c @@ -5015,6 +5015,28 @@ ENUMX BFD_RELOC_RX_ABS16UL ENUMX BFD_RELOC_RX_RELAX +ENUMX + BFD_RELOC_RX_COPY +ENUMX + BFD_RELOC_RX_GLOB_DAT +ENUMX + BFD_RELOC_RX_JMP_SLOT +ENUMX + BFD_RELOC_RX_RELATIVE +ENUMX + BFD_RELOC_RX_GOT +ENUMX + BFD_RELOC_RX_GOTOFF +ENUMX + BFD_RELOC_RX_PLT +ENUMX + BFD_RELOC_RX_GOTFUNCDESC +ENUMX + BFD_RELOC_RX_GOTOFFFUNCDESC +ENUMX + BFD_RELOC_RX_FUNCDESC +ENUMX + BFD_RELOC_RX_FUNCDESC_VALUE ENUMDOC Renesas RX Relocations. From patchwork Mon Mar 16 09:31:43 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yoshinori Sato X-Patchwork-Id: 131781 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id CA5794BB3B83 for ; Mon, 16 Mar 2026 09:34:14 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org CA5794BB3B83 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=nifty.com header.i=@nifty.com header.a=rsa-sha256 header.s=default-1th84yt82rvi header.b=gTKgif60 X-Original-To: binutils@sourceware.org Delivered-To: binutils@sourceware.org Received: from mta-snd-e05.mail.nifty.com (mta-snd-e05.mail.nifty.com [106.153.226.37]) by sourceware.org (Postfix) with ESMTPS id 4CD434BC89A4 for ; Mon, 16 Mar 2026 09:31:58 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 4CD434BC89A4 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=nifty.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=nifty.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 4CD434BC89A4 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=106.153.226.37 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1773653518; cv=none; b=KDmyRYm/LNEmU0CI/fTeNtIbZS4FHdZQKKYAvkiLK7to/69DO0AQseCjFh+yd3y6GPgAzXM6HoLmixm3YnOucCk1wS0wrj7SqUjjAvDvIfj/s5Lq/8tYB2h3J60rLsaEdTziC7h7ezUW3LK/zPNZiXoW1ZDFpKLMsEtskLcbp8w= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1773653518; c=relaxed/simple; bh=9ZZUWjfb9qyn+Ko/xBLOcthT3RU5gniWraaERu7Q5hE=; h=From:To:Subject:Date:Message-ID:MIME-Version:DKIM-Signature; b=YPx5Uax2Ly3bUJ4t+1HdAqrDLCwLXU8vF8vB7bc7WzLbFtsZ/K0ki1Jjc3X2W/NU1DkNCmn8mgcXCJdRXIlSQGHoE+cTx+BNxT8riJ+ZZ3zulPqxTg9JIWtlNlWwEc3wuMBxTE+UdUSOYsP4rTIulhx9vQ8hd6zckj4u/lpFi/0= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 4CD434BC89A4 Received: from sakura.ysato.name by mta-snd-e05.mail.nifty.com with ESMTP id <20260316093156397.WQER.36235.sakura.ysato.name@nifty.com>; Mon, 16 Mar 2026 18:31:56 +0900 Received: from SIOS1075.constellations.internal (ZM005235.ppp.dion.ne.jp [222.8.5.235]) by sakura.ysato.name (Postfix) with ESMTPSA id 190D71C028B; Mon, 16 Mar 2026 18:31:56 +0900 (JST) From: Yoshinori Sato To: binutils@sourceware.org Cc: Yoshinori Sato Subject: [RFC PATCH v2 2/4] RX: gas rx-linux target FDPIC support Date: Mon, 16 Mar 2026 18:31:43 +0900 Message-ID: <20260316093151.360635-3-yoshinori.sato@nifty.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260316093151.360635-1-yoshinori.sato@nifty.com> References: <20260316093151.360635-1-yoshinori.sato@nifty.com> MIME-Version: 1.0 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=default-1th84yt82rvi; t=1773653516; bh=w6PV1zW3D82Zep3s3hjpjIourF1Bf+L596tn6HQUOQ8=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=gTKgif606wL7nKQSgiE2m7slAtEYUwQCpjnIaBhnL09fab6hGYGXs45u3OM7fWtF5WADr61Q PNoa/Tq9c3iRswDvsi01fqaeHbxKi18rpgPyzvwL2h1Q/dWpraxFCehqA1/sAsZIW2OHZUrOPI pnbBeDsDyeV4EDrs3ujzbhHw3HjR9cljgZQ00/L/PiF+oVUoRWhJjeQojuZzasJ5Bh7SbYtRgi XYyOli6bKZB2N3lXYf8zIOtQbuhXTO0XmF56sn4fXPHFtYNIfMWvCN+1AwmT/fYVexh0SSH3he g66gE7+YZNCgv+bdfSx28mkHqHBimqvK2/bSqj/aHYDbfoiQ== X-Spam-Status: No, score=-10.2 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_BLOCKED, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_PASS, TXREP, URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: binutils@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Binutils mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: binutils-bounces~patchwork=sourceware.org@sourceware.org * config/rx-parse.y (displacement): Fix expression displacement. (displacement): Add PIC relocation. * config/tc-rx.c (fdpic): New. in fdpic mode. (options): Add OPTION_FDPIC. (md_longopts): Add "--fdpic". (md_parse_option): Likewise. (md_show_usage): Likewise. (rx_end_of_match): New. Lookup relocation type helper. (rx_parse_name): New. parse symbol relocation type. (md_assemble): PIC relocation support. (md_convert_flag): Likewise. (md_cons_fix_new): Likewise. (md_apply_fix): Likewise. (rx_force_relocation): New. (rx_fix_adjustable): New. (rx_elf_final_processing): set EF_RX_FDPIC flag for fdpic output. * config/tc-rx.h (md_parse_name): New. (TC_FORCE_RELOCATION): New. (O_PIC_reloc): New. (tc_fix_adjustable): New. * config/rx-defs.h (rx_fix_adjustable): New prototype. * testsuite/gas/rx/mov.d: Add expression displacement case. * testsuite/gas/rx/mov.sm: Likewise. Signed-off-by: Yoshinori Sato --- gas/config/rx-defs.h | 1 + gas/config/rx-parse.y | 16 ++- gas/config/tc-rx.c | 269 ++++++++++++++++++++++++++++++++++-- gas/config/tc-rx.h | 18 ++- gas/testsuite/gas/rx/mov.d | 3 + gas/testsuite/gas/rx/mov.sm | 7 + 6 files changed, 298 insertions(+), 16 deletions(-) diff --git a/gas/config/rx-defs.h b/gas/config/rx-defs.h index 8fa708df311..d57abfeae96 100644 --- a/gas/config/rx-defs.h +++ b/gas/config/rx-defs.h @@ -68,6 +68,7 @@ extern int rx_parse (void); extern int rx_wrap (void); extern void rx_note_string_insn_use (void); extern void rx_post (char); +extern bool rx_fix_adjustable (fixS *fixP); extern char * rx_lex_start; extern char * rx_lex_end; diff --git a/gas/config/rx-parse.y b/gas/config/rx-parse.y index 4d657b5df67..224c7ba208b 100644 --- a/gas/config/rx-parse.y +++ b/gas/config/rx-parse.y @@ -1934,8 +1934,12 @@ displacement (expressionS exp, int msize) valueT val; int vshift = 0; - if (exp.X_op == O_symbol - && exp.X_md) + /* "foo - bar[Rn]" case, use dsp16[Rn] addressing. */ + if (exp.X_op == O_subtract) + exp.X_md = BFD_RELOC_RX_DIFF; + + if (((exp.X_op == O_symbol || exp.X_op == O_PIC_reloc) && exp.X_md) || + (exp.X_op == O_subtract)) { switch (exp.X_md) { @@ -1954,6 +1958,14 @@ displacement (expressionS exp, int msize) } O2 (exp); return 2; + case BFD_RELOC_16_GOT_PCREL: + exp.X_md = BFD_RELOC_RX_GOT; + O2 (exp); + return 2; + case BFD_RELOC_RX_GOTFUNCDESC: + exp.X_md = BFD_RELOC_RX_GOTFUNCDESC; + O2 (exp); + return 2; } } diff --git a/gas/config/tc-rx.c b/gas/config/tc-rx.c index 794f64a54f4..9dd14af4c1a 100644 --- a/gas/config/tc-rx.c +++ b/gas/config/tc-rx.c @@ -40,13 +40,16 @@ const char line_separator_chars[] = "!"; const char EXP_CHARS[] = "eE"; const char FLT_CHARS[] = "dD"; + +/* Whether --fdpic was given. */ +static bool fdpic = false; #ifndef TE_LINUX bool rx_use_conventional_section_names = false; static int elf_flags = E_FLAG_RX_ABI; #else bool rx_use_conventional_section_names = true; -static int elf_flags; +static int elf_flags = 0; #endif static bool rx_use_small_data_limit = false; @@ -75,6 +78,7 @@ enum options OPTION_USES_RX_ABI, OPTION_CPU, OPTION_DISALLOW_STRING_INSNS, + OPTION_FDPIC, }; #define RX_SHORTOPTS "" @@ -103,6 +107,7 @@ const struct option md_longopts[] = {"mrx-abi", no_argument, NULL, OPTION_USES_RX_ABI}, {"mcpu", required_argument, NULL, OPTION_CPU}, {"mno-allow-string-insns", no_argument, NULL, OPTION_DISALLOW_STRING_INSNS}, + {"fdpic", no_argument, NULL, OPTION_FDPIC}, {NULL, no_argument, NULL, 0} }; const size_t md_longopts_size = sizeof (md_longopts); @@ -198,6 +203,9 @@ md_parse_option (int c ATTRIBUTE_UNUSED, const char * arg ATTRIBUTE_UNUSED) case OPTION_DISALLOW_STRING_INSNS: elf_flags |= E_FLAG_RX_SINSNS_SET | E_FLAG_RX_SINSNS_NO; return 1; + case OPTION_FDPIC: + fdpic = true; + return 1; } return 0; @@ -218,7 +226,8 @@ md_show_usage (FILE * stream) fprintf (stream, _(" --mpid\n")); fprintf (stream, _(" --mint-register=\n")); fprintf (stream, _(" --mcpu=\n")); - fprintf (stream, _(" --mno-allow-string-insns")); + fprintf (stream, _(" --mno-allow-string-insns\n")); + fprintf (stream, _(" --fdpic")); } static void @@ -1120,6 +1129,97 @@ scan_for_infix_rx_pseudo_ops (char * str) return true; } +inline static char * +rx_end_of_match (char *cont, const char *what) +{ + int len = strlen (what); + + if (strncasecmp (cont, what, strlen (what)) == 0 + && ! is_part_of_name (cont[len])) + return cont + len; + + return NULL; +} + +#ifdef TE_LINUX +int +rx_parse_name (char const *name, expressionS *exprP, + enum expr_mode mode, char *nextcharP) +{ + char *next = input_line_pointer; + char *next_end; + int reloc_type; + segT segment; + + static const struct suffix_list { + const char *name; + int reloc; + } suffixes[] = { + { "GOTOFFFUNCDESC", BFD_RELOC_RX_GOTOFFFUNCDESC }, + { "GOTFUNCDESC", BFD_RELOC_RX_GOTFUNCDESC }, + { "GOTOFF", BFD_RELOC_32_GOTOFF }, + { "FUNCDESC", BFD_RELOC_RX_FUNCDESC }, + { "GOT", BFD_RELOC_16_GOT_PCREL }, + { "PLT", BFD_RELOC_32_PLT_PCREL }, + { NULL, -1 }, + }; + const struct suffix_list *s; + + if (!fdpic) + return 0; + + exprP->X_op_symbol = NULL; + exprP->X_add_symbol = symbol_find_or_make (name); + + if (*nextcharP != '@') + goto no_suffix; + for (s = suffixes; s->name != NULL; s++) + { + if ((next_end = rx_end_of_match (next + 1, s->name))) + { + reloc_type = s->reloc; + break; + } + } + if (s->name == NULL) + goto no_suffix; + + *input_line_pointer = *nextcharP; + input_line_pointer = next_end; + *nextcharP = *input_line_pointer; + *input_line_pointer = '\0'; + + exprP->X_op = O_PIC_reloc; + exprP->X_add_number = 0; + exprP->X_md = reloc_type; + return 1; + + no_suffix: + /* If we have an absolute symbol or a reg, then we know its + value now. */ + segment = S_GET_SEGMENT (exprP->X_add_symbol); + if (mode != expr_defer && segment == absolute_section) + { + exprP->X_op = O_constant; + exprP->X_add_number = S_GET_VALUE (exprP->X_add_symbol); + exprP->X_add_symbol = NULL; + } + else if (mode != expr_defer && segment == reg_section) + { + exprP->X_op = O_register; + exprP->X_add_number = S_GET_VALUE (exprP->X_add_symbol); + exprP->X_add_symbol = NULL; + } + else + { + exprP->X_op = O_symbol; + exprP->X_add_number = 0; + } + + return 1; +} +#endif + void md_assemble (char * str) { @@ -1168,7 +1268,9 @@ md_assemble (char * str) APPEND (ops, n_ops); APPEND (post, n_post); - if (rx_bytes.link_relax && rx_bytes.n_fixups) +#ifdef TE_LINUX + if (rx_bytes.link_relax && rx_bytes.n_fixups && + rx_bytes.fixups[0].exp.X_op != O_PIC_reloc) { fixS * f; @@ -1181,6 +1283,7 @@ md_assemble (char * str) BFD_RELOC_RX_RELAX); frag_then->tc_frag_data->link_relax_fixP = f; } +#endif for (i = 0; i < rx_bytes.n_fixups; i ++) { @@ -1206,12 +1309,41 @@ md_assemble (char * str) else exp = & rx_bytes.fixups[i].exp; - f = fix_new_exp (frag_then, - (char *) bytes + idx - frag_then->fr_literal, - rx_bytes.fixups[i].nbits / 8, - exp, - rx_bytes.fixups[i].type == RXREL_PCREL ? 1 : 0, - rel); +#ifdef TE_LINUX + if (exp->X_op == O_PIC_reloc + && exp->X_md != BFD_RELOC_RX_GOT + && exp->X_md != BFD_RELOC_RX_GOTFUNCDESC) + { + exp->X_op = O_symbol; + f = fix_new_exp (frag_then, + (char *) bytes + idx - frag_then->fr_literal, + 4, + exp, + 0, + exp->X_md); + } + else if (exp->X_op == O_PIC_reloc && + (exp->X_md == BFD_RELOC_RX_GOT + || exp->X_md == BFD_RELOC_RX_GOTFUNCDESC)) + { + exp->X_op = O_symbol; + f = fix_new_exp (frag_then, + (char *) bytes + idx - frag_then->fr_literal, + 2, + exp, + 0, + exp->X_md); + } + else +#endif + { + f = fix_new_exp (frag_then, + (char *) bytes + idx - frag_then->fr_literal, + rx_bytes.fixups[i].nbits / 8, + exp, + rx_bytes.fixups[i].type == RXREL_PCREL ? 1 : 0, + rel); + } if (frag_then->tc_frag_data) frag_then->tc_frag_data->fixups[i].fixP = f; } @@ -1788,7 +1920,7 @@ md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED, int fi = (rxb->n_fixups > 1) ? 1 : 0; fixS * fix = rxb->fixups[fi].fixP; - tprintf ("\033[31mconvrt frag: addr %08lx fix %ld var %ld ofs %ld lit %p opc %p type %d sub %d\033[0m\n", + tprintf ("\033[31mconvert frag: addr %08lx fix %ld var %ld ofs %ld lit %p opc %p type %d sub %d\033[0m\n", (unsigned long) (fragP->fr_address + (fragP->fr_opcode - fragP->fr_literal)), (long) fragP->fr_fix, (long) fragP->fr_var, (long) fragP->fr_offset, @@ -1895,7 +2027,14 @@ md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED, op[2] = (disp >> 8) & 0xff; op[1] = disp; #endif - reloc_type = keep_reloc ? BFD_RELOC_24_PCREL : BFD_RELOC_NONE; + if (fragP->tc_frag_data->fixups->exp.X_md != BFD_RELOC_32_PLT_PCREL) + { + reloc_type = keep_reloc ? BFD_RELOC_24_PCREL : BFD_RELOC_NONE; + } + else + { + reloc_type = BFD_RELOC_32_PLT_PCREL; + } reloc_adjust = 1; break; @@ -1998,7 +2137,14 @@ md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED, op[2] = (disp >> 8) & 0xff; op[1] = disp; #endif - reloc_type = keep_reloc ? BFD_RELOC_24_PCREL : BFD_RELOC_NONE; + if (fragP->tc_frag_data->fixups->exp.X_md != BFD_RELOC_32_PLT_PCREL) + { + reloc_type = keep_reloc ? BFD_RELOC_24_PCREL : BFD_RELOC_NONE; + } + else + { + reloc_type = BFD_RELOC_32_PLT_PCREL; + } reloc_adjust = 0; break; @@ -2053,6 +2199,23 @@ md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED, int li; char * imm = op + fragP->tc_frag_data->relax[ri].val_ofs; + if (rxb->fixups[fi].exp.X_op == O_symbol) + { +#ifdef TE_LINUX + switch(rxb->fixups[fi].exp.X_md) + { + case BFD_RELOC_16_GOT_PCREL: + reloc_type = BFD_RELOC_RX_GOT; + break; + case BFD_RELOC_32_GOTOFF: + case BFD_RELOC_RX_GOTFUNCDESC: + case BFD_RELOC_RX_GOTOFFFUNCDESC: + case BFD_RELOC_RX_FUNCDESC: + reloc_type = rxb->fixups[fi].exp.X_md; + break; + } +#endif + } switch (nbytes) { case 1: @@ -2097,7 +2260,27 @@ md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED, imm[2] = addr0 >> 16; imm[3] = addr0 >> 24; #endif - reloc_type = BFD_RELOC_RX_32_OP; +#ifdef TE_LINUX + if (rxb->fixups[fi].exp.X_op == O_symbol) + { + switch(rxb->fixups[fi].exp.X_md) + { + case BFD_RELOC_16_GOT_PCREL: + reloc_type = BFD_RELOC_RX_GOT; + break; + case BFD_RELOC_32_GOTOFF: + case BFD_RELOC_RX_GOTFUNCDESC: + case BFD_RELOC_RX_GOTOFFFUNCDESC: + case BFD_RELOC_RX_FUNCDESC: + reloc_type = rxb->fixups[fi].exp.X_md; + break; + default: + reloc_type = BFD_RELOC_RX_32_OP; + } + } + else +#endif + reloc_type = BFD_RELOC_RX_32_OP; break; default: as_bad (_("invalid immediate size")); @@ -2152,6 +2335,9 @@ md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED, break; case BFD_RELOC_24_PCREL: case BFD_RELOC_RX_24_OP: +#ifdef TE_LINUX + case BFD_RELOC_32_PLT_PCREL: +#endif fix->fx_size = 3; break; case BFD_RELOC_RX_32_OP: @@ -2220,6 +2406,9 @@ rx_cons_fix_new (fragS * frag, expressionS * exp, bfd_reloc_code_real_type type) { + + type = BFD_RELOC_UNUSED; + switch (size) { case 1: @@ -2247,6 +2436,13 @@ rx_cons_fix_new (fragS * frag, type = BFD_RELOC_RX_DIFF; } +#ifdef TE_LINUX + if (exp->X_op == O_PIC_reloc) + { + type = BFD_RELOC_RX_FUNCDESC; + exp->X_op = O_symbol; + } +#endif fix_new_exp (frag, where, size, exp, 0, type); } @@ -2433,6 +2629,21 @@ md_apply_fix (struct fix *f, #endif break; +#ifdef TE_LINUX + case BFD_RELOC_RX_GOT: + case BFD_RELOC_RX_GOTFUNCDESC: + f->fx_no_overflow = 1; + op[0] = op[1] = 0; + break; + case BFD_RELOC_RX_GOTOFFFUNCDESC: + case BFD_RELOC_RX_FUNCDESC: + case BFD_RELOC_32_PLT_PCREL: + case BFD_RELOC_32_GOTOFF: + /* This field fill in ld */ + op[0] = op[1] = op[2] = op[3] = 0; + break; +#endif + default: as_bad (_("Unknown reloc in md_apply_fix: %s"), bfd_get_reloc_code_name (f->fx_r_type)); @@ -2681,12 +2892,44 @@ rx_note_string_insn_use (void) elf_flags |= E_FLAG_RX_SINSNS_SET | E_FLAG_RX_SINSNS_YES; } +#ifdef TE_LINUX +int +rx_force_relocation (fixS *fix) +{ + /* Make sure some relocations get emitted. */ + if (fix->fx_r_type == BFD_RELOC_RX_GOT + || fix->fx_r_type == BFD_RELOC_RX_GOTOFF + || fix->fx_r_type == BFD_RELOC_RX_GOTFUNCDESC + || fix->fx_r_type == BFD_RELOC_RX_GOTOFFFUNCDESC + || generic_force_reloc (fix)) + return 1; + return 0; +} + +bool +rx_fix_adjustable (fixS *fixP) +{ + if (fixP->fx_r_type == BFD_RELOC_32_PLT_PCREL + || fixP->fx_r_type == BFD_RELOC_16_GOT_PCREL + || fixP->fx_r_type == BFD_RELOC_RX_GOT + || fixP->fx_r_type == BFD_RELOC_32_GOTOFF + || fixP->fx_r_type == BFD_RELOC_RX_GOTFUNCDESC + || fixP->fx_r_type == BFD_RELOC_RX_GOTOFFFUNCDESC + || fixP->fx_r_type == BFD_RELOC_RX_FUNCDESC) + return false; + return true; +} +#endif + /* Set the ELF specific flags. */ void rx_elf_final_processing (void) { elf_elfheader (stdoutput)->e_flags |= elf_flags; + + if (fdpic) + elf_elfheader (stdoutput)->e_flags |= EF_RX_FDPIC; } /* Scan the current input line for occurrences of Renesas diff --git a/gas/config/tc-rx.h b/gas/config/tc-rx.h index 8a37b36275d..72e176eb7b7 100644 --- a/gas/config/tc-rx.h +++ b/gas/config/tc-rx.h @@ -75,12 +75,28 @@ extern void rx_frag_init (fragS *); rx_validate_fix_sub (FIX) extern int rx_validate_fix_sub (struct fix *); +#ifdef TE_LINUX +#define md_parse_name(name, exprP, mode, nextcharP) \ + rx_parse_name ((name), (exprP), (mode), (nextcharP)) +int rx_parse_name (char const *, expressionS *, + enum expr_mode, char *); +/* We need to force out some relocations when relaxing. */ +#define TC_FORCE_RELOCATION(fix) rx_force_relocation (fix) +extern int rx_force_relocation (struct fix *); +#endif #define TC_CONS_FIX_NEW(FRAG, WHERE, NBYTES, EXP, RELOC) \ rx_cons_fix_new (FRAG, WHERE, NBYTES, EXP, RELOC) extern void rx_cons_fix_new (fragS *, int, int, expressionS *, bfd_reloc_code_real_type); -#define tc_fix_adjustable(x) 0 +/* This is used to construct expressions out of @GOTOFF, @PLT and @GOT + symbols. The relocation type is stored in X_md. */ +#define O_PIC_reloc O_md1 + +#ifdef TE_LINUX +#define tc_fix_adjustable(x) rx_fix_adjustable(x) +extern bool rx_fix_adjustable (struct fix *); +#endif #define md_do_align(n, fill, len, max, around) \ if ((n) \ diff --git a/gas/testsuite/gas/rx/mov.d b/gas/testsuite/gas/rx/mov.d index 276b6d9d898..4c5d2389746 100644 --- a/gas/testsuite/gas/rx/mov.d +++ b/gas/testsuite/gas/rx/mov.d @@ -528,3 +528,6 @@ Disassembly of section .*: [0-9a-f]+: fd 2e 0f mov.l \[-r0\], r15 [0-9a-f]+: fd 2e f0 mov.l \[-r15\], r0 [0-9a-f]+: fd 2e ff mov.l \[-r15\], r15 + [0-9a-f]+: ce 00 04 00 mov.b 4\[r0\], r0 + [0-9a-f]+: de 00 02 00 mov.w 4\[r0\], r0 + [0-9a-f]+: ee 00 01 00 mov.l 4\[r0\], r0 diff --git a/gas/testsuite/gas/rx/mov.sm b/gas/testsuite/gas/rx/mov.sm index 8bebbf5908a..03bec4a7bc1 100644 --- a/gas/testsuite/gas/rx/mov.sm +++ b/gas/testsuite/gas/rx/mov.sm @@ -31,3 +31,10 @@ mov{bwl} [{reg}+],{reg} mov{bwl} {reg},[-{reg}] mov{bwl} [-{reg}],{reg} + +1: mov.B 2f - 1b[r0], r0 +2: +1: mov.W 2f - 1b[r0], r0 +2: +1: mov.L 2f - 1b[r0], r0 +2: From patchwork Mon Mar 16 09:31:44 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yoshinori Sato X-Patchwork-Id: 131780 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id 6985C4B3588D for ; Mon, 16 Mar 2026 09:33:31 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 6985C4B3588D Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=nifty.com header.i=@nifty.com header.a=rsa-sha256 header.s=default-1th84yt82rvi header.b=Z+sb1f5O X-Original-To: binutils@sourceware.org Delivered-To: binutils@sourceware.org Received: from mta-sp-w04.mail.nifty.com (mta-sp-w04.mail.nifty.com [106.153.228.36]) by sourceware.org (Postfix) with ESMTPS id 543464BC8976 for ; Mon, 16 Mar 2026 09:31:58 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 543464BC8976 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=nifty.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=nifty.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 543464BC8976 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=106.153.228.36 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1773653518; cv=none; b=El1RNM+YXxZv7BPzOD6cOVRgEcpeXPXACyrH9Fdfd70V1u68xz/i6vZ0D93duaGn/xiBwGkjzLUdsyc+lDkY4szCVDBm1k0jla4ojcpJDPWJkw5z2/gQLCFa3aL20GXyBvz8opeRnyvciVDkPwu8he5oUPbmx0zdNdhyP7k0Y9E= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1773653518; c=relaxed/simple; bh=0nKFRc5ph9BZ92rhYd6XUZxkhy8RtBxhvNKQ3yAkZjQ=; h=From:To:Subject:Date:Message-ID:MIME-Version:DKIM-Signature; b=ACMbAAVyn07DU1oS9XCVqKr/T6rFsg6OSTKEmGJuQYJ59xw950R4SS8FzLwW5vqyUTdjswrFaQ2XmVlkDSE2lgshSqQ4QLHbWOrJSwZ4zFXwuPA7oOkx+gerC/gk7NU4qxHgfbP1HCAIY6rW0ESVNBMtZ8u6NCPJR3XnTWzT/e4= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 543464BC8976 Received: from mta-snd-w09.mail.nifty.com by mta-sp-w04.mail.nifty.com with ESMTP id <20260316093156636.XMPB.123589.mta-snd-w09.mail.nifty.com@nifty.com>; Mon, 16 Mar 2026 18:31:56 +0900 Received: from sakura.ysato.name by mta-snd-w09.mail.nifty.com with ESMTP id <20260316093156577.KRMR.116672.sakura.ysato.name@nifty.com>; Mon, 16 Mar 2026 18:31:56 +0900 Received: from SIOS1075.constellations.internal (ZM005235.ppp.dion.ne.jp [222.8.5.235]) by sakura.ysato.name (Postfix) with ESMTPSA id 41D061C02BC; Mon, 16 Mar 2026 18:31:56 +0900 (JST) From: Yoshinori Sato To: binutils@sourceware.org Cc: Yoshinori Sato Subject: [RFC PATCH v2 3/4] RX: ld rx-linux target FDPIC support Date: Mon, 16 Mar 2026 18:31:44 +0900 Message-ID: <20260316093151.360635-4-yoshinori.sato@nifty.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260316093151.360635-1-yoshinori.sato@nifty.com> References: <20260316093151.360635-1-yoshinori.sato@nifty.com> MIME-Version: 1.0 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=default-1th84yt82rvi; t=1773653516; bh=LGNNIFxLG0CLtHHQYJIo+JXIMnsMUHC59eU2ne6YqeY=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=Z+sb1f5OO9odtfrI4TBP1VW9MtrCiRpBm5ezdi8ZLzc+MSOnsYonhpKZcPQPLkd9vTVZvXwj vijQGmdYnTaWotwevQoR2jXeYbnDh775UDTm/a2CgxBuSmonJgD7WWRdqsFg968coa75MnuP7Z AIu0sU7n/I3SpnGRVjmPEy1/xvgEHYHyFjAnaJLCci8usP1yL+jW5y0Wo+M7e49dD9pkTpdd7A YTlw5BikZEcXhpnr6tbDrtNt6pLNSmm8+XhELANNyL/k5XDVb+SE5V9X57QaIkGsN0AdX207p2 NPELIwvXc3sM8vozOrUbFwBOOql+CcMnh3pX3KfAuYnmn9TQ== X-Spam-Status: No, score=-11.0 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_BLOCKED, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_PASS, TXREP, URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: binutils@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Binutils mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: binutils-bounces~patchwork=sourceware.org@sourceware.org * emulparams/elf32rx_linux.sh: Add FDPIC sections. Signed-off-by: Yoshinori Sato --- ld/emulparams/elf32rx_linux.sh | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/ld/emulparams/elf32rx_linux.sh b/ld/emulparams/elf32rx_linux.sh index 3abe4165d56..aded467de7b 100644 --- a/ld/emulparams/elf32rx_linux.sh +++ b/ld/emulparams/elf32rx_linux.sh @@ -4,14 +4,26 @@ OUTPUT_FORMAT="elf32-rx-linux" # See also `include/elf/rx.h' TEXT_START_ADDR=0x10000000 ARCH=rx -ENTRY=start -EMBEDDED=yes +ENTRY=_start TEMPLATE_NAME=elf EXTRA_EM_FILE=rxlinux ELFSIZE=32 -MAXPAGESIZE=256 +MAXPAGESIZE="CONSTANT (MAXPAGESIZE)" +COMMONPAGESIZE="CONSTANT (COMMONPAGESIZE)" +GENERATE_SHLIB_SCRIPT=yes +GENERATE_PIE_SCRIPT=yes +# mul #1, r0 +NOP=0x76100100 +NO_SMALL_DATA=yes -STACK_ADDR="(DEFINED(__stack) ? __stack : 0xbffffffc)" -STACK_SENTINEL="LONG(0xdeaddead)" -# We do not need .stack for shared library. -test -n "$CREATE_SHLIB" && unset STACK_ADDR +GOT=".got ${RELOCATING-0} : {${RELOCATING+ *(.got) *(.got.funcdesc) *(.got.plt) } }" +OTHER_GOT_RELOC_SECTIONS=" + .rela.got.funcdesc ${RELOCATING-0} : { *(.rela.got.funcdesc) } +" +OTHER_READONLY_SECTIONS=" + .rofixup : { + ${RELOCATING+__ROFIXUP_LIST__ = .;} + *(.rofixup) + ${RELOCATING+__ROFIXUP_END__ = .;} + } +" From patchwork Mon Mar 16 09:31:45 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yoshinori Sato X-Patchwork-Id: 131782 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id B45154BAD144 for ; Mon, 16 Mar 2026 09:36:46 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org B45154BAD144 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=nifty.com header.i=@nifty.com header.a=rsa-sha256 header.s=default-1th84yt82rvi header.b=NJpiyNpr X-Original-To: binutils@sourceware.org Delivered-To: binutils@sourceware.org Received: from mta-sp-w04.mail.nifty.com (mta-sp-w04.mail.nifty.com [IPv6:2001:268:fa30:84a:6a:99:e4:24]) by sourceware.org (Postfix) with ESMTPS id A4AA84BC7EFE for ; Mon, 16 Mar 2026 09:32:04 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org A4AA84BC7EFE Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=nifty.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=nifty.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org A4AA84BC7EFE Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2001:268:fa30:84a:6a:99:e4:24 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1773653533; cv=none; b=MqwjqWDYoBKSYe/nVb1CLMgCI4GOo2SI3tWskg6vwo740wxk8w/+xp/6Qew8zbgxniP3hW9ejAwXBXtP+Rjvw07/BeGatuL52n3Fz6stXdtpeOCNKKVQX7lsm3WwZFmrFUwXAMacf/ANTIlMEWjOJpTxXA+5klfuVYEVTZy4DzE= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1773653533; c=relaxed/simple; bh=ND5hFoFGQBf2C4lMgJlqCJnUIkqOikfrO7qOX/vaO6s=; h=From:To:Subject:Date:Message-ID:MIME-Version:DKIM-Signature; b=VU7WbXiOWbKEf31rs/BN4395GKoluDRXWedZk2sjQVsjBG7wO0t2Pph8ipoZJwNlcLqaHGPEce1zg5v+Ch1jJje2VKpEksa0ji2iULnwAW4wg90l2kUvpksn/L6YtPiOWRbwc0tKjN0FOkebTUfBKc99oKBsmyaLReh/xJEgcvA= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org A4AA84BC7EFE Received: from mta-snd-w09.mail.nifty.com by mta-sp-w04.mail.nifty.com with ESMTP id <20260316093202944.XMPD.123589.mta-snd-w09.mail.nifty.com@nifty.com>; Mon, 16 Mar 2026 18:32:02 +0900 Received: from sakura.ysato.name by mta-snd-w09.mail.nifty.com with ESMTP id <20260316093202421.KRNR.116672.sakura.ysato.name@nifty.com>; Mon, 16 Mar 2026 18:32:02 +0900 Received: from SIOS1075.constellations.internal (ZM005235.ppp.dion.ne.jp [222.8.5.235]) by sakura.ysato.name (Postfix) with ESMTPSA id 6972B1C0312; Mon, 16 Mar 2026 18:31:56 +0900 (JST) From: Yoshinori Sato To: binutils@sourceware.org Cc: Yoshinori Sato Subject: [RFC PATCH v2 4/4] RX: rx-linux target FDPIC support Date: Mon, 16 Mar 2026 18:31:45 +0900 Message-ID: <20260316093151.360635-5-yoshinori.sato@nifty.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260316093151.360635-1-yoshinori.sato@nifty.com> References: <20260316093151.360635-1-yoshinori.sato@nifty.com> MIME-Version: 1.0 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=default-1th84yt82rvi; t=1773653522; bh=XTsRbx9fxz1KKxzwlSp5Sa6lcWfYDzb8YQ+LFpVTT7g=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=NJpiyNprRCpsx1hXDQHSQ1FiI7dgO3J8TUB2WGl//cka81jpHQBx21SFchKy23TCPgIs6GvH TvtEltmjTmaQsnu2Trp3oTD12lWvaZI2njH9T+u7fWuraE8zecEXbNLp1UB2d0/6D3jVyUb4rK ngqWd23vnoikPsrm1hVTB5cs+lguQWTqr+y/DXmTP1J6ADHNZrY85ECNo6cUhdIh1fYn3vZBkd mRfzeOS/4Qxm0xsOK7/uQvLvYsEwVhz2q6Y3wgnio1WbZJTh80+AD4zibTTjjDn6lxaBK/YYT8 nnfQdGU4WUHTX59jfHrPZ5Q6JisX4jnpX0hOpUqyQQsqbOiQ== X-Spam-Status: No, score=-11.3 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_BLOCKED, SPF_HELO_PASS, SPF_PASS, TXREP, URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: binutils@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Binutils mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: binutils-bounces~patchwork=sourceware.org@sourceware.org * elf/rx.h: Add FDPIC relocations. and FDPIC type. Signed-off-by: Yoshinori Sato --- include/elf/rx.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/include/elf/rx.h b/include/elf/rx.h index a79ac26f080..8b70821f559 100644 --- a/include/elf/rx.h +++ b/include/elf/rx.h @@ -55,6 +55,19 @@ START_RELOC_NUMBERS (elf_rx_reloc_type) RELOC_NUMBER (R_RX_DIR16_REV, 0x11) RELOC_NUMBER (R_RX_DIR3U_PCREL, 0x12) + /* PIC stuff */ + RELOC_NUMBER (R_RX_GOT, 0x13) + RELOC_NUMBER (R_RX_PLT, 0x14) + RELOC_NUMBER (R_RX_COPY, 0x15) + RELOC_NUMBER (R_RX_GLOB_DAT, 0x16) + RELOC_NUMBER (R_RX_JMP_SLOT, 0x17) + RELOC_NUMBER (R_RX_RELATIVE, 0x18) + RELOC_NUMBER (R_RX_GOTOFF, 0x19) + RELOC_NUMBER (R_RX_GOTFUNCDESC, 0x1a) + RELOC_NUMBER (R_RX_GOTOFFFUNCDESC, 0x1b) + RELOC_NUMBER (R_RX_FUNCDESC, 0x1c) + RELOC_NUMBER (R_RX_FUNCDESC_VALUE, 0x1d) + /* These are extensions added by Red Hat. */ RELOC_NUMBER (R_RX_RH_3_PCREL, 0x20) /* Like R_RX_DIR8S_PCREL but only 3-bits. */ RELOC_NUMBER (R_RX_RH_16_OP, 0x21) /* Like R_RX_DIR16 but for opcodes - always big endian. */ @@ -113,6 +126,8 @@ END_RELOC_NUMBERS (R_RX_max) #define EF_RX_CPU_RX 0x00000079 /* FIXME: this collides with the E_FLAG_RX_... values below. */ #define EF_RX_CPU_MASK 0x000003FF /* specific cpu bits. */ #define EF_RX_ALL_FLAGS (EF_RX_CPU_MASK) +#define EF_RX_PIC 0x1000 +#define EF_RX_FDPIC 0x2000 /* Values for the e_flags field in the ELF header. */ #define E_FLAG_RX_64BIT_DOUBLES (1 << 0)