From dfdaf3eb7edac939f5d1a32db2968944852b28fa Mon Sep 17 00:00:00 2001 From: Tom Stellard Date: Tue, 9 Dec 2014 20:03:50 -0500 Subject: [PATCH] radeon: Teach radeon_elf_read() how to parse reloc information v3 v2: - Use strdup for copying reloc names. - Free reloc memory. v3: - Add free_relocs parameter to radeon_shader_binary_free_members() --- src/gallium/drivers/radeon/r600_pipe_common.h | 8 +++ src/gallium/drivers/radeon/radeon_elf_util.c | 61 +++++++++++++++++-- src/gallium/drivers/radeon/radeon_elf_util.h | 12 +++- src/gallium/drivers/radeonsi/si_compute.c | 2 +- src/gallium/drivers/radeonsi/si_shader.c | 2 +- 5 files changed, 78 insertions(+), 7 deletions(-) diff --git a/src/gallium/drivers/radeon/r600_pipe_common.h b/src/gallium/drivers/radeon/r600_pipe_common.h index 60b8faeb29b..6224668ea6e 100644 --- a/src/gallium/drivers/radeon/r600_pipe_common.h +++ b/src/gallium/drivers/radeon/r600_pipe_common.h @@ -89,6 +89,11 @@ struct r600_common_context; +struct radeon_shader_reloc { + char *name; + uint64_t offset; +}; + struct radeon_shader_binary { /** Shader code */ unsigned char *code; @@ -113,6 +118,9 @@ struct radeon_shader_binary { uint64_t *global_symbol_offsets; unsigned global_symbol_count; + struct radeon_shader_reloc *relocs; + unsigned reloc_count; + /** Set to 1 if the disassembly for this binary has been dumped to * stderr. */ int disassembled; diff --git a/src/gallium/drivers/radeon/radeon_elf_util.c b/src/gallium/drivers/radeon/radeon_elf_util.c index 8cda57afff6..fd0632b7500 100644 --- a/src/gallium/drivers/radeon/radeon_elf_util.c +++ b/src/gallium/drivers/radeon/radeon_elf_util.c @@ -53,7 +53,8 @@ static void parse_symbol_table(Elf_Data *symbol_table_data, while (gelf_getsym(symbol_table_data, i++, &symbol)) { unsigned i; - if (GELF_ST_BIND(symbol.st_info) != STB_GLOBAL) { + if (GELF_ST_BIND(symbol.st_info) != STB_GLOBAL || + symbol.st_shndx == 0 /* Undefined symbol */) { continue; } @@ -75,6 +76,32 @@ static void parse_symbol_table(Elf_Data *symbol_table_data, } } +static void parse_relocs(Elf *elf, Elf_Data *relocs, Elf_Data *symbols, + unsigned symbol_sh_link, + struct radeon_shader_binary *binary) +{ + unsigned i; + + if (!relocs || !symbols || !binary->reloc_count) { + return; + } + binary->relocs = CALLOC(binary->reloc_count, + sizeof(struct radeon_shader_reloc)); + for (i = 0; i < binary->reloc_count; i++) { + GElf_Sym symbol; + GElf_Rel rel; + char *symbol_name; + struct radeon_shader_reloc *reloc = &binary->relocs[i]; + + gelf_getrel(relocs, i, &rel); + gelf_getsym(symbols, GELF_R_SYM(rel.r_info), &symbol); + symbol_name = elf_strptr(elf, symbol_sh_link, symbol.st_name); + + reloc->offset = rel.r_offset; + reloc->name = strdup(symbol_name); + } +} + void radeon_elf_read(const char *elf_data, unsigned elf_size, struct radeon_shader_binary *binary, unsigned debug) @@ -82,7 +109,9 @@ void radeon_elf_read(const char *elf_data, unsigned elf_size, char *elf_buffer; Elf *elf; Elf_Scn *section = NULL; + Elf_Data *symbols = NULL, *relocs = NULL; size_t section_str_index; + unsigned symbol_sh_link; /* One of the libelf implementations * (http://www.mr511.de/software/english.htm) requires calling @@ -128,11 +157,18 @@ void radeon_elf_read(const char *elf_data, unsigned elf_size, binary->rodata = MALLOC(binary->rodata_size * sizeof(unsigned char)); memcpy(binary->rodata, section_data->d_buf, binary->rodata_size); } else if (!strncmp(name, ".symtab", 7)) { - section_data = elf_getdata(section, section_data); - parse_symbol_table(section_data, §ion_header, binary); + symbols = elf_getdata(section, section_data); + symbol_sh_link = section_header.sh_link; + parse_symbol_table(symbols, §ion_header, binary); + } else if (!strcmp(name, ".rel.text")) { + relocs = elf_getdata(section, section_data); + binary->reloc_count = section_header.sh_size / + section_header.sh_entsize; } } + parse_relocs(elf, relocs, symbols, symbol_sh_link, binary); + if (elf){ elf_end(elf); } @@ -162,8 +198,25 @@ const unsigned char *radeon_shader_binary_config_start( return binary->config; } -void radeon_shader_binary_free_members(struct radeon_shader_binary *binary) { +void radeon_shader_binary_free_relocs(struct radeon_shader_reloc *relocs, + unsigned reloc_count) +{ + unsigned i; + for (i = 0; i < reloc_count; i++) { + FREE(relocs[i].name); + } + FREE(relocs); +} + +void radeon_shader_binary_free_members(struct radeon_shader_binary *binary, + unsigned free_relocs) +{ FREE(binary->code); FREE(binary->config); FREE(binary->rodata); + + if (free_relocs) { + radeon_shader_binary_free_relocs(binary->relocs, + binary->reloc_count); + } } diff --git a/src/gallium/drivers/radeon/radeon_elf_util.h b/src/gallium/drivers/radeon/radeon_elf_util.h index ccac5638310..ab83f98ea69 100644 --- a/src/gallium/drivers/radeon/radeon_elf_util.h +++ b/src/gallium/drivers/radeon/radeon_elf_util.h @@ -30,6 +30,7 @@ #include struct radeon_shader_binary; +struct radeon_shader_reloc; /* * Parse the elf binary stored in \p elf_data and create a @@ -49,6 +50,15 @@ const unsigned char *radeon_shader_binary_config_start( /** * Free all memory allocated for members of \p binary. This function does * not free \p binary. + * + * @param free_relocs If false, reolc information will not be freed. + */ +void radeon_shader_binary_free_members(struct radeon_shader_binary *binary, + unsigned free_relocs); + +/** + * Free \p relocs and all member data. */ -void radeon_shader_binary_free_members(struct radeon_shader_binary *binary); +void radeon_shader_binary_free_relocs(struct radeon_shader_reloc *relocs, + unsigned reloc_count); #endif /* RADEON_ELF_UTIL_H */ diff --git a/src/gallium/drivers/radeonsi/si_compute.c b/src/gallium/drivers/radeonsi/si_compute.c index f911e1f7620..20fec84ed77 100644 --- a/src/gallium/drivers/radeonsi/si_compute.c +++ b/src/gallium/drivers/radeonsi/si_compute.c @@ -439,7 +439,7 @@ static void si_delete_compute_state(struct pipe_context *ctx, void* state){ pipe_resource_reference( (struct pipe_resource **)&program->input_buffer, NULL); - radeon_shader_binary_free_members(&program->binary); + radeon_shader_binary_free_members(&program->binary, true); FREE(program); } diff --git a/src/gallium/drivers/radeonsi/si_shader.c b/src/gallium/drivers/radeonsi/si_shader.c index a891bc651d7..81cb2ef31bb 100644 --- a/src/gallium/drivers/radeonsi/si_shader.c +++ b/src/gallium/drivers/radeonsi/si_shader.c @@ -2621,7 +2621,7 @@ int si_compile_llvm(struct si_screen *sscreen, struct si_shader *shader, return r; } r = si_shader_binary_read(sscreen, shader, &binary); - radeon_shader_binary_free_members(&binary); + radeon_shader_binary_free_members(&binary, true); return r; } -- 2.30.2