1 /* 2 * Copyright 2014 Advanced Micro Devices, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 * SOFTWARE. 22 * 23 * Authors: Tom Stellard <thomas.stellard (at) amd.com> 24 * 25 */ 26 27 #include "radeon_elf_util.h" 28 #include "r600_pipe_common.h" 29 30 #include "util/u_memory.h" 31 32 #include <gelf.h> 33 #include <libelf.h> 34 #include <stdio.h> 35 36 static void parse_symbol_table(Elf_Data *symbol_table_data, 37 const GElf_Shdr *symbol_table_header, 38 struct radeon_shader_binary *binary) 39 { 40 GElf_Sym symbol; 41 unsigned i = 0; 42 unsigned symbol_count = 43 symbol_table_header->sh_size / symbol_table_header->sh_entsize; 44 45 /* We are over allocating this list, because symbol_count gives the 46 * total number of symbols, and we will only be filling the list 47 * with offsets of global symbols. The memory savings from 48 * allocating the correct size of this list will be small, and 49 * I don't think it is worth the cost of pre-computing the number 50 * of global symbols. 51 */ 52 binary->global_symbol_offsets = CALLOC(symbol_count, sizeof(uint64_t)); 53 54 while (gelf_getsym(symbol_table_data, i++, &symbol)) { 55 unsigned i; 56 if (GELF_ST_BIND(symbol.st_info) != STB_GLOBAL || 57 symbol.st_shndx == 0 /* Undefined symbol */) { 58 continue; 59 } 60 61 binary->global_symbol_offsets[binary->global_symbol_count] = 62 symbol.st_value; 63 64 /* Sort the list using bubble sort. This list will usually 65 * be small. */ 66 for (i = binary->global_symbol_count; i > 0; --i) { 67 uint64_t lhs = binary->global_symbol_offsets[i - 1]; 68 uint64_t rhs = binary->global_symbol_offsets[i]; 69 if (lhs < rhs) { 70 break; 71 } 72 binary->global_symbol_offsets[i] = lhs; 73 binary->global_symbol_offsets[i - 1] = rhs; 74 } 75 ++binary->global_symbol_count; 76 } 77 } 78 79 static void parse_relocs(Elf *elf, Elf_Data *relocs, Elf_Data *symbols, 80 unsigned symbol_sh_link, 81 struct radeon_shader_binary *binary) 82 { 83 unsigned i; 84 85 if (!relocs || !symbols || !binary->reloc_count) { 86 return; 87 } 88 binary->relocs = CALLOC(binary->reloc_count, 89 sizeof(struct radeon_shader_reloc)); 90 for (i = 0; i < binary->reloc_count; i++) { 91 GElf_Sym symbol; 92 GElf_Rel rel; 93 char *symbol_name; 94 struct radeon_shader_reloc *reloc = &binary->relocs[i]; 95 96 gelf_getrel(relocs, i, &rel); 97 gelf_getsym(symbols, GELF_R_SYM(rel.r_info), &symbol); 98 symbol_name = elf_strptr(elf, symbol_sh_link, symbol.st_name); 99 100 reloc->offset = rel.r_offset; 101 strncpy(reloc->name, symbol_name, sizeof(reloc->name)-1); 102 reloc->name[sizeof(reloc->name)-1] = 0; 103 } 104 } 105 106 void radeon_elf_read(const char *elf_data, unsigned elf_size, 107 struct radeon_shader_binary *binary) 108 { 109 char *elf_buffer; 110 Elf *elf; 111 Elf_Scn *section = NULL; 112 Elf_Data *symbols = NULL, *relocs = NULL; 113 size_t section_str_index; 114 unsigned symbol_sh_link = 0; 115 116 /* One of the libelf implementations 117 * (http://www.mr511.de/software/english.htm) requires calling 118 * elf_version() before elf_memory(). 119 */ 120 elf_version(EV_CURRENT); 121 elf_buffer = MALLOC(elf_size); 122 memcpy(elf_buffer, elf_data, elf_size); 123 124 elf = elf_memory(elf_buffer, elf_size); 125 126 elf_getshdrstrndx(elf, §ion_str_index); 127 128 while ((section = elf_nextscn(elf, section))) { 129 const char *name; 130 Elf_Data *section_data = NULL; 131 GElf_Shdr section_header; 132 if (gelf_getshdr(section, §ion_header) != §ion_header) { 133 fprintf(stderr, "Failed to read ELF section header\n"); 134 return; 135 } 136 name = elf_strptr(elf, section_str_index, section_header.sh_name); 137 if (!strcmp(name, ".text")) { 138 section_data = elf_getdata(section, section_data); 139 binary->code_size = section_data->d_size; 140 binary->code = MALLOC(binary->code_size * sizeof(unsigned char)); 141 memcpy(binary->code, section_data->d_buf, binary->code_size); 142 } else if (!strcmp(name, ".AMDGPU.config")) { 143 section_data = elf_getdata(section, section_data); 144 binary->config_size = section_data->d_size; 145 binary->config = MALLOC(binary->config_size * sizeof(unsigned char)); 146 memcpy(binary->config, section_data->d_buf, binary->config_size); 147 } else if (!strcmp(name, ".AMDGPU.disasm")) { 148 /* Always read disassembly if it's available. */ 149 section_data = elf_getdata(section, section_data); 150 binary->disasm_string = strndup(section_data->d_buf, 151 section_data->d_size); 152 } else if (!strncmp(name, ".rodata", 7)) { 153 section_data = elf_getdata(section, section_data); 154 binary->rodata_size = section_data->d_size; 155 binary->rodata = MALLOC(binary->rodata_size * sizeof(unsigned char)); 156 memcpy(binary->rodata, section_data->d_buf, binary->rodata_size); 157 } else if (!strncmp(name, ".symtab", 7)) { 158 symbols = elf_getdata(section, section_data); 159 symbol_sh_link = section_header.sh_link; 160 parse_symbol_table(symbols, §ion_header, binary); 161 } else if (!strcmp(name, ".rel.text")) { 162 relocs = elf_getdata(section, section_data); 163 binary->reloc_count = section_header.sh_size / 164 section_header.sh_entsize; 165 } 166 } 167 168 parse_relocs(elf, relocs, symbols, symbol_sh_link, binary); 169 170 if (elf){ 171 elf_end(elf); 172 } 173 FREE(elf_buffer); 174 175 /* Cache the config size per symbol */ 176 if (binary->global_symbol_count) { 177 binary->config_size_per_symbol = 178 binary->config_size / binary->global_symbol_count; 179 } else { 180 binary->global_symbol_count = 1; 181 binary->config_size_per_symbol = binary->config_size; 182 } 183 } 184 185 const unsigned char *radeon_shader_binary_config_start( 186 const struct radeon_shader_binary *binary, 187 uint64_t symbol_offset) 188 { 189 unsigned i; 190 for (i = 0; i < binary->global_symbol_count; ++i) { 191 if (binary->global_symbol_offsets[i] == symbol_offset) { 192 unsigned offset = i * binary->config_size_per_symbol; 193 return binary->config + offset; 194 } 195 } 196 return binary->config; 197 } 198