1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
|
/* 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;
}
|