Branch data Line data Source code
1 : : /* RISC-V specific symbolic name handling.
2 : : Copyright (C) 2024 Mark J. Wielaard <mark@klomp.org>
3 : : This file is part of elfutils.
4 : :
5 : : This file is free software; you can redistribute it and/or modify
6 : : it under the terms of either
7 : :
8 : : * the GNU Lesser General Public License as published by the Free
9 : : Software Foundation; either version 3 of the License, or (at
10 : : your option) any later version
11 : :
12 : : or
13 : :
14 : : * the GNU General Public License as published by the Free
15 : : Software Foundation; either version 2 of the License, or (at
16 : : your option) any later version
17 : :
18 : : or both in parallel, as here.
19 : :
20 : : elfutils is distributed in the hope that it will be useful, but
21 : : WITHOUT ANY WARRANTY; without even the implied warranty of
22 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 : : General Public License for more details.
24 : :
25 : : You should have received copies of the GNU General Public License and
26 : : the GNU Lesser General Public License along with this program. If
27 : : not, see <http://www.gnu.org/licenses/>. */
28 : :
29 : : #ifdef HAVE_CONFIG_H
30 : : # include <config.h>
31 : : #endif
32 : :
33 : : #include <assert.h>
34 : : #include <elf.h>
35 : : #include <stddef.h>
36 : : #include <string.h>
37 : :
38 : : #define BACKEND riscv_
39 : : #include "libebl_CPU.h"
40 : :
41 : :
42 : : /* Check for the simple reloc types. */
43 : : Elf_Type
44 : 12442 : riscv_reloc_simple_type (Ebl *ebl __attribute__ ((unused)), int type,
45 : : int *addsub)
46 : : {
47 [ - + + + : 12442 : switch (type)
+ - - + +
+ - ]
48 : : {
49 : : case R_RISCV_SET8:
50 : : return ELF_T_BYTE;
51 : : case R_RISCV_SET16:
52 : : return ELF_T_HALF;
53 : : case R_RISCV_32:
54 : : case R_RISCV_SET32:
55 : : return ELF_T_WORD;
56 : : case R_RISCV_64:
57 : : return ELF_T_XWORD;
58 : 88 : case R_RISCV_ADD16:
59 : 88 : *addsub = 1;
60 : 88 : return ELF_T_HALF;
61 : 88 : case R_RISCV_SUB16:
62 : 88 : *addsub = -1;
63 : 88 : return ELF_T_HALF;
64 : 0 : case R_RISCV_ADD32:
65 : 0 : *addsub = 1;
66 : 0 : return ELF_T_WORD;
67 : 0 : case R_RISCV_SUB32:
68 : 0 : *addsub = -1;
69 : 0 : return ELF_T_WORD;
70 : 48 : case R_RISCV_ADD64:
71 : 48 : *addsub = 1;
72 : 48 : return ELF_T_XWORD;
73 : 48 : case R_RISCV_SUB64:
74 : 48 : *addsub = -1;
75 : 48 : return ELF_T_XWORD;
76 : 32 : default:
77 : 32 : return ELF_T_NUM;
78 : : }
79 : : }
80 : :
81 : : /* Check whether machine flags are valid. */
82 : : bool
83 : 2 : riscv_machine_flag_check (GElf_Word flags)
84 : : {
85 : 2 : return ((flags &~ (EF_RISCV_RVC
86 : 2 : | EF_RISCV_FLOAT_ABI)) == 0);
87 : : }
88 : :
89 : : /* Check whether given symbol's st_value and st_size are OK despite failing
90 : : normal checks. */
91 : : bool
92 : 2 : riscv_check_special_symbol (Elf *elf, const GElf_Sym *sym,
93 : : const char *name, const GElf_Shdr *destshdr)
94 : : {
95 [ - + ]: 2 : if (name == NULL)
96 : : return false;
97 : :
98 : 2 : size_t shstrndx;
99 [ - + ]: 2 : if (elf_getshdrstrndx (elf, &shstrndx) != 0)
100 : : return false;
101 : 2 : const char *sname = elf_strptr (elf, shstrndx, destshdr->sh_name);
102 [ - + ]: 2 : if (sname == NULL)
103 : : return false;
104 : :
105 : : /* _GLOBAL_OFFSET_TABLE_ points to the start of the .got section, but it
106 : : is preceded by the .got.plt section in the output .got section. */
107 [ - + ]: 2 : if (strcmp (name, "_GLOBAL_OFFSET_TABLE_") == 0)
108 : : {
109 [ # # ]: 0 : if (strcmp (sname, ".got") == 0
110 [ # # ]: 0 : && sym->st_value >= destshdr->sh_addr
111 [ # # ]: 0 : && sym->st_value < destshdr->sh_addr + destshdr->sh_size)
112 : : return true;
113 [ # # ]: 0 : else if (strcmp (sname, ".got.plt") == 0)
114 : : {
115 : : /* Find .got section and compare against that. */
116 : : Elf_Scn *scn = NULL;
117 [ # # ]: 0 : while ((scn = elf_nextscn (elf, scn)) != NULL)
118 : : {
119 : 0 : GElf_Shdr shdr_mem;
120 : 0 : GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
121 [ # # ]: 0 : if (shdr != NULL)
122 : : {
123 : 0 : sname = elf_strptr (elf, shstrndx, shdr->sh_name);
124 [ # # # # ]: 0 : if (sname != NULL && strcmp (sname, ".got") == 0)
125 : 0 : return (sym->st_value >= shdr->sh_addr
126 [ # # # # ]: 0 : && sym->st_value < shdr->sh_addr + shdr->sh_size);
127 : : }
128 : : }
129 : : }
130 : : }
131 : :
132 : : /* __global_pointer$ points to the .sdata section with an offset of
133 : : 0x800. It might however fall in the .got section, in which case we
134 : : cannot check the offset. The size always should be zero. */
135 [ + - ]: 2 : if (strcmp (name, "__global_pointer$") == 0)
136 : 0 : return (((strcmp (sname, ".sdata") == 0
137 [ # # ]: 0 : && sym->st_value == destshdr->sh_addr + 0x800)
138 [ # # ]: 0 : || strcmp (sname, ".got") == 0)
139 [ # # # # ]: 0 : && sym->st_size == 0);
140 : :
141 : : return false;
142 : : }
143 : :
144 : : const char *
145 : 0 : riscv_segment_type_name (int segment, char *buf __attribute__ ((unused)),
146 : : size_t len __attribute__ ((unused)))
147 : : {
148 [ # # ]: 0 : switch (segment)
149 : : {
150 : : case PT_RISCV_ATTRIBUTES:
151 : : return "RISCV_ATTRIBUTES";
152 : : }
153 : 0 : return NULL;
154 : : }
155 : :
156 : : /* Return symbolic representation of section type. */
157 : : const char *
158 : 114 : riscv_section_type_name (int type,
159 : : char *buf __attribute__ ((unused)),
160 : : size_t len __attribute__ ((unused)))
161 : : {
162 [ + - ]: 114 : switch (type)
163 : : {
164 : : case SHT_RISCV_ATTRIBUTES:
165 : : return "RISCV_ATTRIBUTES";
166 : : }
167 : :
168 : 114 : return NULL;
169 : : }
170 : :
171 : : const char *
172 : 0 : riscv_dynamic_tag_name (int64_t tag, char *buf __attribute__ ((unused)),
173 : : size_t len __attribute__ ((unused)))
174 : : {
175 [ # # ]: 0 : switch (tag)
176 : : {
177 : : case DT_RISCV_VARIANT_CC:
178 : : return "RISCV_VARIANT_CC";
179 : : }
180 : 0 : return NULL;
181 : : }
182 : :
183 : : bool
184 : 60 : riscv_dynamic_tag_check (int64_t tag)
185 : : {
186 : 60 : return tag == DT_RISCV_VARIANT_CC;
187 : : }
|