1/* KVX-specific support for ELF. 2 Copyright (C) 2009-2024 Free Software Foundation, Inc. 3 Contributed by Kalray SA. 4 5 This file is part of BFD, the Binary File Descriptor library. 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 3 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program; see the file COPYING3. If not, 19 see <http://www.gnu.org/licenses/>. */ 20 21#include "sysdep.h" 22#include "elfxx-kvx.h" 23#include <stdarg.h> 24#include <string.h> 25 26/* Return non-zero if the indicated VALUE has overflowed the maximum 27 range expressible by a unsigned number with the indicated number of 28 BITS. */ 29 30static bfd_reloc_status_type 31kvx_unsigned_overflow (bfd_vma value, unsigned int bits) 32{ 33 bfd_vma lim; 34 if (bits >= sizeof (bfd_vma) * 8) 35 return bfd_reloc_ok; 36 lim = (bfd_vma) 1 << bits; 37 if (value >= lim) 38 return bfd_reloc_overflow; 39 return bfd_reloc_ok; 40} 41 42/* Return non-zero if the indicated VALUE has overflowed the maximum 43 range expressible by an signed number with the indicated number of 44 BITS. */ 45 46static bfd_reloc_status_type 47kvx_signed_overflow (bfd_vma value, unsigned int bits) 48{ 49 bfd_vma lim; 50 51 if (bits >= sizeof (bfd_vma) * 8) 52 return bfd_reloc_ok; 53 lim = (bfd_vma) 1 << (bits - 1); 54 if (value + lim >= lim * 2) 55 return bfd_reloc_overflow; 56 return bfd_reloc_ok; 57} 58 59/* Insert the addend/value into the instruction or data object being 60 relocated. */ 61bfd_reloc_status_type 62_bfd_kvx_elf_put_addend (bfd *abfd, 63 bfd_byte *address, 64 bfd_reloc_code_real_type r_type ATTRIBUTE_UNUSED, 65 reloc_howto_type *howto, 66 bfd_signed_vma addend) 67{ 68 bfd_reloc_status_type status = bfd_reloc_ok; 69 bfd_vma contents; 70 int size; 71 72 size = bfd_get_reloc_size (howto); 73 switch (size) 74 { 75 case 2: 76 contents = bfd_get_16 (abfd, address); 77 break; 78 case 4: 79 if (howto->src_mask != 0xffffffff) 80 /* Must be 32-bit instruction, always little-endian. */ 81 contents = bfd_getl32 (address); 82 else 83 /* Must be 32-bit data (endianness dependent). */ 84 contents = bfd_get_32 (abfd, address); 85 break; 86 case 8: 87 contents = bfd_get_64 (abfd, address); 88 break; 89 default: 90 abort (); 91 } 92 93 switch (howto->complain_on_overflow) 94 { 95 case complain_overflow_dont: 96 break; 97 case complain_overflow_signed: 98 status = kvx_signed_overflow (addend, 99 howto->bitsize + howto->rightshift); 100 break; 101 case complain_overflow_unsigned: 102 status = kvx_unsigned_overflow (addend, 103 howto->bitsize + howto->rightshift); 104 break; 105 case complain_overflow_bitfield: 106 default: 107 abort (); 108 } 109 110 addend >>= howto->rightshift; 111 112 /* FIXME KVX : AARCH64 is "redoing" what the link_relocate bfd 113 * function does ie. extract bitfields and apply then to the 114 * existing content (insn) (howto's job) Not sure exactly 115 * why. Maybe because we need this even when not applying reloc 116 * against a input_bfd (eg. when doing PLT). On KVX, we have not 117 * reached a point where we would need to write similar 118 * functions for each insn. So we'll simply enrich the default 119 * case for handling a bit more than "right aligned bitfields" 120 * 121 * Beware that this won't be able to apply generic howto ! 122 */ 123 124 /* if (howto->dst_mask & (howto->dst_mask + 1)) */ 125 /* return bfd_reloc_notsupported; */ 126 addend <<= howto->bitpos; 127 contents = ((contents & ~howto->dst_mask) | (addend & howto->dst_mask)); 128 129 switch (size) 130 { 131 case 2: 132 bfd_put_16 (abfd, contents, address); 133 break; 134 case 4: 135 if (howto->dst_mask != 0xffffffff) 136 /* must be 32-bit instruction, always little-endian */ 137 bfd_putl32 (contents, address); 138 else 139 /* must be 32-bit data (endianness dependent) */ 140 bfd_put_32 (abfd, contents, address); 141 break; 142 case 8: 143 bfd_put_64 (abfd, contents, address); 144 break; 145 default: 146 abort (); 147 } 148 149 return status; 150} 151 152bool 153_bfd_kvx_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) 154{ 155 int offset; 156 size_t size; 157 158 switch (note->descsz) 159 { 160 case 680: /* sizeof(struct elf_prstatus) on Linux/kvx. */ 161 /* pr_cursig */ 162 elf_tdata (abfd)->core->signal = bfd_get_16 (abfd, note->descdata + 12); 163 164 /* pr_pid */ 165 elf_tdata (abfd)->core->lwpid = bfd_get_32 (abfd, note->descdata + 32); 166 167 /* pr_reg */ 168 offset = 112; 169 size = 560; 170 break; 171 172 default: 173 return false; 174 } 175 176 /* Make a ".reg/999" section. */ 177 return _bfd_elfcore_make_pseudosection (abfd, ".reg", size, 178 note->descpos + offset); 179} 180 181bool 182_bfd_kvx_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) 183{ 184 switch (note->descsz) 185 { 186 case 136: /* This is sizeof(struct elf_prpsinfo) on Linux/kvx. */ 187 elf_tdata (abfd)->core->pid = bfd_get_32 (abfd, note->descdata + 24); 188 elf_tdata (abfd)->core->program 189 = _bfd_elfcore_strndup (abfd, note->descdata + 40, 16); 190 elf_tdata (abfd)->core->command 191 = _bfd_elfcore_strndup (abfd, note->descdata + 56, 80); 192 break; 193 194 default: 195 return false; 196 } 197 198 /* Note that for some reason, a spurious space is tacked 199 onto the end of the args in some (at least one anyway) 200 implementations, so strip it off if it exists. */ 201 202 { 203 char *command = elf_tdata (abfd)->core->command; 204 int n = strlen (command); 205 206 if (n > 0 && command[n - 1] == ' ') 207 command[n - 1] = 0; 208 } 209 210 return true; 211} 212