xref: /netbsd-src/external/gpl3/binutils/dist/bfd/elfxx-kvx.c (revision cb63e24e8d6aae7ddac1859a9015f48b1d8bd90e)
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 
30 static bfd_reloc_status_type
kvx_unsigned_overflow(bfd_vma value,unsigned int bits)31 kvx_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 
46 static bfd_reloc_status_type
kvx_signed_overflow(bfd_vma value,unsigned int bits)47 kvx_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.  */
61 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)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 
152 bool
_bfd_kvx_elf_grok_prstatus(bfd * abfd,Elf_Internal_Note * note)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 
181 bool
_bfd_kvx_elf_grok_psinfo(bfd * abfd,Elf_Internal_Note * note)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