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 : : }