radeon: Teach radeon_elf_read() how to parse reloc information v3
authorTom Stellard <thomas.stellard@amd.com>
Wed, 10 Dec 2014 01:03:50 +0000 (20:03 -0500)
committerTom Stellard <thomas.stellard@amd.com>
Tue, 20 Jan 2015 14:55:43 +0000 (09:55 -0500)
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
src/gallium/drivers/radeon/radeon_elf_util.c
src/gallium/drivers/radeon/radeon_elf_util.h
src/gallium/drivers/radeonsi/si_compute.c
src/gallium/drivers/radeonsi/si_shader.c

index 60b8faeb29b428cc645be9232214c70d6f378af8..6224668ea6e0121f90601cfdd41564555b28a92a 100644 (file)
 
 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;
index 8cda57afff6afc1fcf7593d7e004868736f4bdca..fd0632b7500e4b3fcb6aad8a1eb68717e122ffd3 100644 (file)
@@ -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, &section_header, binary);
+                       symbols = elf_getdata(section, section_data);
+                       symbol_sh_link = section_header.sh_link;
+                       parse_symbol_table(symbols, &section_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);
+       }
 }
index ccac56383103eb77bce3936d18d3f6273e9d0baf..ab83f98ea69c202513e6700542ac24a8fae75f15 100644 (file)
@@ -30,6 +30,7 @@
 #include <stdint.h>
 
 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 */
index f911e1f762030fd79e464d228888d27e0dbbb46b..20fec84ed77d9ff9239dc8e3c945f5416468b147 100644 (file)
@@ -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);
 }
 
index a891bc651d7bab2afdf3a36b50dc5a867253019a..81cb2ef31bb14d67d1e7d9ad9b40c3cb1b28dc22 100644 (file)
@@ -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;
 }