/src/elfutils/backends/riscv_symbol.c
Line | Count | Source |
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 | | riscv_reloc_simple_type (Ebl *ebl __attribute__ ((unused)), int type, |
45 | | int *addsub) |
46 | 0 | { |
47 | 0 | switch (type) |
48 | 0 | { |
49 | 0 | case R_RISCV_SET8: |
50 | 0 | return ELF_T_BYTE; |
51 | 0 | case R_RISCV_SET16: |
52 | 0 | return ELF_T_HALF; |
53 | 0 | case R_RISCV_32: |
54 | 0 | case R_RISCV_SET32: |
55 | 0 | return ELF_T_WORD; |
56 | 0 | case R_RISCV_64: |
57 | 0 | return ELF_T_XWORD; |
58 | 0 | case R_RISCV_ADD16: |
59 | 0 | *addsub = 1; |
60 | 0 | return ELF_T_HALF; |
61 | 0 | case R_RISCV_SUB16: |
62 | 0 | *addsub = -1; |
63 | 0 | 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 | 0 | case R_RISCV_ADD64: |
71 | 0 | *addsub = 1; |
72 | 0 | return ELF_T_XWORD; |
73 | 0 | case R_RISCV_SUB64: |
74 | 0 | *addsub = -1; |
75 | 0 | return ELF_T_XWORD; |
76 | 0 | default: |
77 | 0 | return ELF_T_NUM; |
78 | 0 | } |
79 | 0 | } |
80 | | |
81 | | /* Check whether machine flags are valid. */ |
82 | | bool |
83 | | riscv_machine_flag_check (GElf_Word flags) |
84 | 0 | { |
85 | 0 | return ((flags &~ (EF_RISCV_RVC |
86 | 0 | | EF_RISCV_FLOAT_ABI)) == 0); |
87 | 0 | } |
88 | | |
89 | | /* Check whether given symbol's st_value and st_size are OK despite failing |
90 | | normal checks. */ |
91 | | bool |
92 | | riscv_check_special_symbol (Elf *elf, const GElf_Sym *sym, |
93 | | const char *name, const GElf_Shdr *destshdr) |
94 | 0 | { |
95 | 0 | if (name == NULL) |
96 | 0 | return false; |
97 | | |
98 | 0 | size_t shstrndx; |
99 | 0 | if (elf_getshdrstrndx (elf, &shstrndx) != 0) |
100 | 0 | return false; |
101 | 0 | const char *sname = elf_strptr (elf, shstrndx, destshdr->sh_name); |
102 | 0 | if (sname == NULL) |
103 | 0 | 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 | 0 | if (strcmp (name, "_GLOBAL_OFFSET_TABLE_") == 0) |
108 | 0 | { |
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 | 0 | return true; |
113 | 0 | else if (strcmp (sname, ".got.plt") == 0) |
114 | 0 | { |
115 | | /* Find .got section and compare against that. */ |
116 | 0 | Elf_Scn *scn = NULL; |
117 | 0 | while ((scn = elf_nextscn (elf, scn)) != NULL) |
118 | 0 | { |
119 | 0 | GElf_Shdr shdr_mem; |
120 | 0 | GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); |
121 | 0 | if (shdr != NULL) |
122 | 0 | { |
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 | 0 | } |
128 | 0 | } |
129 | 0 | } |
130 | 0 | } |
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 | 0 | 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 | 0 | return false; |
142 | 0 | } |
143 | | |
144 | | const char * |
145 | | riscv_segment_type_name (int segment, char *buf __attribute__ ((unused)), |
146 | | size_t len __attribute__ ((unused))) |
147 | 0 | { |
148 | 0 | switch (segment) |
149 | 0 | { |
150 | 0 | case PT_RISCV_ATTRIBUTES: |
151 | 0 | return "RISCV_ATTRIBUTES"; |
152 | 0 | } |
153 | 0 | return NULL; |
154 | 0 | } |
155 | | |
156 | | /* Return symbolic representation of section type. */ |
157 | | const char * |
158 | | riscv_section_type_name (int type, |
159 | | char *buf __attribute__ ((unused)), |
160 | | size_t len __attribute__ ((unused))) |
161 | 0 | { |
162 | 0 | switch (type) |
163 | 0 | { |
164 | 0 | case SHT_RISCV_ATTRIBUTES: |
165 | 0 | return "RISCV_ATTRIBUTES"; |
166 | 0 | } |
167 | | |
168 | 0 | return NULL; |
169 | 0 | } |
170 | | |
171 | | const char * |
172 | | riscv_dynamic_tag_name (int64_t tag, char *buf __attribute__ ((unused)), |
173 | | size_t len __attribute__ ((unused))) |
174 | 0 | { |
175 | 0 | switch (tag) |
176 | 0 | { |
177 | 0 | case DT_RISCV_VARIANT_CC: |
178 | 0 | return "RISCV_VARIANT_CC"; |
179 | 0 | } |
180 | 0 | return NULL; |
181 | 0 | } |
182 | | |
183 | | bool |
184 | | riscv_dynamic_tag_check (int64_t tag) |
185 | 0 | { |
186 | 0 | return tag == DT_RISCV_VARIANT_CC; |
187 | 0 | } |