radeon_elf_util.c revision 7dd1f45bc41c4a936b0ff84400840524bb9f8871
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@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 36static 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 79static 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 reloc->name = strdup(symbol_name); 102 } 103} 104 105void radeon_elf_read(const char *elf_data, unsigned elf_size, 106 struct radeon_shader_binary *binary) 107{ 108 char *elf_buffer; 109 Elf *elf; 110 Elf_Scn *section = NULL; 111 Elf_Data *symbols = NULL, *relocs = NULL; 112 size_t section_str_index; 113 unsigned symbol_sh_link = 0; 114 115 /* One of the libelf implementations 116 * (http://www.mr511.de/software/english.htm) requires calling 117 * elf_version() before elf_memory(). 118 */ 119 elf_version(EV_CURRENT); 120 elf_buffer = MALLOC(elf_size); 121 memcpy(elf_buffer, elf_data, elf_size); 122 123 elf = elf_memory(elf_buffer, elf_size); 124 125 elf_getshdrstrndx(elf, §ion_str_index); 126 127 while ((section = elf_nextscn(elf, section))) { 128 const char *name; 129 Elf_Data *section_data = NULL; 130 GElf_Shdr section_header; 131 if (gelf_getshdr(section, §ion_header) != §ion_header) { 132 fprintf(stderr, "Failed to read ELF section header\n"); 133 return; 134 } 135 name = elf_strptr(elf, section_str_index, section_header.sh_name); 136 if (!strcmp(name, ".text")) { 137 section_data = elf_getdata(section, section_data); 138 binary->code_size = section_data->d_size; 139 binary->code = MALLOC(binary->code_size * sizeof(unsigned char)); 140 memcpy(binary->code, section_data->d_buf, binary->code_size); 141 } else if (!strcmp(name, ".AMDGPU.config")) { 142 section_data = elf_getdata(section, section_data); 143 binary->config_size = section_data->d_size; 144 binary->config = MALLOC(binary->config_size * sizeof(unsigned char)); 145 memcpy(binary->config, section_data->d_buf, binary->config_size); 146 } else if (!strcmp(name, ".AMDGPU.disasm")) { 147 /* Always read disassembly if it's available. */ 148 section_data = elf_getdata(section, section_data); 149 binary->disasm_string = strndup(section_data->d_buf, 150 section_data->d_size); 151 } else if (!strncmp(name, ".rodata", 7)) { 152 section_data = elf_getdata(section, section_data); 153 binary->rodata_size = section_data->d_size; 154 binary->rodata = MALLOC(binary->rodata_size * sizeof(unsigned char)); 155 memcpy(binary->rodata, section_data->d_buf, binary->rodata_size); 156 } else if (!strncmp(name, ".symtab", 7)) { 157 symbols = elf_getdata(section, section_data); 158 symbol_sh_link = section_header.sh_link; 159 parse_symbol_table(symbols, §ion_header, binary); 160 } else if (!strcmp(name, ".rel.text")) { 161 relocs = elf_getdata(section, section_data); 162 binary->reloc_count = section_header.sh_size / 163 section_header.sh_entsize; 164 } 165 } 166 167 parse_relocs(elf, relocs, symbols, symbol_sh_link, binary); 168 169 if (elf){ 170 elf_end(elf); 171 } 172 FREE(elf_buffer); 173 174 /* Cache the config size per symbol */ 175 if (binary->global_symbol_count) { 176 binary->config_size_per_symbol = 177 binary->config_size / binary->global_symbol_count; 178 } else { 179 binary->global_symbol_count = 1; 180 binary->config_size_per_symbol = binary->config_size; 181 } 182} 183 184const unsigned char *radeon_shader_binary_config_start( 185 const struct radeon_shader_binary *binary, 186 uint64_t symbol_offset) 187{ 188 unsigned i; 189 for (i = 0; i < binary->global_symbol_count; ++i) { 190 if (binary->global_symbol_offsets[i] == symbol_offset) { 191 unsigned offset = i * binary->config_size_per_symbol; 192 return binary->config + offset; 193 } 194 } 195 return binary->config; 196} 197 198void radeon_shader_binary_free_relocs(struct radeon_shader_reloc *relocs, 199 unsigned reloc_count) 200{ 201 unsigned i; 202 for (i = 0; i < reloc_count; i++) { 203 FREE(relocs[i].name); 204 } 205 FREE(relocs); 206} 207 208void radeon_shader_binary_free_members(struct radeon_shader_binary *binary, 209 unsigned free_relocs) 210{ 211 FREE(binary->code); 212 FREE(binary->config); 213 FREE(binary->rodata); 214 215 if (free_relocs) { 216 radeon_shader_binary_free_relocs(binary->relocs, 217 binary->reloc_count); 218 } 219} 220