/* KVX-specific support for ELF. Copyright (C) 2009-2024 Free Software Foundation, Inc. Contributed by Kalray SA. This file is part of BFD, the Binary File Descriptor library. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING3. If not, see . */ #include "sysdep.h" #include "elfxx-kvx.h" #include #include /* Return non-zero if the indicated VALUE has overflowed the maximum range expressible by a unsigned number with the indicated number of BITS. */ static bfd_reloc_status_type kvx_unsigned_overflow (bfd_vma value, unsigned int bits) { bfd_vma lim; if (bits >= sizeof (bfd_vma) * 8) return bfd_reloc_ok; lim = (bfd_vma) 1 << bits; if (value >= lim) return bfd_reloc_overflow; return bfd_reloc_ok; } /* Return non-zero if the indicated VALUE has overflowed the maximum range expressible by an signed number with the indicated number of BITS. */ static bfd_reloc_status_type kvx_signed_overflow (bfd_vma value, unsigned int bits) { bfd_vma lim; if (bits >= sizeof (bfd_vma) * 8) return bfd_reloc_ok; lim = (bfd_vma) 1 << (bits - 1); if (value + lim >= lim * 2) return bfd_reloc_overflow; return bfd_reloc_ok; } /* Insert the addend/value into the instruction or data object being relocated. */ bfd_reloc_status_type _bfd_kvx_elf_put_addend (bfd *abfd, bfd_byte *address, bfd_reloc_code_real_type r_type ATTRIBUTE_UNUSED, reloc_howto_type *howto, bfd_signed_vma addend) { bfd_reloc_status_type status = bfd_reloc_ok; bfd_vma contents; int size; size = bfd_get_reloc_size (howto); switch (size) { case 2: contents = bfd_get_16 (abfd, address); break; case 4: if (howto->src_mask != 0xffffffff) /* Must be 32-bit instruction, always little-endian. */ contents = bfd_getl32 (address); else /* Must be 32-bit data (endianness dependent). */ contents = bfd_get_32 (abfd, address); break; case 8: contents = bfd_get_64 (abfd, address); break; default: abort (); } switch (howto->complain_on_overflow) { case complain_overflow_dont: break; case complain_overflow_signed: status = kvx_signed_overflow (addend, howto->bitsize + howto->rightshift); break; case complain_overflow_unsigned: status = kvx_unsigned_overflow (addend, howto->bitsize + howto->rightshift); break; case complain_overflow_bitfield: default: abort (); } addend >>= howto->rightshift; /* FIXME KVX : AARCH64 is "redoing" what the link_relocate bfd * function does ie. extract bitfields and apply then to the * existing content (insn) (howto's job) Not sure exactly * why. Maybe because we need this even when not applying reloc * against a input_bfd (eg. when doing PLT). On KVX, we have not * reached a point where we would need to write similar * functions for each insn. So we'll simply enrich the default * case for handling a bit more than "right aligned bitfields" * * Beware that this won't be able to apply generic howto ! */ /* if (howto->dst_mask & (howto->dst_mask + 1)) */ /* return bfd_reloc_notsupported; */ addend <<= howto->bitpos; contents = ((contents & ~howto->dst_mask) | (addend & howto->dst_mask)); switch (size) { case 2: bfd_put_16 (abfd, contents, address); break; case 4: if (howto->dst_mask != 0xffffffff) /* must be 32-bit instruction, always little-endian */ bfd_putl32 (contents, address); else /* must be 32-bit data (endianness dependent) */ bfd_put_32 (abfd, contents, address); break; case 8: bfd_put_64 (abfd, contents, address); break; default: abort (); } return status; } bool _bfd_kvx_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) { int offset; size_t size; switch (note->descsz) { case 680: /* sizeof(struct elf_prstatus) on Linux/kvx. */ /* pr_cursig */ elf_tdata (abfd)->core->signal = bfd_get_16 (abfd, note->descdata + 12); /* pr_pid */ elf_tdata (abfd)->core->lwpid = bfd_get_32 (abfd, note->descdata + 32); /* pr_reg */ offset = 112; size = 560; break; default: return false; } /* Make a ".reg/999" section. */ return _bfd_elfcore_make_pseudosection (abfd, ".reg", size, note->descpos + offset); } bool _bfd_kvx_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) { switch (note->descsz) { case 136: /* This is sizeof(struct elf_prpsinfo) on Linux/kvx. */ elf_tdata (abfd)->core->pid = bfd_get_32 (abfd, note->descdata + 24); elf_tdata (abfd)->core->program = _bfd_elfcore_strndup (abfd, note->descdata + 40, 16); elf_tdata (abfd)->core->command = _bfd_elfcore_strndup (abfd, note->descdata + 56, 80); break; default: return false; } /* Note that for some reason, a spurious space is tacked onto the end of the args in some (at least one anyway) implementations, so strip it off if it exists. */ { char *command = elf_tdata (abfd)->core->command; int n = strlen (command); if (n > 0 && command[n - 1] == ' ') command[n - 1] = 0; } return true; }