2023-08-16 21:22:28 +08:00
|
|
|
/* KVX-specific support for ELF.
|
2024-01-04 19:52:08 +08:00
|
|
|
Copyright (C) 2009-2024 Free Software Foundation, Inc.
|
2023-08-16 21:22:28 +08:00
|
|
|
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)
|
|
|
|
{
|
2023-08-22 14:36:32 +08:00
|
|
|
bfd_vma lim;
|
2023-08-16 21:22:28 +08:00
|
|
|
|
|
|
|
if (bits >= sizeof (bfd_vma) * 8)
|
|
|
|
return bfd_reloc_ok;
|
2023-08-22 14:36:32 +08:00
|
|
|
lim = (bfd_vma) 1 << (bits - 1);
|
|
|
|
if (value + lim >= lim * 2)
|
2023-08-16 21:22:28 +08:00
|
|
|
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,
|
2023-08-22 14:32:33 +08:00
|
|
|
bfd_byte *address,
|
|
|
|
bfd_reloc_code_real_type r_type ATTRIBUTE_UNUSED,
|
|
|
|
reloc_howto_type *howto,
|
|
|
|
bfd_signed_vma addend)
|
2023-08-16 21:22:28 +08:00
|
|
|
{
|
|
|
|
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,
|
2023-08-22 14:32:33 +08:00
|
|
|
howto->bitsize + howto->rightshift);
|
2023-08-16 21:22:28 +08:00
|
|
|
break;
|
|
|
|
case complain_overflow_unsigned:
|
|
|
|
status = kvx_unsigned_overflow (addend,
|
2023-08-22 14:32:33 +08:00
|
|
|
howto->bitsize + howto->rightshift);
|
2023-08-16 21:22:28 +08:00
|
|
|
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;
|
|
|
|
}
|