| /* 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 <http://www.gnu.org/licenses/>. */ |
| |
| #include "sysdep.h" |
| #include "elfxx-kvx.h" |
| #include <stdarg.h> |
| #include <string.h> |
| |
| /* 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; |
| } |