diff options
author | Gil Pitney <gil.pitney@linaro.org> | 2014-10-28 18:00:42 -0700 |
---|---|---|
committer | Gil Pitney <gil.pitney@linaro.org> | 2014-10-28 18:00:42 -0700 |
commit | 61b2c94d9e64758e55730be6a3fc9006c171db85 (patch) | |
tree | f564f09ebf93ba293dfa225bd374df6f1f37aa01 /src/core/dsp/ocl_load |
Initial Commit: Based on TI OpenCL v0.8, originally based on clover.shamrock_v0.8
This is a continuation of the clover OpenCL project:
http://people.freedesktop.org/~steckdenis/clover
based on the contributions from Texas Instruments for Keystone II DSP device:
git.ti.com/opencl
and adding contributions from Linaro for ARM CPU-only support.
See README.txt for more info, and build instructions.
Signed-off-by: Gil Pitney <gil.pitney@linaro.org>
Diffstat (limited to 'src/core/dsp/ocl_load')
29 files changed, 10401 insertions, 0 deletions
diff --git a/src/core/dsp/ocl_load/C60_DLOAD_DYN/c60_dynamic.c b/src/core/dsp/ocl_load/C60_DLOAD_DYN/c60_dynamic.c new file mode 100644 index 0000000..545ba92 --- /dev/null +++ b/src/core/dsp/ocl_load/C60_DLOAD_DYN/c60_dynamic.c @@ -0,0 +1,200 @@ +/* +* c60_dynamic.c +* +* C6x-specific dynamic loader functionality +* +* Copyright (C) 2009-2014 Texas Instruments Incorporated - http://www.ti.com/ +* +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +*/ + +#ifdef C60_TARGET +#include "c60_elf32.h" +#include <inttypes.h> +#include "dload.h" + +/*****************************************************************************/ +/* c60_process_dynamic_tag() */ +/* */ +/* Process C6x specific dynamic tags. */ +/*****************************************************************************/ +BOOL DLDYN_c60_process_dynamic_tag(DLIMP_Dynamic_Module* dyn_module, int i) +{ + switch (dyn_module->dyntab[i].d_tag) + { + /*------------------------------------------------------------------*/ + /* DT_C6000_GSYM_OFFSET: Dynamic symbol table is partitioned into */ + /* local and global symbols. This tag has the */ + /* offset into the dynamic symbol table where */ + /* the global symbol table starts. */ + /*------------------------------------------------------------------*/ + case DT_C6000_GSYM_OFFSET: + dyn_module->gsymtab_offset = dyn_module->dyntab[i].d_un.d_val; +#if LOADER_DEBUG + if (debugging_on) + DLIF_trace("Found global symbol table: %d\n", + dyn_module->gsymtab_offset); +#endif + return TRUE; + + /*------------------------------------------------------------------*/ + /* DT_C6000_GSTR_OFFSET: Contains the offset into the dynamic */ + /* string table where the global symbol names */ + /* start. */ + /*------------------------------------------------------------------*/ + case DT_C6000_GSTR_OFFSET: + dyn_module->gstrtab_offset = dyn_module->dyntab[i].d_un.d_val; +#if LOADER_DEBUG + if (debugging_on) + DLIF_trace("Found global string table: %d\n", + dyn_module->gstrtab_offset); +#endif + return TRUE; + + /*------------------------------------------------------------------*/ + /* DT_C6000_DSBT_BASE: Contains address of DSBT in executable or */ + /* shared object. */ + /* We store the tag's location in the dynamic */ + /* module object so that we can update it */ + /* easily after the sections have been */ + /* allocated (tag value is relocated). */ + /*------------------------------------------------------------------*/ + case DT_C6000_DSBT_BASE: + dyn_module->dsbt_base_tagidx = i; + return TRUE; + + /*------------------------------------------------------------------*/ + /* DT_C6000_DSBT_INDEX: Contains specific request for a DSBT */ + /* index. If this object module doesn't get */ + /* the index it requested, then the load will */ + /* fail (object module has already assumed */ + /* that it got the DSBT index it asks for; */ + /* references to the DSBT index will not have */ + /* relocation entries associated with them). */ + /*------------------------------------------------------------------*/ + case DT_C6000_DSBT_INDEX: + dyn_module->dsbt_index = dyn_module->dyntab[i].d_un.d_val; + return TRUE; + + /*------------------------------------------------------------------*/ + /* DT_C6000_DSBT_SIZE: Contains the size of the DSBT allocated for */ + /* this object module. It must be big enough */ + /* to hold the content of the master DSBT. */ + /*------------------------------------------------------------------*/ + case DT_C6000_DSBT_SIZE: + dyn_module->dsbt_size = dyn_module->dyntab[i].d_un.d_val; + return TRUE; + + } + + return FALSE; +} + +/*****************************************************************************/ +/* DLDYN_c60_relocate_dynamic_tag_info() */ +/* */ +/* Update any target specific dynamic tag values that are associated with */ +/* a section address. Return TRUE if the tag value is successfully */ +/* updated or if the tag is not associated with a section address, and */ +/* FALSE if we can't find the sectoin associated with the tag or if the */ +/* tag type is not recognized. */ +/* */ +/*****************************************************************************/ +BOOL DLDYN_c60_relocate_dynamic_tag_info(DLIMP_Dynamic_Module *dyn_module, + int32_t i) +{ + switch (dyn_module->dyntab[i].d_tag) + { + /*---------------------------------------------------------------------*/ + /* These tags do not point to sections. */ + /*---------------------------------------------------------------------*/ + case DT_C6000_GSYM_OFFSET: + case DT_C6000_GSTR_OFFSET: + case DT_C6000_DSBT_INDEX: + case DT_C6000_DSBT_SIZE: + return TRUE; + + /*---------------------------------------------------------------------*/ + /* DT_C6000_DSBT_BASE: This tag value provides the virtual address of */ + /* the .dsbt section. We will go find the program */ + /* header entry associated with the DSBT section */ + /* and update this tag with the section's run */ + /* address. */ + /*---------------------------------------------------------------------*/ + case DT_C6000_DSBT_BASE: + return DLIMP_update_dyntag_section_address(dyn_module, i); + } + + DLIF_error(DLET_MISC, "Invalid dynamic tag encountered, %d\n", + (int)dyn_module->dyntab[i].d_tag); + return FALSE; +} + +/*****************************************************************************/ +/* c60_process_eiosabi() */ +/* */ +/* Process the EI_OSABI value. Verify that the OSABI is supported and set */ +/* any variables which depend on the OSABI. */ +/*****************************************************************************/ +BOOL DLDYN_c60_process_eiosabi(DLIMP_Dynamic_Module* dyn_module) +{ + uint8_t osabi = dyn_module->fhdr.e_ident[EI_OSABI]; + + if (dyn_module->relocatable) + { + /*-------------------------------------------------------------------*/ + /* ELFOSABI_C6000_ELFABI - C6x Baremetal ABI */ + /*-------------------------------------------------------------------*/ + if (osabi == ELFOSABI_C6000_ELFABI) + return TRUE; + +#if 0 + /*-------------------------------------------------------------------*/ + /* ELFOSABI_C6000_LINUX - C6x Linux ABI */ + /* presently unsupported */ + /*-------------------------------------------------------------------*/ + if (osabi == ELFOSABI_C6000_LINUX) + return TRUE; +#endif + } + else + { + /*-------------------------------------------------------------------*/ + /* Static executables should have an OSABI of NONE. */ + /*-------------------------------------------------------------------*/ + if (osabi == ELFOSABI_NONE) + return TRUE; + } + + return FALSE; +} + +#endif diff --git a/src/core/dsp/ocl_load/C60_DLOAD_DYN/c60_dynamic.h b/src/core/dsp/ocl_load/C60_DLOAD_DYN/c60_dynamic.h new file mode 100644 index 0000000..da99604 --- /dev/null +++ b/src/core/dsp/ocl_load/C60_DLOAD_DYN/c60_dynamic.h @@ -0,0 +1,53 @@ +/* +* c60_dynamic.h +* +* Interface into C6x-specific dynamic loader functionality +* +* Copyright (C) 2009-2014 Texas Instruments Incorporated - http://www.ti.com/ +* +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +*/ + +#ifndef DLOAD_C60_H +#define DLOAD_C60_H + +#include "dload.h" + +BOOL DLDYN_c60_process_dynamic_tag(DLIMP_Dynamic_Module* dyn_module, int i); +BOOL DLDYN_c60_process_eiosabi(DLIMP_Dynamic_Module* dyn_module); +BOOL DLDYN_c60_relocate_dynamic_tag_info(DLIMP_Dynamic_Module *dyn_module, int32_t i); + +#define T_INTSZ 32 +#define T_CHARSZ 8 +#define MEM_INC 8 +#define PTR_SZ 32 + +#endif diff --git a/src/core/dsp/ocl_load/C60_DLOAD_DYN/c60_elf32.h b/src/core/dsp/ocl_load/C60_DLOAD_DYN/c60_elf32.h new file mode 100644 index 0000000..418db17 --- /dev/null +++ b/src/core/dsp/ocl_load/C60_DLOAD_DYN/c60_elf32.h @@ -0,0 +1,160 @@ +/* +* c60_elf32.h +* +* C6x-specific data structures for 32-bit ELF object format files. +* +* Copyright (C) 2009-2014 Texas Instruments Incorporated - http://www.ti.com/ +* +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +*/ + +#ifndef C60_ELF32_H +#define C60_ELF32_H + +#include "elf32.h" + +/*---------------------------------------------------------------------------*/ +/* C6x specific EI_OSABI values */ +/*---------------------------------------------------------------------------*/ +enum +{ + ELFOSABI_C6000_ELFABI = 64, /* C6X Baremetal OSABI */ + ELFOSABI_C6000_LINUX = 65 /* C6X Linux OSABI */ +}; + +/*---------------------------------------------------------------------------*/ +/* File Header Flags (value of "e_flags") */ +/*---------------------------------------------------------------------------*/ +enum +{ + EF_C6000_REL = 0x01 /* Contains static relocations. A ET_EXEC or */ + /* ET_DYN file w/ this flag set can be */ + /* treated as ET_REL during static linking. */ +}; + +/*---------------------------------------------------------------------------*/ +/* Segment Types (value of "p_type") */ +/*---------------------------------------------------------------------------*/ +enum +{ + PT_C6000_PHATTRS = 0x70000000 /* Extended Program Header Attributes*/ +}; + +/*---------------------------------------------------------------------------*/ +/* C6x specific section types */ +/*---------------------------------------------------------------------------*/ +enum +{ + + /*------------------------------------------------------------------------*/ + /* Section types defined by the C6x ELFABI. */ + /* Note: ABI defined section type should be named SHT_C6000_xxx */ + /*------------------------------------------------------------------------*/ + SHT_C6000_UNWIND = 0x70000001, /* Exception Index Table */ + SHT_C6000_PREEMPTMAP = 0x70000002, /* Pre-emption Map */ + + SHT_C6000_ATTRIBUTES = 0x70000003, /* Obj File Compatability Attributes */ + + /*------------------------------------------------------------------------*/ + /* The following section types are not part of C6x ABI. As per the ABI, */ + /* the processor specific values not defined in the ABI are reserved for */ + /* future use. Here we reserve the range 0x7F000000 through 0x7FFFFFFFF */ + /* for the TI specific processor section types. */ + /* Note: TI specific section type should be named SHT_TI_xxx */ + /*------------------------------------------------------------------------*/ + SHT_TI_ICODE = 0x7F000000, /* ICODE representation */ + SHT_TI_XREF = 0x7F000001, /* Symbol cross reference */ + SHT_TI_HANDLER = 0x7F000002, /* Handler function table */ + SHT_TI_INITINFO = 0x7F000003, /* Info for C auto-init of variables */ + SHT_TI_PHATTRS = 0x7F000004 /* Extended Program Header Attributes*/ +}; + +/*****************************************************************************/ +/* C6x-Specific Dynamic Array Tags (C6x ELF ABI Section ??? - AEGUPD) */ +/* NOTE: */ +/* As per GABI a tag whose value is even number indicates a dynamic tag */ +/* that uses d_ptr. Odd number indicates the use of d_val or doesn't use */ +/* neither d_val nor d_ptr. */ +/*****************************************************************************/ +enum +{ + /*------------------------------------------------------------------------*/ + /* OSABI specific tags: */ + /* From 0x6000000D thru 0x6FFFF000 */ + /*------------------------------------------------------------------------*/ + DT_C6000_GSYM_OFFSET = 0x6000000D, /* d_val -- OSABI Specific -- */ + DT_C6000_GSTR_OFFSET = 0x6000000F, /* d_val -- OSABI Specific -- */ + + /*------------------------------------------------------------------------*/ + /* Processor specific tags: */ + /* From 0x70000000 thru 0x7FFFFFFF */ + /*------------------------------------------------------------------------*/ + DT_C6000_DSBT_BASE = 0x70000000, /* d_ptr -- Platform Specific -- */ + DT_C6000_DSBT_SIZE = 0x70000001, /* d_val -- Platform Specific -- */ + DT_C6000_PREEMPTMAP = 0x70000002, /* d_ptr -- Platform Specific -- */ + DT_C6000_DSBT_INDEX = 0x70000003 /* d_val -- Platform Specific -- */ +}; + +/*---------------------------------------------------------------------------*/ +/* C6x Dynamic Relocation Types */ +/*---------------------------------------------------------------------------*/ +typedef enum +{ + R_C6000_NONE = 0, + R_C6000_ABS32 = 1, + R_C6000_ABS16 = 2, + R_C6000_ABS8 = 3, + R_C6000_PCR_S21 = 4, + R_C6000_PCR_S12 = 5, + R_C6000_PCR_S10 = 6, + R_C6000_PCR_S7 = 7, + R_C6000_ABS_S16 = 8, + R_C6000_ABS_L16 = 9, + R_C6000_ABS_H16 = 10, + R_C6000_SBR_U15_B = 11, + R_C6000_SBR_U15_H = 12, + R_C6000_SBR_U15_W = 13, + R_C6000_SBR_S16 = 14, + R_C6000_SBR_L16_B = 15, + R_C6000_SBR_L16_H = 16, + R_C6000_SBR_L16_W = 17, + R_C6000_SBR_H16_B = 18, + R_C6000_SBR_H16_H = 19, + R_C6000_SBR_H16_W = 20, + R_C6000_SBR_GOT_U15_W = 21, + R_C6000_SBR_GOT_L16_W = 22, + R_C6000_SBR_GOT_H16_W = 23, + R_C6000_DSBT_INDEX = 24, + R_C6000_PREL31 = 25, + R_C6000_COPY = 26 +}C60_RELOC_TYPE; + +#endif /* C60_ELF32_H */ diff --git a/src/core/dsp/ocl_load/C60_DLOAD_REL/c60_reloc.c b/src/core/dsp/ocl_load/C60_DLOAD_REL/c60_reloc.c new file mode 100644 index 0000000..3c79e35 --- /dev/null +++ b/src/core/dsp/ocl_load/C60_DLOAD_REL/c60_reloc.c @@ -0,0 +1,1101 @@ +/* +* c60_reloc.c +* +* Process C6x-specific dynamic relocations for core dynamic loader. +* +* Copyright (C) 2009-2014 Texas Instruments Incorporated - http://www.ti.com/ +* +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +*/ + +#include <limits.h> +#include "relocate.h" +#include "symtab.h" +#include "c60_elf32.h" +#include "dload_api.h" +#include "util.h" +#include "dload_endian.h" +#include "c60_reloc.h" + +#define MASK(n,s) (((1 << n) - 1) << s) + +/*---------------------------------------------------------------------------*/ +/* C6x Relocations Supported */ +/* */ +/* See the C6000 ELF ABI Specification for more details. */ +/* */ +/* R_C6000_ABS32 | .field X,32 */ +/* R_C6000_ABS16 | .field X,16 */ +/* R_C6000_ABS8 | .field X,8 */ +/* R_C6000_PCR_S21 | B foo */ +/* CALLP foo, B3 */ +/* R_C6000_PCR_S12 | BNOP foo */ +/* R_C6000_PCR_S10 | BPOS foo, A10 */ +/* BDEC foo, A1 */ +/* R_C6000_PCR_S7 | ADDKPC foo, B3, 4 */ +/* R_C6000_ABS_S16 | MVK sym, A0 */ +/* R_C6000_ABS_L16 | MVKL sym, A0 */ +/* MVKLH sym, A0 */ +/* R_C6000_ABS_H16 | MVKH sym, A0 */ +/* R_C6000_SBR_U15_B | LDB *+B14(sym), A1 */ +/* ADDAB B14, sym, A1 */ +/* R_C6000_SBR_U15_H | LDH *+B14(sym), A1 */ +/* ADDAH B14, sym, A1 */ +/* R_C6000_SBR_U15_W | LDW *+B14(sym), A1 */ +/* ADDAW B14, sym, A1 */ +/* R_C6000_SBR_S16 | MVK sym-$bss, A0 */ +/* R_C6000_SBR_L16_B | MVKL (sym-$bss), A0 */ +/* R_C6000_SBR_L16_H | MVKL (sym-$bss)/2,A0 */ +/* R_C6000_SBR_L16_W | MVKL (sym-$bss)/4,A0 */ +/* R_C6000_SBR_H16_B | MVKH (sym-$bss), A0 */ +/* R_C6000_SBR_H16_H | MVKH (sym-$bss)/2,A0 */ +/* R_C6000_SBR_H16_W | MVKH (sym-$bss)/4,A0 */ +/* R_C6000_SBR_GOT_U15_W | LDW *+B14[GOT(sym)],A0 */ +/* R_C6000_SBR_GOT_L16_W | MVKL $DPR_GOT(sym), A0 */ +/* R_C6000_SBR_GOT_H16_W | MVKH $DPR_GOT(sym), A0 */ +/* R_C6000_DSBT_INDEX | LDW *+B14[$DSBT_index()], DP */ +/* */ +/*---------------------------------------------------------------------------*/ + +/*****************************************************************************/ +/* WRITE_RELOC_R() - Perform a relocation into a buffered segment. */ +/*****************************************************************************/ +static void write_reloc_r(uint8_t* buffered_segment, + uint32_t segment_offset, + int r_type, uint32_t r) +{ + uint32_t* rel_field_ptr = (uint32_t*)(buffered_segment + segment_offset); + +#if LOADER_DEBUG + /*------------------------------------------------------------------------*/ + /* Print some details about the relocation we are about to process. */ + /*------------------------------------------------------------------------*/ + if(debugging_on) + { + DLIF_trace("RWRT: segment_offset: %d\n", segment_offset); + DLIF_trace("RWRT: buffered_segment: 0x%x\n", + (uint32_t)buffered_segment); + DLIF_trace("RWRT: rel_field_ptr: 0x%x\n", (uint32_t)rel_field_ptr); + DLIF_trace("RWRT: result: 0x%x\n", r); + } +#endif + + + /*------------------------------------------------------------------------*/ + /* Given the relocation type, carry out relocation into a 4 byte packet */ + /* within the buffered segment. */ + /*------------------------------------------------------------------------*/ + switch(r_type) + { + case R_C6000_ABS32: + *rel_field_ptr = r; + break; + case R_C6000_PREL31: + *rel_field_ptr = (*rel_field_ptr & ~MASK(30,0)) | r; + break; + case R_C6000_ABS16: + *((uint16_t*)(buffered_segment + segment_offset)) = r; + break; + case R_C6000_ABS8: + *((uint8_t*)(buffered_segment + segment_offset)) = r; + break; + case R_C6000_PCR_S21: + *rel_field_ptr = (*rel_field_ptr & ~MASK(21,7)) | (r << 7); + break; + case R_C6000_PCR_S12: + *rel_field_ptr = (*rel_field_ptr & ~MASK(12,16)) | (r << 16); + break; + case R_C6000_PCR_S10: + *rel_field_ptr = (*rel_field_ptr & ~MASK(10,13)) | (r << 13); + break; + case R_C6000_PCR_S7: + *rel_field_ptr = (*rel_field_ptr & ~MASK(7,16)) | (r << 16); + break; + + case R_C6000_ABS_S16: + *rel_field_ptr = (*rel_field_ptr & ~MASK(16,7)) | (r << 7); + break; + case R_C6000_ABS_L16: + *rel_field_ptr = (*rel_field_ptr & ~MASK(16,7)) | (r << 7); + break; + case R_C6000_ABS_H16: + *rel_field_ptr = (*rel_field_ptr & ~MASK(16,7)) | (r << 7); + break; + + case R_C6000_SBR_U15_B: + *rel_field_ptr = (*rel_field_ptr & ~MASK(15,8)) | (r << 8); + break; + case R_C6000_SBR_U15_H: + *rel_field_ptr = (*rel_field_ptr & ~MASK(15,8)) | (r << 8); + break; + case R_C6000_SBR_U15_W: + case R_C6000_DSBT_INDEX: + *rel_field_ptr = (*rel_field_ptr & ~MASK(15,8)) | (r << 8); + break; + + case R_C6000_SBR_S16: + case R_C6000_SBR_L16_B: + case R_C6000_SBR_L16_H: + case R_C6000_SBR_L16_W: + case R_C6000_SBR_H16_B: + case R_C6000_SBR_H16_H: + case R_C6000_SBR_H16_W: + *rel_field_ptr = (*rel_field_ptr & ~MASK(16,7)) | (r << 7); + break; + + /*---------------------------------------------------------------------*/ + /* Linux "import-as-own" copy relocations are not yet supported. */ + /*---------------------------------------------------------------------*/ + case R_C6000_COPY: + + default: + DLIF_error(DLET_RELOC, + "write_reloc_r called with invalid relocation type!\n"); + } + +#if LOADER_DEBUG + if (debugging_on) + DLIF_trace("reloc_field 0x%x\n", *rel_field_ptr); +#endif +} + +/*****************************************************************************/ +/* PACK_RESULT() - Pack the result of a relocation calculation for storage */ +/* in the relocation field. */ +/*****************************************************************************/ +static int32_t pack_result(int32_t unpacked_result, int r_type) +{ + switch(r_type) + { + case R_C6000_ABS32: + case R_C6000_ABS16: + case R_C6000_ABS8: + case R_C6000_ABS_S16: + case R_C6000_ABS_L16: + case R_C6000_SBR_U15_B: + case R_C6000_SBR_S16: + case R_C6000_SBR_L16_B: + return unpacked_result; + + case R_C6000_SBR_U15_H: + case R_C6000_SBR_L16_H: + case R_C6000_PREL31: + return unpacked_result >> 1; + + case R_C6000_PCR_S21: + case R_C6000_PCR_S12: + case R_C6000_PCR_S10: + case R_C6000_PCR_S7: + case R_C6000_SBR_U15_W: + case R_C6000_SBR_L16_W: + case R_C6000_DSBT_INDEX: + return unpacked_result >> 2; + + case R_C6000_ABS_H16: + case R_C6000_SBR_H16_B: + return unpacked_result >> 16; + + case R_C6000_SBR_H16_H: + return unpacked_result >> 17; + + case R_C6000_SBR_H16_W: + return unpacked_result >> 18; + + /*---------------------------------------------------------------------*/ + /* Linux "import-as-own" copy relocations are not yet supported. */ + /*---------------------------------------------------------------------*/ + case R_C6000_COPY: + + default: + DLIF_error(DLET_RELOC, + "pack_result called with invalid relocation type!\n"); + return 0; + } +} + +/*****************************************************************************/ +/* MASK_RESULT() - Mask the result of a relocation calculation so that it */ +/* fits the size of the relocation type's field. */ +/*****************************************************************************/ +static int32_t mask_result(int32_t unmasked_result, int r_type) +{ + switch(r_type) + { + case R_C6000_ABS8: + return unmasked_result & 0xFF; + + case R_C6000_ABS32: + return unmasked_result; + + case R_C6000_ABS16: + case R_C6000_ABS_S16: + case R_C6000_ABS_L16: + case R_C6000_ABS_H16: + case R_C6000_SBR_S16: + case R_C6000_SBR_L16_B: + case R_C6000_SBR_L16_H: + case R_C6000_SBR_L16_W: + case R_C6000_SBR_H16_B: + case R_C6000_SBR_H16_H: + case R_C6000_SBR_H16_W: + return unmasked_result & 0xFFFF; + + case R_C6000_PCR_S21: + return unmasked_result & 0x1FFFFF; + + case R_C6000_PCR_S12: + return unmasked_result & 0xFFF; + + case R_C6000_PCR_S10: + return unmasked_result & 0x3FF; + + case R_C6000_PCR_S7: + return unmasked_result & 0x7F; + + case R_C6000_SBR_U15_B: + case R_C6000_SBR_U15_H: + case R_C6000_SBR_U15_W: + case R_C6000_DSBT_INDEX: + return unmasked_result & 0x7FFF; + + case R_C6000_PREL31: + return unmasked_result & 0x7FFFFFFF; + + /*---------------------------------------------------------------------*/ + /* Linux "import-as-own" copy relocations are not yet supported. */ + /*---------------------------------------------------------------------*/ + case R_C6000_COPY: + + default: + DLIF_error(DLET_RELOC, + "mask_result called with invalid relocation type!\n"); + return 0; + } +} + +/*****************************************************************************/ +/* REL_OVERFLOW() */ +/* */ +/* Check relocation value against the range associated with a given */ +/* relocation type field size and signedness. */ +/* */ +/*****************************************************************************/ +static BOOL rel_overflow(C60_RELOC_TYPE r_type, int32_t reloc_value) +{ + /*------------------------------------------------------------------------*/ + /* Select appropriate range check based on relocation type. */ + /*------------------------------------------------------------------------*/ + switch(r_type) + { + case R_C6000_ABS16: return ((reloc_value > 65535) || + (reloc_value < -32768)); + case R_C6000_ABS8: return ((reloc_value > 255) || + (reloc_value < -128)); + case R_C6000_PCR_S21: return ((reloc_value >= 0x400000) || + (reloc_value < -0x400000)); + case R_C6000_PCR_S12: return ((reloc_value >= 0x2000) || + (reloc_value < -0x2000)); + case R_C6000_PCR_S10: return ((reloc_value >= 0x800) || + (reloc_value < -0x800)); + case R_C6000_PCR_S7: return ((reloc_value >= 0x100) || + (reloc_value < -0x100)); + case R_C6000_SBR_S16: + case R_C6000_ABS_S16: return ((reloc_value >= 0x8000) || + (reloc_value < -0x8000)); + case R_C6000_SBR_U15_B: return (((uint32_t)reloc_value) >= 0x8000); + case R_C6000_SBR_U15_H: return (((uint32_t)reloc_value) >= 0xFFFF); + case R_C6000_DSBT_INDEX: + case R_C6000_SBR_U15_W: return (((uint32_t)reloc_value) >= 0x1FFFD); + + + /*---------------------------------------------------------------------*/ + /* Some relocation types suppress overflow checking at link-time. */ + /*---------------------------------------------------------------------*/ + case R_C6000_ABS_L16: + case R_C6000_ABS_H16: + case R_C6000_SBR_L16_B: + case R_C6000_SBR_L16_H: + case R_C6000_SBR_L16_W: + case R_C6000_SBR_H16_B: + case R_C6000_SBR_H16_H: + case R_C6000_SBR_H16_W: + return 0; + + /*---------------------------------------------------------------------*/ + /* 32-bit relocation field values are not checked for overflow. */ + /*---------------------------------------------------------------------*/ + case R_C6000_ABS32: + case R_C6000_PREL31: + return 0; + + /*---------------------------------------------------------------------*/ + /* If relocation type did not appear in the above switch, then we */ + /* didn't expect to see it. */ + /*---------------------------------------------------------------------*/ + default: + DLIF_error(DLET_RELOC, + "rel_overflow called with invalid relocation type!\n"); + } + + return 1; +} + +#if LOADER_DEBUG || LOADER_PROFILE +extern int DLREL_relocations; +extern time_t DLREL_total_reloc_time; +#endif + +/*****************************************************************************/ +/* RELOC_DO() - Process a single relocation entry. */ +/*****************************************************************************/ +static void reloc_do(C60_RELOC_TYPE r_type, + uint32_t segment_vaddr, + uint8_t *segment_buffer, + uint32_t addend, + uint32_t symval, + uint32_t spc, + int wrong_endian, + uint32_t base_pointer, + int32_t dsbt_index) +{ + int32_t reloc_value = 0; + +#if LOADER_DEBUG || LOADER_PROFILE + /*------------------------------------------------------------------------*/ + /* In debug mode, keep a count of the number of relocations processed. */ + /* In profile mode, start the clock on a given relocation. */ + /*------------------------------------------------------------------------*/ + int start_time = 0; + if (debugging_on || profiling_on) + { + DLREL_relocations++; + if (profiling_on) start_time = clock(); + } +#endif + + /*------------------------------------------------------------------------*/ + /* Calculate the relocation value according to the rules associated with */ + /* the given relocation type. */ + /*------------------------------------------------------------------------*/ + switch(r_type) + { + /*---------------------------------------------------------------------*/ + /* Straight-Up Address relocations (address references). */ + /*---------------------------------------------------------------------*/ + case R_C6000_ABS32: + case R_C6000_ABS16: + case R_C6000_ABS8: + case R_C6000_ABS_S16: + case R_C6000_ABS_L16: + case R_C6000_ABS_H16: + reloc_value = symval + addend; + break; + + /*---------------------------------------------------------------------*/ + /* PC-Relative relocations (calls and branches). */ + /*---------------------------------------------------------------------*/ + case R_C6000_PCR_S21: + case R_C6000_PCR_S12: + case R_C6000_PCR_S10: + case R_C6000_PCR_S7: + { + /*------------------------------------------------------------------*/ + /* Add SPC to segment address to get the PC. Mask for exec-packet */ + /* boundary. */ + /*------------------------------------------------------------------*/ + int32_t opnd_p = (spc + segment_vaddr) & 0xffffffe0; + reloc_value = symval + addend - opnd_p; + break; + } + + /*---------------------------------------------------------------------*/ + /* "Place"-relative relocations (TDEH). */ + /*---------------------------------------------------------------------*/ + /* These relocations occur in data and refer to a label that occurs */ + /* at some signed 32-bit offset from the place where the relocation */ + /* occurs. */ + /*---------------------------------------------------------------------*/ + case R_C6000_PREL31: + { + /*------------------------------------------------------------------*/ + /* Compute location of relocation entry and subtract it from the */ + /* address of the location being referenced (it is computed very */ + /* much like a PC-relative relocation, but it occurs in data and */ + /* is called a "place"-relative relocation). */ + /*------------------------------------------------------------------*/ + /* If this is an Elf32_Rel type relocation, then addend is assumed */ + /* to have been scaled when it was unpacked (field << 1). */ + /*------------------------------------------------------------------*/ + /* For Elf32_Rela type relocations the addend is assumed to be a */ + /* signed 32-bit integer value. */ + /*------------------------------------------------------------------*/ + /* Offset is not fetch-packet relative; doesn't need to be masked. */ + /*------------------------------------------------------------------*/ + int32_t opnd_p = (spc + segment_vaddr); + reloc_value = symval + addend - opnd_p; + break; + } + + /*---------------------------------------------------------------------*/ + /* Static-Base Relative relocations (near-DP). */ + /*---------------------------------------------------------------------*/ + case R_C6000_SBR_U15_B: + case R_C6000_SBR_U15_H: + case R_C6000_SBR_U15_W: + case R_C6000_SBR_S16: + case R_C6000_SBR_L16_B: + case R_C6000_SBR_L16_H: + case R_C6000_SBR_L16_W: + case R_C6000_SBR_H16_B: + case R_C6000_SBR_H16_H: + case R_C6000_SBR_H16_W: + reloc_value = symval + addend - base_pointer; + break; + + /*---------------------------------------------------------------------*/ + /* R_C6000_DSBT_INDEX - uses value assigned by the dynamic loader to */ + /* be the DSBT index for this module as a scaled offset when */ + /* referencing the DSBT. The DSBT base address is in symval and the */ + /* static base is in base_pointer. DP-relative offset to slot in */ + /* DSBT is the offset of the DSBT relative to the DP plus the */ + /* scaled DSBT index into the DSBT. */ + /*---------------------------------------------------------------------*/ + case R_C6000_DSBT_INDEX: + reloc_value = ((symval + addend) - base_pointer) + (dsbt_index << 2); + break; + + /*---------------------------------------------------------------------*/ + /* Linux "import-as-own" copy relocation: after DSO initialization, */ + /* copy the named object from the DSO into the executable's BSS */ + /*---------------------------------------------------------------------*/ + /* Linux "import-as-own" copy relocations are not yet supported. */ + /*---------------------------------------------------------------------*/ + case R_C6000_COPY: + + /*---------------------------------------------------------------------*/ + /* Unrecognized relocation type. */ + /*---------------------------------------------------------------------*/ + default: + DLIF_error(DLET_RELOC, + "reloc_do called with invalid relocation type!\n"); + break; + } + + /*------------------------------------------------------------------------*/ + /* Overflow checking. Is relocation value out of range for the size and */ + /* type of the current relocation? */ + /*------------------------------------------------------------------------*/ + if (rel_overflow(r_type, reloc_value)) + DLIF_error(DLET_RELOC, "relocation overflow!\n"); + + /*------------------------------------------------------------------------*/ + /* Move relocation value to appropriate offset for relocation field's */ + /* location. */ + /*------------------------------------------------------------------------*/ + reloc_value = pack_result(reloc_value, r_type); + + /*------------------------------------------------------------------------*/ + /* Mask packed result to the size of the relocation field. */ + /*------------------------------------------------------------------------*/ + reloc_value = mask_result(reloc_value, r_type); + + /*------------------------------------------------------------------------*/ + /* If necessary, Swap endianness of data at relocation address. */ + /*------------------------------------------------------------------------*/ + if (wrong_endian) + DLIMP_change_endian32((int32_t*)(segment_buffer + spc)); + + /*------------------------------------------------------------------------*/ + /* Write the relocated 4-byte packet back to the segment buffer. */ + /*------------------------------------------------------------------------*/ + write_reloc_r(segment_buffer, spc, r_type, reloc_value); + + /*------------------------------------------------------------------------*/ + /* Change endianness of segment address back to original. */ + /*------------------------------------------------------------------------*/ + if (wrong_endian) + DLIMP_change_endian32((int32_t*)(segment_buffer + spc)); + +#if LOADER_DEBUG || LOADER_PROFILE + /*------------------------------------------------------------------------*/ + /* In profile mode, add elapsed time for this relocation to total time */ + /* spent doing relocations. */ + /*------------------------------------------------------------------------*/ + if (profiling_on) + DLREL_total_reloc_time += (clock() - start_time); + if (debugging_on) + DLIF_trace("reloc_value = 0x%x\n", reloc_value); +#endif +} + +/*****************************************************************************/ +/* REL_UNPACK_ADDEND() */ +/* */ +/* Unpack addend value from the relocation field. */ +/* */ +/*****************************************************************************/ +static void rel_unpack_addend(C60_RELOC_TYPE r_type, + uint8_t *address, + uint32_t *addend) +{ + /*------------------------------------------------------------------------*/ + /* C6000 does not support Elf32_Rel type relocations in the dynamic */ + /* loader core. We will emit an internal error and abort until this */ + /* support is added. I abort here because this is necessarily a target- */ + /* specific part of the relocation infrastructure. */ + /*------------------------------------------------------------------------*/ + *addend = 0; + + DLIF_error(DLET_RELOC, + "Internal Error: unpacking addend values from the relocation " + "field is not supported in the C6000 dynamic loader at this " + "time; aborting\n"); + DLIF_exit(1); +} + +/*****************************************************************************/ +/* REL_SWAP_ENDIAN() */ +/* */ +/* Return TRUE if we should change the endianness of a relocation field. */ +/* */ +/*****************************************************************************/ +static BOOL rel_swap_endian(DLIMP_Dynamic_Module *dyn_module, + C60_RELOC_TYPE r_type) +{ + if (dyn_module->wrong_endian) return TRUE; + + return FALSE; +} + +/*****************************************************************************/ +/* REL_CHANGE_ENDIAN() */ +/* */ +/* Change the endianness of the relocation field at the specified address */ +/* in the segment's data. */ +/* */ +/*****************************************************************************/ +static void rel_change_endian(C60_RELOC_TYPE r_type, uint8_t *address) +{ + /*------------------------------------------------------------------------*/ + /* On C6000, all instructions are 32-bits wide. */ + /*------------------------------------------------------------------------*/ + DLIMP_change_endian32((int32_t *)address); +} + +/*****************************************************************************/ +/* READ_REL_TABLE() */ +/* */ +/* Read in an Elf32_Rel type relocation table. This function allocates */ +/* host memory for the table. */ +/* */ +/*****************************************************************************/ +static void read_rel_table(struct Elf32_Rel **rel_table, + int32_t table_offset, + uint32_t relnum, uint32_t relent, + LOADER_FILE_DESC *fd, BOOL wrong_endian) +{ + if (relnum == 0) { *rel_table = NULL; return; } + + *rel_table = (struct Elf32_Rel *)DLIF_malloc(relnum * relent); + DLIF_fseek(fd, table_offset, LOADER_SEEK_SET); + DLIF_fread(*rel_table, relnum, relent, fd); + + if (wrong_endian) + { + int i; + for (i = 0; i < relnum; i++) + DLIMP_change_rel_endian(*rel_table + i); + } +} + +/*****************************************************************************/ +/* PROCESS_REL_TABLE() */ +/* */ +/* Process table of Elf32_Rel type relocations. */ +/* */ +/*****************************************************************************/ +static void process_rel_table(DLOAD_HANDLE handle, + DLIMP_Loaded_Segment* seg, + struct Elf32_Rel *rel_table, + uint32_t relnum, + int32_t *start_relidx, + uint32_t ti_static_base, + DLIMP_Dynamic_Module* dyn_module) +{ + Elf32_Addr seg_start_addr = seg->input_vaddr; + Elf32_Addr seg_end_addr = seg_start_addr + seg->phdr.p_memsz; + BOOL found = FALSE; + int32_t relidx = *start_relidx; + + /*------------------------------------------------------------------------*/ + /* If the given start reloc index is out of range, then start from the */ + /* beginning of the given table. */ + /*------------------------------------------------------------------------*/ + if (relidx >= relnum) relidx = 0; + + /*------------------------------------------------------------------------*/ + /* Spin through Elf32_Rel type relocation table. */ + /*------------------------------------------------------------------------*/ + for ( ; relidx < relnum; relidx++) + { + /*---------------------------------------------------------------------*/ + /* If the relocation offset falls within the segment, process it. */ + /*---------------------------------------------------------------------*/ + if (rel_table[relidx].r_offset >= seg_start_addr && + rel_table[relidx].r_offset < seg_end_addr) + { + Elf32_Addr r_symval = 0; + C60_RELOC_TYPE r_type = + (C60_RELOC_TYPE)ELF32_R_TYPE(rel_table[relidx].r_info); + int32_t r_symid = ELF32_R_SYM(rel_table[relidx].r_info); + + uint8_t *reloc_address = NULL; + uint32_t pc = 0; + uint32_t addend = 0; + + BOOL change_endian = FALSE; + + found = TRUE; + + /*------------------------------------------------------------------*/ + /* If symbol definition is not found, don't do the relocation. */ + /* An error is generated by the lookup function. */ + /*------------------------------------------------------------------*/ + if (!DLSYM_canonical_lookup(handle, r_symid, dyn_module, &r_symval)) + continue; + + /*------------------------------------------------------------------*/ + /* Addend value is stored in the relocation field. */ + /* We'll need to unpack it from the data for the segment that is */ + /* currently being relocated. */ + /*------------------------------------------------------------------*/ + pc = rel_table[relidx].r_offset - seg->input_vaddr; + reloc_address = (uint8_t *)seg->host_address + pc; + + change_endian = rel_swap_endian(dyn_module, r_type); + if (change_endian) + rel_change_endian(r_type, reloc_address); + + rel_unpack_addend( + (C60_RELOC_TYPE)ELF32_R_TYPE(rel_table[relidx].r_info), + reloc_address, &addend); + + /*------------------------------------------------------------------*/ + /* Perform actual relocation. This is a really wide function */ + /* interface and could do with some encapsulation. */ + /*------------------------------------------------------------------*/ + reloc_do(r_type, + seg->phdr.p_vaddr, + seg->host_address, + addend, + r_symval, + pc, + dyn_module->wrong_endian, + ti_static_base, + dyn_module->dsbt_index); + + } + + else if (found) + break; + } +} + +/*****************************************************************************/ +/* READ_RELA_TABLE() */ +/* */ +/* Read in an Elf32_Rela type relocation table. This function allocates */ +/* host memory for the table. */ +/* */ +/*****************************************************************************/ +static void read_rela_table(struct Elf32_Rela **rela_table, + int32_t table_offset, + uint32_t relanum, uint32_t relaent, + LOADER_FILE_DESC *fd, BOOL wrong_endian) +{ + if (relanum == 0) { *rela_table = NULL; return; } + *rela_table = (struct Elf32_Rela *)DLIF_malloc(relanum * relaent); + DLIF_fseek(fd, table_offset, LOADER_SEEK_SET); + DLIF_fread(*rela_table, relanum, relaent, fd); + + if (wrong_endian) + { + int i; + for (i = 0; i < relanum; i++) + DLIMP_change_rela_endian(*rela_table + i); + } +} + +/*****************************************************************************/ +/* PROCESS_RELA_TABLE() */ +/* */ +/* Process a table of Elf32_Rela type relocations. */ +/* */ +/*****************************************************************************/ +static void process_rela_table(DLOAD_HANDLE handle, + DLIMP_Loaded_Segment *seg, + struct Elf32_Rela *rela_table, + uint32_t relanum, + int32_t *start_relidx, + uint32_t ti_static_base, + DLIMP_Dynamic_Module *dyn_module) +{ + Elf32_Addr seg_start_addr = seg->input_vaddr; + Elf32_Addr seg_end_addr = seg_start_addr + seg->phdr.p_memsz; + BOOL found = FALSE; + int32_t relidx = *start_relidx; + + /*-----------------------------------------------------------------------*/ + /* If the given start reloc index is out of range, then start from */ + /* the beginning of the given table. */ + /*-----------------------------------------------------------------------*/ + if (relidx > relanum) relidx = 0; + + /*-----------------------------------------------------------------------*/ + /* Spin through RELA relocation table. */ + /*-----------------------------------------------------------------------*/ + for ( ; relidx < relanum; relidx++) + { + /*-------------------------------------------------------------------*/ + /* If the relocation offset falls within the segment, process it. */ + /*-------------------------------------------------------------------*/ + if (rela_table[relidx].r_offset >= seg_start_addr && + rela_table[relidx].r_offset < seg_end_addr) + { + Elf32_Addr r_symval; + C60_RELOC_TYPE r_type = + (C60_RELOC_TYPE)ELF32_R_TYPE(rela_table[relidx].r_info); + int32_t r_symid = ELF32_R_SYM(rela_table[relidx].r_info); + + found = TRUE; + + /*---------------------------------------------------------------*/ + /* If symbol definition is not found, don't do the relocation. */ + /* An error is generated by the lookup function. */ + /*---------------------------------------------------------------*/ + if (!DLSYM_canonical_lookup(handle, r_symid, dyn_module, &r_symval)) + continue; + + /*---------------------------------------------------------------*/ + /* Perform actual relocation. This is a really wide function */ + /* interface and could do with some encapsulation. */ + /*---------------------------------------------------------------*/ + reloc_do(r_type, + seg->phdr.p_vaddr, + seg->host_address, + rela_table[relidx].r_addend, + r_symval, + rela_table[relidx].r_offset - seg->input_vaddr, + dyn_module->wrong_endian, + ti_static_base, + dyn_module->dsbt_index); + } + + else if (found) + break; + } +} + +/*****************************************************************************/ +/* PROCESS_GOT_RELOCS() */ +/* */ +/* Process all GOT relocations. It is possible to have both Elf32_Rel */ +/* and Elf32_Rela type relocations in the same file, so we handle tham */ +/* both. */ +/* */ +/*****************************************************************************/ +static void process_got_relocs(DLOAD_HANDLE handle, + struct Elf32_Rel* rel_table, uint32_t relnum, + struct Elf32_Rela* rela_table, uint32_t relanum, + DLIMP_Dynamic_Module* dyn_module) +{ + DLIMP_Loaded_Segment *seg = + (DLIMP_Loaded_Segment*)(dyn_module->loaded_module->loaded_segments.buf); + uint32_t num_segs = dyn_module->loaded_module->loaded_segments.size; + int32_t rel_relidx = 0; + int32_t rela_relidx = 0; + uint32_t seg_idx = 0; + uint32_t ti_static_base = 0; + + /*------------------------------------------------------------------------*/ + /* Get the value of the static base (__TI_STATIC_BASE) which will be */ + /* passed into the relocation table processing functions. */ + /*------------------------------------------------------------------------*/ + if (!DLSYM_lookup_local_symtab("__TI_STATIC_BASE", dyn_module->symtab, + dyn_module->symnum, &ti_static_base)) + DLIF_error(DLET_RELOC, "Could not resolve value of __TI_STATIC_BASE\n"); + + /*------------------------------------------------------------------------*/ + /* Process relocations segment by segment. */ + /*------------------------------------------------------------------------*/ + for (seg_idx = 0; seg_idx < num_segs; seg_idx++) + { + /*---------------------------------------------------------------------*/ + /* Relocations should not occur in uninitialized segments. */ + /*---------------------------------------------------------------------*/ + if (!seg[seg_idx].phdr.p_filesz) continue; + + if (rela_table) + process_rela_table(handle, (seg + seg_idx), + rela_table, relanum, &rela_relidx, + ti_static_base, dyn_module); + + if (rel_table) + process_rel_table(handle, (seg + seg_idx), + rel_table, relnum, &rel_relidx, + ti_static_base, dyn_module); + } +} + +/*****************************************************************************/ +/* PROCESS_PLTGOT_RELOCS() */ +/* */ +/* Process all PLTGOT relocation entries. The PLTGOT relocation table */ +/* can be either Elf32_Rel or Elf32_Rela type. All PLTGOT relocations */ +/* ar guaranteed to belong to the same segment. */ +/* */ +/*****************************************************************************/ +static void process_pltgot_relocs(DLOAD_HANDLE handle, + void* plt_reloc_table, + int reltype, + uint32_t pltnum, + DLIMP_Dynamic_Module* dyn_module) +{ + Elf32_Addr r_offset = (reltype == DT_REL) ? + ((struct Elf32_Rel *)plt_reloc_table)->r_offset : + ((struct Elf32_Rela *)plt_reloc_table)->r_offset; + + DLIMP_Loaded_Segment* seg = + (DLIMP_Loaded_Segment*)(dyn_module->loaded_module->loaded_segments.buf); + + uint32_t num_segs = dyn_module->loaded_module->loaded_segments.size; + int32_t plt_relidx = 0; + uint32_t seg_idx = 0; + uint32_t ti_static_base = 0; + + /*------------------------------------------------------------------------*/ + /* Get the value of the static base (__TI_STATIC_BASE) which will be */ + /* passed into the relocation table processing functions. */ + /*------------------------------------------------------------------------*/ + if (!DLSYM_lookup_local_symtab("__TI_STATIC_BASE", dyn_module->symtab, + dyn_module->symnum, &ti_static_base)) + DLIF_error(DLET_RELOC, "Could not resolve value of __TI_STATIC_BASE\n"); + + /*------------------------------------------------------------------------*/ + /* For each segment s, check if the relocation falls within s. If so, */ + /* then all other relocations are guaranteed to fall with s. Process */ + /* all relocations and then return. */ + /*------------------------------------------------------------------------*/ + for (seg_idx = 0; seg_idx < num_segs; seg_idx++) + { + Elf32_Addr seg_start_addr = seg[seg_idx].input_vaddr; + Elf32_Addr seg_end_addr = seg_start_addr + seg[seg_idx].phdr.p_memsz; + + /*---------------------------------------------------------------------*/ + /* Relocations should not occur in uninitialized segments. */ + /*---------------------------------------------------------------------*/ + if(!seg[seg_idx].phdr.p_filesz) continue; + + if (r_offset >= seg_start_addr && + r_offset < seg_end_addr) + { + if (reltype == DT_REL) + process_rel_table(handle, (seg + seg_idx), + (struct Elf32_Rel *)plt_reloc_table, + pltnum, &plt_relidx, + ti_static_base, dyn_module); + else + process_rela_table(handle, (seg + seg_idx), + (struct Elf32_Rela *)plt_reloc_table, + pltnum, &plt_relidx, + ti_static_base, dyn_module); + + break; + } + } +} + +/*****************************************************************************/ +/* RELOCATE() - Perform RELA and REL type relocations for given ELF object */ +/* file that we are in the process of loading and relocating. */ +/*****************************************************************************/ +void DLREL_c60_relocate(DLOAD_HANDLE handle, + LOADER_FILE_DESC *fd, DLIMP_Dynamic_Module *dyn_module) +{ + struct Elf32_Dyn *dyn_nugget = dyn_module->dyntab; + struct Elf32_Rela *rela_table = NULL; + struct Elf32_Rel *rel_table = NULL; + struct Elf32_Rela *rela_plt_table = NULL; + struct Elf32_Rel *rel_plt_table = NULL; + + /*------------------------------------------------------------------------*/ + /* Read the size of the relocation table (DT_RELASZ) and the size per */ + /* relocation (DT_RELAENT) from the dynamic segment. */ + /*------------------------------------------------------------------------*/ + uint32_t relasz = DLIMP_get_first_dyntag(DT_RELASZ, dyn_nugget); + uint32_t relaent = DLIMP_get_first_dyntag(DT_RELAENT, dyn_nugget); + uint32_t relanum = 0; + + /*------------------------------------------------------------------------*/ + /* Read the size of the relocation table (DT_RELSZ) and the size per */ + /* relocation (DT_RELENT) from the dynamic segment. */ + /*------------------------------------------------------------------------*/ + uint32_t relsz = DLIMP_get_first_dyntag(DT_RELSZ, dyn_nugget); + uint32_t relent = DLIMP_get_first_dyntag(DT_RELENT, dyn_nugget); + uint32_t relnum = 0; + + /*------------------------------------------------------------------------*/ + /* Read the size of the relocation table (DT_PLTRELSZ) and the type of */ + /* of the PLTGOT relocation table (DT_PLTREL): one of DT_REL or DT_RELA */ + /*------------------------------------------------------------------------*/ + uint32_t pltrelsz = DLIMP_get_first_dyntag(DT_PLTRELSZ, dyn_nugget); + int pltreltyp = DLIMP_get_first_dyntag(DT_PLTREL, dyn_nugget); + uint32_t pltnum = 0; + + /*------------------------------------------------------------------------*/ + /* Find/record DSBT index associated with this module. */ + /*------------------------------------------------------------------------*/ + if (is_dsbt_module(dyn_module) && + (dyn_module->dsbt_index == DSBT_INDEX_INVALID)) + dyn_module->dsbt_index = + DLIF_get_dsbt_index(dyn_module->loaded_module->file_handle); + + /*------------------------------------------------------------------------*/ + /* Read the PLTGOT relocation table from the file */ + /* The PLTGOT table is a subsection at the end of either the DT_REL or */ + /* DT_RELA table. The size of the table it belongs to DT_REL(A)SZ */ + /* includes the size of the PLTGOT table. So it must be adjusted so that */ + /* the GOT relocation tables only contain actual GOT relocations. */ + /*------------------------------------------------------------------------*/ + if (pltrelsz != INT_MAX && pltrelsz != 0) + { + if (pltreltyp == DT_REL) + { + pltnum = pltrelsz/relent; + relsz -= pltrelsz; + read_rel_table((&rel_plt_table), + DLIMP_get_first_dyntag(DT_JMPREL, dyn_nugget), + pltnum, relent, fd, dyn_module->wrong_endian); + } + + else if (pltreltyp == DT_RELA) + { + pltnum = pltrelsz/relaent; + relasz -= pltrelsz; + read_rela_table((&rela_plt_table), + DLIMP_get_first_dyntag(DT_JMPREL, dyn_nugget), + pltnum, relaent, fd, dyn_module->wrong_endian); + } + + else + { + DLIF_error(DLET_RELOC, + "DT_PLTREL is invalid: must be either %d or %d\n", + DT_REL, DT_RELA); + } + } + + /*------------------------------------------------------------------------*/ + /* Read the DT_RELA GOT relocation table from the file */ + /*------------------------------------------------------------------------*/ + if (relasz != INT_MAX && relasz != 0) + { + relanum = relasz/relaent; + read_rela_table(&rela_table, DLIMP_get_first_dyntag(DT_RELA, dyn_nugget), + relanum, relaent, fd, dyn_module->wrong_endian); + } + + /*------------------------------------------------------------------------*/ + /* Read the DT_REL GOT relocation table from the file */ + /*------------------------------------------------------------------------*/ + if (relsz != INT_MAX && relsz != 0) + { + relnum = relsz/relent; + read_rel_table(&rel_table, DLIMP_get_first_dyntag(DT_REL, dyn_nugget), + relnum, relent, fd, dyn_module->wrong_endian); + } + + /*------------------------------------------------------------------------*/ + /* Process the PLTGOT relocations */ + /*------------------------------------------------------------------------*/ + if (rela_plt_table) + process_pltgot_relocs(handle, rela_plt_table, pltreltyp, pltnum, + dyn_module); + + if (rel_plt_table) + process_pltgot_relocs(handle, rel_plt_table, pltreltyp, pltnum, + dyn_module); + + /*------------------------------------------------------------------------*/ + /* Process the GOT relocations */ + /*------------------------------------------------------------------------*/ + if (rel_table || rela_table) + process_got_relocs(handle, rel_table, relnum, rela_table, relanum, + dyn_module); + + /*-------------------------------------------------------------------------*/ + /* Free memory used for ELF relocation table copies. */ + /*-------------------------------------------------------------------------*/ + if (rela_table) DLIF_free(rela_table); + if (rel_table) DLIF_free(rel_table); + if (rela_plt_table) DLIF_free(rela_plt_table); + if (rel_plt_table) DLIF_free(rel_plt_table); +} + +/*****************************************************************************/ +/* UNIT TESTING INTERFACE */ +/*****************************************************************************/ +#ifdef UNIT_TEST +void unit_c60_reloc_do(C60_RELOC_TYPE r_type, + uint8_t *address_space, + uint32_t addend, uint32_t symval, uint32_t pc, + uint32_t static_base, int wrong_endian, + int32_t dsbt_index) +{ + reloc_do(r_type, (uint32_t)address_space, address_space, + addend, symval, pc, FALSE, static_base, dsbt_index); +} + +#if 0 /* RELA TYPE RELOCATIONS HAVE ADDEND IN RELOCATION ENTRY */ +void unit_c60_rel_unpack_addend(C60_RELOC_TYPE r_type, + uint8_t* address, + uint32_t* addend) +{ + rel_unpack_addend(r_type, address, addend); +} +#endif + +BOOL unit_c60_rel_overflow(C60_RELOC_TYPE r_type, int32_t reloc_value) +{ + return rel_overflow(r_type, reloc_value); +} +#endif + diff --git a/src/core/dsp/ocl_load/C60_DLOAD_REL/c60_reloc.h b/src/core/dsp/ocl_load/C60_DLOAD_REL/c60_reloc.h new file mode 100644 index 0000000..8ccd60e --- /dev/null +++ b/src/core/dsp/ocl_load/C60_DLOAD_REL/c60_reloc.h @@ -0,0 +1,30 @@ +/****************************************************************************** + * Copyright (c) 2013-2014, Texas Instruments Incorporated - http://www.ti.com/ + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Texas Instruments Incorporated nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +void DLREL_c60_relocate(DLOAD_HANDLE handle, LOADER_FILE_DESC *fd, + DLIMP_Dynamic_Module *dyn_module); diff --git a/src/core/dsp/ocl_load/C60_DLOAD_REL/test_c60_reloc.cpp b/src/core/dsp/ocl_load/C60_DLOAD_REL/test_c60_reloc.cpp new file mode 100644 index 0000000..acde023 --- /dev/null +++ b/src/core/dsp/ocl_load/C60_DLOAD_REL/test_c60_reloc.cpp @@ -0,0 +1,825 @@ +/* +* test_c60_reloc.cpp +* +* C6x Relocation Unit Tests. +* +* Copyright (C) 2009-2014 Texas Instruments Incorporated - http://www.ti.com/ +* +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +*/ + +#include "test_c60_reloc.h" +#include <stdlib.h> +#include <stdio.h> + +/*****************************************************************************/ +/* C60_TestRelocDo */ +/* */ +/* Tests the C60 version of reloc_do. In cases where multiple relocation */ +/* types are implemented in the same way, only one type is tested. For */ +/* instance, R_C6000_xxx, R_C6000_yyy, and R_C6000_zzz are implemented in */ +/* the exact same way and, therefore, only R_C6000_xxx is tested. */ +/* */ +/* Each test follows the same flow: */ +/* 1. A valid instruction is constructed for the relocation type being */ +/* tested. */ +/* 2. Addend, symbol value, and pc are then created. */ +/* (NOTE: static base is not needed, and so 0 is passed. Also, same */ +/* endianness is assumed.) */ +/* 3. reloc_do() is called */ +/* 4. The result is checked. */ +/* 5. Repeat if variations should be considered. */ +/* */ +/*****************************************************************************/ +//void C60_TestRelocDo::test_R_C6000_NONE() { } + +void C60_TestRelocDo::test_R_C6000_ABS32() +{ + uint32_t address_space = 0x0; + uint32_t addend = 0x4; + uint32_t symval = 0x2001000; + uint32_t pc = 0x0; + + unit_c60_reloc_do(R_C6000_ABS32, + (uint8_t*) &address_space, + addend, symval, pc, 0, 0, 0); + + TS_ASSERT_EQUALS(address_space, 0x2001004); +} + +void C60_TestRelocDo::test_R_C6000_ABS16() +{ + uint16_t address_space = 0x0; + uint32_t addend = 0x4; + uint32_t symval = 0xFFE; + uint32_t pc = 0x0; + + unit_c60_reloc_do(R_C6000_ABS16, + (uint8_t*) &address_space, + addend, symval, pc, 0, 0, 0); + + TS_ASSERT_EQUALS(address_space, 0x1002); +} + +void C60_TestRelocDo::test_R_C6000_ABS8() +{ + uint8_t address_space = 0x0; + uint32_t addend = 0x4; + uint32_t symval = 0xE; + uint32_t pc = 0x0; + + unit_c60_reloc_do(R_C6000_ABS8, + &address_space, + addend, symval, pc, 0, 0, 0); + + TS_ASSERT_EQUALS(address_space, 0x12); +} + +/*---------------------------------------------------------------------------*/ +/* PC-Relative Relocation Tests */ +/* */ +/* Our relocation handler assumes that the address of 'opcode' is where the */ +/* relocation is. Therefore, when creating a PCR test case, we will compute */ +/* a value for symval and pc in terms of &opcode. */ +/* */ +/*---------------------------------------------------------------------------*/ +void C60_TestRelocDo::test_R_C6000_PCR_S21() +{ + uint32_t opcode = 0x00000010; + uint32_t addend = 0x4; + uint32_t symval = ((uint32_t)&opcode & 0xffffffe0) + 0x50000; + uint32_t pc = 0x0; + + /* Test #1 -- destination is forward from PC */ + /* PCR21 offset = 0x14001 */ + unit_c60_reloc_do(R_C6000_PCR_S21, + (uint8_t*) &opcode, + addend, symval, pc, 0, 0, 0); + + TS_ASSERT_EQUALS(opcode, 0x00a00090); + + /* Test #2 -- symval definition implies offset is negative */ + /* PCR21 offset = 0x1d4001 (signed - negative) */ + opcode = 0x00000010; + symval = ((uint32_t)&opcode & 0xffffffe0) - 0xb0000; + unit_c60_reloc_do(R_C6000_PCR_S21, + (uint8_t*) &opcode, + addend, symval, pc, 0, 0, 0); + + TS_ASSERT_EQUALS(opcode, 0x0ea00090); +} + +void C60_TestRelocDo::test_R_C6000_PCR_S12() +{ + uint32_t opcode = 0x00002120; /* BNOP */ + uint32_t addend = 0x4; + uint32_t symval = ((uint32_t)&opcode & 0xffffffe0) + 0x500; + uint32_t pc = 0x0; + + /* Test #1 -- destination is forward from PC */ + /* PCR12 offset = 0x141 */ + unit_c60_reloc_do(R_C6000_PCR_S12, + (uint8_t*) &opcode, + addend, symval, pc, 0, 0, 0); + + TS_ASSERT_EQUALS(opcode, 0x01412120); + + /* Test #2 -- symval definition implies offset is negative */ + /* PCR12 offset = 0xd41 (signed - negative) */ + opcode = 0x00002120; + symval = ((uint32_t)&opcode & 0xffffffe0) - 0xb00; + unit_c60_reloc_do(R_C6000_PCR_S12, + (uint8_t*) &opcode, + addend, symval, pc, 0, 0, 0); + + TS_ASSERT_EQUALS(opcode, 0x0d412120); +} + +void C60_TestRelocDo::test_R_C6000_PCR_S10() +{ + uint32_t opcode = 0x01001020; /* BDEC */ + uint32_t addend = 0x4; + uint32_t symval = ((uint32_t)&opcode & 0xffffffe0) + 0x50; + uint32_t pc = 0x0; + + /* Test #1 -- destination is forward from PC */ + /* PCR10 offset = 0x15 */ + unit_c60_reloc_do(R_C6000_PCR_S10, + (uint8_t*) &opcode, + addend, symval, pc, 0, 0, 0); + + TS_ASSERT_EQUALS(opcode, 0x0102b020); + + /* Test #2 -- symval definition implies offset is negative */ + /* PCR10 offset = 0x355 (signed - negative) */ + opcode = 0x01001020; + symval = ((uint32_t)&opcode & 0xffffffe0) - 0xb0; + unit_c60_reloc_do(R_C6000_PCR_S10, + (uint8_t*) &opcode, + addend, symval, pc, 0, 0, 0); + + TS_ASSERT_EQUALS(opcode, 0x017ab020); +} + +void C60_TestRelocDo::test_R_C6000_PCR_S7() +{ + uint32_t opcode = 0x03006160; /* ADDKPC */ + uint32_t addend = 0x4; + uint32_t symval = ((uint32_t)&opcode & 0xffffffe0) + 0x50; + uint32_t pc = 0x0; + + /* Test #1 -- destination is forward from PC */ + /* PCR7 offset = 0x15 */ + unit_c60_reloc_do(R_C6000_PCR_S7, + (uint8_t*) &opcode, + addend, symval, pc, 0, 0, 0); + + TS_ASSERT_EQUALS(opcode, 0x03156160); + + /* Test #2 -- symval definition implies offset is negative */ + /* PCR7 offset = 0x75 (signed - negative) */ + opcode = 0x03006160; + symval = ((uint32_t)&opcode & 0xffffffe0) - 0x30; + unit_c60_reloc_do(R_C6000_PCR_S7, + (uint8_t*) &opcode, + addend, symval, pc, 0, 0, 0); + + TS_ASSERT_EQUALS(opcode, 0x03756160); +} + +void C60_TestRelocDo::test_R_C6000_ABS_S16() +{ + uint32_t opcode = 0x03000028; /* MVK */ + uint32_t addend = 0x4; + uint32_t symval = 0xFFE; + uint32_t pc = 0x0; + + unit_c60_reloc_do(R_C6000_ABS_S16, + (uint8_t*) &opcode, + addend, symval, pc, 0, 0, 0); + + TS_ASSERT_EQUALS(opcode, 0x03080128); +} + +void C60_TestRelocDo::test_R_C6000_ABS_L16() +{ + uint32_t opcode = 0x03000028; /* MVKL */ + uint32_t addend = 0x4; + uint32_t symval = 0x04560FFE; + uint32_t pc = 0x0; + + unit_c60_reloc_do(R_C6000_ABS_L16, + (uint8_t*) &opcode, + addend, symval, pc, 0, 0, 0); + + TS_ASSERT_EQUALS(opcode, 0x03080128); +} + +void C60_TestRelocDo::test_R_C6000_ABS_H16() +{ + uint32_t opcode = 0x03000068; /* MVKH */ + uint32_t addend = 0x4; + uint32_t symval = 0x04560FFE; + uint32_t pc = 0x0; + + unit_c60_reloc_do(R_C6000_ABS_H16, + (uint8_t*) &opcode, + addend, symval, pc, 0, 0, 0); + + TS_ASSERT_EQUALS(opcode, 0x03022b68); +} + +void C60_TestRelocDo::test_R_C6000_SBR_U15_B() +{ + uint32_t opcode = 0x0300002c; /* LDB */ + uint32_t addend = 0x0; + uint32_t static_base = 0x04000000; + uint32_t symval = (static_base + 0x1357); + uint32_t pc = 0x0; + + /* unsigned 15-bit SBR offset = 0x1357 */ + /* encoded in bits 22 - 8 */ + unit_c60_reloc_do(R_C6000_SBR_U15_B, + (uint8_t*) &opcode, + addend, symval, pc, static_base, 0, 0); + + TS_ASSERT_EQUALS(opcode, 0x0313572c); +} + +void C60_TestRelocDo::test_R_C6000_SBR_U15_H() +{ + uint32_t opcode = 0x0300004c; /* LDH */ + uint32_t addend = 0x0; + uint32_t static_base = 0x04000000; + uint32_t symval = (static_base + 0x2246); + uint32_t pc = 0x0; + + /* unsigned 16-bit SBR offset = 0x2246 */ + /* scaled 15-bit SBR offset = 0x1123 */ + /* encoded in bits 22 - 8 */ + unit_c60_reloc_do(R_C6000_SBR_U15_H, + (uint8_t*) &opcode, + addend, symval, pc, static_base, 0, 0); + + TS_ASSERT_EQUALS(opcode, 0x0311234c); +} + +void C60_TestRelocDo::test_R_C6000_SBR_U15_W() +{ + uint32_t opcode = 0x0300006c; /* LDW */ + uint32_t addend = 0x0; + uint32_t static_base = 0x04000000; + uint32_t symval = (static_base + 0x448c); + uint32_t pc = 0x0; + + /* unsigned 17-bit SBR offset = 0x448c */ + /* scaled 15-bit SBR offset = 0x1123 */ + /* encoded in bits 22 - 8 */ + unit_c60_reloc_do(R_C6000_SBR_U15_W, + (uint8_t*) &opcode, + addend, symval, pc, static_base, 0, 0); + + TS_ASSERT_EQUALS(opcode, 0x0311236c); +} + +void C60_TestRelocDo::test_R_C6000_SBR_S16() +{ + uint32_t opcode = 0x03000028; /* MVK */ + uint32_t addend = 0x0; + uint32_t static_base = 0x04000000; + uint32_t symval = (static_base + 0x1357); + uint32_t pc = 0x0; + + /* Test #1 positive signed 16-bit offset */ + /* 16-bit SBR offset = 0x1357 */ + /* encoded in bits 22-7 of opcode */ + unit_c60_reloc_do(R_C6000_SBR_S16, + (uint8_t*) &opcode, + addend, symval, pc, static_base, 0, 0); + + TS_ASSERT_EQUALS(opcode, 0x0309aba8); + + /* Test #2 negative signed 16-bit offset */ + /* 16-bit SBR offset = 0xeca9 (-0x1357) */ + /* encoded in bits 22-7 of opcode */ + symval = (static_base - 0x1357); + unit_c60_reloc_do(R_C6000_SBR_S16, + (uint8_t*) &opcode, + addend, symval, pc, static_base, 0, 0); + + TS_ASSERT_EQUALS(opcode, 0x037654a8); +} + +void C60_TestRelocDo::test_R_C6000_SBR_L16_B() +{ + uint32_t opcode = 0x03000028; /* MVKL */ + uint32_t addend = 0x0; + uint32_t static_base = 0x04000000; + uint32_t symval = (static_base + 0x11123); + uint32_t pc = 0x0; + + /* 16-bit SBR offset = 0x1123 */ + /* encoded in bits 22-7 of opcode */ + unit_c60_reloc_do(R_C6000_SBR_L16_B, + (uint8_t*) &opcode, + addend, symval, pc, static_base, 0, 0); + + TS_ASSERT_EQUALS(opcode, 0x030891a8); +} + +void C60_TestRelocDo::test_R_C6000_SBR_L16_H() +{ + uint32_t opcode = 0x03000028; /* MVKL */ + uint32_t addend = 0x0; + uint32_t static_base = 0x04000000; + uint32_t symval = (static_base + 0x12246); + uint32_t pc = 0x0; + + /* 17-bit SBR offset = 0x12246 */ + /* scaled SBR offset = 0x9123 */ + /* encoded in bits 22-7 of opcode */ + unit_c60_reloc_do(R_C6000_SBR_L16_H, + (uint8_t*) &opcode, + addend, symval, pc, static_base, 0, 0); + + TS_ASSERT_EQUALS(opcode, 0x034891a8); +} + +void C60_TestRelocDo::test_R_C6000_SBR_L16_W() +{ + uint32_t opcode = 0x03000028; /* MVKL */ + uint32_t addend = 0x0; + uint32_t static_base = 0x04000000; + uint32_t symval = (static_base + 0x1448c); + uint32_t pc = 0x0; + + /* 18-bit SBR offset = 0x1448c */ + /* scaled SBR offset = 0x5123 */ + /* encoded in bits 22-7 of opcode */ + unit_c60_reloc_do(R_C6000_SBR_L16_W, + (uint8_t*) &opcode, + addend, symval, pc, static_base, 0, 0); + + TS_ASSERT_EQUALS(opcode, 0x032891a8); +} + +void C60_TestRelocDo::test_R_C6000_SBR_H16_B() +{ + uint32_t opcode = 0x03000068; /* MVKH */ + uint32_t addend = 0x0; + uint32_t static_base = 0x04000000; + uint32_t symval = (static_base + 0x357448c); + uint32_t pc = 0x0; + + /* total SBR offset = 0x357448c */ + /* upper 16-bits of SBR offset = 0x357 */ + /* encoded in bits 22-7 of opcode */ + unit_c60_reloc_do(R_C6000_SBR_H16_B, + (uint8_t*) &opcode, + addend, symval, pc, static_base, 0, 0); + + TS_ASSERT_EQUALS(opcode, 0x0301abe8); +} + +void C60_TestRelocDo::test_R_C6000_SBR_H16_H() +{ + uint32_t opcode = 0x03000068; /* MVKH */ + uint32_t addend = 0x0; + uint32_t static_base = 0x04000000; + uint32_t symval = (static_base + 0x357448c); + uint32_t pc = 0x0; + + /* total SBR offset = 0x357448c */ + /* scaled SBR offset = 0x1aba246 */ + /* upper 16-bits of scaled SBR offset = 0x1ab */ + /* encoded in bits 22-7 of opcode */ + unit_c60_reloc_do(R_C6000_SBR_H16_H, + (uint8_t*) &opcode, + addend, symval, pc, static_base, 0, 0); + + TS_ASSERT_EQUALS(opcode, 0x0300d5e8); +} + +void C60_TestRelocDo::test_R_C6000_SBR_H16_W() +{ + uint32_t opcode = 0x03000068; /* MVKH */ + uint32_t addend = 0x0; + uint32_t static_base = 0x04000000; + uint32_t symval = (static_base + 0x357448c); + uint32_t pc = 0x0; + + /* total SBR offset = 0x357448c */ + /* scaled SBR offset = 0x0d5d123 */ + /* upper 16-bits of scaled SBR offset = 0x0d5 */ + /* encoded in bits 22-7 of opcode */ + unit_c60_reloc_do(R_C6000_SBR_H16_W, + (uint8_t*) &opcode, + addend, symval, pc, static_base, 0, 0); + + TS_ASSERT_EQUALS(opcode, 0x03006ae8); +} + +/* The DSBT table is accessed via DP-relative addressing with */ +/* an LDW instruction, but the DSBT_INDEX is really an index */ +/* into the DSBT table, the index is scaled to a 4-word offset. */ +void C60_TestRelocDo::test_R_C6000_DSBT_INDEX() +{ + uint32_t opcode = 0x0300006c; /* LDW */ + uint32_t addend = 0x0; + uint32_t static_base = 0x04000000; + uint32_t symval = static_base; + uint32_t pc = 0x0; + + unit_c60_reloc_do(R_C6000_DSBT_INDEX, + (uint8_t*) &opcode, + addend, symval, pc, static_base, 0, 3); + + TS_ASSERT_EQUALS(opcode, 0x0300036c); +} + +/*****************************************************************************/ +/* C60_TestRelUnpackAddend */ +/* */ +/* Tests the C60 rel_unpack_addend function. */ +/* */ +/* In cases where the addends are unpacked in the same way, only one is */ +/* tested. */ +/* */ +/* All tests follow the same flow: */ +/* */ +/* 1. Create a valid instruction for the relocation type, where the addend */ +/* is packed in the instruction. */ +/* 2. Call rel_unpack_addend(). */ +/* 3. Check that the addend is correct. */ +/* */ +/* Relocations may be tested multiple times to handle variations, such as */ +/* positive/negative addends, extra bits depending on the encoding, etc. */ +/* */ +/* NOTE!! C60 ONLY SUPPORTS RELA TYPE RELOCATIONS, SO ADDEND FIELD IS STORED */ +/* IN RELOCATION ENTRY ITSELF. */ +/*****************************************************************************/ +#if 0 +void C60_TestRelUnpackAddend::test_R_C6000_ABS32() +{ + uint32_t address_space=0xFEDCBA9; + uint32_t addend; + + unit_c60_rel_unpack_addend(R_C6000_ABS32, + (uint8_t*)&address_space, + &addend); + + TS_ASSERT_EQUALS(addend, address_space); +} + +void C60_TestRelUnpackAddend::test_R_C6000_ABS16() +{ + uint16_t address_space=0x7FFF; + uint32_t addend; + + unit_c60_rel_unpack_addend(R_C6000_ABS16, + (uint8_t*)&address_space, + &addend); + + TS_ASSERT_EQUALS(addend, 0x7FFF); + + address_space = 0x8000; + + unit_c60_rel_unpack_addend(R_C6000_ABS16, + (uint8_t*)&address_space, + &addend); + + TS_ASSERT_EQUALS(addend, 0xFFFF8000); +} +#endif + + +/*****************************************************************************/ +/* C60_TestRelOverflow */ +/* */ +/* Test the C60 rel_overflow function. */ +/* */ +/* In each case, we test the upper and lower bounds of each relocation type. */ +/* Only relocation types where the overflow is checked in rel_overflow are */ +/* considered. In most cases four tests are performed to test the upper and */ +/* lower bounds (1 pass and 1 fail for each). */ +/* */ +/* NOTE!! HAVEN'T REFACTORED OVERFLOW CHECK OUT OF RELOCATION HANDLERS FOR */ +/* C60, SO OVERFLOW SHOULD BE TESTED AS PART OF THE RELOC DO(???) */ +/* */ +/*****************************************************************************/ +void C60_TestRelOverflow::test_R_C6000_ABS16() +{ + int32_t reloc_val = 0xFFFF; + int rval; + + rval = unit_c60_rel_overflow(R_C6000_ABS16, reloc_val); + + TS_ASSERT_EQUALS(rval, 0); + + reloc_val = 0x10000; + + rval = unit_c60_rel_overflow(R_C6000_ABS16, reloc_val); + + TS_ASSERT_EQUALS(rval, 1); + + reloc_val = -0x8000; + + rval = unit_c60_rel_overflow(R_C6000_ABS16, reloc_val); + + TS_ASSERT_EQUALS(rval, 0); + + reloc_val = -0x8001; + + rval = unit_c60_rel_overflow(R_C6000_ABS16, reloc_val); + + TS_ASSERT_EQUALS(rval, 1); +} + +void C60_TestRelOverflow::test_R_C6000_ABS8() +{ + int32_t reloc_val = 0xFF; + int rval; + + rval = unit_c60_rel_overflow(R_C6000_ABS8, reloc_val); + + TS_ASSERT_EQUALS(rval, 0); + + reloc_val = 0x100; + + rval = unit_c60_rel_overflow(R_C6000_ABS8, reloc_val); + + TS_ASSERT_EQUALS(rval, 1); + + reloc_val = -0x80; + + rval = unit_c60_rel_overflow(R_C6000_ABS8, reloc_val); + + TS_ASSERT_EQUALS(rval, 0); + + reloc_val = -0x81; + + rval = unit_c60_rel_overflow(R_C6000_ABS8, reloc_val); + + TS_ASSERT_EQUALS(rval, 1); +} + +void C60_TestRelOverflow::test_R_C6000_PCR_S21() +{ + int32_t reloc_val = 0x3FFFFC; + int rval; + + rval = unit_c60_rel_overflow(R_C6000_PCR_S21, reloc_val); + + TS_ASSERT_EQUALS(rval, 0); + + reloc_val = 0x400000; + + rval = unit_c60_rel_overflow(R_C6000_PCR_S21, reloc_val); + + TS_ASSERT_EQUALS(rval, 1); + + reloc_val = -0x400000; + + rval = unit_c60_rel_overflow(R_C6000_PCR_S21, reloc_val); + + TS_ASSERT_EQUALS(rval, 0); + + reloc_val = -0x400001; + + rval = unit_c60_rel_overflow(R_C6000_PCR_S21, reloc_val); + + TS_ASSERT_EQUALS(rval, 1); +} + +void C60_TestRelOverflow::test_R_C6000_PCR_S12() +{ + int32_t reloc_val = 0x1FFC; + int rval; + + rval = unit_c60_rel_overflow(R_C6000_PCR_S12, reloc_val); + + TS_ASSERT_EQUALS(rval, 0); + + reloc_val = 0x2000; + + rval = unit_c60_rel_overflow(R_C6000_PCR_S12, reloc_val); + + TS_ASSERT_EQUALS(rval, 1); + + reloc_val = -0x2000; + + rval = unit_c60_rel_overflow(R_C6000_PCR_S12, reloc_val); + + TS_ASSERT_EQUALS(rval, 0); + + reloc_val = -0x2001; + + rval = unit_c60_rel_overflow(R_C6000_PCR_S12, reloc_val); + + TS_ASSERT_EQUALS(rval, 1); +} + +void C60_TestRelOverflow::test_R_C6000_PCR_S10() +{ + int32_t reloc_val = 0x7FC; + int rval; + + rval = unit_c60_rel_overflow(R_C6000_PCR_S10, reloc_val); + + TS_ASSERT_EQUALS(rval, 0); + + reloc_val = 0x800; + + rval = unit_c60_rel_overflow(R_C6000_PCR_S10, reloc_val); + + TS_ASSERT_EQUALS(rval, 1); + + reloc_val = -0x800; + + rval = unit_c60_rel_overflow(R_C6000_PCR_S10, reloc_val); + + TS_ASSERT_EQUALS(rval, 0); + + reloc_val = -0x801; + + rval = unit_c60_rel_overflow(R_C6000_PCR_S10, reloc_val); + + TS_ASSERT_EQUALS(rval, 1); +} + +void C60_TestRelOverflow::test_R_C6000_PCR_S7() +{ + int32_t reloc_val = 0xFC; + int rval; + + rval = unit_c60_rel_overflow(R_C6000_PCR_S7, reloc_val); + + TS_ASSERT_EQUALS(rval, 0); + + reloc_val = 0x100; + + rval = unit_c60_rel_overflow(R_C6000_PCR_S7, reloc_val); + + TS_ASSERT_EQUALS(rval, 1); + + reloc_val = -0x100; + + rval = unit_c60_rel_overflow(R_C6000_PCR_S7, reloc_val); + + TS_ASSERT_EQUALS(rval, 0); + + reloc_val = -0x101; + + rval = unit_c60_rel_overflow(R_C6000_PCR_S7, reloc_val); + + TS_ASSERT_EQUALS(rval, 1); +} + +void C60_TestRelOverflow::test_R_C6000_SBR_S16() +{ + int32_t reloc_val = 0x7FFF; + int rval; + + rval = unit_c60_rel_overflow(R_C6000_SBR_S16, reloc_val); + + TS_ASSERT_EQUALS(rval, 0); + + reloc_val = 0x8000; + + rval = unit_c60_rel_overflow(R_C6000_SBR_S16, reloc_val); + + TS_ASSERT_EQUALS(rval, 1); + + reloc_val = -0x8000; + + rval = unit_c60_rel_overflow(R_C6000_SBR_S16, reloc_val); + + TS_ASSERT_EQUALS(rval, 0); + + reloc_val = -0x8001; + + rval = unit_c60_rel_overflow(R_C6000_SBR_S16, reloc_val); + + TS_ASSERT_EQUALS(rval, 1); +} + +void C60_TestRelOverflow::test_R_C6000_ABS_S16() +{ + int32_t reloc_val = 0x7FFF; + int rval; + + rval = unit_c60_rel_overflow(R_C6000_ABS_S16, reloc_val); + + TS_ASSERT_EQUALS(rval, 0); + + reloc_val = 0x8000; + + rval = unit_c60_rel_overflow(R_C6000_ABS_S16, reloc_val); + + TS_ASSERT_EQUALS(rval, 1); + + reloc_val = -0x8000; + + rval = unit_c60_rel_overflow(R_C6000_ABS_S16, reloc_val); + + TS_ASSERT_EQUALS(rval, 0); + + reloc_val = -0x8001; + + rval = unit_c60_rel_overflow(R_C6000_ABS_S16, reloc_val); + + TS_ASSERT_EQUALS(rval, 1); +} + +void C60_TestRelOverflow::test_R_C6000_SBR_U15_B() +{ + uint32_t reloc_val = 0x7FFF; + int rval; + + rval = unit_c60_rel_overflow(R_C6000_SBR_U15_B, reloc_val); + + TS_ASSERT_EQUALS(rval, 0); + + reloc_val = 0x8000; + + rval = unit_c60_rel_overflow(R_C6000_SBR_U15_B, reloc_val); + + TS_ASSERT_EQUALS(rval, 1); +} + +void C60_TestRelOverflow::test_R_C6000_SBR_U15_H() +{ + uint32_t reloc_val = 0xFFFE; + int rval; + + rval = unit_c60_rel_overflow(R_C6000_SBR_U15_H, reloc_val); + + TS_ASSERT_EQUALS(rval, 0); + + reloc_val = 0xFFFF; + + rval = unit_c60_rel_overflow(R_C6000_SBR_U15_H, reloc_val); + + TS_ASSERT_EQUALS(rval, 1); +} + +void C60_TestRelOverflow::test_R_C6000_SBR_U15_W() +{ + uint32_t reloc_val = 0x1FFFC; + int rval; + + rval = unit_c60_rel_overflow(R_C6000_SBR_U15_W, reloc_val); + + TS_ASSERT_EQUALS(rval, 0); + + reloc_val = 0x1FFFD; + + rval = unit_c60_rel_overflow(R_C6000_SBR_U15_W, reloc_val); + + TS_ASSERT_EQUALS(rval, 1); +} + +void C60_TestRelOverflow::test_R_C6000_DSBT_INDEX() +{ + uint32_t reloc_val = 0x1FFFC; + int rval; + + rval = unit_c60_rel_overflow(R_C6000_DSBT_INDEX, reloc_val); + + TS_ASSERT_EQUALS(rval, 0); + + reloc_val = 0x1FFFD; + + rval = unit_c60_rel_overflow(R_C6000_DSBT_INDEX, reloc_val); + + TS_ASSERT_EQUALS(rval, 1); +} + diff --git a/src/core/dsp/ocl_load/C60_DLOAD_REL/test_c60_reloc.h b/src/core/dsp/ocl_load/C60_DLOAD_REL/test_c60_reloc.h new file mode 100644 index 0000000..67a437d --- /dev/null +++ b/src/core/dsp/ocl_load/C60_DLOAD_REL/test_c60_reloc.h @@ -0,0 +1,101 @@ +/* +* test_c60_reloc.h +* +* Specification of C6x-specific relocation handler unit tests. +* +* Copyright (C) 2009-2014 Texas Instruments Incorporated - http://www.ti.com/ +* +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +*/ + +#ifndef _TEST_C60_RELOC_H_ +#define _TEST_C60_RELOC_H_ +#include "c60_elf32.h" +#include <cxxtest/TestSuite.h> + +extern "C" +{ +extern void unit_c60_reloc_do(C60_RELOC_TYPE r_type, uint8_t* address, + uint32_t addend, uint32_t symval, uint32_t pc, + uint32_t base_pointer, int wrong_endian, int32_t dsbt_index); + +extern void unit_c60_rel_unpack_addend(C60_RELOC_TYPE r_type, + uint8_t* address, + uint32_t* addend); + +extern int unit_c60_rel_overflow(C60_RELOC_TYPE r_type, int32_t reloc_value); + +} + +class C60_TestRelocDo : public CxxTest::TestSuite +{ + public: + void test_R_C6000_ABS32(); + void test_R_C6000_ABS16(); + void test_R_C6000_ABS8(); + void test_R_C6000_PCR_S21(); + void test_R_C6000_PCR_S12(); + void test_R_C6000_PCR_S10(); + void test_R_C6000_PCR_S7(); + void test_R_C6000_ABS_S16(); + void test_R_C6000_ABS_L16(); + void test_R_C6000_ABS_H16(); + void test_R_C6000_SBR_U15_B(); + void test_R_C6000_SBR_U15_H(); + void test_R_C6000_SBR_U15_W(); + void test_R_C6000_SBR_S16(); + void test_R_C6000_SBR_L16_B(); + void test_R_C6000_SBR_L16_H(); + void test_R_C6000_SBR_L16_W(); + void test_R_C6000_SBR_H16_B(); + void test_R_C6000_SBR_H16_H(); + void test_R_C6000_SBR_H16_W(); + void test_R_C6000_DSBT_INDEX(); +}; + +class C60_TestRelOverflow : public CxxTest::TestSuite +{ + public: + void test_R_C6000_ABS16(); + void test_R_C6000_ABS8(); + void test_R_C6000_PCR_S21(); + void test_R_C6000_PCR_S12(); + void test_R_C6000_PCR_S10(); + void test_R_C6000_PCR_S7(); + void test_R_C6000_SBR_S16(); + void test_R_C6000_ABS_S16(); + void test_R_C6000_SBR_U15_B(); + void test_R_C6000_SBR_U15_H(); + void test_R_C6000_SBR_U15_W(); + void test_R_C6000_DSBT_INDEX(); +}; + +#endif /* _TEST_C60_RELOC_H_ */ diff --git a/src/core/dsp/ocl_load/CMakeLists.txt b/src/core/dsp/ocl_load/CMakeLists.txt new file mode 100644 index 0000000..a459542 --- /dev/null +++ b/src/core/dsp/ocl_load/CMakeLists.txt @@ -0,0 +1,26 @@ +include_directories (. + C60_DLOAD_REL + C60_DLOAD_DYN + DLOAD_SYM + DLOAD + DLOAD_API + DLWRAPPER + ) + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -DC60_TARGET -DLOADER_DEBUG -g -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast") + +set(OCL_LOAD_SRC_FILES + ocl_load.c + C60_DLOAD_REL/c60_reloc.c + C60_DLOAD_DYN/c60_dynamic.c + DLOAD_SYM/symtab.c + DLOAD/ArrayList.c + DLOAD/dload.c + DLOAD/elf32.c + DLOAD/dload_endian.c +) + +add_library(oclload STATIC ${OCL_LOAD_SRC_FILES}) + +SET(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/lib) + diff --git a/src/core/dsp/ocl_load/DLOAD/ArrayList.c b/src/core/dsp/ocl_load/DLOAD/ArrayList.c new file mode 100644 index 0000000..4452bfc --- /dev/null +++ b/src/core/dsp/ocl_load/DLOAD/ArrayList.c @@ -0,0 +1,122 @@ +/* +* ArrayList.c +* +* Array_List is a C implementation of a C++ vector class. +* +* This class emulates a resizable array along the lines of a C++ +* vector or Java ArrayList class in C, and uses the convention +* of passing a pointer to the current "object" as the first +* argument. +* +* Usage is defined as follows: +* +* Array_List obj; +* AL_initialize(&obj, sizeof(type_name)); +* +* ... +* +* type_name *ptr = (type_name*)(obj.buf); +* for(i = 0; i < AL_size(&obj); i++) +* do_something_to(ptr[i]); +* type_name to_append = ...; +* AL_append(&obj, &to_append); +* +* ... +* +* AL_destroy(&obj); +* +* +* Copyright (C) 2009-2014 Texas Instruments Incorporated - http://www.ti.com/ +* +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +*/ + +#include <inttypes.h> +#include <string.h> +#include "ArrayList.h" +#include "dload_api.h" + +/*****************************************************************************/ +/* AL_INITIALIZE() - Initialize a newly created Array_List object. */ +/*****************************************************************************/ +void AL_initialize(Array_List* obj, int32_t type_size, int32_t num_elem) +{ + if (num_elem == 0) num_elem = 1; + obj->buf = DLIF_malloc(type_size * num_elem); + obj->type_size = type_size; + obj->size = 0; + obj->buffer_size = num_elem; +} + +/*****************************************************************************/ +/* AL_APPEND() - Append an element to the end of an Array_List. */ +/*****************************************************************************/ +void AL_append(Array_List* obj, void* to_append) +{ + /*------------------------------------------------------------------------*/ + /* If there is already space in the specified buffer for the new data, */ + /* just append it to the end of the data that is already in the buffer. */ + /*------------------------------------------------------------------------*/ + if (obj->size < obj->buffer_size) + memcpy(((uint8_t*)obj->buf) + obj->type_size * ((obj->size)++), to_append, + obj->type_size); + + /*------------------------------------------------------------------------*/ + /* Grow the buffer if we need more space to add the new data to it. */ + /*------------------------------------------------------------------------*/ + else + { + void* old_buffer = obj->buf; + obj->buffer_size *= 2; + obj->buf = DLIF_malloc(obj->buffer_size*obj->type_size); + memcpy(obj->buf,old_buffer,obj->size*obj->type_size); + DLIF_free(old_buffer); + memcpy(((uint8_t*)obj->buf) + obj->type_size *((obj->size)++), to_append, + obj->type_size); + } +} + +/*****************************************************************************/ +/* AL_SIZE() - Get the number of elements in an Array_List. */ +/*****************************************************************************/ +int32_t AL_size(Array_List* obj) +{ + return obj->size; +} + +/*****************************************************************************/ +/* AL_DESTROY() - Free up memory associated with an Array_List that is no */ +/* longer in use. */ +/*****************************************************************************/ +void AL_destroy(Array_List* obj) +{ + DLIF_free(obj->buf); +} diff --git a/src/core/dsp/ocl_load/DLOAD/ArrayList.h b/src/core/dsp/ocl_load/DLOAD/ArrayList.h new file mode 100644 index 0000000..2c03788 --- /dev/null +++ b/src/core/dsp/ocl_load/DLOAD/ArrayList.h @@ -0,0 +1,92 @@ +/* +* ArrayList.h +* +* This implementation of ArrayList is a replacement for the C++ +* vector class in C. +* +* This class emulates a resizable array along the lines of a C++ +* vector or Java ArrayList class in C, and uses the convention +* of passing a pointer to the current "object" as the first +* argument. +* +* Usage is defined as follows: +* +* Array_List obj; +* AL_initialize(&obj, sizeof(type_name)); +* +* ... +* +* type_name *ptr = (type_name*)(obj.buf); +* for(i = 0; i < AL_size(&obj); i++) +* do_something_to(ptr[i]); +* type_name to_append = ...; +* AL_append(&obj, &to_append); +* +* ... +* +* AL_destroy(&obj); +* +* Copyright (C) 2009-2014 Texas Instruments Incorporated - http://www.ti.com/ +* +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +*/ + +#ifndef ARRAYLIST_H +#define ARRAYLIST_H + +#include <inttypes.h> + +/**********************************************************************/ +/* Array_List - structure type specification. */ +/**********************************************************************/ +typedef struct +{ + void *buf; + int32_t type_size; + int32_t size; + int32_t buffer_size; +} Array_List; + +/*--------------------------------------------------------------------*/ +/* Array_List Member Functions: */ +/* */ +/* AL_initialize() - Initialize a newly created Array_List object. */ +/* AL_append() - Append an element to the end of an Array_List. */ +/* AL_size() - Get number of elements in an Array_List. */ +/* AL_destroy() - Free memory associated with an Array_List that is */ +/* no longer in use. */ +/*--------------------------------------------------------------------*/ +void AL_initialize(Array_List* obj, int32_t type_size, int32_t num_elem); +void AL_append(Array_List* obj, void* to_append); +int32_t AL_size(Array_List* obj); +void AL_destroy(Array_List* obj); + +#endif diff --git a/src/core/dsp/ocl_load/DLOAD/Queue.h b/src/core/dsp/ocl_load/DLOAD/Queue.h new file mode 100644 index 0000000..3f85c16 --- /dev/null +++ b/src/core/dsp/ocl_load/DLOAD/Queue.h @@ -0,0 +1,194 @@ +/* +* Queue.h +* +* Interface to Linked List +* ------------------------ +* +* This is an implementation of a type-independent linked list class for C. +* It's basically a template class, but uses macros instead so that it can +* be compiled with a C-only compiler. +* +* To define a linked list class: +* #include "Queue.h" +* TYPE_QUEUE_DEFINITION(object_type,Class_Identifier) +* +* In a separate C file: +* #include "Queue.h" +* TYPE_QUEUE_DEFINITION(object_type,Class_Identifier) +* TYPE_QUEUE_IMPLEMENTATION(object_type,Class_Identifier) +* +* Now, to create a list: +* Class_Identifier_Queue name; +* Get it initialized to zero everywhere somehow, maybe like this: +* Class_Identifier_initialize_queue(&name); +* +* To add to the list: +* Class_Identifier_enqueue(&name, object); +* +* To iterate over the list: +* Class_Identifier_Queue_Node *it = name.front; +* while(it) { do_something_to_(it->value); it = it->next; } +* +* To delete from the list: +* If it's the first node: +* Class_Identifier_dequeue(&name); +* If it's not: +* predecessor_node->next_ptr = deleted_node->next_ptr; +* name.size--; +* +* Copyright (C) 2009-2014 Texas Instruments Incorporated - http://www.ti.com/ +* +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +*/ + +#ifndef QUEUE_H +#define QUEUE_H + +#include <inttypes.h> +#include "dload_api.h" + +/*****************************************************************************/ +/* TYPE_QUEUE_DEFINITION() - Define structure specifications for a linked */ +/* list of t_name objects. */ +/*****************************************************************************/ +#define TYPE_QUEUE_DEFINITION(t, t_name) \ +struct t_name##_Queue_Node_ \ +{ \ + t value; \ + struct t_name##_Queue_Node_* next_ptr; \ +}; \ +typedef struct t_name##_Queue_Node_ t_name##_Queue_Node; \ + \ +typedef struct \ +{ \ + t_name##_Queue_Node* front_ptr; \ + t_name##_Queue_Node* back_ptr; \ + int32_t size; \ +} t_name##_Queue; \ + \ +extern void t_name##_initialize_queue(t_name##_Queue* queue); \ +extern void t_name##_enqueue(t_name##_Queue* queue, t to_enqueue); \ +extern t t_name##_dequeue(t_name##_Queue* queue); \ +extern void t_name##_remove(t_name##_Queue* queue, t to_remove); + +/*****************************************************************************/ +/* TYPE_QUEUE_INITIALIZER() - Define the initializer to initialize Queues. */ +/*****************************************************************************/ +#define TYPE_QUEUE_INITIALIZER {NULL, NULL, 0} + + +/*****************************************************************************/ +/* TYPE_QUEUE_IMPLEMENTATION() - Define member functions of new linked list */ +/* "class" of t_name objects. */ +/* */ +/* <type>_initialize_queue() - clears the queue */ +/* <type>_enqueue() - adds a <t> type object to the end of the queue */ +/* <type>_dequeue() - remove a <t> type object from the front of the queue */ +/* and provide access to it to the caller */ +/* <type>_remove() - find and remove a <t> type object from the queue */ +/*****************************************************************************/ +#define TYPE_QUEUE_IMPLEMENTATION(t, t_name) \ +void t_name##_initialize_queue (t_name##_Queue* queue) \ +{ \ + queue->front_ptr = queue->back_ptr = NULL; \ + queue->size = 0; \ +} \ +void t_name##_enqueue(t_name##_Queue* queue, t to_enqueue) \ +{ \ + queue->size++; \ + \ + if(!queue->back_ptr) \ + queue->back_ptr = queue->front_ptr = \ + (t_name##_Queue_Node*) \ + (DLIF_malloc(sizeof(t_name##_Queue_Node))); \ + else \ + { \ + queue->back_ptr->next_ptr = \ + (t_name##_Queue_Node*)(DLIF_malloc( \ + sizeof(t_name##_Queue_Node))); \ + queue->back_ptr = queue->back_ptr->next_ptr; \ + } \ + \ + queue->back_ptr->value = to_enqueue; \ + queue->back_ptr->next_ptr = NULL; \ +} \ + \ +t t_name##_dequeue(t_name##_Queue* queue) \ +{ \ + t to_ret; \ + t_name##_Queue_Node* next_ptr = NULL; \ + \ + if (!queue->size) return (t) NULL; \ + \ + next_ptr = queue->front_ptr->next_ptr; \ + queue->size--; \ + to_ret = queue->front_ptr->value; \ + DLIF_free((void*)(queue->front_ptr)); \ + \ + if(!queue->size) \ + queue->front_ptr = queue->back_ptr = NULL; \ + else \ + queue->front_ptr = next_ptr; \ + \ + return to_ret; \ +} \ + \ +void t_name##_remove(t_name##_Queue* queue, t to_remove) \ +{ \ + t_name##_Queue_Node* prev_ptr = NULL; \ + t_name##_Queue_Node* curr_ptr = queue->front_ptr; \ + t_name##_Queue_Node* next_ptr = NULL; \ + \ + for (; curr_ptr; curr_ptr = next_ptr) \ + { \ + next_ptr = curr_ptr->next_ptr; \ + if (curr_ptr->value == to_remove) break; \ + prev_ptr = curr_ptr; \ + } \ + \ + if (curr_ptr) \ + { \ + if (prev_ptr) prev_ptr->next_ptr = next_ptr; \ + queue->size--; \ + DLIF_free((void*)(curr_ptr)); \ + } \ + \ + if (!queue->size) \ + queue->front_ptr = queue->back_ptr = NULL; \ + else \ + { \ + if (!prev_ptr) queue->front_ptr = next_ptr; \ + if (!next_ptr) queue->back_ptr = prev_ptr; \ + } \ +} + + +#endif diff --git a/src/core/dsp/ocl_load/DLOAD/Stack.h b/src/core/dsp/ocl_load/DLOAD/Stack.h new file mode 100644 index 0000000..d36f5e0 --- /dev/null +++ b/src/core/dsp/ocl_load/DLOAD/Stack.h @@ -0,0 +1,155 @@ +/* +* Stack.h +* +* Interface to Stack +* ------------------ +* +* This is an implementation of a type-independent stack implemented as +* a signly linked list class for C. It's basically a template class, but +* uses macros instead, so that it can be compiled with a C-only compiler. +* +* To define a Stack class: +* #include "Stack.h" +* TYPE_STACK_DEFINITION(object_type,Class_Identifier) +* +* In a separate C file: +* #include "Stack.h" +* TYPE_STACK_DEFINITION(object_type,Class_Identifier) +* TYPE_STACK_IMPLEMENTATION(object_type,Class_Identifier) +* +* Now, to create a stack: +* struct Class_Identifier_Stack name; +* Get it initialized to zero everywhere somehow, maybe like this: +* initialize_stack_Class_Identifier(&name); +* +* To add to the stack: +* push_Class_Identifier(&name, object); +* +* To access the top of the stack: +* Class_Identifier_Stack_Node *tos = name.top_ptr; +* do_something_to_(tos->value); +* +* To delete from the stack: +* if (name.size > 0) pop_Class_Identifier(&name); +* +* Copyright (C) 2009-2014 Texas Instruments Incorporated - http://www.ti.com/ +* +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +*/ + +#ifndef STACK_H +#define STACK_H + +#include <inttypes.h> +#include "dload_api.h" + +/*****************************************************************************/ +/* TYPE_STACK_DEFINITION() - Define structure specifications for a last-in, */ +/* first-out linked list of t_name objects. */ +/*****************************************************************************/ +#define TYPE_STACK_DEFINITION(t, t_name) \ +struct t_name##_Stack_Node_ \ +{ \ + t value; \ + struct t_name##_Stack_Node_* next_ptr; \ +}; \ +typedef struct t_name##_Stack_Node_ t_name##_Stack_Node; \ + \ +typedef struct \ +{ \ + t_name##_Stack_Node* top_ptr; \ + t_name##_Stack_Node* bottom_ptr; \ + int size; \ +} t_name##_Stack; \ + \ +extern void t_name##_initialize_stack(t_name##_Stack* stack); \ +extern void t_name##_push(t_name##_Stack* stack, t to_push); \ +extern t t_name##_pop(t_name##_Stack* stack); + +/*****************************************************************************/ +/* TYPE_STACK_DEFINITION() - Define the initializer to initalize Stacks. */ +/*****************************************************************************/ +#define TYPE_STACK_INITIALIZER {NULL, NULL, 0 } + +/*****************************************************************************/ +/* TYPE_STACK_IMPLEMENTATION() - Define member functions of new LIFO linked */ +/* list "class" of t_name objects. */ +/* */ +/* <type>_initialize_stack() - clears the stack */ +/* <type>_push() - pushes a <t> type object to the top of the stack */ +/* <type>_pop() - pop a <t> type object from the top of the stack */ +/* and provide access to it to the caller */ +/*****************************************************************************/ +#define TYPE_STACK_IMPLEMENTATION(t, t_name) \ +void t_name##_initialize_stack (t_name##_Stack* stack) \ +{ \ + stack->top_ptr = stack->bottom_ptr = NULL; \ + stack->size = 0; \ +} \ +void t_name##_push(t_name##_Stack* stack, t to_push) \ +{ \ + stack->size++; \ + \ + if(!stack->top_ptr) \ + { \ + stack->bottom_ptr = stack->top_ptr = \ + (t_name##_Stack_Node*)(DLIF_malloc(sizeof(t_name##_Stack_Node))); \ + stack->top_ptr->next_ptr = NULL; \ + } \ + else \ + { \ + t_name##_Stack_Node* next_ptr = stack->top_ptr; \ + stack->top_ptr = \ + (t_name##_Stack_Node*)(DLIF_malloc(sizeof(t_name##_Stack_Node))); \ + stack->top_ptr->next_ptr = next_ptr; \ + } \ + \ + stack->top_ptr->value = to_push; \ +} \ + \ +t t_name##_pop(t_name##_Stack* stack) \ +{ \ + t to_ret; \ + t_name##_Stack_Node* next_ptr = stack->top_ptr->next_ptr; \ + \ + stack->size--; \ + to_ret = stack->top_ptr->value; \ + DLIF_free((void*)(stack->top_ptr)); \ + \ + if(!stack->size) \ + stack->top_ptr = stack->bottom_ptr = NULL; \ + else \ + stack->top_ptr = next_ptr; \ + \ + return to_ret; \ +} + +#endif diff --git a/src/core/dsp/ocl_load/DLOAD/dload.c b/src/core/dsp/ocl_load/DLOAD/dload.c new file mode 100644 index 0000000..e5924d8 --- /dev/null +++ b/src/core/dsp/ocl_load/DLOAD/dload.c @@ -0,0 +1,3534 @@ +/* +* dload.c +* +* Core Dynamic Loader Reference Implementation +* +* This implementation of the core dynamic loader is platform independent, +* but it is object file format dependent. In particular, this +* implementation supports ELF object file format. +* +* Copyright (C) 2009-2014 Texas Instruments Incorporated - http://www.ti.com/ +* +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +*/ + +#include <limits.h> +#include <inttypes.h> +#include <string.h> +#include <time.h> + +#include "ArrayList.h" +#include "Queue.h" +#include "Stack.h" + +#include "symtab.h" +#include "dload_endian.h" +#include "elf32.h" +#include "dload.h" +#include "relocate.h" +#include "dload_api.h" + +#ifdef ARM_TARGET +#include "arm_dynamic.h" +#endif + +#ifdef C60_TARGET +#include "c60_dynamic.h" +#endif + +#include "virtual_targets.h" + +/*---------------------------------------------------------------------------*/ +/* These globals are used only to test the reference client implementation. */ +/*---------------------------------------------------------------------------*/ +int global_argc; +char **global_argv; + +/*---------------------------------------------------------------------------*/ +/* Contains filenames (type const char*) the system is in the process of */ +/* loading. Used to detect cycles in incorrectly compiled ELF binaries. */ +/*---------------------------------------------------------------------------*/ +Array_List DLIMP_module_dependency_list; + +/*---------------------------------------------------------------------------*/ +/* Contains objects (type DLIMP_Loaded_Module) that the system has loaded into */ +/* target memory. */ +/*---------------------------------------------------------------------------*/ +TYPE_QUEUE_IMPLEMENTATION(DLIMP_Loaded_Module*, loaded_module_ptr) +loaded_module_ptr_Queue DLIMP_loaded_objects = TYPE_QUEUE_INITIALIZER; + +/*---------------------------------------------------------------------------*/ +/* Dependency Graph Queue - FIFO queue of dynamic modules that are loaded */ +/* when client asks to load a dynamic executable or library. Note that */ +/* dependents that have already been loaded with another module will not */ +/* appear on this queue. */ +/*---------------------------------------------------------------------------*/ +TYPE_STACK_IMPLEMENTATION(DLIMP_Dynamic_Module*, dynamic_module_ptr) +dynamic_module_ptr_Stack DLIMP_dependency_stack = TYPE_STACK_INITIALIZER; + +/*---------------------------------------------------------------------------*/ +/* Current virtual target set after reading the file headers. This is used */ +/* to access target specific functions. */ +/*---------------------------------------------------------------------------*/ +VIRTUAL_TARGET *cur_target = NULL; + +/*---------------------------------------------------------------------------*/ +/* Support for profiling performance of dynamic loader core. */ +/*---------------------------------------------------------------------------*/ +#if LOADER_DEBUG +static clock_t cycle0 = 0; +static clock_t cycle_end = 0; +#define profile_start_clock() (cycle0 = clock()) +#define profile_stop_clock() (cycle_end = clock()) +#define profile_cycle_count() (cycle_end - cycle0) +#endif + +/*---------------------------------------------------------------------------*/ +/* The dynamic loader will now create a table TI_init_table to store */ +/* pre-init and init data. This is done because pre-init and */ +/* init functions could reference as-yet unrelocated symbols from other */ +/* modules. As such it is safer to store relevant function addresses and */ +/* execute them only after all modules are relocated. */ +/*---------------------------------------------------------------------------*/ +TYPE_QUEUE_IMPLEMENTATION(IF_single_record*, IF_table) +IF_table_Queue TI_init_table = TYPE_QUEUE_INITIALIZER; + +static VIRTUAL_TARGET *get_vt_obj(int given_id); +static void read_args_from_section(DLIMP_Loaded_Module* ep_module); +static BOOL seg_has_space_for_write(DLIMP_Loaded_Module* lmodule, int sz); +static BOOL write_arguments_to_args_section(DLOAD_HANDLE handle, + int argc, char** argv, + DLIMP_Loaded_Module *ep_module); + +/*****************************************************************************/ +/* DLOAD_create() */ +/* */ +/* Create an instance of the dynamic loader core. */ +/* */ +/* client_handle: Private client token to be returned during select DLIF */ +/* function calls. */ +/* */ +/* returns: an opaque DLOAD core loader handle, identifying this instance.*/ +/* */ +/*****************************************************************************/ +DLOAD_HANDLE DLOAD_create(void *client_handle) +{ + LOADER_OBJECT *pLoaderObject = DLIF_malloc(sizeof(LOADER_OBJECT)); + + /*-----------------------------------------------------------------------*/ + /* Fill out the Loader Object: */ + /*-----------------------------------------------------------------------*/ + /* Set up initial objects_loading queue. */ + /*-----------------------------------------------------------------------*/ + AL_initialize(&(pLoaderObject->DLIMP_module_dependency_list), + sizeof (const char*), 1); + + /*-----------------------------------------------------------------------*/ + /* Initialize Loaded Module Ptr Queue */ + /*-----------------------------------------------------------------------*/ + loaded_module_ptr_initialize_queue(&pLoaderObject->DLIMP_loaded_objects); + + /*-----------------------------------------------------------------------*/ + /* Initialize Dynamic Module Ptr Stack */ + /*-----------------------------------------------------------------------*/ + dynamic_module_ptr_initialize_stack(&pLoaderObject->DLIMP_dependency_stack); + + pLoaderObject->file_handle = 1; + + /*-----------------------------------------------------------------------*/ + /* Store client token, so it can be handed back during DLIF calls */ + /*-----------------------------------------------------------------------*/ + pLoaderObject->client_handle = client_handle; + + return((DLOAD_HANDLE)pLoaderObject); +} + +/*****************************************************************************/ +/* DLOAD_destroy() */ +/* */ +/* Remove an instance of the dynamic loader core, and free all resources */ +/* allocated during DLOAD_create(). */ +/* */ +/* client_handle: Private client token to be returned during select DLIF */ +/* function calls. */ +/* Preconditions: 1) handle must be valid. */ +/* 2) Loader instance must be in "UNLOADED" state. */ +/* */ +/*****************************************************************************/ +void DLOAD_destroy(DLOAD_HANDLE handle) +{ + LOADER_OBJECT * pLoaderObject; + + pLoaderObject = (LOADER_OBJECT *)handle; + AL_destroy(&(pLoaderObject->DLIMP_module_dependency_list)); + + /*--------------------------*/ + /* Free the instance object */ + /*--------------------------*/ + DLIF_free (pLoaderObject); +} + +/*****************************************************************************/ +/* DLIMP_get_first_dyntag() */ +/* */ +/* Return value for first tag entry in the given dynamic table whose */ +/* tag type matches the given key. */ +/* */ +/*****************************************************************************/ +uint32_t DLIMP_get_first_dyntag(int tag, struct Elf32_Dyn* dyn_table) +{ + /*------------------------------------------------------------------------*/ + /* Spin through dynamic segment looking for a specific dynamic tag. */ + /* Return the value associated with the tag, if the tag is found. */ + /*------------------------------------------------------------------------*/ + struct Elf32_Dyn *dtp = dyn_table; + + while (dtp->d_tag != DT_NULL) + { + if (dtp->d_tag == tag) return dtp->d_un.d_val; + else dtp++; + } + + /*------------------------------------------------------------------------*/ + /* Tag wasn't found, return a known bogus value for the tag. */ + /*------------------------------------------------------------------------*/ + return INT_MAX; +} + +/*****************************************************************************/ +/* dload_and_allocate_dependencies() */ +/* */ +/* If not already loaded, load each dependent file identified in the */ +/* dynamic segment with a DT_NEEDED tag. Dependent files are listed in */ +/* order and should be loaded in the same order that they appear in the */ +/* dynamic segment. */ +/* */ +/*****************************************************************************/ +static BOOL dload_and_allocate_dependencies( DLOAD_HANDLE handle, + DLIMP_Dynamic_Module *dyn_module) +{ + /*------------------------------------------------------------------------*/ + /* Spin through each dynamic tag entry in the dynamic segment. */ + /*------------------------------------------------------------------------*/ + struct Elf32_Dyn* dyn_nugget = dyn_module->dyntab; + LOADER_OBJECT *pHandle = (LOADER_OBJECT *)handle; + +#if LOADER_DEBUG + if (debugging_on) + DLIF_trace("Starting dload_and_allocate_dependencies() for %s ...\n", + dyn_module->name); +#endif + + while(dyn_nugget->d_tag != DT_NULL) + { + /*---------------------------------------------------------------------*/ + /* For each DT_NEEDED dynamic tag that we find in the dynamic segment, */ + /* load the dependent file identified by the so_name value attached */ + /* to the DT_NEEDED dynamic tag. */ + /*---------------------------------------------------------------------*/ + if (dyn_nugget->d_tag == DT_NEEDED) + { + loaded_module_ptr_Queue_Node* ptr; + +#if LOADER_DEBUG + if (debugging_on) + DLIF_trace("Found DT_NEEDED: %s\n", + dyn_module->strtab+dyn_nugget->d_un.d_val); +#endif + + /*------------------------------------------------------------------*/ + /* Find out if the file named by the DT_NEEDED tag has already */ + /* been loaded. If it has, then we only have to bump the use count */ + /* of the named dependent file. */ + /*------------------------------------------------------------------*/ + for (ptr = pHandle->DLIMP_loaded_objects.front_ptr; ptr != NULL; + ptr = ptr->next_ptr) + { + + + if (!strcmp(ptr->value->name, + dyn_module->strtab + dyn_nugget->d_un.d_val)) + { + ptr->value->use_count++; + AL_append(&(dyn_module->loaded_module->dependencies), + &(ptr->value->file_handle)); + break; + } + } + + /*------------------------------------------------------------------*/ + /* If the named dependent file has not been loaded, then we ask the */ + /* client to invoke a load of the dependent file on our behalf. */ + /*------------------------------------------------------------------*/ + if (ptr == NULL) + { + int32_t dependent_handle = DLIF_load_dependent( + pHandle->client_handle, + dyn_module->strtab + + dyn_nugget->d_un.d_val); + AL_append(&(dyn_module->loaded_module->dependencies), + &dependent_handle); + if (dependent_handle == 0) return FALSE; + } + } + + dyn_nugget++; + } + +#if LOADER_DEBUG + if (debugging_on) + DLIF_trace("Finished dload_and_allocate_dependencies() for %s\n", + dyn_module->name); +#endif + + return TRUE; +} + +/*****************************************************************************/ +/* load_object() */ +/* */ +/* Finish the process of loading an object file. */ +/* */ +/*****************************************************************************/ +static int load_object(LOADER_FILE_DESC *fd, DLIMP_Dynamic_Module *dyn_module) +{ + /*------------------------------------------------------------------------*/ + /* With the dynamic loader already running on the target, we are able to */ + /* relocate directly into target memory, so there is nothing more to be */ + /* done (at least in the bare-metal dynamic linking ABI model). */ + /*------------------------------------------------------------------------*/ + return 1; +} + +/*****************************************************************************/ +/* write_arguments_to_args_section() */ +/* */ +/* Write argv and argc to .args section. */ +/* */ +/*****************************************************************************/ +static BOOL write_arguments_to_args_section(DLOAD_HANDLE handle, + int argc, char** argv, + DLIMP_Loaded_Module *ep_module) +{ + int mem_inc = MEM_INC; + int ptr_sz = PTR_SZ; + int p_size = ptr_sz / mem_inc; + int i_size = T_INTSZ / mem_inc; + int c_size = T_CHARSZ /mem_inc; + int argv_offset = 0; + int str_offset = 0; + int size = 0; + int arg; + int *targ_argv_pointers = NULL; + LOADER_OBJECT *pHandle = (LOADER_OBJECT *)handle; + + uint8_t *c_args = NULL; + +#if LOADER_DEBUG + if (debugging_on) + DLIF_trace("Write_arguments_to_args_section:\n"); +#endif + + /*-----------------------------------------------------------------------*/ + /* IF NO ARGUMENTS, ABORT QUIETLY, WITH a SUCCESSFUL CODE. */ + /*-----------------------------------------------------------------------*/ + if (argc == 0) return TRUE; + + /*-----------------------------------------------------------------------*/ + /* __c_args__ points to the beginning of the .args section, if there */ + /* is one. This is stored in the Loaded Module, and must have a */ + /* legitimate address. If not, abort with Warning. */ + /*-----------------------------------------------------------------------*/ + c_args = ep_module->c_args; + if (!c_args || c_args == (uint8_t *)0xFFFFFFFF) + { + DLIF_warning(DLWT_MISC, "__c_args__ does not have valid value.\n"); + return FALSE; + } + + /*-----------------------------------------------------------------------*/ + /* WE OUGHT TO WORRY ABOUT ALIGNMENT: IF SECTION ISN'T PROPERLY ALIGNED, */ + /* ABORT THE PROCESSING OF ARGUMENTS WITH A NICE ERROR MESSAGE. */ + /*-----------------------------------------------------------------------*/ + if (c_args && ((Elf32_Addr)c_args & (MAX(p_size, i_size) - 1))) + { + DLIF_warning(DLWT_MISC, ".args section not properly aligned\n"); + return FALSE; + } + + /*-----------------------------------------------------------------------*/ + /* CALCULATE OFFSET IN TABLE WHERE ARGV AND THE STRINGS WILL BE STORED. */ + /* NOTE THAT argv MAY NEED MORE ALIGNMENT THAN AN INTEGER, SO ITS OFFSET */ + /* IS REALLY THE MAXIMUM OF A POINTER SIZE AND INTEGER SIZE. ALSO NOTE */ + /* WE NEED TO ALLOCATE AN EXTRA POINTER FOR argv[argc]. */ + /*-----------------------------------------------------------------------*/ + argv_offset = MAX(p_size, i_size); + str_offset = argv_offset + (argc * p_size) + p_size ; + + /*-----------------------------------------------------------------------*/ + /* CALCULATE SPACE REQUIRED FOR WRITING OUT .args SECTION. CHECK IF THE */ + /* SEGMENT HAS ENOUGH SPACE AVAILABLE. IF NOT, RETURN WITH ERROR CODE. */ + /*-----------------------------------------------------------------------*/ + size = str_offset; + + for (arg = 0; arg < argc; arg++) + size += (c_size * (strlen(argv[arg]) + 1)); + + if (!seg_has_space_for_write(ep_module, size)) + { + DLIF_warning(DLWT_MISC, + "Segment has insufficient space for .args contents\n"); + return FALSE; + } + + /*-----------------------------------------------------------------------*/ + /* OVERALL, WE NEED TO CREATE A TARGET IMAGE THAT CORRESPONDS TO: */ + /* int argc; */ + /* char *argv[argc]; */ + /* <strings pointed to by argv> */ + /* So say, for C6x, for "-v -d", we would need 22 bytes: */ + /* 4 bytes // argc */ + /* 4 bytes // argv[0] pointer value */ + /* 4 bytes // argv[1] pointer value */ + /* 4 bytes // argv[argc] end of pointer value array, normally 0 */ + /* 3 bytes // "-v" */ + /* 3 bytes // "-d" */ + /*-----------------------------------------------------------------------*/ + + /*-----------------------------------------------------------------------*/ + /* FIRST WRITE OUT ARGC. */ + /*-----------------------------------------------------------------------*/ +#if LOADER_DEBUG + if (debugging_on) + DLIF_trace ("-- Copy %d bytes from 0x%x to 0x%x\n", + i_size, (uint32_t) &argc, (uint32_t) c_args); +#endif + + DLIF_memcpy(pHandle->client_handle, c_args, &argc, i_size); + + /*-----------------------------------------------------------------------*/ + /* CREATE AN INTERNAL ARRAY OF ARGV POINTER VALUES, THEN WRITE THEM OUT */ + /*-----------------------------------------------------------------------*/ + targ_argv_pointers = (int *)DLIF_malloc((argc + 1) * sizeof(int)); + for (arg = 0; arg < argc ; arg++) + { + targ_argv_pointers[arg] = (int)(str_offset + c_args); + str_offset += (strlen(argv[arg]) + 1) * c_size; + +#if LOADER_DEBUG + if (debugging_on) + DLIF_trace ("\t\ttarg_argv_pointers[%d] : 0x%x\n", + arg, targ_argv_pointers[arg]); +#endif + } + + targ_argv_pointers[argc] = 0; + + /*-----------------------------------------------------------------------*/ + /* WRITE OUT THIS INTERNAL ARRAY OF ARGV POINTER VALUES */ + /*-----------------------------------------------------------------------*/ + for (arg = 0; arg <= argc; arg++) + { +#if LOADER_DEBUG + if (debugging_on) + DLIF_trace ("-- Copy %d bytes from 0x%x to 0x%x\n", + p_size, (uint32_t) &targ_argv_pointers[arg], + (uint32_t) (c_args + argv_offset)); +#endif + DLIF_memcpy(pHandle->client_handle, + (void *)(c_args + argv_offset), + &targ_argv_pointers[arg], + p_size); + argv_offset += p_size; + } + +#if LOADER_DEBUG +if (debugging_on) +{ + DLIF_trace ("\t\targv being copied : 0x%x\n",(uint32_t)argv); + for (arg = 0; arg < argc; arg++) + { + DLIF_trace ("\t\t---\n\t\t&argv[%d] being copied : 0x%x\n", arg, + (uint32_t)&argv[arg]); + DLIF_trace ("\t\targv[%d] being copied : 0x%x\n",arg, + (uint32_t)argv[arg]); + DLIF_trace ("\t\targv[%d] being copied : %s\n",arg, (char *)argv[arg]); + } +} +#endif + + /*-----------------------------------------------------------------------*/ + /* LASTLY WRITE OUT ALL THE STRINGS. */ + /*-----------------------------------------------------------------------*/ + for (arg = 0; arg < argc; arg++) + { +#if LOADER_DEBUG + if (debugging_on) + DLIF_trace ("-- Copy %d bytes from 0x%x to 0x%x\n", + (uint32_t)strlen(argv[arg]) + 1, + (uint32_t)&argv[arg], + (uint32_t)(targ_argv_pointers[arg])); +#endif + DLIF_memcpy(pHandle->client_handle, + (void *)(targ_argv_pointers[arg]), + argv[arg], + strlen(argv[arg]) + 1); + } + + return TRUE; +} + + +/*****************************************************************************/ +/* initialize_loaded_module() */ +/* */ +/* Initialize DLIMP_Loaded_Module internal data object associated with a */ +/* dynamic module. This function will also set up a queue of */ +/* DLIMP_Loaded_Segment(s) associated with the loaded module. */ +/* This function is called as we are getting ready to actually load the */ +/* object file contents into target memory. Each segment will get a */ +/* target memory request that it can use to ask the client for target */ +/* memory space. This function will also assign a file handle to the */ +/* loaded module. */ +/* */ +/*---------------------------------------------------------------------------*/ +/* */ +/* In applications that use the DSBT model, this function will also need to */ +/* negotiate the module's DSBT index with the client. */ +/* */ +/*****************************************************************************/ +static void initialize_loaded_module(DLOAD_HANDLE handle, + DLIMP_Dynamic_Module *dyn_module) +{ + int i; + LOADER_OBJECT *pHandle = (LOADER_OBJECT *)handle; + + /*------------------------------------------------------------------------*/ + /* Allocate a DLIMP_Loaded_Module data structure for the specified ELF */ + /* file and assign a file handle for it (bumping the file handle counter */ + /* as we go). */ + /*------------------------------------------------------------------------*/ + DLIMP_Loaded_Module *loaded_module = + dyn_module->loaded_module = DLIF_malloc(sizeof(DLIMP_Loaded_Module)); + +#if LOADER_DEBUG || LOADER_PROFILE + /*------------------------------------------------------------------------*/ + /* Start clock on initialization of loaded module object. */ + /*------------------------------------------------------------------------*/ + if (debugging_on || profiling_on) + { + DLIF_trace("Starting initialize_loaded_module() ...\n"); + if (profiling_on) profile_start_clock(); + } +#endif + + if (dyn_module->name) + { + loaded_module->name = DLIF_malloc(strlen(dyn_module->name) + 1); + strcpy(loaded_module->name, dyn_module->name); + } + else + loaded_module->name = "<unknown>"; + + loaded_module->file_handle = pHandle->file_handle++; + loaded_module->direct_dependent_only = dyn_module->direct_dependent_only; + loaded_module->use_count = 1; + + /*------------------------------------------------------------------------*/ + /* In case we wrapped around the file handle, return error. */ + /*------------------------------------------------------------------------*/ + if (pHandle->file_handle == 0) + DLIF_error(DLET_MISC, "DLOAD File handle overflowed.\n"); + + /*------------------------------------------------------------------------*/ + /* Initially the loaded module does not have access to its global */ + /* symbols. These need to be copied from the dynamic module (see call */ + /* to DLSYM_copy_globals() below). */ + /* */ + /* THESE INITIALIZATIONS SHOULD BE MOVED TO AN INIT ROUTINE FOR THE */ + /* LOADED MODULE */ + /*------------------------------------------------------------------------*/ + loaded_module->gsymtab = NULL; + loaded_module->gstrtab = NULL; + loaded_module->gsymnum = loaded_module->gstrsz = 0; + + /*------------------------------------------------------------------------*/ + /* Initialize the Array_List of dependencies. */ + /*------------------------------------------------------------------------*/ + AL_initialize(&(loaded_module->dependencies), sizeof(int), 1); + + if (dyn_module->symtab) + DLSYM_copy_globals(dyn_module); + + /*------------------------------------------------------------------------*/ + /* Initialize the module loaded segments Array_List. */ + /*------------------------------------------------------------------------*/ + AL_initialize(&(loaded_module->loaded_segments), + sizeof(DLIMP_Loaded_Segment), dyn_module->phnum); + + /*------------------------------------------------------------------------*/ + /* Spin thru segment headers and process each load segment encountered. */ + /*------------------------------------------------------------------------*/ + for (i = 0; i < dyn_module->phnum; i++) + if (dyn_module->phdr[i].p_type == PT_LOAD) + { + /*------------------------------------------------------------------*/ + /* Note that this is parallel to and does not supplant the ELF */ + /* phdr tables. */ + /*------------------------------------------------------------------*/ + DLIMP_Loaded_Segment seg; + seg.obj_desc = DLIF_malloc(sizeof(struct DLOAD_MEMORY_SEGMENT)); + seg.phdr.p_vaddr = dyn_module->phdr[i].p_vaddr; + seg.phdr.p_offset = dyn_module->phdr[i].p_offset; + seg.obj_desc->target_page = 0; /*not used*/ + seg.modified = 0; + seg.phdr.p_filesz = seg.obj_desc->objsz_in_bytes + = dyn_module->phdr[i].p_filesz; + seg.phdr.p_memsz = seg.obj_desc->memsz_in_bytes + = dyn_module->phdr[i].p_memsz; + seg.phdr.p_align = dyn_module->phdr[i].p_align; + seg.phdr.p_flags = dyn_module->phdr[i].p_flags; + AL_append(&(loaded_module->loaded_segments), &seg); + } + + /*------------------------------------------------------------------------*/ + /* Initialize the DSO termination information for this module. */ + /* It will be copied over from the enclosing dyn_module object when */ + /* placement is completed and dyn_module's local copy of the dynamic */ + /* table is updated. */ + /*------------------------------------------------------------------------*/ + loaded_module->fini_array = (Elf32_Addr) NULL; + loaded_module->fini_arraysz = 0; + loaded_module->fini = (Elf32_Addr) NULL; + +#if LOADER_DEBUG || LOADER_PROFILE + if (debugging_on || profiling_on) + { + DLIF_trace("Finished initialize_loaded_module()\n"); + if (profiling_on) + { + profile_stop_clock(); + DLIF_trace("Took %lu cycles.\n", + (unsigned long)profile_cycle_count()); + } + } +#endif + +} + +/*****************************************************************************/ +/* load_static_segment() */ +/* */ +/* The core dynamic loader requires that a statically linked executable */ +/* be placed in target memory at the location that was determined during */ +/* the static link that created the executable. Failure to get the */ +/* required target memory where the static executable is to be loaded */ +/* will cause the dynamic loader to emit an error and abort the load. */ +/* */ +/*****************************************************************************/ +static BOOL load_static_segment(DLOAD_HANDLE handle, LOADER_FILE_DESC *fd, + DLIMP_Dynamic_Module *dyn_module) +{ + int i; + DLIMP_Loaded_Segment* seg = (DLIMP_Loaded_Segment*) + (dyn_module->loaded_module->loaded_segments.buf); + LOADER_OBJECT *pHandle = (LOADER_OBJECT *)handle; + + /*------------------------------------------------------------------------*/ + /* For each segment in the loaded module, build up a target memory */ + /* request for the segment, get rights to target memory where we want */ + /* to load the segment from the client, then get the client to write the */ + /* segment contents out to target memory to the appropriate address. */ + /*------------------------------------------------------------------------*/ + for (i = 0; i < dyn_module->loaded_module->loaded_segments.size; i++) + { + struct DLOAD_MEMORY_REQUEST targ_req; + seg[i].obj_desc->target_page = 0; + targ_req.flags = 0; + + /*---------------------------------------------------------------------*/ + /* This is a static executable. DLIF_allocate should give us the */ + /* address we ask for or fail. */ + /*---------------------------------------------------------------------*/ + if (seg[i].phdr.p_flags & PF_X) targ_req.flags |= DLOAD_SF_executable; + if (seg[i].phdr.p_flags & PF_W) targ_req.flags |= DLOAD_SF_writable; + + + targ_req.align = seg[i].phdr.p_align; + seg[i].obj_desc->target_address = (TARGET_ADDRESS)seg[i].phdr.p_vaddr; + targ_req.flags &= ~DLOAD_SF_relocatable; + targ_req.fp = fd; + targ_req.segment = seg[i].obj_desc; + targ_req.offset = seg[i].phdr.p_offset; + targ_req.flip_endian = dyn_module->wrong_endian; + + /*---------------------------------------------------------------------*/ + /* Ask the client side of the dynamic loader to allocate target memory */ + /* for this segment to be loaded into. */ + /*---------------------------------------------------------------------*/ + if (!DLIF_allocate(pHandle->client_handle, &targ_req)) return FALSE; + + /*---------------------------------------------------------------------*/ + /* If there is any initialized data in the segment, we'll first write */ + /* it into a host writable buffer (DLIF_copy()) and then flush it to */ + /* target memory. */ + /*---------------------------------------------------------------------*/ + if (seg[i].phdr.p_filesz) + { + DLIF_copy(pHandle->client_handle, &targ_req); + DLIF_write(pHandle->client_handle, &targ_req); + } + } + + return TRUE; +} + +/*****************************************************************************/ +/* relocate_target_dynamic_tag_info() */ +/* */ +/* Update a target specific dynamic tag value that happens to be a */ +/* virtual address of a section. Returns TRUE if the tag was updated or */ +/* is not a virtual address and FALSE if it was not successfully updated */ +/* or was not recognized. */ +/*****************************************************************************/ +static BOOL relocate_target_dynamic_tag_info(DLIMP_Dynamic_Module *dyn_module, + int i) +{ + return cur_target->relocate_dynamic_tag_info(dyn_module, i); +} + +/*****************************************************************************/ +/* DLIMP_update_dyntag_section_address() */ +/* */ +/* Given the index of a dynamic tag which we happen to know points to a */ +/* section address, find the program header table entry associated with */ +/* the specified address and update the tag value with the real address */ +/* of the section. */ +/* */ +/*****************************************************************************/ +BOOL DLIMP_update_dyntag_section_address(DLIMP_Dynamic_Module *dyn_module, + int32_t i) +{ + int j; + DLIMP_Loaded_Segment *seg = (DLIMP_Loaded_Segment *) + (dyn_module->loaded_module->loaded_segments.buf); + + /*------------------------------------------------------------------------*/ + /* If dynamic tag does not access an existing section, then no update */ + /* is required. */ + /*------------------------------------------------------------------------*/ + if (dyn_module->dyntab[i].d_un.d_ptr == (Elf32_Addr)0) + { return TRUE; } + + for (j = 0; j < dyn_module->loaded_module->loaded_segments.size; j++) + { + if ((dyn_module->dyntab[i].d_un.d_ptr >= seg[j].input_vaddr) && + (dyn_module->dyntab[i].d_un.d_ptr < + (seg[j].input_vaddr + seg[j].phdr.p_memsz))) + { + dyn_module->dyntab[i].d_un.d_ptr += + (seg[j].phdr.p_vaddr - seg[j].input_vaddr); + return TRUE; + } + } + + return FALSE; +} + +/*****************************************************************************/ +/* relocate_dynamic_tag_info() */ +/* */ +/* Once segment allocation has been completed, we'll need to go through */ +/* the dynamic table and update any tag values that happen to be virtual */ +/* addresses of segments (DT_C6000_DSBT_BASE, for example). */ +/* */ +/*****************************************************************************/ +static BOOL relocate_dynamic_tag_info(LOADER_FILE_DESC *fd, + DLIMP_Dynamic_Module *dyn_module) +{ + /*------------------------------------------------------------------------*/ + /* Spin through dynamic table loking for tags that have a value which is */ + /* the virtual address of a section. After the sections are allocated, */ + /* we'll need to update these values with the new address of the section. */ + /*------------------------------------------------------------------------*/ + int i; + for (i = 0; dyn_module->dyntab[i].d_tag != DT_NULL; i++) + { + switch (dyn_module->dyntab[i].d_tag) + { + /*------------------------------------------------------------------*/ + /* Only tag values that are virtual addresses will be affected. */ + /*------------------------------------------------------------------*/ + case DT_NEEDED: + case DT_PLTRELSZ: + case DT_HASH: + case DT_STRTAB: + case DT_SYMTAB: + case DT_RELA: + case DT_RELASZ: + case DT_RELAENT: + case DT_STRSZ: + case DT_SYMENT: + case DT_SONAME: + case DT_RPATH: + case DT_SYMBOLIC: + case DT_REL: + case DT_RELSZ: + case DT_RELENT: + case DT_PLTREL: + case DT_DEBUG: + case DT_TEXTREL: + case DT_BIND_NOW: + case DT_INIT_ARRAYSZ: + case DT_RUNPATH: + case DT_FLAGS: + case DT_PREINIT_ARRAYSZ: + continue; + + /*------------------------------------------------------------------*/ + /* NOTE!!! */ + /* case DT_ENCODING: -- tag type has same "id" as DT_PREINIT_ARRAY */ + /*------------------------------------------------------------------*/ + + /*------------------------------------------------------------------*/ + /* This is a generic dynamic tag whose value is a virtual address */ + /* of a section. It needs to be relocated to the section's actual */ + /* address in target memory. */ + /*------------------------------------------------------------------*/ + case DT_PREINIT_ARRAY: + case DT_INIT: + case DT_INIT_ARRAY: + if (!DLIMP_update_dyntag_section_address(dyn_module, i)) + return FALSE; + + continue; + + /*------------------------------------------------------------------*/ + /* Once we have resolved the actual address of termination function */ + /* sections, we need to copy their addresses over to the loaded */ + /* module object (dyn_module will be deleted before we get to */ + /* unloading the module). */ + /*------------------------------------------------------------------*/ + case DT_FINI_ARRAY: + case DT_FINI: + if (!DLIMP_update_dyntag_section_address(dyn_module, i)) + return FALSE; + + if (dyn_module->dyntab[i].d_tag == DT_FINI) + dyn_module->loaded_module->fini = + dyn_module->dyntab[i].d_un.d_ptr; + else + dyn_module->loaded_module->fini_array = + dyn_module->dyntab[i].d_un.d_ptr; + + continue; + + case DT_FINI_ARRAYSZ: + dyn_module->loaded_module->fini_arraysz = + dyn_module->dyntab[i].d_un.d_val; + continue; + + /*------------------------------------------------------------------*/ + /* Is this a virtual address??? */ + /*------------------------------------------------------------------*/ + case DT_JMPREL: /* is this a virtual address??? */ + continue; + + /*------------------------------------------------------------------*/ + /* The remaining dynamic tag types should be target specific. If */ + /* something generic slips through to here, then the handler for */ + /* relocating target specific dynamic tags should fail. */ + /*------------------------------------------------------------------*/ + default: + if (!relocate_target_dynamic_tag_info(dyn_module, i)) + return FALSE; + } + } + + /*------------------------------------------------------------------------*/ + /* We've gotten through all of the dynamic table without incident. */ + /* All dynamic tag values that were virtual section addresses should have */ + /* been updated with the final address of the section that they point to. */ + /*------------------------------------------------------------------------*/ + return TRUE; +} + +/*****************************************************************************/ +/* allocate_dynamic_segments_and relocate_symbols() */ +/* */ +/* Allocate target memory for each segment in this module, getting a */ +/* host-accessible space to copy the content of each segment into. Then */ +/* update the symbol table and program header table to reflect the new */ +/* target address for each segment. Processing of the dynamic relocation */ +/* entries will wait until all dependent files have been loaded and */ +/* allocated into target memory. */ +/* */ +/*---------------------------------------------------------------------------*/ +/* */ +/* The relocation entries in the ELF file do not handle the necessary */ +/* adjustments to the memory addresses in the program header or symbol */ +/* tables. These must be done manually. */ +/* */ +/* This is harder for us than for most dynamic loaders, because we have to */ +/* work in environments without virtual memory and thus where the offsets */ +/* between segments in memory may be different than they were in the file. */ +/* So, even though a dynamic loader usually only has to adjust all the */ +/* segments by a single fixed offset, we need to offset the symbols and */ +/* program header addresses segment by segment. This job is done by the */ +/* function below. */ +/* */ +/*****************************************************************************/ +static BOOL allocate_dynamic_segments_and_relocate_symbols + (DLOAD_HANDLE handle, + LOADER_FILE_DESC *fd, + DLIMP_Dynamic_Module *dyn_module) +{ + int i,j; + DLIMP_Loaded_Segment* seg = (DLIMP_Loaded_Segment*) + (dyn_module->loaded_module->loaded_segments.buf); + struct Elf32_Ehdr *fhdr = &(dyn_module->fhdr); + LOADER_OBJECT *pHandle = (LOADER_OBJECT *)handle; + +#if LOADER_DEBUG || LOADER_PROFILE + if (debugging_on || profiling_on) + { + DLIF_trace("Dynamic executable found.\n" + "Starting allocate_dynamic_segments_and_relocate_symbols()" + "...\n"); + if (profiling_on) profile_start_clock(); + } +#endif + + /*------------------------------------------------------------------------*/ + /* Spin through the list of loaded segments from the current module. */ + /*------------------------------------------------------------------------*/ + for (i = 0; i < dyn_module->loaded_module->loaded_segments.size; i++) + { + /*--------------------------------------------------------------------*/ + /* Allocate target memory for segment via client-provided target */ + /* memory API. */ + /*--------------------------------------------------------------------*/ + int32_t addr_offset; + struct DLOAD_MEMORY_REQUEST targ_req; + seg[i].obj_desc->target_page = 0; + targ_req.flags = 0; + if (seg[i].phdr.p_flags & PF_X) targ_req.flags |= DLOAD_SF_executable; + if (seg[i].phdr.p_flags & PF_W) targ_req.flags |= DLOAD_SF_writable; + + targ_req.align = 0x20; + seg[i].obj_desc->target_address = (TARGET_ADDRESS)seg[i].phdr.p_vaddr; + targ_req.flags |= DLOAD_SF_relocatable; + targ_req.fp = fd; + targ_req.segment = seg[i].obj_desc; + targ_req.offset = seg[i].phdr.p_offset; + targ_req.flip_endian = dyn_module->wrong_endian; + + if (!DLIF_allocate(pHandle->client_handle, &targ_req)) + { + DLIF_error(DLET_MEMORY, "DLIF allocation failure.\n"); + return FALSE; + } + + /*--------------------------------------------------------------------*/ + /* Calculate the offset we need to adjust segment header and symbol */ + /* table addresses. */ + /*--------------------------------------------------------------------*/ + addr_offset = (int32_t)(seg[i].obj_desc->target_address) - + (int32_t)(seg[i].phdr.p_vaddr); + +#if LOADER_DEBUG + if (debugging_on) + { + DLIF_trace("Segment %d (at 0x%x, 0x%x bytes) relocated to 0x%x\n", i, + (int32_t)(seg[i].phdr.p_vaddr), + (int32_t)(seg[i].phdr.p_memsz), + (int32_t)(seg[i].obj_desc->target_address)); + DLIF_trace("Addr Offset is 0x%x\n", addr_offset); + } +#endif + + /*--------------------------------------------------------------------*/ + /* Update program entry point if needed. Need to replace to deal */ + /* with full ELF initialization routine. */ + /*--------------------------------------------------------------------*/ + if (dyn_module->relocate_entry_point && + fhdr->e_entry >= (Elf32_Addr)(seg[i].phdr.p_vaddr) && + fhdr->e_entry < + (Elf32_Addr)((uint8_t*)(seg[i].phdr.p_vaddr) + + (uint32_t)(seg[i].phdr.p_memsz))) + { +#if LOADER_DEBUG + if (debugging_on) + { + DLIF_trace("Entry point 0x%x relocated to 0x%x\n", + fhdr->e_entry, fhdr->e_entry + addr_offset); + } +#endif + fhdr->e_entry += addr_offset; + + /*------------------------------------------------------------------*/ + /* Mark the entry point as being relocated so we will not do it */ + /* again. */ + /*------------------------------------------------------------------*/ + dyn_module->relocate_entry_point = FALSE; + } + + /*---------------------------------------------------------------------*/ + /* Fix program header entries in segment and Elf32_Phdr structs. */ + /*---------------------------------------------------------------------*/ + for (j = 0; j < fhdr->e_phnum; j++) + if (dyn_module->phdr[j].p_vaddr == (Elf32_Addr)seg[i].phdr.p_vaddr) + { + dyn_module->phdr[j].p_vaddr += addr_offset; + dyn_module->phdr[i].p_paddr += addr_offset; + break; + } + + seg[i].input_vaddr = (Elf32_Addr)(seg[i].phdr.p_vaddr); + seg[i].phdr.p_vaddr += addr_offset; + + /*---------------------------------------------------------------------*/ + /* Great, now the hard part: fix offsets in symbols. It would be nice */ + /* if there were an easier way to deal with this. */ + /*---------------------------------------------------------------------*/ + { + struct Elf32_Sym *gsymtab = + ((struct Elf32_Sym*)(dyn_module->loaded_module->gsymtab)); + Elf32_Addr segment_start = (Elf32_Addr)seg[i].phdr.p_vaddr; + Elf32_Addr segment_end = (Elf32_Addr)seg[i].phdr.p_vaddr + + seg[i].phdr.p_memsz; + Elf32_Word global_index = dyn_module->symnum - + dyn_module->loaded_module->gsymnum; + + for (j = 0; j < dyn_module->symnum; j++) + { + /*---------------------------------------------------------------*/ + /* Get the relocated symbol value. */ + /*---------------------------------------------------------------*/ + Elf32_Addr symval_adj = dyn_module->symtab[j].st_value + + addr_offset; + + /*---------------------------------------------------------------*/ + /* If the symbol is defined in this segment, update the symbol */ + /* value and mark the symbol so that we don't relocate it again. */ + /*---------------------------------------------------------------*/ + if (symval_adj >= segment_start && symval_adj < segment_end && + dyn_module->symtab[j].st_shndx != INT16_MAX) + { + dyn_module->symtab[j].st_value = symval_adj; + + /*------------------------------------------------------------*/ + /* The module symbol table only has the global symbols. */ + /*------------------------------------------------------------*/ + if (j >= global_index) + gsymtab[j-global_index].st_value = symval_adj; + + /*------------------------------------------------------------*/ + /* Mark the symbol as relocated. */ + /*------------------------------------------------------------*/ + dyn_module->symtab[j].st_shndx = INT16_MAX; + } + } + } + } + + /*------------------------------------------------------------------------*/ + /* Update dynamic tag information. Some dynamic tags have values which */ + /* are virtual addresses of sections. These values need to be updated */ + /* once segment allocation is completed and the new segment addresses are */ + /* known. */ + /*------------------------------------------------------------------------*/ + /* We should only traverse through the dynamic table once because we want */ + /* to avoid the possibility of updating the same tag multiple times (an */ + /* error, if it happens). */ + /*------------------------------------------------------------------------*/ + if (!relocate_dynamic_tag_info(fd, dyn_module)) + { + DLIF_error(DLET_MISC, "Failed dynamic table update.\n"); + return FALSE; + } + +#if LOADER_DEBUG || LOADER_PROFILE + if (debugging_on || profiling_on) + { + DLIF_trace("Finished allocate_dynamic_segments_and_relocate_symbols()\n"); + if (profiling_on) + { + profile_stop_clock(); + DLIF_trace("Took %lu cycles.\n", (unsigned long) profile_cycle_count()); + } + } +#endif + + return TRUE; +} + +/*****************************************************************************/ +/* delete_DLIMP_Loaded_Module() */ +/* */ +/* Free host memory associated with a DLIMP_Loaded_Module data structure */ +/* and all of the DLIMP_Loaded_Segment objects that are associated with */ +/* it. */ +/* */ +/*****************************************************************************/ +static void delete_DLIMP_Loaded_Module(DLOAD_HANDLE handle, + DLIMP_Loaded_Module **pplm) +{ + DLIMP_Loaded_Module *loaded_module = *pplm; + DLIMP_Loaded_Segment *segments = (DLIMP_Loaded_Segment*) + (loaded_module->loaded_segments.buf); + LOADER_OBJECT *pHandle = (LOADER_OBJECT *)handle; + + /*-----------------------------------------------------------------------*/ + /* Spin through the segments attached to this loaded module, freeing up */ + /* any target memory that was allocated by the client for the segment. */ + /*-----------------------------------------------------------------------*/ + int i; + for (i = 0; i < loaded_module->loaded_segments.size; i++) + { + if (!DLIF_release(pHandle->client_handle, segments[i].obj_desc)) + DLIF_error(DLET_MISC, "Failed call to DLIF_release!\n");; + DLIF_free(segments[i].obj_desc); + } + + /*----------------------------------------------------------------------*/ + /* Hacky way of indicating that the base image is no longer available. */ + /* WHHHHAAAAAAATTT!?!?!?!?!?! */ + /*----------------------------------------------------------------------*/ + if (loaded_module->file_handle == DLIMP_application_handle) + DLIMP_application_handle = 0; + + /*-----------------------------------------------------------------------*/ + /* Free host heap memory that was allocated for the internal loaded */ + /* module data structure members. */ + /*-----------------------------------------------------------------------*/ + if (loaded_module->name) DLIF_free(loaded_module->name); + if (loaded_module->gsymtab) DLIF_free(loaded_module->gsymtab); + loaded_module->gsymnum = 0; + if (loaded_module->gstrtab) DLIF_free(loaded_module->gstrtab); + loaded_module->gstrsz = 0; + AL_destroy(&(loaded_module->loaded_segments)); + AL_destroy(&(loaded_module->dependencies)); + + /*-----------------------------------------------------------------------*/ + /* Finally, free the host memory for the loaded module object, then NULL */ + /* the pointer that was passed in. */ + /*-----------------------------------------------------------------------*/ + DLIF_free(loaded_module); + *pplm = NULL; +} + +/*****************************************************************************/ +/* new_DLIMP_Dynamic_Module() */ +/* */ +/* Allocate a dynamic module data structure from host memory and */ +/* initialize its members to their default values. */ +/* */ +/*****************************************************************************/ +static DLIMP_Dynamic_Module *new_DLIMP_Dynamic_Module(LOADER_FILE_DESC *fd) +{ + /*-----------------------------------------------------------------------*/ + /* Allocate space for dynamic module data structure from host memory. */ + /*-----------------------------------------------------------------------*/ + DLIMP_Dynamic_Module *dyn_module = + (DLIMP_Dynamic_Module *)DLIF_malloc(sizeof(DLIMP_Dynamic_Module)); + + /*-----------------------------------------------------------------------*/ + /* Initialize data members of the new dynamic module data structure. */ + /*-----------------------------------------------------------------------*/ + dyn_module->name = NULL; + dyn_module->fd = fd; + dyn_module->phdr = NULL; + dyn_module->phnum = 0; + dyn_module->strtab = NULL; + dyn_module->strsz = 0; + dyn_module->dyntab = NULL; + dyn_module->symtab = NULL; + dyn_module->symnum = 0; + dyn_module->gsymtab_offset = 0; + dyn_module->gstrtab_offset = 0; + dyn_module->c_args = NULL; + dyn_module->argc = 0; + dyn_module->argv = NULL; + dyn_module->loaded_module = NULL; + dyn_module->wrong_endian = 0; + dyn_module->direct_dependent_only = TRUE; + dyn_module->relocatable = FALSE; + dyn_module->relocate_entry_point = TRUE; + + dyn_module->dsbt_size = 0; + dyn_module->dsbt_index = DSBT_INDEX_INVALID; + dyn_module->dsbt_base_tagidx = -1; + + dyn_module->preinit_array_idx = -1; + dyn_module->preinit_arraysz = 0; + dyn_module->init_idx = -1; + dyn_module->init_array_idx = -1; + dyn_module->init_arraysz = 0; + + return dyn_module; +} + +/*****************************************************************************/ +/* detach_loaded_module() */ +/* */ +/* Detach loaded module data structure from given dynamic module. When */ +/* an object file has been successfully loaded, the loader core will */ +/* detach the loaded module data structure from the dynamic module data */ +/* structure because the loaded module must continue to persist until is */ +/* is actually unloaded from target memory. If there is a problem with */ +/* the load, then the host memory associated with the loaded module will */ +/* be released as part of the destruction of the dynamic module. */ +/* */ +/*****************************************************************************/ +static +DLIMP_Loaded_Module *detach_loaded_module(DLIMP_Dynamic_Module *dyn_module) +{ + if (dyn_module && dyn_module->loaded_module) + { + DLIMP_Loaded_Module *loaded_module = dyn_module->loaded_module; + dyn_module->loaded_module = NULL; + return loaded_module; + } + + return NULL; +} +/*****************************************************************************/ +/* delete_DLIMP_Dynamic_Module() */ +/* */ +/* Remove local copies of the string table, symbol table, program header */ +/* table, and dynamic table. */ +/* */ +/*****************************************************************************/ +static void delete_DLIMP_Dynamic_Module(DLOAD_HANDLE handle, + DLIMP_Dynamic_Module **ppdm) +{ + DLIMP_Dynamic_Module *dyn_module = NULL; + + if (!ppdm || (*ppdm == NULL)) + { + DLIF_error(DLET_MISC, + "Internal Error: invalid argument to dynamic module " + "destructor function; aborting loader\n"); + DLIF_exit(1); + } + + dyn_module = *ppdm; + if (dyn_module->name) DLIF_free(dyn_module->name); + if (dyn_module->strtab) DLIF_free(dyn_module->strtab); + if (dyn_module->symtab) DLIF_free(dyn_module->symtab); + if (dyn_module->phdr) DLIF_free(dyn_module->phdr); + if (dyn_module->dyntab) DLIF_free(dyn_module->dyntab); + + /*------------------------------------------------------------------------*/ + /* If we left the loaded module attached to the dynamic module, then */ + /* something must have gone wrong with the load. Remove the loaded */ + /* module from the queue of loaded modules, if it is there. Then free */ + /* the host memory allocated to the loaded module and its segments. */ + /*------------------------------------------------------------------------*/ + if (dyn_module->loaded_module != NULL) + delete_DLIMP_Loaded_Module(handle, &(dyn_module->loaded_module)); + + /*------------------------------------------------------------------------*/ + /* Finally, free the host memory for this dynamic module object and NULL */ + /* the pointer to the object. */ + /*------------------------------------------------------------------------*/ + DLIF_free(dyn_module); + *ppdm = NULL; +} + +/*****************************************************************************/ +/* file_header_magic_number_is_valid() */ +/* */ +/* Given an object file header, check the magic number to ensure that it */ +/* is an object file format that we recognize. This implementation of */ +/* the dynamic loader core will handle ELF object file format. */ +/* */ +/*****************************************************************************/ +static BOOL file_header_magic_number_is_valid(struct Elf32_Ehdr* header) +{ + /*------------------------------------------------------------------------*/ + /* Check for correct ELF magic numbers in file header. */ + /*------------------------------------------------------------------------*/ + if (!header->e_ident[EI_MAG0] == ELFMAG0 || + !header->e_ident[EI_MAG1] == ELFMAG1 || + !header->e_ident[EI_MAG2] == ELFMAG2 || + !header->e_ident[EI_MAG3] == ELFMAG3) + { + DLIF_error(DLET_FILE, "Invalid ELF magic number.\n"); + return FALSE; + } + + return TRUE; +} + +/*****************************************************************************/ +/* file_header_machine_is_valid() */ +/* */ +/* Check if the machine specified in the file header is supported by the */ +/* loader. If the loader was compiled with support for all targets, */ +/* the machine will be initially set to EM_NONE. Once a module has been */ +/* loaded, all remaining modules must have the same machine value. */ +/*****************************************************************************/ +static int file_header_machine_is_valid(Elf32_Half e_machine) +{ + /*------------------------------------------------------------------------*/ + /* Currently we support only ARM or C6x */ + /*------------------------------------------------------------------------*/ + switch(e_machine) + { +#ifdef ARM_TARGET + case EM_ARM : return TRUE; +#endif +#ifdef C60_TARGET + case EM_TI_C6000 : return TRUE; +#endif + + default : return FALSE; + } +} + +/*****************************************************************************/ +/* is_valid_elf_object_file() */ +/* */ +/* Check file size against anticipated end location of string table, */ +/* symbol table, program header tables, etc. If we anything untoward, */ +/* then we declare that the ELF file is corrupt and the load is aborted. */ +/* */ +/*****************************************************************************/ +static BOOL is_valid_elf_object_file(LOADER_FILE_DESC *fd, + DLIMP_Dynamic_Module *dyn_module) +{ + uint32_t fsz; + int i; + + /*------------------------------------------------------------------------*/ + /* Get file size. */ + /*------------------------------------------------------------------------*/ + DLIF_fseek(fd, 0, LOADER_SEEK_END); + fsz = DLIF_ftell(fd); + + /*------------------------------------------------------------------------*/ + /* Check for invalid table sizes (string table, symbol table, and */ + /* program header tables). */ + /*------------------------------------------------------------------------*/ + if (!((dyn_module->strsz < fsz) && + (dyn_module->symnum < fsz) && + (dyn_module->phnum * sizeof(struct Elf32_Phdr)) < fsz)) + { + DLIF_error(DLET_FILE, "Invalid ELF table bounds.\n"); + return FALSE; + } + + /*------------------------------------------------------------------------*/ + /* Check for null so_name string in file with dynamic information. */ + /*------------------------------------------------------------------------*/ + if (dyn_module->dyntab && !strcmp(dyn_module->name, "")) + { + DLIF_error(DLET_MISC, "Dynamic file lacks SO_NAME identifier.\n"); + return FALSE; + } + + /*------------------------------------------------------------------------*/ + /* Check for invalid program header information. */ + /*------------------------------------------------------------------------*/ + for (i = 0; i < dyn_module->phnum; i++) + { + struct Elf32_Phdr* phdr = dyn_module->phdr + i; + + /*---------------------------------------------------------------------*/ + /* Sanity check for relative sizes of filesz and memsz. */ + /*---------------------------------------------------------------------*/ + if (!(phdr->p_type != PT_LOAD || phdr->p_filesz <= phdr->p_memsz)) + { + DLIF_error(DLET_MISC, + "Invalid file or memory size for segment %d.\n", i); + return FALSE; + } + + /*---------------------------------------------------------------------*/ + /* Check that segment file offset doesn't go off the end of the file. */ + /*---------------------------------------------------------------------*/ + if (!(phdr->p_offset + phdr->p_filesz < fsz)) + { + DLIF_error(DLET_FILE, + "File location of segment %d is past the end of file.\n", i); + return FALSE; + } + } + + /*------------------------------------------------------------------------*/ + /* Check that a ET_DYN-type file is relocatable. */ + /*------------------------------------------------------------------------*/ + if (dyn_module->fhdr.e_type == ET_DYN && !dyn_module->symtab) return FALSE; + + /*------------------------------------------------------------------------*/ + /* All checks passed. */ + /*------------------------------------------------------------------------*/ + return TRUE; +} + +/*****************************************************************************/ +/* process_eiosabi() */ +/* */ +/* Check the EI_OSABI field to validate it and set any parameters based on */ +/* it. */ +/*****************************************************************************/ +static BOOL process_eiosabi(DLIMP_Dynamic_Module* dyn_module) +{ + return cur_target->process_eiosabi(dyn_module); +} + +/*****************************************************************************/ +/* dload_file_header() */ +/* */ +/* Read ELF file header. Store critical information in the provided */ +/* DLIMP_Dynamic_Module record. Check file header for validity. */ +/* */ +/*****************************************************************************/ +static BOOL dload_file_header(LOADER_FILE_DESC *fd, + DLIMP_Dynamic_Module *dyn_module) +{ + /*------------------------------------------------------------------------*/ + /* Read ELF file header from given input file. */ + /*------------------------------------------------------------------------*/ + DLIF_fread(&(dyn_module->fhdr), sizeof(struct Elf32_Ehdr), 1, fd); + + /*------------------------------------------------------------------------*/ + /* Determine target vs. host endian-ness. Does header data need to be */ + /* byte swapped? */ + /*------------------------------------------------------------------------*/ + dyn_module->wrong_endian = + (dyn_module->fhdr.e_ident[EI_DATA] != DLIMP_get_endian()); + + /*------------------------------------------------------------------------*/ + /* Swap file header structures, if needed. */ + /*------------------------------------------------------------------------*/ + if (dyn_module->wrong_endian) + DLIMP_change_ehdr_endian(&(dyn_module->fhdr)); + + /*------------------------------------------------------------------------*/ + /* Write out magic ELF information for debug purposes. */ + /*------------------------------------------------------------------------*/ +#if LOADER_DEBUG + if (debugging_on) + { + DLIF_trace("ELF: %c%c%c\n", dyn_module->fhdr.e_ident[1], + dyn_module->fhdr.e_ident[2], + dyn_module->fhdr.e_ident[3]); + DLIF_trace("ELF file header entry point: %x\n", + dyn_module->fhdr.e_entry); + } +#endif + + + /*------------------------------------------------------------------------*/ + /* Verify magic numbers in ELF file header. */ + /*------------------------------------------------------------------------*/ + if (!file_header_magic_number_is_valid(&(dyn_module->fhdr))) + { + DLIF_error(DLET_FILE, "Invalid ELF file header magic number.\n"); + return FALSE; + } + + if (!file_header_machine_is_valid(dyn_module->fhdr.e_machine)) + { + DLIF_error(DLET_FILE, "Invalid ELF file target machine.\n"); + return FALSE; + } + + /*------------------------------------------------------------------------*/ + /* Verify file is an executable or dynamic shared object or library. */ + /*------------------------------------------------------------------------*/ + if ((dyn_module->fhdr.e_type != ET_EXEC) && + (dyn_module->fhdr.e_type != ET_DYN)) + { + DLIF_error(DLET_FILE, "Invalid ELF file type.\n"); + return FALSE; + } + +#if LOADER_DEBUG || LOADER_PROFILE + /*------------------------------------------------------------------------*/ + /* Stop profiling clock when file header information has finished */ + /* loading. Re-start clock on initialization of symbol table, and */ + /* dynamic table pointers. */ + /*------------------------------------------------------------------------*/ + if (debugging_on || profiling_on) + { + DLIF_trace("done.\n"); + if (profiling_on) + { + profile_stop_clock(); + DLIF_trace("Took %lu cycles.\n", + (unsigned long)profile_cycle_count()); + profile_start_clock(); + } + } +#endif + + return TRUE; +} + +/*****************************************************************************/ +/* dload_program_header_table() */ +/* */ +/* Make a local copy of the ELF object file's program header table in the */ +/* dynamic module data structure. */ +/* */ +/*****************************************************************************/ +static void dload_program_header_table(LOADER_FILE_DESC *fd, + DLIMP_Dynamic_Module *dyn_module) +{ + /*------------------------------------------------------------------------*/ + /* Read the program header tables from the object file. */ + /*------------------------------------------------------------------------*/ + struct Elf32_Ehdr *fhdr = &(dyn_module->fhdr); + dyn_module->phdr = (struct Elf32_Phdr*) + (DLIF_malloc(fhdr->e_phnum * fhdr->e_phentsize)); + DLIF_fseek(fd, fhdr->e_phoff, LOADER_SEEK_SET); + DLIF_fread(dyn_module->phdr, fhdr->e_phentsize, fhdr->e_phnum,fd); + dyn_module->phnum = fhdr->e_phnum; + + /*------------------------------------------------------------------------*/ + /* Byte swap the program header tables if the target endian-ness is not */ + /* the same as the host endian-ness. */ + /*------------------------------------------------------------------------*/ + if (dyn_module->wrong_endian) + { + int i; + for (i = 0; i < dyn_module->phnum; i++) + DLIMP_change_phdr_endian(dyn_module->phdr + i); + } +} + +/*****************************************************************************/ +/* dload_headers() */ +/* */ +/* Read ELF object file header and program header table information into */ +/* the given dynamic module data structure. If the object file contains */ +/* dynamic information, read in the dynamic tags, dynamic symbol table, */ +/* and global string table. Check to make sure that we are not already */ +/* in the process of loading the module (circular dependencies), then */ +/* perform some level of sanity checking on the content of the file to */ +/* provide some assurance that the file is not corrupted. */ +/* */ +/*****************************************************************************/ +static BOOL dload_headers(LOADER_FILE_DESC *fd, + DLIMP_Dynamic_Module *dyn_module) +{ +#if LOADER_DEBUG || LOADER_PROFILE + /*------------------------------------------------------------------------*/ + /* More progress information. Start timing if profiling is enabled. */ + /*------------------------------------------------------------------------*/ + if (debugging_on || profiling_on) + { + DLIF_trace("\nReading file headers ...\n"); + if (profiling_on) profile_start_clock(); + } +#endif + + /*------------------------------------------------------------------------*/ + /* Read file header information and check vs. expected ELF object file */ + /* header content. */ + /*------------------------------------------------------------------------*/ + if (!dload_file_header(fd, dyn_module)) + return FALSE; + + /*------------------------------------------------------------------------*/ + /* Read program header table information into the dynamic module object. */ + /*------------------------------------------------------------------------*/ + dload_program_header_table(fd, dyn_module); + + /*------------------------------------------------------------------------*/ + /* Once headers have been read in, use e_machine to set virtual target. */ + /* This can then be used to access target specific functions. */ + /*------------------------------------------------------------------------*/ + cur_target = get_vt_obj(dyn_module->fhdr.e_machine); + if (!cur_target) + { + DLIF_error(DLET_FILE, "Attempt to load invalid ELF file, '%s'.\n", + dyn_module->name); + return FALSE; + } + + return TRUE; +} + +/*****************************************************************************/ +/* find_dynamic_segment() */ +/* */ +/* Find the dynamic segment in the given ELF object file, if there is */ +/* one. If the segment is found, then the segment ID output parameter */ +/* is set to the index of the dynamic segment in the program header */ +/* table. If the dynamic segment is not found, the dynamic module's */ +/* relocatable flag is set to FALSE, and return FALSE. */ +/* */ +/*****************************************************************************/ +static BOOL find_dynamic_segment(DLIMP_Dynamic_Module *dyn_module, + Elf32_Word *dyn_seg_idx) +{ + int i; + + /*------------------------------------------------------------------------*/ + /* We should have a valid dynamic module pointer and somewhere to put the */ + /* dynamic segment id, if we find one. If either of these are missing, */ + /* we should get an internal error and abort the loader. */ + /*------------------------------------------------------------------------*/ + if ((dyn_module == NULL) || (dyn_seg_idx == NULL)) + { + DLIF_error(DLET_MISC, "Internal error: find_dynamic_segment() needs " + "non-NULL arguments.\n"); + DLIF_exit(1); + } + + /*------------------------------------------------------------------------*/ + /* Spin through segment program headers to find the dynamic segment. */ + /*------------------------------------------------------------------------*/ + dyn_module->relocatable = TRUE; + for (i = 0; i < dyn_module->phnum; i++) + if (dyn_module->phdr[i].p_type == PT_DYNAMIC) + { *dyn_seg_idx = i; return TRUE; } + + /*------------------------------------------------------------------------*/ + /* No dynamic segment found, mark the object module as not relocatable */ + /* and warn the user. */ + /*------------------------------------------------------------------------*/ + dyn_module->relocatable = FALSE; + + return FALSE; +} + +/*****************************************************************************/ +/* copy_dynamic_table() */ +/* */ +/* Make a local copy of the dynamic table read from the dynamic segment */ +/* in the ELF object file. */ +/* */ +/*****************************************************************************/ +static void copy_dynamic_table(LOADER_FILE_DESC *fd, + DLIMP_Dynamic_Module *dyn_module, + Elf32_Word dyn_seg_idx) +{ + /*------------------------------------------------------------------------*/ + /* Allocate space for the dynamic table from host memory and read its */ + /* content from the ELF object file. */ + /*------------------------------------------------------------------------*/ + Elf32_Word num_elem; + dyn_module->dyntab = DLIF_malloc(dyn_module->phdr[dyn_seg_idx].p_filesz); + num_elem = dyn_module->phdr[dyn_seg_idx].p_filesz / sizeof(struct Elf32_Dyn); + DLIF_fseek(fd, dyn_module->phdr[dyn_seg_idx].p_offset, LOADER_SEEK_SET); + DLIF_fread(dyn_module->dyntab, sizeof(struct Elf32_Dyn), num_elem, fd); + + /*------------------------------------------------------------------------*/ + /* If necessary, byte swap each entry in the dynamic table. */ + /*------------------------------------------------------------------------*/ + if (dyn_module->wrong_endian) + { + int i; + for (i = 0; i < num_elem; i++) + DLIMP_change_dynent_endian(&dyn_module->dyntab[i]); + } +} + +/*****************************************************************************/ +/* process_target_dynamic_tag() */ +/* */ +/* Process a target specific dynamic tag entry. Returns TRUE if the tag */ +/* was handled and FALSE if it was not recognized. */ +/*****************************************************************************/ +static BOOL process_target_dynamic_tag(DLIMP_Dynamic_Module* dyn_module, int i) +{ + return cur_target->process_dynamic_tag(dyn_module, i); +} + +/*****************************************************************************/ +/* process_dynamic_table() */ +/* */ +/* Process dynamic tag entries from the dynamic table. At the conclusion */ +/* of this function, we should have made a copy of the global symbols */ +/* and the global symbol names. */ +/* */ +/*****************************************************************************/ +static BOOL process_dynamic_table(LOADER_FILE_DESC *fd, + DLIMP_Dynamic_Module *dyn_module) +{ + int i; + BOOL soname_found = FALSE; + Elf32_Addr soname_offset = 0; + Elf32_Addr strtab_offset = 0; + Elf32_Addr hash_offset = 0; + Elf32_Addr symtab_offset = 0; + + /*------------------------------------------------------------------------*/ + /* Iterate over the dynamic table in order to process dynamic tags. */ + /* See ELF TIS Specification for details on the meaning of each dynamic */ + /* tag. The C6000 ELF ABI Specification provides more details about the */ + /* TI specific C6000 ELF ABI tags. */ + /*------------------------------------------------------------------------*/ + for (i = 0; dyn_module->dyntab[i].d_tag != DT_NULL; i++) + { + switch(dyn_module->dyntab[i].d_tag) + { + /*------------------------------------------------------------------*/ + /* DT_SONAME: Contains name of dynamic object, used for dependency */ + /* comparisons. Its value is an offset from the start */ + /* of the string table. We need to copy the string at */ + /* this offset into dmodule->name. */ + /*------------------------------------------------------------------*/ + case DT_SONAME: +#if LOADER_DEBUG + if (debugging_on) DLIF_trace("Found SO_NAME.\n"); +#endif + /*---------------------------------------------------------------*/ + /* We store the offset of the so_name in the dynamic string */ + /* table so that it doesn't matter which dynamic tag we see */ + /* first (DT_SONAME actually is generated before DT_STRTAB). */ + /*---------------------------------------------------------------*/ + soname_found = TRUE; + soname_offset = dyn_module->dyntab[i].d_un.d_ptr; + break; + + /*------------------------------------------------------------------*/ + /* DT_STRSZ: Contains the size of the string table. */ + /*------------------------------------------------------------------*/ + case DT_STRSZ: + dyn_module->strsz = dyn_module->dyntab[i].d_un.d_val; + +#if LOADER_DEBUG + if (debugging_on) + DLIF_trace("Found string table Size: 0x%x\n", dyn_module->strsz); +#endif + break; + + /*------------------------------------------------------------------*/ + /* DT_STRTAB: Contains the file offset of the string table. The */ + /* tag directly after this is guaranteed to be DT_STRSZ, */ + /* containing the string table size. We need to */ + /* allocate memory for the string table and copy it from */ + /* the file. */ + /*------------------------------------------------------------------*/ + case DT_STRTAB: + strtab_offset = dyn_module->dyntab[i].d_un.d_ptr; +#if LOADER_DEBUG + if (debugging_on) + DLIF_trace("Found string table: 0x%x\n", strtab_offset); +#endif + break; + + /*------------------------------------------------------------------*/ + /* DT_HASH: Contains the file offset of the symbol hash table. */ + /*------------------------------------------------------------------*/ + case DT_HASH: + hash_offset = dyn_module->dyntab[i].d_un.d_ptr; +#if LOADER_DEBUG + if (debugging_on) + DLIF_trace("Found symbol hash table: 0x%x\n", hash_offset); +#endif + break; + + /*------------------------------------------------------------------*/ + /* DT_SYMTAB: Contains the file offset of the symbol table. */ + /*------------------------------------------------------------------*/ + case DT_SYMTAB: + symtab_offset = dyn_module->dyntab[i].d_un.d_ptr; +#if LOADER_DEBUG + if (debugging_on) + DLIF_trace("Found symbol table: 0x%x\n", symtab_offset); +#endif + break; + + /*------------------------------------------------------------------*/ + /* DSO Initialization / Termination Model Dynamic Tags */ + /*------------------------------------------------------------------*/ + /* For initialization tags, we store indices and array sizes in */ + /* the dyn_module. Termination works a little different, the */ + /* indices into the local copy of the dynamic table are stored in */ + /* dyn_module, but the DT_FINI_ARRAYSZ value is recorded with the */ + /* loaded module. */ + /*------------------------------------------------------------------*/ + /* After placement is done, the DT_FINI and DT_FINI_ARRAY values */ + /* need to be copied from the local dynamic table into the loaded */ + /* module object. */ + /*------------------------------------------------------------------*/ + case DT_PREINIT_ARRAY: + dyn_module->preinit_array_idx = i; + break; + + case DT_PREINIT_ARRAYSZ: + dyn_module->preinit_arraysz = dyn_module->dyntab[i].d_un.d_val; + break; + + case DT_INIT: + dyn_module->init_idx = i; + break; + + case DT_INIT_ARRAY: + dyn_module->init_array_idx = i; + break; + + case DT_INIT_ARRAYSZ: + dyn_module->init_arraysz = dyn_module->dyntab[i].d_un.d_val; + break; + + /*------------------------------------------------------------------*/ + /* This information will be copied over to the loaded module */ + /* object after placement has been completed and the information */ + /* in the dynamic table has been relocated. */ + /*------------------------------------------------------------------*/ + case DT_FINI_ARRAY: + case DT_FINI_ARRAYSZ: + case DT_FINI: + break; + + /*------------------------------------------------------------------*/ + /* Unrecognized tag, may not be illegal, but is not explicitly */ + /* handled by this function. Should it be? */ + /*------------------------------------------------------------------*/ + default: + { + if (!process_target_dynamic_tag(dyn_module, i)) + { +#if LOADER_DEBUG + if (debugging_on) + DLIF_trace("Unrecognized dynamic tag: 0x%X\n", + dyn_module->dyntab[i].d_tag); +#endif + } + + break; + } + + } + } + + /*------------------------------------------------------------------------*/ + /* If string table offset and size were found, read string table in from */ + /* the ELF object file. */ + /*------------------------------------------------------------------------*/ + if (strtab_offset && dyn_module->strsz) + { + DLIF_fseek(fd, strtab_offset, LOADER_SEEK_SET); + dyn_module->strtab = DLIF_malloc(dyn_module->strsz); + DLIF_fread(dyn_module->strtab, sizeof(uint8_t), dyn_module->strsz, fd); + } + else + { + DLIF_warning(DLWT_MISC, + "Mandatory dynamic tag DT_STRTAB/DT_STRSZ not found!\n"); + return FALSE; + } + + + /*------------------------------------------------------------------------*/ + /* If symbol hash table is found read-in the hash table. */ + /*------------------------------------------------------------------------*/ + if (hash_offset) + { + /*---------------------------------------------------------------------*/ + /* Hash table has the following format. nchain equals the number of */ + /* entries in the symbol table (symnum) */ + /* */ + /* +----------------------------+ */ + /* | nbucket | */ + /* +----------------------------+ */ + /* | nchain | */ + /* +----------------------------+ */ + /* | bucket[0] | */ + /* | ... | */ + /* | bucket[nbucket-1] | */ + /* +----------------------------+ */ + /* | chain[0] | */ + /* | ... | */ + /* | chain[nchain-1] | */ + /* +----------------------------+ */ + /*---------------------------------------------------------------------*/ + Elf32_Word hash_nbucket; + Elf32_Word hash_nchain; + + /*---------------------------------------------------------------------*/ + /* Seek to the hash offset and read first two words into nbucket and */ + /* symnum. */ + /*---------------------------------------------------------------------*/ + DLIF_fseek(fd, hash_offset, LOADER_SEEK_SET); + DLIF_fread(&(hash_nbucket), sizeof(Elf32_Word), 1, fd); + DLIF_fread(&(hash_nchain), sizeof(Elf32_Word), 1, fd); + if (dyn_module->wrong_endian) + { + DLIMP_change_endian32((int32_t*)(&(hash_nbucket))); + DLIMP_change_endian32((int32_t*)(&(hash_nchain))); + } + + /*---------------------------------------------------------------------*/ + /* The number of entires in the dynamic symbol table is not encoded */ + /* anywhere in the elf file. However, the nchain is guaranteed to be */ + /* the same as the number of symbols. Use nchain to set the symnum. */ + /*---------------------------------------------------------------------*/ + dyn_module->symnum = hash_nchain; +#if LOADER_DEBUG + if (debugging_on) DLIF_trace("symnum=%d\n", hash_nchain); +#endif + } + else + { + DLIF_warning(DLWT_MISC, "Mandatory dynamic tag DT_HASH is not found!\n"); + return FALSE; + } + + /*------------------------------------------------------------------------*/ + /* Read dynamic symbol table. */ + /*------------------------------------------------------------------------*/ + if (symtab_offset) + { + int j = 0; + DLIF_fseek(fd, symtab_offset, LOADER_SEEK_SET); + dyn_module->symtab = + DLIF_malloc(dyn_module->symnum * sizeof(struct Elf32_Sym)); + DLIF_fread(dyn_module->symtab, sizeof(struct Elf32_Sym), + dyn_module->symnum, fd); + if (dyn_module->wrong_endian) + { + for (j = 0; j < dyn_module->symnum; j++) + DLIMP_change_sym_endian(dyn_module->symtab + j); + } + + /*---------------------------------------------------------------------*/ + /* The st_name field of an Elf32_Sym entity is an offset into the */ + /* string table. Convert it into a pointer to the string. */ + /*---------------------------------------------------------------------*/ + if (strtab_offset) + for (j = 0; j < dyn_module->symnum; j++) + dyn_module->symtab[j].st_name += (Elf32_Word) dyn_module->strtab; + } + else + { + DLIF_warning(DLWT_MISC, + "Mandatory dynamic tag DT_SYMTAB is not found!\n"); + return FALSE; + } + + /*------------------------------------------------------------------------*/ + /* Read the SONAME. */ + /*------------------------------------------------------------------------*/ + if (!soname_found) + { + DLIF_warning(DLWT_MISC, "Dynamic tag DT_SONAME is not found!\n"); + dyn_module->name = DLIF_malloc(sizeof(char)); + *dyn_module->name = '\0'; + } + else + { + dyn_module->name = + DLIF_malloc(strlen(dyn_module->strtab + soname_offset) + 1); + strcpy(dyn_module->name, dyn_module->strtab + soname_offset); + +#if LOADER_DEBUG + if (debugging_on) + DLIF_trace("Name of dynamic object: %s\n", dyn_module->name); +#endif + } + + return TRUE; +} + + +/*****************************************************************************/ +/* dload_dynamic_information() */ +/* */ +/* Given a dynamic module with a dynamic segment which is located via */ +/* given dynamic segment index, make a local copy of the dynamic table */ +/* in the dynamic module object, then process the dynamic tag entries in */ +/* the table. */ +/* */ +/*****************************************************************************/ +static BOOL dload_dynamic_information(LOADER_FILE_DESC *fd, + DLIMP_Dynamic_Module *dyn_module, + Elf32_Word dyn_seg_idx) +{ + /*------------------------------------------------------------------------*/ + /* Read a copy of the dynamic table into the dynamic module object. */ + /*------------------------------------------------------------------------*/ + copy_dynamic_table(fd, dyn_module, dyn_seg_idx); + + /*------------------------------------------------------------------------*/ + /* Process dynamic entries in the dynamic table. If any problems are */ + /* encountered, the loader should emit an error or warning and return */ + /* FALSE here. */ + /*------------------------------------------------------------------------*/ + return process_dynamic_table(fd, dyn_module); +} + +/*****************************************************************************/ +/* check_circular_dependency() */ +/* */ +/* Determine whether a dynamic module is already in the process of being */ +/* loaded before we try to start loading it again. If it is already */ +/* being loaded, then the dynamic loader has detected a circular */ +/* dependency. An error will be emitted and the load will be aborted. */ +/* */ +/*****************************************************************************/ +static BOOL check_circular_dependency(DLOAD_HANDLE handle, + const char *dyn_mod_name) +{ + /*------------------------------------------------------------------------*/ + /* Check the name of the given dependency module to be loaded against the */ + /* list of modules that are currently in the process of being loaded. */ + /* Report an error if any circular dependencies are detected. */ + /*------------------------------------------------------------------------*/ + int i; + LOADER_OBJECT *pHandle = (LOADER_OBJECT *)handle; + + for (i = 0; i < pHandle->DLIMP_module_dependency_list.size; i++) + if (!strcmp(dyn_mod_name, + ((char**)(pHandle->DLIMP_module_dependency_list.buf))[i])) + { + DLIF_error(DLET_MISC, + "Circular dependency detected, '%s' is already in the " + "process of loading.\n", dyn_mod_name); + return FALSE; + } + + return TRUE; +} + +/*****************************************************************************/ +/* dload_dynamic_segment() */ +/* */ +/* Find the dynamic segment in the given ELF module, if there is one. */ +/* If there is a dynamic segment, then make a local copy of the dynamic */ +/* table in the dynamic module object provided, then process the dynamic */ +/* tag entries in the table. */ +/* */ +/* If there is no dynamic segment, then we return success from this */ +/* function, marking the dynamic module as "not relocatable". */ +/* */ +/*****************************************************************************/ +static BOOL dload_dynamic_segment(DLOAD_HANDLE handle, + LOADER_FILE_DESC *fd, + DLIMP_Dynamic_Module *dyn_module) +{ + /*------------------------------------------------------------------------*/ + /* If we don't find dynamic segment, the relocatable flag will have been */ + /* set to false to indicate that the module is a static executable. We */ + /* still return TRUE from this function so that we can proceed with */ + /* static loading. */ + /*------------------------------------------------------------------------*/ + Elf32_Word dyn_seg_idx = 0; + if (!find_dynamic_segment(dyn_module, &dyn_seg_idx)) + return TRUE; + + /*------------------------------------------------------------------------*/ + /* Process the OSABI now, after we know if the module is relocatable. */ + /*------------------------------------------------------------------------*/ + if (!process_eiosabi(dyn_module)) + { + DLIF_error(DLET_FILE, "Unsupported EI_OSABI value.\n"); + return FALSE; + } + + /*------------------------------------------------------------------------*/ + /* Read the dynamic table from the ELF file, then process the dynamic */ + /* tags in the table. */ + /*------------------------------------------------------------------------*/ + if (!dload_dynamic_information(fd, dyn_module, dyn_seg_idx)) + return FALSE; + + /*------------------------------------------------------------------------*/ + /* Check to make sure that this module is not already being loaded. If */ + /* is, then it will cause a circular dependency to be introduced. */ + /* Loader should detect circular dependencies and emit an error. */ + /*------------------------------------------------------------------------*/ + if (!check_circular_dependency(handle, dyn_module->name)) + return FALSE; + + return TRUE; +} + +/*****************************************************************************/ +/* COPY_SEGMENTS() - */ +/* */ +/* Copy all segments into host memory. */ +/*****************************************************************************/ +static void copy_segments(DLOAD_HANDLE handle, LOADER_FILE_DESC* fp, + DLIMP_Dynamic_Module* dyn_module) +{ + DLIMP_Loaded_Segment* seg = + (DLIMP_Loaded_Segment*)(dyn_module->loaded_module->loaded_segments.buf); + int s, seg_size = dyn_module->loaded_module->loaded_segments.size; + LOADER_OBJECT *pHandle = (LOADER_OBJECT *)handle; + + + for (s=0; s<seg_size; s++) + { + struct DLOAD_MEMORY_REQUEST targ_req; + targ_req.fp = fp; + targ_req.segment = seg[s].obj_desc; + targ_req.offset = seg[s].phdr.p_offset; + targ_req.flags = DLOAD_SF_relocatable; + + if (seg[s].phdr.p_flags & PF_X) targ_req.flags |= DLOAD_SF_executable; + if (seg[s].phdr.p_flags & PF_W) targ_req.flags |= DLOAD_SF_writable; + + targ_req.align = seg[s].phdr.p_align; + + /*---------------------------------------------------------------------*/ + /* Copy segment data from the file into host buffer where it can */ + /* be relocated. */ + /*---------------------------------------------------------------------*/ + DLIF_copy(pHandle->client_handle, &targ_req); + seg[s].host_address = targ_req.host_address; + } +} + +/*****************************************************************************/ +/* WRITE_SEGMENTS() - */ +/* */ +/* Write all segments to target memory. */ +/*****************************************************************************/ +static void write_segments(DLOAD_HANDLE handle, + LOADER_FILE_DESC* fp, + DLIMP_Dynamic_Module* dyn_module) +{ + LOADER_OBJECT *pHandle = (LOADER_OBJECT *)handle; + DLIMP_Loaded_Segment* seg = + (DLIMP_Loaded_Segment*)(dyn_module->loaded_module->loaded_segments.buf); + int s, seg_size = dyn_module->loaded_module->loaded_segments.size; + + for (s=0; s<seg_size; s++) + { + struct DLOAD_MEMORY_REQUEST targ_req; + + targ_req.fp = fp; + targ_req.segment = seg[s].obj_desc; + targ_req.offset = seg[s].phdr.p_offset; + targ_req.flags = DLOAD_SF_relocatable; + + if (seg[s].phdr.p_flags & PF_X) targ_req.flags |= DLOAD_SF_executable; + if (seg[s].phdr.p_flags & PF_W) targ_req.flags |= DLOAD_SF_writable; + + targ_req.align = seg[s].phdr.p_align; + targ_req.host_address = seg[s].host_address; + + /*---------------------------------------------------------------------*/ + /* Copy segment data from the file into host buffer where it can */ + /* be relocated. */ + /*---------------------------------------------------------------------*/ + DLIF_write(pHandle->client_handle, &targ_req); + } +} + +/*****************************************************************************/ +/* SEG_HAS_SPACE_FOR_WRITE() - */ +/* */ +/* Check if segment has enough space to recieve contents of .args section. */ +/*****************************************************************************/ +static BOOL seg_has_space_for_write(DLIMP_Loaded_Module* lmodule, int sz) +{ + DLIMP_Loaded_Segment* seg = + (DLIMP_Loaded_Segment*)(lmodule->loaded_segments.buf); + int s, seg_size = lmodule->loaded_segments.size; + + Elf32_Addr write_address = (Elf32_Addr)lmodule->c_args; + + for (s=0; s<seg_size; s++) + { + Elf32_Addr seg_boundary = + seg[s].phdr.p_vaddr + seg[s].obj_desc->memsz_in_bytes; + + /*---------------------------------------------------------------------*/ + /* If address to write to is greater than segment addr and less than */ + /* segment end, it must lie in current segment. */ + /*---------------------------------------------------------------------*/ + if ((write_address >= seg[s].phdr.p_vaddr) && + (write_address < seg_boundary)) + { + if ((write_address + sz) > seg_boundary) + { +#if LOADER_DEBUG + if (debugging_on) + { + DLIF_trace("Write requires 0x%x bytes\n",write_address + sz); + DLIF_trace("Seg boundary at : 0x%x\n",seg_boundary); + DLIF_trace("WARNING - Not enough space in segment\n"); + } +#endif + return FALSE; + } + else return TRUE; + } + } + /*------------------------------------------------------------------------*/ + /* Given address doesn't belong to any known segment. */ + /*------------------------------------------------------------------------*/ + return FALSE; +} + + +/*****************************************************************************/ +/* DLOAD_initialize() */ +/* */ +/* Construct and initialize data structures internal to the dynamic */ +/* loader core. */ +/* */ +/*---------------------------------------------------------------------------*/ +/* */ +/* This function is deprecated, replaced by DLOAD_create(). */ +/* */ +/*****************************************************************************/ +void DLOAD_initialize(DLOAD_HANDLE handle) +{ +} + +/*****************************************************************************/ +/* DLOAD_finalize() */ +/* */ +/* Destroy and finalize data structures internal to the dynamic */ +/* loader core. */ +/* */ +/*---------------------------------------------------------------------------*/ +/* */ +/* This function is deprecated, replaced by DLOAD_destroy(). */ +/* */ +/*****************************************************************************/ +void DLOAD_finalize(DLOAD_HANDLE handle) +{ +} + +/*****************************************************************************/ +/* dload_static_executable() */ +/* */ +/* Account for target memory allocated to static executable and wrap up */ +/* loading. No relocation is necessary. */ +/* */ +/*****************************************************************************/ +static int32_t dload_static_executable(DLOAD_HANDLE handle, + LOADER_FILE_DESC *fd, + DLIMP_Dynamic_Module *dyn_module) +{ + int32_t local_file_handle = 0; + +#if LOADER_DEBUG + if (debugging_on) DLIF_trace("Starting dload_static_executable() ...\n"); +#endif + + /*------------------------------------------------------------------------*/ + /* Set entry point for static executable and attempt to allocate target */ + /* memory for the static executable. */ + /*------------------------------------------------------------------------*/ + dyn_module->loaded_module->entry_point = dyn_module->fhdr.e_entry; + if (load_static_segment(handle, fd, dyn_module) && + load_object(fd, dyn_module)) + { + /*---------------------------------------------------------------------*/ + /* If successful, we'll want to detach the loaded module object from */ + /* the dynamic module object that created it. Take note of the file */ + /* handle. */ + /*---------------------------------------------------------------------*/ + DLIMP_Loaded_Module *loaded_module = detach_loaded_module(dyn_module); + local_file_handle = loaded_module->file_handle; + } + + /*------------------------------------------------------------------------*/ + /* Static load failed. Flag an error. */ + /*------------------------------------------------------------------------*/ + else + DLIF_error(DLET_MEMORY, + "Failed to allocate target memory for static executable.\n"); + + /*------------------------------------------------------------------------*/ + /* Destruct dynamic module object. */ + /*------------------------------------------------------------------------*/ + delete_DLIMP_Dynamic_Module(handle, &dyn_module); + +#if LOADER_DEBUG + if (debugging_on) DLIF_trace("Finished dload_static_executable()\n"); +#endif + + return local_file_handle; +} + +#if LOADER_DEBUG || LOADER_PROFILE +int DLREL_relocations; +time_t DLREL_total_reloc_time; +#endif + +/*****************************************************************************/ +/* process_dynamic_module_relocations() */ +/* */ +/* Make a host-accessible copy of all of the segments, process all */ +/* relocation entries associated with the given module within that */ +/* space, then write the updated segment buffers back out to target */ +/* memory. */ +/* */ +/*****************************************************************************/ +static void process_dynamic_module_relocations(DLOAD_HANDLE handle, + LOADER_FILE_DESC *fd, + DLIMP_Dynamic_Module *dyn_module) +{ +#if LOADER_DEBUG || LOADER_PROFILE + if(debugging_on || profiling_on) + { + DLIF_trace("Running relocate()...\n"); + if (profiling_on) profile_start_clock(); + } +#endif + + /*------------------------------------------------------------------------*/ + /* Copy segments from file to host memory */ + /*------------------------------------------------------------------------*/ + copy_segments(handle, fd, dyn_module); + + /*------------------------------------------------------------------------*/ + /* Process dynamic relocations. */ + /*------------------------------------------------------------------------*/ + DLREL_relocate(handle, fd, dyn_module); + + /*------------------------------------------------------------------------*/ + /* Write segments from host memory to target memory */ + /*------------------------------------------------------------------------*/ + write_segments(handle, fd, dyn_module); + +#if LOADER_DEBUG || LOADER_PROFILE + /*------------------------------------------------------------------------*/ + /* Report timing and progress information for relocation step. */ + /*------------------------------------------------------------------------*/ + if (debugging_on || profiling_on) + { + if (profiling_on) + { + profile_stop_clock(); + DLIF_trace("Took %lu cycles.\n", + (unsigned long) profile_cycle_count()); + DLIF_trace("Total reloc time: %lu\n", + (unsigned long) DLREL_total_reloc_time); + DLIF_trace("Time per relocation: %ld\n", + DLREL_relocations ? DLREL_total_reloc_time / DLREL_relocations : 0); + } + + DLIF_trace("Number of relocations: %d\n", DLREL_relocations); + DLIF_trace("\nAbout to run load_object()..."); + DLREL_total_reloc_time = DLREL_relocations = 0; + if (profiling_on) profile_start_clock(); + } +#endif + +} + +/*****************************************************************************/ +/* store_preinit_data() */ +/* */ +/* Given a dynamic module object, store pre-initialization function */ +/* information. The user may also provide a custom iniitialization */ +/* function that needs to be executed before the compiler */ +/* generated static initialization functions are executed. */ +/* The dynamic loader will now create a table TI_init_table to store */ +/* pre-init and init data. This is done because pre-init and */ +/* init functions could reference as-yet unrelocated symbols from other */ +/* modules. As such it is safer to store relevant function addresses and */ +/* execute them only after all modules are relocated (CQ34088). */ +/* */ +/*****************************************************************************/ +static void store_preinit_data(DLIMP_Dynamic_Module *dyn_module) +{ + IF_single_record *preinit_rec = NULL; + /*------------------------------------------------------------------------*/ + /* Check for presence of DT_PREINIT_ARRAY and DT_PREINIT_ARRAYSZ */ + /* dynamic tags associated with this module. The dyn_module object will */ + /* hold the relevant indices into the local copy of the dynamic table. */ + /* The value of the DT_INIT_ARRAY tag will have been updated after */ + /* placement of the module was completed. Arrays of size 0 will be */ + /* ignored (CQ36935). */ + /*------------------------------------------------------------------------*/ + if (dyn_module->preinit_arraysz > 0) + { + preinit_rec = (IF_single_record *)DLIF_malloc(sizeof(IF_single_record)); + /*---------------------------------------------------------------------*/ + /* Retrieve the address of the .preinit_array section from the value */ + /* of the DT_PREINIT_ARRAY tag, and store it in the TI_init_table. */ + /*---------------------------------------------------------------------*/ + preinit_rec->size = dyn_module->preinit_arraysz; + preinit_rec->sect_addr = (TARGET_ADDRESS) + (dyn_module->dyntab[dyn_module->preinit_array_idx].d_un.d_ptr); + } + + if (preinit_rec) IF_table_enqueue(&TI_init_table, preinit_rec); +} + +/*****************************************************************************/ +/* store_init_data() */ +/* */ +/* Given a dynamic module object, save off initialization function(s) for */ +/* all global and static data objects that are defined in the module */ +/* which require construction. The dynamic loader will now create a table */ +/* TI_init_table to store pre-init and init data. This is done because */ +/* pre-init and init functions could reference as-yet unrelocated symbols */ +/* from other modules. As such it is safer to store relevant function */ +/* addresses and execute them only after all modules are relocated. */ +/* */ +/*****************************************************************************/ +static void store_init_data(DLIMP_Dynamic_Module *dyn_module) +{ + /*------------------------------------------------------------------------*/ + /* Check for presence of a DT_INIT dynamic tag associated with this */ + /* module. The dynamic module will hold the index into the local copy of */ + /* the dynamic table. This entry in the dynamic table will have been */ + /* updated after placement of the module is completed. */ + /*------------------------------------------------------------------------*/ + if (dyn_module->init_idx != -1) + { + IF_single_record *init_rec = + (IF_single_record *)DLIF_malloc(sizeof(IF_single_record)); + /*---------------------------------------------------------------------*/ + /* Retrieve the address of the initialization function from the value */ + /* of the DT_INIT tag, and get the client to execute the function. */ + /*---------------------------------------------------------------------*/ + init_rec->size = 0; + init_rec->sect_addr = (TARGET_ADDRESS) + (dyn_module->dyntab[dyn_module->init_idx].d_un.d_ptr); + + IF_table_enqueue(&TI_init_table, init_rec); + } + + /*------------------------------------------------------------------------*/ + /* Check for presence of a DT_INIT_ARRAY and DT_INIT_ARRAYSZ dynamic tags */ + /* associated with this module. The dyn_module object will hold the */ + /* relevant indices into the local copy of the dynamic table. The value */ + /* of the DT_INIT_ARRAY tag will have been updated after placement of the */ + /* module was completed. Arraysz must be a postive number > 0, else it */ + /* be ignored (CQ36935). */ + /*------------------------------------------------------------------------*/ + if (dyn_module->init_arraysz > 0) + { + IF_single_record *arr_rec = + (IF_single_record *)DLIF_malloc(sizeof(IF_single_record)); + /*---------------------------------------------------------------------*/ + /* Retrieve the address of the .init_array section from the value of */ + /* DT_INIT_ARRAY tag. */ + /*---------------------------------------------------------------------*/ + arr_rec->size = dyn_module->init_arraysz; + arr_rec->sect_addr = (TARGET_ADDRESS) + (dyn_module->dyntab[dyn_module->init_array_idx].d_un.d_ptr); + + IF_table_enqueue(&TI_init_table, arr_rec); + } +} + +/*****************************************************************************/ +/* execute_module_initialization() */ +/* */ +/* Given a dynamic module object, execute pre-initialization and */ +/* initialization function(s) for all global and static data objects that */ +/* are defined in the module which require construction. The user may */ +/* also provide a custom iniitialization function that needs to be */ +/* executed before the compiler generated static initialization functions */ +/* are executed. */ +/* Note that the functions to be executed have already been saved off in */ +/* the TI_init_table, by store_preinit_data() and store_init_data(). */ +/* */ +/*****************************************************************************/ +static void execute_module_initialization(DLOAD_HANDLE handle) +{ + IF_single_record *val = NULL; + IF_table_Queue_Node *curr_ptr = TI_init_table.front_ptr; + LOADER_OBJECT *pHandle = (LOADER_OBJECT *)handle; + + for (; curr_ptr; curr_ptr = curr_ptr->next_ptr) + { + val = curr_ptr->value; + + /*---------------------------------------------------------------------*/ + /* A size of 0 indicates DT_INIT, otherwise this is an ARRAY. */ + /*---------------------------------------------------------------------*/ + if (val->size != 0) + { + /*------------------------------------------------------------------*/ + /* Now make a loader-accessible copy of the .init_array section. */ + /*------------------------------------------------------------------*/ + int32_t i; + int32_t num_init_fcns = val->size/sizeof(TARGET_ADDRESS); + TARGET_ADDRESS *init_array_buf = (TARGET_ADDRESS *) + DLIF_malloc(val->size); + + DLIF_read(pHandle->client_handle, + init_array_buf, 1, val->size, + (TARGET_ADDRESS)val->sect_addr); + + /*------------------------------------------------------------------*/ + /* Call each function whose address occupies an entry in array in */ + /* the order that they appear in the array. The size of the array is*/ + /* provided by the init_arraysz field in the dynamic module (copied */ + /* earlier when the dynamic table was read in). Make sure that */ + /* function addresses are valid before execution. */ + /*------------------------------------------------------------------*/ + for (i = 0; i < num_init_fcns; i++) + if (init_array_buf[i]) + DLIF_execute(pHandle->client_handle, + (TARGET_ADDRESS)(init_array_buf[i])); + else + DLIF_warning(DLWT_MISC, + "DT_INIT_ARRAY/DT_PREINIT_ARRAY function address is NULL!"); + + DLIF_free(init_array_buf); + } + else + { + if (val->sect_addr) + DLIF_execute(pHandle->client_handle, + (TARGET_ADDRESS)(val->sect_addr)); + else + DLIF_warning(DLWT_MISC, "DT_INIT function address is NULL!"); + } + } +} + +/*****************************************************************************/ +/* adjust_module_init_fini() */ +/* If the dynamic loader need not process the module initialization */ +/* and termination (fini section) then adjust the module info so that */ +/* the respective sizes become zero. */ +/*****************************************************************************/ +static void adjust_module_init_fini(DLIMP_Dynamic_Module *dm) +{ + /*------------------------------------------------------------------------*/ + /* The C6x RTS boot code has the function _c_int00 which performs */ + /* the C/C++ initialization. This function processes the .init_array */ + /* to perform the C/C++ initialization and handles termination through */ + /* the at_exit functionality. If the dynamic executable we are loading */ + /* includes _c_int00, the loader assumes that the application code takes */ + /* care of all initialization and termination. Hence the loader won't */ + /* perform the initialization and termination. */ + /* NOTE: Use of __TI_STACK_SIZE is a hack. The _c_int00 symbol is not */ + /* in the dynamic symbol table. The right fix is for the linker */ + /* not to generate the init array tags if the build includes RTS */ + /* boot routine. */ + /*------------------------------------------------------------------------*/ + if (dm->fhdr.e_type == ET_EXEC && + DLSYM_lookup_local_symtab("__TI_STACK_SIZE", dm->symtab, dm->symnum, + NULL)) + { + dm->init_arraysz = 0; + dm->init_array_idx = -1; + + dm->preinit_arraysz = 0; + dm->preinit_array_idx = -1; + + dm->loaded_module->fini_arraysz = 0; + dm->loaded_module->fini_array = (Elf32_Addr) NULL; + dm->loaded_module->fini = (Elf32_Addr) NULL; + } +} + +/*****************************************************************************/ +/* relocate_dependency_graph_modules() */ +/* */ +/* For each dynamic module on the dependency stack, process dynamic */ +/* relocation entries then perform initialization for all global and */ +/* static objects that are defined in tha given module. The stack is */ +/* emptied from the top (LIFO). Each dynamic module object is popped */ +/* off the top of the stack, the module gets relocated, its global and */ +/* static objects that need to be constructed will be constructed, and */ +/* then, after detaching the loaded module object from its dynamic */ +/* module, the dynamic module object is destructed. */ +/* */ +/*****************************************************************************/ +static +int32_t relocate_dependency_graph_modules(DLOAD_HANDLE handle, + LOADER_FILE_DESC *fd, + DLIMP_Dynamic_Module *dyn_module) +{ + /*------------------------------------------------------------------------*/ + /* Processing of relocations will only be triggered when this function */ + /* is called from the top-level object module (at the bottom of the */ + /* dependency graph stack). */ + /*------------------------------------------------------------------------*/ + int32_t local_file_handle = dyn_module->loaded_module->file_handle; + LOADER_OBJECT *pHandle = (LOADER_OBJECT *)handle; + dynamic_module_ptr_Stack_Node *ptr = + pHandle->DLIMP_dependency_stack.bottom_ptr; + if (ptr && (ptr->value != dyn_module)) return local_file_handle; + + if (is_dsbt_module(dyn_module)) + { + /*--------------------------------------------------------------------*/ + /* Assign DSBT indices. */ + /*--------------------------------------------------------------------*/ + DLIF_assign_dsbt_indices(); + + /*--------------------------------------------------------------------*/ + /* Update the content of all DSBTs for any module that uses the */ + /* DSBT model. */ + /*--------------------------------------------------------------------*/ + DLIF_update_all_dsbts(); + } + + /*------------------------------------------------------------------------*/ + /* Ok, we are ready to process relocations. The relocation tables */ + /* associated with dependent files will be processed first. Consume */ + /* dynamic module objects from the dependency graph stack from dependents */ + /* to the root of the dependency graph. */ + /*------------------------------------------------------------------------*/ + while (pHandle->DLIMP_dependency_stack.size > 0) + { + DLIMP_Dynamic_Module *dyn_mod_ptr = + dynamic_module_ptr_pop(&pHandle->DLIMP_dependency_stack); + + /*---------------------------------------------------------------------*/ + /* Process dynamic relocations associated with this module. */ + /*---------------------------------------------------------------------*/ + process_dynamic_module_relocations(handle, dyn_mod_ptr->fd, dyn_mod_ptr); + + /*---------------------------------------------------------------------*/ + /* __c_args__ points to the beginning of the .args section, if there */ + /* is one. Record this pointer in the ELF file internal data object. */ + /* Also store this in the loaded module, since this will be needed to */ + /* write argv, argc to .args at execution time. */ + /*---------------------------------------------------------------------*/ + DLSYM_lookup_local_symtab("__c_args__", dyn_mod_ptr->symtab, + dyn_mod_ptr->symnum, + (Elf32_Addr *)&dyn_mod_ptr->c_args); + dyn_mod_ptr->loaded_module->c_args = dyn_mod_ptr->c_args; + + /*---------------------------------------------------------------------*/ + /* Pick up entry point address from ELF file header. */ + /* We currently only support a single entry point into the ELF file. */ + /* To support Braveheart notion of nodes, with multiple entry points,*/ + /* we'll need to get the list of entry points associated with a node,*/ + /* then add capability to the "execute" command to select the entry */ + /* point that we want to start executing from. */ + /*---------------------------------------------------------------------*/ + dyn_mod_ptr->loaded_module->entry_point = dyn_mod_ptr->fhdr.e_entry; + + /*---------------------------------------------------------------------*/ + /* Copy command-line arguments into args section and deal with DSBT */ + /* issues (copy DSBT to its run location). */ + /* Note that below function is commented out because this doesn't do */ + /* much as of now. */ + /*---------------------------------------------------------------------*/ + //load_object(dyn_mod_ptr->fd, dyn_mod_ptr); + + /*---------------------------------------------------------------------*/ + /* Perform initialization, if needed, for this module. */ + /*---------------------------------------------------------------------*/ + store_init_data(dyn_mod_ptr); + + /*---------------------------------------------------------------------*/ + /* Free all dependent file pointers. */ + /*---------------------------------------------------------------------*/ + if (dyn_mod_ptr->fd != fd) + { + DLIF_fclose(dyn_mod_ptr->fd); + dyn_mod_ptr->fd = NULL; + } + + /*---------------------------------------------------------------------*/ + /* Detach loaded module object from the dynamic module object that */ + /* created it, then throw away the dynamic module object. */ + /*---------------------------------------------------------------------*/ + detach_loaded_module(dyn_mod_ptr); + delete_DLIMP_Dynamic_Module(handle, &dyn_mod_ptr); + } + + return local_file_handle; +} + +/*****************************************************************************/ +/* DLOAD_load() */ +/* */ +/* Dynamically load the specified file and return a file handle for the */ +/* loaded file. If the load fails, this function will return a value of */ +/* zero (0) for the file handle. */ +/* */ +/* The core loader must have read access to the file pointed to by fd. */ +/* */ +/*****************************************************************************/ +int32_t DLOAD_load(DLOAD_HANDLE handle, LOADER_FILE_DESC *fd) +{ + int32_t fl_handle; + + LOADER_OBJECT *pHandle = (LOADER_OBJECT *)handle; + DLIMP_Dynamic_Module *dyn_module = new_DLIMP_Dynamic_Module(fd); + + if (!dyn_module) + return 0; + +#if LOADER_DEBUG + /*------------------------------------------------------------------------*/ + /* Spit out some loader progress information when we begin loading an */ + /* object. */ + /*------------------------------------------------------------------------*/ + if (debugging_on) DLIF_trace("Loading file...\n"); +#endif + + /*------------------------------------------------------------------------*/ + /* If no access to a program was provided, there is nothing to do. */ + /*------------------------------------------------------------------------*/ + if (!fd) + { + DLIF_error(DLET_FILE, "Missing file specification.\n"); + delete_DLIMP_Dynamic_Module(handle, &dyn_module); + return 0; + } + + /*------------------------------------------------------------------------*/ + /* Read file headers and dynamic information into dynamic module. */ + /*------------------------------------------------------------------------*/ + if (!dload_headers(fd, dyn_module)) + { + delete_DLIMP_Dynamic_Module(handle, &dyn_module); + return 0; + } + + /*------------------------------------------------------------------------*/ + /* Find the dynamic segment, if there is one, and read dynamic */ + /* information from the ELF object file into the dynamic module data */ + /* structure associated with this file. */ + /*------------------------------------------------------------------------*/ + if (!dload_dynamic_segment(handle, fd, dyn_module)) + return 0; + + /*------------------------------------------------------------------------*/ + /* Perform sanity checking on the read-in ELF file. */ + /*------------------------------------------------------------------------*/ + if (!is_valid_elf_object_file(fd, dyn_module)) + { + DLIF_error(DLET_FILE, "Attempt to load invalid ELF file, '%s'.\n", + dyn_module->name); + return 0; + } + +#if LOADER_DEBUG || LOADER_PROFILE + /*------------------------------------------------------------------------*/ + /* Stop clock on initialization of ELF file information. Start clock on */ + /* initialization of ELF module. */ + /*------------------------------------------------------------------------*/ + if (debugging_on || profiling_on) + { + DLIF_trace("Finished dload_dynamic_segment.\n"); + if (profiling_on) + { + profile_stop_clock(); + DLIF_trace("Took %lu cycles.\n", + (unsigned long) profile_cycle_count()); + } + } +#endif + + /*------------------------------------------------------------------------*/ + /* Initialize internal ELF module and segment structures. Sets */ + /* loaded_module in *dyn_module. This also deals with assigning a file */ + /* handle and bumping file handle counter. */ + /*------------------------------------------------------------------------*/ + initialize_loaded_module(handle, dyn_module); + + /*------------------------------------------------------------------------*/ + /* Append Module structure to loaded object list. */ + /*------------------------------------------------------------------------*/ + loaded_module_ptr_enqueue(&pHandle->DLIMP_loaded_objects, + dyn_module->loaded_module); + + /*------------------------------------------------------------------------*/ + /* Support static loading as special case. */ + /*------------------------------------------------------------------------*/ + if (!dyn_module->relocatable) + return dload_static_executable(handle, fd, dyn_module); + + /*------------------------------------------------------------------------*/ + /* Get space & address for segments, and offset symbols and program */ + /* header table to reflect the relocated address. Also offset the */ + /* addresses in the internal Segment structures used by the Module */ + /* structure. Note that this step needs to be performed prior and in */ + /* addition to the relocation entry processing. */ + /*------------------------------------------------------------------------*/ + if (!allocate_dynamic_segments_and_relocate_symbols(handle, fd, dyn_module)) + return 0; + + /*------------------------------------------------------------------------*/ + /* __c_args__ points to the beginning of the .args section, if there is */ + /* one. __TI_STATIC_BASE points to the beginning of the DP-relative data */ + /* segment (value to initialize DP). Record these addresses in the ELF */ + /* file internal data object. */ + /*------------------------------------------------------------------------*/ + DLSYM_lookup_local_symtab("__c_args__", dyn_module->symtab, + dyn_module->symnum, + (Elf32_Addr *)&dyn_module->c_args); + + DLSYM_lookup_local_symtab("__TI_STATIC_BASE", dyn_module->symtab, + dyn_module->symnum, + (Elf32_Addr *)&dyn_module->static_base); + dyn_module->loaded_module->static_base = dyn_module->static_base; + + /*------------------------------------------------------------------------*/ + /* If the user application performs initialization and termination, */ + /* the dynamic loader shouldn't process the init/fini sections. */ + /* Check and adjust the init/fini information accordingly. */ + /*------------------------------------------------------------------------*/ + adjust_module_init_fini(dyn_module); + + /*------------------------------------------------------------------------*/ + /* Execute any user defined pre-initialization functions that may be */ + /* associated with a dynamic executable module. */ + /*------------------------------------------------------------------------*/ + if (dyn_module->fhdr.e_type == ET_EXEC) + store_preinit_data(dyn_module); + + /*------------------------------------------------------------------------*/ + /* Append current ELF file to list of objects currently loading. */ + /* This is used to detect circular dependencies while we are processing */ + /* the dependents of this file. */ + /*------------------------------------------------------------------------*/ + AL_append(&pHandle->DLIMP_module_dependency_list, &dyn_module->name); + + /*------------------------------------------------------------------------*/ + /* Push this dynamic module object onto the dependency stack. */ + /* All of the modules on the stack will get relocated after all of the */ + /* dependent files have been loaded and allocated. */ + /*------------------------------------------------------------------------*/ + dynamic_module_ptr_push(&pHandle->DLIMP_dependency_stack, dyn_module); + + /*------------------------------------------------------------------------*/ + /* If this object file uses the DSBT model, then register a DSBT index */ + /* request with the client's DSBT support management. */ + /*------------------------------------------------------------------------*/ + if (is_dsbt_module(dyn_module) && + !DLIF_register_dsbt_index_request(handle, + dyn_module->name, + dyn_module->loaded_module->file_handle, + dyn_module->dsbt_index)) + return 0; + + /*------------------------------------------------------------------------*/ + /* Load this ELF file's dependees (all files on its DT_NEEDED list). */ + /* Dependees must be loaded and relocated before processing this module's */ + /* relocations. */ + /*------------------------------------------------------------------------*/ + if (!dload_and_allocate_dependencies(handle, dyn_module)) + return 0; + + /*------------------------------------------------------------------------*/ + /* Remove the current ELF file from the list of files that are in the */ + /* process of loading. */ + /*------------------------------------------------------------------------*/ + pHandle->DLIMP_module_dependency_list.size--; + + /*------------------------------------------------------------------------*/ + /* Process relocation entries. */ + /*------------------------------------------------------------------------*/ + fl_handle = relocate_dependency_graph_modules(handle, fd, dyn_module); + + /*------------------------------------------------------------------------*/ + /* With initialization complete, and all relocations having been resolved */ + /* do module initialization. */ + /*------------------------------------------------------------------------*/ + execute_module_initialization(handle); + + return fl_handle; +} + +/*****************************************************************************/ +/* DLOAD_get_entry_names() */ +/* */ +/* Build a list of entry point names for a loaded object. Currently, */ +/* any global symbol in the module is considered a valid entry point */ +/* regardless of whether it is defined in code or associated with a */ +/* data object. We would need to process the content of the symbol */ +/* table entry or its debug information to determine whether it is a */ +/* valid entry point or not. */ +/* */ +/*****************************************************************************/ +BOOL DLOAD_get_entry_names(DLOAD_HANDLE handle, + uint32_t file_handle, + int32_t *entry_pt_cnt, + char ***entry_pt_names) +{ + /*------------------------------------------------------------------------*/ + /* Spin through list of loaded files until we find the file handle we */ + /* are looking for. Then build a list of entry points from that file's */ + /* symbol table. */ + /*------------------------------------------------------------------------*/ + LOADER_OBJECT *pHandle = (LOADER_OBJECT *)handle; + + loaded_module_ptr_Queue_Node* ptr; + for (ptr = pHandle->DLIMP_loaded_objects.front_ptr; ptr != NULL; + ptr = ptr->next_ptr) + { + if (ptr->value->file_handle == file_handle) + { + DLIMP_Loaded_Module *module = ptr->value; + struct Elf32_Sym *symtab; + int i; + + /*------------------------------------------------------------------*/ + /* Any symbol in our file's symbol table is considered a valid */ + /* entry point. */ + /*------------------------------------------------------------------*/ + symtab = (struct Elf32_Sym*)module->gsymtab; + *entry_pt_cnt = module->gsymnum; + *entry_pt_names = DLIF_malloc(*entry_pt_cnt * sizeof(char*)); + for (i = 0; i < module->gsymnum; i++) + { + const char *sym_name = (const char *)symtab[i].st_name; + **entry_pt_names = DLIF_malloc(strlen(sym_name) + 1); + strcpy(**entry_pt_names,sym_name); + } + + return TRUE; + } + } + + /*------------------------------------------------------------------------*/ + /* We didn't find the file we were looking for, return false. */ + /*------------------------------------------------------------------------*/ + return FALSE; +} + +/*****************************************************************************/ +/* DLOAD_prepare_for_execution() */ +/* */ +/* Given a file handle, prepare for execution : */ +/* - Return entry point associated with that module in the *sym_val */ +/* output parameter. */ +/* - Write out the given arguments to the .args section contained in the */ +/* same module. */ +/* - As a test (for the Reference implementation) read the arguments */ +/* using the DLIF_read_arguments() function and set global argc,argv. */ +/* */ +/*****************************************************************************/ +BOOL DLOAD_prepare_for_execution(DLOAD_HANDLE handle, uint32_t file_handle, + TARGET_ADDRESS *sym_val, + int argc, char** argv) +{ + /*------------------------------------------------------------------------*/ + /* Spin through list of loaded files until we find the file handle we */ + /* are looking for. Then return the entry point address associated with */ + /* that module. */ + /*------------------------------------------------------------------------*/ + DLIMP_Loaded_Module *ep_loaded_module; + loaded_module_ptr_Queue_Node* ptr; + LOADER_OBJECT *pHandle = (LOADER_OBJECT *)handle; + + for (ptr = pHandle->DLIMP_loaded_objects.front_ptr; ptr != NULL; + ptr = ptr->next_ptr) + if (ptr->value->file_handle == file_handle) + { + *sym_val = (TARGET_ADDRESS)(ptr->value->entry_point); + ep_loaded_module = ptr->value; + + /*------------------------------------------------------------------*/ + /* Write argc, argv to the .args section in this module. */ + /*------------------------------------------------------------------*/ + if (!write_arguments_to_args_section(handle, argc, argv, + ep_loaded_module)) + { + DLIF_error(DLET_MISC, "Couldn't write to .args section\n"); + return FALSE; + } + + /*------------------------------------------------------------------*/ + /* For the Reference Implementation we simulate a "boot" (rts boot */ + /* routine reads argc, argv from .args), by reading argc, argv from */ + /* .args section. Note that we just wrote these values to the .args */ + /* so this read serves as a test for the Reference Implementation. */ + /*------------------------------------------------------------------*/ + read_args_from_section(ep_loaded_module); + return TRUE; + } + + /*------------------------------------------------------------------------*/ + /* We didn't find the file we were looking for, return false. */ + /*------------------------------------------------------------------------*/ + return FALSE; +} + +/*****************************************************************************/ +/* DLOAD_load_arguments() */ +/* */ +/* Write out the given arguments to the .args section contained in the */ +/* same module. */ +/* */ +/*****************************************************************************/ +BOOL DLOAD_load_arguments(DLOAD_HANDLE handle, uint32_t file_handle, + int argc, char** argv) +{ + /*------------------------------------------------------------------------*/ + /* Spin through list of loaded files until we find the file handle we */ + /* are looking for. Then return the entry point address associated with */ + /* that module. */ + /*------------------------------------------------------------------------*/ + DLIMP_Loaded_Module *ep_loaded_module; + loaded_module_ptr_Queue_Node* ptr; + LOADER_OBJECT *pHandle = (LOADER_OBJECT *)handle; + + for (ptr = pHandle->DLIMP_loaded_objects.front_ptr; ptr != NULL; + ptr = ptr->next_ptr) + if (ptr->value->file_handle == file_handle) + { + ep_loaded_module = ptr->value; + + /*------------------------------------------------------------------*/ + /* Write argc, argv to the .args section in this module. */ + /*------------------------------------------------------------------*/ + if (!write_arguments_to_args_section(handle, argc, argv, + ep_loaded_module)) + { + DLIF_error(DLET_MISC, "Couldn't write to .args section\n"); + return FALSE; + } + } + + /*------------------------------------------------------------------------*/ + /* We didn't find the file we were looking for, return false. */ + /*------------------------------------------------------------------------*/ + return FALSE; +} + +/*****************************************************************************/ +/* DLOAD_get_entry_point() */ +/* */ +/* Given a file handle, return the entry point associated with that */ +/* module in the *sym_val output parameter. */ +/* */ +/*****************************************************************************/ +BOOL DLOAD_get_entry_point(DLOAD_HANDLE handle, uint32_t file_handle, + TARGET_ADDRESS *sym_val) +{ + /*------------------------------------------------------------------------*/ + /* Spin through list of loaded files until we find the file handle we */ + /* are looking for. Then return the entry point address associated with */ + /* that module. */ + /*------------------------------------------------------------------------*/ + loaded_module_ptr_Queue_Node* ptr; + LOADER_OBJECT *pHandle = (LOADER_OBJECT *)handle; + + for (ptr = pHandle->DLIMP_loaded_objects.front_ptr; ptr != NULL; + ptr = ptr->next_ptr) + if (ptr->value->file_handle == file_handle) + { + *sym_val = (TARGET_ADDRESS)(ptr->value->entry_point); + return TRUE; + } + + /*------------------------------------------------------------------------*/ + /* We didn't find the file we were looking for, return false. */ + /*------------------------------------------------------------------------*/ + return FALSE; +} + +/*****************************************************************************/ +/* DLOAD_query_symbol() */ +/* */ +/* Query the value of a global symbol from a specific file. The value */ +/* result will be written to *sym_val. The function returns TRUE if the */ +/* symbol was found, and FALSE if it wasn't. */ +/* */ +/*****************************************************************************/ +BOOL DLOAD_query_symbol(DLOAD_HANDLE handle, + uint32_t file_handle, + const char *sym_name, + TARGET_ADDRESS *sym_val) +{ + /*------------------------------------------------------------------------*/ + /* Spin through list of loaded files until we find the file handle we */ + /* are looking for. Then return the value (target address) associated */ + /* with the symbol we are looking for in that file. */ + /*------------------------------------------------------------------------*/ + loaded_module_ptr_Queue_Node* ptr; + LOADER_OBJECT *pHandle = (LOADER_OBJECT *)handle; + + for (ptr = pHandle->DLIMP_loaded_objects.front_ptr; ptr != NULL; + ptr = ptr->next_ptr) + { + if (ptr->value->file_handle == file_handle) + { + DLIMP_Loaded_Module *module = ptr->value; + struct Elf32_Sym *symtab; + int i; + + /*------------------------------------------------------------------*/ + /* Search through the symbol table by name. */ + /*------------------------------------------------------------------*/ + symtab = (struct Elf32_Sym*)module->gsymtab; + for(i=0; i < module->gsymnum; i++) + { + if (!strcmp(sym_name, (const char *)symtab[i].st_name)) + { + *sym_val = (TARGET_ADDRESS) symtab[i].st_value; + return TRUE; + } + } + } + } + + /*------------------------------------------------------------------------*/ + /* We didn't find the symbol we were looking for, return false. */ + /*------------------------------------------------------------------------*/ + return FALSE; +} + + + +/*****************************************************************************/ +/* unlink_loaded_module() */ +/* */ +/* Unlink a loaded module data object from the list of loaded objects, */ +/* returning a pointer to the object so that it can be deconstructed. */ +/* */ +/*****************************************************************************/ +static DLIMP_Loaded_Module *unlink_loaded_module(DLOAD_HANDLE handle, + loaded_module_ptr_Queue_Node *back_ptr, + loaded_module_ptr_Queue_Node *lm_node) +{ + DLIMP_Loaded_Module *loaded_module = lm_node->value; + LOADER_OBJECT *pHandle = (LOADER_OBJECT *)handle; + loaded_module_ptr_remove(&pHandle->DLIMP_loaded_objects, lm_node->value); + return loaded_module; +} + +/*****************************************************************************/ +/* execute_module_termination() */ +/* */ +/* Execute termination functions associated with this loaded module. */ +/* Termination functions are called in the reverse order as their */ +/* corresponding initialization functions. */ +/* */ +/*****************************************************************************/ +static void execute_module_termination(DLOAD_HANDLE handle, + DLIMP_Loaded_Module *loaded_module) +{ + LOADER_OBJECT *pHandle = (LOADER_OBJECT *)handle; + + /*------------------------------------------------------------------------*/ + /* If a DT_FINI_ARRAY dynamic tag was encountered for this module, spin */ + /* through the array in reverse order, calling each function address */ + /* stored in the array. */ + /*------------------------------------------------------------------------*/ + if (loaded_module->fini_arraysz != 0) + { + /*---------------------------------------------------------------------*/ + /* Now make a loader-accessible copy of the .fini_array section. */ + /*---------------------------------------------------------------------*/ + int32_t i; + int32_t num_fini_fcns = + loaded_module->fini_arraysz/sizeof(TARGET_ADDRESS); + TARGET_ADDRESS *fini_array_buf = (TARGET_ADDRESS *) + DLIF_malloc(loaded_module->fini_arraysz); + + DLIF_read(pHandle->client_handle, + fini_array_buf, 1, loaded_module->fini_arraysz, + (TARGET_ADDRESS)loaded_module->fini_array); + + /*---------------------------------------------------------------------*/ + /* Now spin through the array in reverse order, executing each */ + /* termination function whose address occupies an entry in the array. */ + /*---------------------------------------------------------------------*/ + for (i = num_fini_fcns - 1; i >= 0; i--) + DLIF_execute(pHandle->client_handle, + (TARGET_ADDRESS)(fini_array_buf[i])); + + DLIF_free(fini_array_buf); + } + + /*------------------------------------------------------------------------*/ + /* If a DT_FINI dynamic tag was encountered for this module, call the */ + /* function indicated by the tag's value to complete the termination */ + /* process for this module. */ + /*------------------------------------------------------------------------*/ + if (loaded_module->fini != (Elf32_Addr) NULL) + DLIF_execute(pHandle->client_handle, + (TARGET_ADDRESS)loaded_module->fini); +} + +/*****************************************************************************/ +/* remove_loaded_module() */ +/* */ +/* Find and unlink a loaded module data object from the list of loaded */ +/* objects, then call its destructor to free the host memory associated */ +/* with the loaded module and all of its loaded segments. */ +/* */ +/*****************************************************************************/ +static void remove_loaded_module(DLOAD_HANDLE handle, + loaded_module_ptr_Queue_Node *lm_node) +{ + DLIMP_Loaded_Module *lm_object = NULL; + loaded_module_ptr_Queue_Node *back_ptr = NULL; + LOADER_OBJECT *pHandle = (LOADER_OBJECT *)handle; + + if (lm_node != pHandle->DLIMP_loaded_objects.front_ptr) + for (back_ptr = pHandle->DLIMP_loaded_objects.front_ptr; + back_ptr->next_ptr != lm_node; + back_ptr = back_ptr->next_ptr); + + lm_object = unlink_loaded_module(handle, back_ptr, lm_node); + + delete_DLIMP_Loaded_Module(handle, &lm_object); +} + +/*****************************************************************************/ +/* DLOAD_unload() */ +/* */ +/* Unload specified module (identified by its file handle) from target */ +/* memory. Free up any target memory that was allocated for the module's */ +/* segments and also any host heap memory that was allocated for the */ +/* internal module and segment data structures. */ +/* */ +/* Return TRUE if program entry is actually destroyed. This is a way of */ +/* communicating to the client when it needs to actually remove debug */ +/* information associated with this module (so that client does not have */ +/* to maintain a use count that mirrors the program entry). */ +/* */ +/*****************************************************************************/ +BOOL DLOAD_unload(DLOAD_HANDLE handle, uint32_t file_handle) +{ + loaded_module_ptr_Queue_Node* lm_node; + LOADER_OBJECT *pHandle = (LOADER_OBJECT *)handle; + + for (lm_node = pHandle->DLIMP_loaded_objects.front_ptr; lm_node != NULL; + lm_node = lm_node->next_ptr) + { + if (lm_node->value->file_handle == file_handle) + { + --lm_node->value->use_count; + if (lm_node->value->use_count == 0) + { + DLIMP_Loaded_Module *loaded_module = + (DLIMP_Loaded_Module *)lm_node->value; + int j; + int *dep_file_handles; + + /*---------------------------------------------------------------*/ + /* Termination functions need to be executed in the reverse */ + /* order as the corresponding initialization functions, so */ + /* before we go unload this module's dependents, we need to */ + /* perform the user/global/static termination functions */ + /* associated with this module. */ + /*---------------------------------------------------------------*/ + execute_module_termination(handle, loaded_module); + + /*---------------------------------------------------------------*/ + /* Unload dependent modules via the client. Client needs to know */ + /* when a dependent gets unloaded so that it can update debug */ + /* information. */ + /*---------------------------------------------------------------*/ + dep_file_handles = (int*)(loaded_module->dependencies.buf); + for (j = 0; j < loaded_module->dependencies.size; j++) + DLIF_unload_dependent(pHandle->client_handle, + dep_file_handles[j]); + + /*---------------------------------------------------------------*/ + /* Find the predecessor node of the value we're deleting, */ + /* because its next_ptr will need to be updated. */ + /* */ + /* We can't keep a back pointer around because */ + /* DLIF_unload_dependent() might free that node, making our */ + /* pointer invalid. Turn the Queue template into a doubly */ + /* linked list if this overhead becomes a problem. */ + /*---------------------------------------------------------------*/ + remove_loaded_module(handle, lm_node); + + /*---------------------------------------------------------------*/ + /* Once unloading is done, reset virtual target to NULL. */ + /*---------------------------------------------------------------*/ + cur_target = NULL; + + return TRUE; + } + } + } + + return FALSE; +} + +/*****************************************************************************/ +/* DLOAD_load_symbols() */ +/* */ +/* Load the symbols from the given file and make symbols available for */ +/* global symbol linkage. */ +/* */ +/*****************************************************************************/ +int32_t DLOAD_load_symbols(DLOAD_HANDLE handle, LOADER_FILE_DESC *fd) +{ + DLIMP_Dynamic_Module *dyn_module = new_DLIMP_Dynamic_Module(fd); + DLIMP_Loaded_Module *loaded_module = NULL; + LOADER_OBJECT *pHandle = (LOADER_OBJECT *)handle; + + /*------------------------------------------------------------------------*/ + /* Ensure we have a valid dynamic module object from the constructor. */ + /*------------------------------------------------------------------------*/ + if (!dyn_module) + return 0; + + /*------------------------------------------------------------------------*/ + /* If no access to a program was provided, there is nothing to do. */ + /*------------------------------------------------------------------------*/ + if (!fd) + { + DLIF_error(DLET_FILE, "Missing file specification.\n"); + return 0; + } + + /*------------------------------------------------------------------------*/ + /* Record argc and argv pointers with the dynamic module record. */ + /*------------------------------------------------------------------------*/ + dyn_module->argc = 0; + dyn_module->argv = NULL; + + /*------------------------------------------------------------------------*/ + /* Read file headers and dynamic information into dynamic module. */ + /*------------------------------------------------------------------------*/ + if (!dload_headers(fd, dyn_module)) + { + delete_DLIMP_Dynamic_Module(handle, &dyn_module); + return 0; + } + + /*------------------------------------------------------------------------*/ + /* Find the dynamic segment, if there is one, and read dynamic */ + /* information from the ELF object file into the dynamic module data */ + /* structure associated with this file. */ + /*------------------------------------------------------------------------*/ + if (!dload_dynamic_segment(handle, fd, dyn_module)) + { + delete_DLIMP_Dynamic_Module(handle, &dyn_module); + return 0; + } + + /*------------------------------------------------------------------------*/ + /* Perform sanity checking on the read-in ELF file. */ + /*------------------------------------------------------------------------*/ + if (!is_valid_elf_object_file(fd, dyn_module)) + { + DLIF_error(DLET_FILE, "Attempt to load invalid ELF file, '%s'.\n", + dyn_module->name); + delete_DLIMP_Dynamic_Module(handle, &dyn_module); + return 0; + } + + /*------------------------------------------------------------------------*/ + /* Initialize internal ELF module and segment structures. Sets */ + /* loaded_module in *dyn_module. This also deals with assigning a file */ + /* handle and bumping file handle counter. */ + /*------------------------------------------------------------------------*/ + initialize_loaded_module(handle, dyn_module); + + /*------------------------------------------------------------------------*/ + /* Add this module to the loaded module queue. */ + /* Detach the loaded module object from the dynamic module thath created */ + /* it. Ownership of the host memory allocated for the loaded module */ + /* object now belongs to the DLIMP_loaded_objects list. */ + /*------------------------------------------------------------------------*/ + loaded_module_ptr_enqueue(&pHandle->DLIMP_loaded_objects, + dyn_module->loaded_module); + + /*------------------------------------------------------------------------*/ + /* Register a DSBT index request for this module and update its own copy */ + /* of the DSBT with the contents of the client's master DSBT. */ + /*------------------------------------------------------------------------*/ + if (is_dsbt_module(dyn_module)) + { + dynamic_module_ptr_push(&pHandle->DLIMP_dependency_stack, dyn_module); + DLIF_register_dsbt_index_request(handle, + dyn_module->name, + dyn_module->loaded_module->file_handle, + dyn_module->dsbt_index); + DLIF_assign_dsbt_indices(); + DLIF_update_all_dsbts(); + dynamic_module_ptr_pop(&pHandle->DLIMP_dependency_stack); + } + + /*------------------------------------------------------------------------*/ + /* Ownership of the host memory allocated for the loaded module object is */ + /* transferred to the DLIMP_loaded_objects list. Free up the host memory */ + /* for the dynamic module that created the loaded module object. Just */ + /* call the destructor function for DLIMP_Dynamic_Module. */ + /*------------------------------------------------------------------------*/ + loaded_module = detach_loaded_module(dyn_module); + if(loaded_module == NULL) + { + delete_DLIMP_Dynamic_Module(handle, &dyn_module); + return 0; + } + delete_DLIMP_Dynamic_Module(handle, &dyn_module); + + /*------------------------------------------------------------------------*/ + /* Return a file handle so that the client can match this file to an ID. */ + /*------------------------------------------------------------------------*/ + return loaded_module->file_handle; +} + +/*****************************************************************************/ +/* DSBT Support Functions */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* DLOAD_get_dsbt_size() */ +/* */ +/* Find the amount of space allocated for the specified module's DSBT. */ +/* It must be big enough to hold a copy of the master DSBT or the client */ +/* will flag an error. Those modules whose DSBT size is zero are assumed */ +/* to not be using the DSBT model. */ +/* */ +/*****************************************************************************/ +uint32_t DLOAD_get_dsbt_size(DLOAD_HANDLE handle, int32_t file_handle) +{ + dynamic_module_ptr_Stack_Node *ptr; + LOADER_OBJECT *pHandle = (LOADER_OBJECT *)handle; + + for (ptr = pHandle->DLIMP_dependency_stack.top_ptr; ptr != NULL; + ptr = ptr->next_ptr) + { + DLIMP_Dynamic_Module *dmp = ptr->value; + if (dmp->loaded_module->file_handle == file_handle) + return dmp->dsbt_size; + } + + return 0; +} + +/*****************************************************************************/ +/* DLOAD_get_static_base() */ +/* */ +/* Look up static base symbol associated with the specified module. */ +/* */ +/*****************************************************************************/ +BOOL DLOAD_get_static_base(DLOAD_HANDLE handle, int32_t file_handle, + TARGET_ADDRESS *static_base) +{ + loaded_module_ptr_Queue_Node* ptr; + LOADER_OBJECT *pHandle = (LOADER_OBJECT *)handle; + + for (ptr = pHandle->DLIMP_loaded_objects.front_ptr; ptr != NULL; + ptr = ptr->next_ptr) + { + DLIMP_Loaded_Module *lmp = ptr->value; + if (lmp->file_handle == file_handle) + { + *static_base = (TARGET_ADDRESS)lmp->static_base; + return TRUE; + } + } + + return FALSE; +} + +/*****************************************************************************/ +/* DLOAD_get_dsbt_base() */ +/* */ +/* Look up address of DSBT for the specified module. */ +/* */ +/*****************************************************************************/ +BOOL DLOAD_get_dsbt_base(DLOAD_HANDLE handle, int32_t file_handle, TARGET_ADDRESS *dsbt_base) +{ + dynamic_module_ptr_Stack_Node *ptr; + LOADER_OBJECT *pHandle = (LOADER_OBJECT *)handle; + + for (ptr = pHandle->DLIMP_dependency_stack.top_ptr; ptr != NULL; + ptr = ptr->next_ptr) + { + DLIMP_Dynamic_Module *dmp = ptr->value; + if (dmp->loaded_module->file_handle == file_handle) + { + *dsbt_base = + (TARGET_ADDRESS)dmp->dyntab[dmp->dsbt_base_tagidx].d_un.d_ptr; + return TRUE; + } + } + + return FALSE; +} + +/*****************************************************************************/ +/* RELOCATE() - Perform RELA and REL type relocations for given ELF object */ +/* file that we are in the process of loading and relocating. */ +/*****************************************************************************/ +void DLREL_relocate(DLOAD_HANDLE handle, LOADER_FILE_DESC* elf_file, + DLIMP_Dynamic_Module* dyn_module) + +{ + cur_target->relocate(handle, elf_file, dyn_module); +} + +/*****************************************************************************/ +/* GET_VT_OBJ() - Once file headers have been read, use the e_machine id to */ +/* figure out the virtul target, so we can access trg specific funcs. */ +/*****************************************************************************/ +static VIRTUAL_TARGET *get_vt_obj(int given_id) +{ + VIRTUAL_TARGET *ptr; + + for(ptr = vt_arr; ptr->machine_id != EM_NONE ; ptr++) + if (ptr->machine_id == given_id) return ptr; + + return NULL; +} + +#if 0 && LOADER_DEBUG // enable to make available in debugger +/*****************************************************************************/ +/* DEBUG_QUEUE() - Debug function. */ +/*****************************************************************************/ +static void debug_queue(LOADER_OBJECT *pHandle, char* position) +{ + loaded_module_ptr_Queue_Node* ptr; + + if (!debugging_on) return; + + DLIF_trace ("\nDEBUG QUEUE : %s, pHandle : 0x%x\n\n", position, + (uint32_t)pHandle); + + for (ptr = pHandle->DLIMP_loaded_objects.front_ptr; ptr != NULL; + ptr = ptr->next_ptr) + { + DLIF_trace ("ptr->value->name : %s\n",ptr->value->name); + } + DLIF_trace ("\n"); +} +#endif + +/*****************************************************************************/ +/* READ_ARGS_FROM_SECTION() - This function reads the argc, argv from the */ +/* .args section, and is used to test Reference implementation. */ +/*****************************************************************************/ +static void read_args_from_section(DLIMP_Loaded_Module* ep_module) +{ + /*------------------------------------------------------------------------*/ + /* Before this function in called, the loader has gotten argv/argc from */ + /* the module and written it out to the .args section. c_args points to */ + /* the .args section. */ + /*------------------------------------------------------------------------*/ + ARGS_CONTAINER *pargs = (ARGS_CONTAINER *)(ep_module->c_args); + if (!pargs || pargs == (ARGS_CONTAINER *)0xFFFFFFFF) + { + global_argc = 0; + global_argv = NULL; + } + else + { + global_argc = pargs->argc; + global_argv = pargs->argv; + } +} diff --git a/src/core/dsp/ocl_load/DLOAD/dload.h b/src/core/dsp/ocl_load/DLOAD/dload.h new file mode 100644 index 0000000..bb7d427 --- /dev/null +++ b/src/core/dsp/ocl_load/DLOAD/dload.h @@ -0,0 +1,334 @@ +/* +* dload.h +* +* Define internal data structures used by core dynamic loader. +* +* Copyright (C) 2009-2014 Texas Instruments Incorporated - http://www.ti.com/ +* +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +*/ + +#ifndef DLOAD_H +#define DLOAD_H + +#include "ArrayList.h" +#include "Queue.h" +#include "Stack.h" +#include "elf32.h" +#include "dload_api.h" +#include "util.h" + +/*---------------------------------------------------------------------------*/ +/* Contains strings with names of files the loader is in process of loading. */ +/* This list is used to keep track of what objects are in the process of */ +/* loading while their dependents are being loaded so that we can detect */ +/* circular dependencies. */ +/*---------------------------------------------------------------------------*/ +extern Array_List DLIMP_module_dependency_list; + +/*---------------------------------------------------------------------------*/ +/* DLIMP_Loaded_Segment */ +/* */ +/* This structure represents a segment loaded on memory. */ +/* */ +/* This data structure should be created using host memory when a module */ +/* is being loaded into target memory. The data structure should persist */ +/* as long as the module stays resident in target memory. It should be */ +/* removed when the last use of the module is unloaded from the target. */ +/*---------------------------------------------------------------------------*/ +typedef struct +{ + struct Elf32_Phdr phdr; + Elf32_Addr input_vaddr; /* original segment load addr */ + BOOL modified; + struct DLOAD_MEMORY_SEGMENT *obj_desc; + void * host_address; +} DLIMP_Loaded_Segment; + +/*---------------------------------------------------------------------------*/ +/* DLIMP_Loaded_Module */ +/* */ +/* This structure contains all the information the dynamic loader needs */ +/* to retain after loading an object file's segments into target memory. */ +/* The data structure is created while the object file is being loaded, */ +/* and should persist until the last use of the module is unloaded from */ +/* target memory. */ +/* */ +/* The information contained here is used by the dynamic loader to */ +/* perform dynamic symbol resolution, to track the use count, and to */ +/* finally deallocate the module's segments when the module is unloaded. */ +/*---------------------------------------------------------------------------*/ +typedef struct +{ + char *name; /* Local copy of so_name */ + int32_t file_handle; + int32_t use_count; + Elf32_Addr entry_point; /* Entry point address into module */ + struct Elf32_Sym *gsymtab; /* Module's global symbol table */ + Elf32_Word gsymnum; /* # global symbols */ + char *gstrtab; /* Module's global symbol names */ + Elf32_Word gstrsz; /* Size of global string table */ + Array_List loaded_segments; /* List of DLIMP_Loaded_Segment(s) */ + Array_List dependencies; /* List of dependent file handles */ + BOOL direct_dependent_only; + + Elf32_Addr fini; /* .fini function/section address */ + Elf32_Addr fini_array; /* .fini_array term fcn ary addr */ + int32_t fini_arraysz; /* sizeof .fini_array */ + uint8_t *c_args; /* address of module's .args sect */ + uint8_t *static_base; /* address of module's STATIC_BASE */ + +} DLIMP_Loaded_Module; + +/*---------------------------------------------------------------------------*/ +/* DLIMP_loaded_objects */ +/* */ +/* A list of loaded module objects (DLIMP_Loaded_Module *) that the */ +/* loader has placed into target memory. */ +/*---------------------------------------------------------------------------*/ +TYPE_QUEUE_DEFINITION(DLIMP_Loaded_Module*, loaded_module_ptr) +extern loaded_module_ptr_Queue DLIMP_loaded_objects; + +/*---------------------------------------------------------------------------*/ +/* DLIMP_Dynamic_Module */ +/* */ +/* This structure represents a dynamic module to be loaded by the dynamic */ +/* loader. It contains all the information necessary to load and relocate */ +/* the module. It actually contains most of the headers, dynamic info, */ +/* dynamic symbol table, string table etc. */ +/* */ +/* This structure is allocated in host memory while an ELF object file is */ +/* being loaded and will be destructed after the file has been */ +/* successfully loaded. To simplify loading and relocation of the object */ +/* file's segments, this data structure maintains a link to the loaded */ +/* module. This link is severed when the load is successfully completed. */ +/* The loaded module data structure will persist until the module is */ +/* actually unloaded from target memory, but this data structure will be */ +/* freed. */ +/* */ +/* If the load of the object file is not successful for any reason, then */ +/* the loaded module will not be detached from the dynamic module. In */ +/* such case, the destructor for the dynamic module will assume */ +/* responsibility for freeing any host memory associated with the loaded */ +/* module and its segments. */ +/*---------------------------------------------------------------------------*/ +typedef struct +{ + char *name; /* Local copy of so_name */ + LOADER_FILE_DESC *fd; /* Access to ELF object file */ + struct Elf32_Ehdr fhdr; /* ELF Object File Header */ + struct Elf32_Phdr *phdr; /* ELF Program Header Table */ + Elf32_Word phnum; /* # entries in program header table */ + char* strtab; /* String Table */ + Elf32_Word strsz; /* String Table size in bytes */ + struct Elf32_Dyn *dyntab; /* Elf Dynamic Table (.dynamic scn) */ + /* This contains a list of dynamic */ + /* tags which is terminated by a NULL */ + /* record. */ + struct Elf32_Sym *symtab; /* Elf Dynamic Symbol Table */ + Elf32_Word symnum; /* # symbols in dynamic symbol table */ + Elf32_Word gsymtab_offset;/* Offset into symbol table where */ + /* global symbols start. */ + Elf32_Word gstrtab_offset;/* Offset into string table where */ + /* global symbol names start. */ + + uint8_t *c_args; + uint8_t *static_base; /* address of module's STATIC_BASE */ + int32_t argc; + char **argv; + DLIMP_Loaded_Module *loaded_module; + int32_t wrong_endian; + BOOL direct_dependent_only; + BOOL relocatable; /* TRUE if module can be relocated */ + /* at load-time. FALSE if module is */ + /* a static executable. */ + BOOL relocate_entry_point; /* TRUE if the entry point has */ + /* not been relocated */ + + int32_t dsbt_index; /* DSBT index requested/assigned */ + uint32_t dsbt_size; /* DSBT size for this module */ + int32_t dsbt_base_tagidx;/* Location of DSBT base dyn tag */ + + int32_t preinit_array_idx; /* DT_PREINIT_ARRAY dyn tag loc */ + int32_t preinit_arraysz; /* sizeof pre-init array */ + int32_t init_idx; /* DT_INIT dynamic tag location */ + int32_t init_array_idx; /* DT_INIT_ARRAY dyn tag location */ + int32_t init_arraysz; /* sizeof init array */ + +} DLIMP_Dynamic_Module; + +/*---------------------------------------------------------------------------*/ +/* DLIMP_dependency_stack */ +/* */ +/* A LIFO stack of dynamic module objects (DLIMP_Dynamic_Module *) that */ +/* is retained while dependent files are being loaded and allocated. It */ +/* is used to guide which dynamic modules need to be relocated after all */ +/* items in the dependency graph have been allocated. The stack is only */ +/* used when the client asks the core loader to load a dynamic executable */ +/* or library. When relocation is completed, this stack should be empty. */ +/*---------------------------------------------------------------------------*/ +TYPE_STACK_DEFINITION(DLIMP_Dynamic_Module*, dynamic_module_ptr) +extern dynamic_module_ptr_Stack DLIMP_dependency_stack; + +/*---------------------------------------------------------------------------*/ +/* Private Loader Object instance. */ +/*---------------------------------------------------------------------------*/ +typedef struct +{ + /*-----------------------------------------------------------------------*/ + /* Contains filenames (type const char*) the system is in the process of */ + /* loading. Used to detect cycles in incorrectly compiled ELF binaries. */ + /*-----------------------------------------------------------------------*/ + Array_List DLIMP_module_dependency_list; + + /*-----------------------------------------------------------------------*/ + /* Contains objects (type DLIMP_Loaded_Module) that the system has loaded*/ + /* into target memory. */ + /*-----------------------------------------------------------------------*/ + loaded_module_ptr_Queue DLIMP_loaded_objects; + + /*-----------------------------------------------------------------------*/ + /* Dependency Graph Queue - FIFO queue of dynamic modules that are loaded*/ + /* when client asks to load a dynamic executable or library. Note that */ + /* dependents that have already been loaded with another module will not */ + /* appear on this queue. */ + /*-----------------------------------------------------------------------*/ + dynamic_module_ptr_Stack DLIMP_dependency_stack; + + /*-----------------------------------------------------------------------*/ + /* Counter for generating unique IDs for file handles. */ + /* NOTE: File handle is assigned sequencially but is never reclaimed */ + /* when the modules are unloaded. It is conceivable that a loader*/ + /* running for a long time and loading and unloading modules */ + /* could wrap-around. The loader generates error in this case. */ + /* Presumably each loader instance has a list of file handles, one for */ + /* each file that it loads, and the file handle serves as an index into */ + /* the list. Therefore even if the same file is loaded by two loader */ + /* instances, both loader instances have a different file handle for the */ + /* file - the file is mapped uniquely to it's appopriate file handle per */ + /* loader instance. */ + /*-----------------------------------------------------------------------*/ + int32_t file_handle; + + /*-----------------------------------------------------------------------*/ + /* Client token, passed in via DLOAD_create() */ + /*-----------------------------------------------------------------------*/ + void * client_handle; +} LOADER_OBJECT; + + +/*****************************************************************************/ +/* IF data : Below are the data structures used to store init-fini data. */ +/*****************************************************************************/ +typedef struct +{ + TARGET_ADDRESS sect_addr; + int32_t size; +} +IF_single_record; + +TYPE_QUEUE_DEFINITION(IF_single_record*, IF_table) +extern IF_table_Queue TI_init_table; + + +/*****************************************************************************/ +/* Container used to read in argc, argv from the .srgs section. */ +/*****************************************************************************/ +typedef struct { int argc; char *argv[1]; } ARGS_CONTAINER; + + +/*****************************************************************************/ +/* is_DSBT_module() */ +/* */ +/* return true if the module uses DSBT model */ +/*****************************************************************************/ +static inline BOOL is_dsbt_module(DLIMP_Dynamic_Module *dyn_module) +{ + return (dyn_module->dsbt_size != 0); +} + +/*****************************************************************************/ +/* is_arm_module() */ +/* */ +/* return true if the module being processed is for ARM */ +/*****************************************************************************/ +static inline BOOL is_arm_module(struct Elf32_Ehdr* fhdr) +{ + return fhdr->e_machine == EM_ARM; +} + +/*****************************************************************************/ +/* is_c60_module() */ +/* */ +/* return true if the module being processed is for C60 */ +/*****************************************************************************/ +static inline BOOL is_c60_module(struct Elf32_Ehdr* fhdr) +{ + return fhdr->e_machine == EM_TI_C6000; +} + +/*---------------------------------------------------------------------------*/ +/* DLIMP_update_dyntag_section_address() */ +/* */ +/* Given the index of a dynamic tag which we happen to know points to a */ +/* section address, find the program header table entry associated with */ +/* the specified address and update the tag value with the real address */ +/* of the section. */ +/* */ +/*---------------------------------------------------------------------------*/ +extern BOOL DLIMP_update_dyntag_section_address(DLIMP_Dynamic_Module *dyn_module, + int32_t i); + +extern uint32_t DLIMP_get_first_dyntag(int tag, struct Elf32_Dyn* dyn_table); + +/*---------------------------------------------------------------------------*/ +/* Global flags to help manage internal debug and profiling efforts. */ +/*---------------------------------------------------------------------------*/ +#ifndef __TI_COMPILER_VERSION__ +#define LOADER_DEBUG 1 +#else +#define LOADER_DEBUG 0 +#endif + +#undef LOADER_DEBUG + +#define LOADER_DEBUG 1 +#define LOADER_PROFILE 1 + +#if LOADER_DEBUG +extern BOOL debugging_on; +#endif + +#if LOADER_DEBUG || LOADER_PROFILE +extern BOOL profiling_on; +#endif + +#endif diff --git a/src/core/dsp/ocl_load/DLOAD/dload_endian.c b/src/core/dsp/ocl_load/DLOAD/dload_endian.c new file mode 100644 index 0000000..ac6413b --- /dev/null +++ b/src/core/dsp/ocl_load/DLOAD/dload_endian.c @@ -0,0 +1,151 @@ +/* +* dload_endian.c +* +* Simple helper functions to assist core loader with endian-ness issues +* when the host endian-ness may be opposite the endian-ness of the target. +* +* Copyright (C) 2009-2014 Texas Instruments Incorporated - http://www.ti.com/ +* +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +*/ + +#include "dload_endian.h" + +/*****************************************************************************/ +/* DLIMP_GET_ENDIAN() - Determine endianness of the host. Uses ELF */ +/* endianness constants. */ +/*****************************************************************************/ +int DLIMP_get_endian() +{ + int32_t x = 0x1; + + if (*((int16_t*)(&x))) return ELFDATA2LSB; + + return ELFDATA2MSB; +} + +/*****************************************************************************/ +/* DLIMP_CHANGE_ENDIAN32() - Swap endianness of a 32-bit integer. */ +/*****************************************************************************/ +void DLIMP_change_endian32(int32_t* to_change) +{ + int32_t temp = 0; + temp += (*to_change & 0x000000FF) << 24; + temp += (*to_change & 0x0000FF00) << 8; + temp += (*to_change & 0x00FF0000) >> 8; + temp += (*to_change & 0xFF000000) >> 24; + *to_change = temp; +} + +/*****************************************************************************/ +/* DLIMP_CHANGE_ENDIAN16() - Swap endianness of a 16-bit integer. */ +/*****************************************************************************/ +void DLIMP_change_endian16(int16_t* to_change) +{ + int16_t temp = 0; + temp += (*to_change & 0x00FF) << 8; + temp += (*to_change & 0xFF00) >> 8; + *to_change = temp; +} + +/*****************************************************************************/ +/* DLIMP_CHANGE_EHDR_ENDIAN() - Swap endianness of an ELF file header. */ +/*****************************************************************************/ +void DLIMP_change_ehdr_endian(struct Elf32_Ehdr* ehdr) +{ + DLIMP_change_endian16((int16_t*)(&ehdr->e_type)); + DLIMP_change_endian16((int16_t*)(&ehdr->e_machine)); + DLIMP_change_endian32((int32_t*)(&ehdr->e_version)); + DLIMP_change_endian32((int32_t*)(&ehdr->e_entry)); + DLIMP_change_endian32((int32_t*)(&ehdr->e_phoff)); + DLIMP_change_endian32((int32_t*)(&ehdr->e_shoff)); + DLIMP_change_endian32((int32_t*)(&ehdr->e_flags)); + DLIMP_change_endian16((int16_t*)(&ehdr->e_ehsize)); + DLIMP_change_endian16((int16_t*)(&ehdr->e_phentsize)); + DLIMP_change_endian16((int16_t*)(&ehdr->e_phnum)); + DLIMP_change_endian16((int16_t*)(&ehdr->e_shentsize)); + DLIMP_change_endian16((int16_t*)(&ehdr->e_shnum)); + DLIMP_change_endian16((int16_t*)(&ehdr->e_shstrndx)); +} + +/*****************************************************************************/ +/* DLIMP_CHANGE_PHDR_ENDIAN() - Swap endianness of an ELF program header. */ +/*****************************************************************************/ +void DLIMP_change_phdr_endian(struct Elf32_Phdr* phdr) +{ + DLIMP_change_endian32((int32_t*)(&phdr->p_type)); + DLIMP_change_endian32((int32_t*)(&phdr->p_offset)); + DLIMP_change_endian32((int32_t*)(&phdr->p_vaddr)); + DLIMP_change_endian32((int32_t*)(&phdr->p_paddr)); + DLIMP_change_endian32((int32_t*)(&phdr->p_filesz)); + DLIMP_change_endian32((int32_t*)(&phdr->p_memsz)); + DLIMP_change_endian32((int32_t*)(&phdr->p_flags)); + DLIMP_change_endian32((int32_t*)(&phdr->p_align)); +} + +/*****************************************************************************/ +/* DLIMP_CHANGE_DYNENT_ENDIAN() - Swap endianness of a dynamic table entry. */ +/*****************************************************************************/ +void DLIMP_change_dynent_endian(struct Elf32_Dyn* dyn) +{ + DLIMP_change_endian32((int32_t*)(&dyn->d_tag)); + DLIMP_change_endian32((int32_t*)(&dyn->d_un.d_val)); +} + +/*****************************************************************************/ +/* DLIMP_CHANGE_SYM_ENDIAN() - Swap endianness of an ELF symbol table entry. */ +/*****************************************************************************/ +void DLIMP_change_sym_endian(struct Elf32_Sym* sym) +{ + DLIMP_change_endian32((int32_t*)(&sym->st_name)); + DLIMP_change_endian32((int32_t*)(&sym->st_value)); + DLIMP_change_endian32((int32_t*)(&sym->st_size)); + DLIMP_change_endian16((int16_t*)(&sym->st_shndx)); +} + +/*****************************************************************************/ +/* DLIMP_CHANGE_RELA_ENDIAN() - Swap endianness of a RELA-type relocation. */ +/*****************************************************************************/ +void DLIMP_change_rela_endian(struct Elf32_Rela* ra) +{ + DLIMP_change_endian32((int32_t*)(&ra->r_offset)); + DLIMP_change_endian32((int32_t*)(&ra->r_info)); + DLIMP_change_endian32((int32_t*)(&ra->r_addend)); +} + +/*****************************************************************************/ +/* DLIMP_CHANGE_REL_ENDIAN() - Swap endianness of a REL-type relocation. */ +/*****************************************************************************/ +void DLIMP_change_rel_endian(struct Elf32_Rel* r) +{ + DLIMP_change_endian32((int32_t*)(&r->r_offset)); + DLIMP_change_endian32((int32_t*)(&r->r_info)); +} diff --git a/src/core/dsp/ocl_load/DLOAD/dload_endian.h b/src/core/dsp/ocl_load/DLOAD/dload_endian.h new file mode 100644 index 0000000..ee74e11 --- /dev/null +++ b/src/core/dsp/ocl_load/DLOAD/dload_endian.h @@ -0,0 +1,58 @@ +/* +* dload_endian.h +* +* Specification of functions used to assist loader with endian-ness issues. +* +* Copyright (C) 2009-2014 Texas Instruments Incorporated - http://www.ti.com/ +* +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +*/ + +#ifndef DLOAD_ENDIAN_H +#define DLOAD_ENDIAN_H + +#include "elf32.h" + +/*---------------------------------------------------------------------------*/ +/* Prototypes for ELF file object reader endianness swap routines. */ +/*---------------------------------------------------------------------------*/ + +int DLIMP_get_endian(void); +void DLIMP_change_endian32(int32_t* to_change); +void DLIMP_change_endian16(int16_t* to_change); +void DLIMP_change_ehdr_endian(struct Elf32_Ehdr* to_change); +void DLIMP_change_phdr_endian(struct Elf32_Phdr* to_change); +void DLIMP_change_dynent_endian(struct Elf32_Dyn* to_change); +void DLIMP_change_sym_endian(struct Elf32_Sym* to_change); +void DLIMP_change_rela_endian(struct Elf32_Rela* to_change); +void DLIMP_change_rel_endian(struct Elf32_Rel* to_change); + +#endif diff --git a/src/core/dsp/ocl_load/DLOAD/elf32.c b/src/core/dsp/ocl_load/DLOAD/elf32.c new file mode 100644 index 0000000..082ba01 --- /dev/null +++ b/src/core/dsp/ocl_load/DLOAD/elf32.c @@ -0,0 +1,652 @@ +/* +* elf32.c +* +* Basic Data Structures for 32-Bit ELF Object Format Files +* +* The data structures in this file come primarily from this specification: +* +* Tool Interface Standard (TIS) +* Executable and Linking Format (ELF) Specification +* Version 1.2 +* +* TIS Committee +* May 1995 +* +* Additions and enhancements from this specification are also included: +* +* System V Application Binary Interface +* DRAFT 17 +* December 2003 +* +* http://sco.com/developers/gabi/2003-12-17/contents.html +* +* This is a C implementation of the data base objects that are commonly +* used in the source for TI development tools that support ELF. +* +* Copyright (C) 2009-2014 Texas Instruments Incorporated - http://www.ti.com/ +* +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +*/ + +#include "elf32.h" + +/*---------------------------------------------------------------------------*/ +/* Dynamic Tag Database */ +/*---------------------------------------------------------------------------*/ + +const struct EDYN_TAG EDYN_TAG_DB[] = +{ + /* EDYN_TAG_NULL */ + { + /* d_tag_name */ "DT_NULL", + /* d_tag_value */ DT_NULL, + /* d_untype */ EDYN_UNTYPE_IGNORED, + /* d_exec_req */ EDYN_TAGREQ_MANDATORY, + /* d_shared_req */ EDYN_TAGREQ_MANDATORY + }, + + /* EDYN_TAG_NEEDED */ + { + /* d_tag_name */ "DT_NEEDED", + /* d_tag_value */ DT_NEEDED, + /* d_untype */ EDYN_UNTYPE_VAL, + /* d_exec_req */ EDYN_TAGREQ_OPTIONAL, + /* d_shared_req */ EDYN_TAGREQ_OPTIONAL + }, + + /* EDYN_TAG_PLTRELSZ */ + { + /* d_tag_name */ "DT_PLTRELSZ", + /* d_tag_value */ DT_PLTRELSZ, + /* d_untype */ EDYN_UNTYPE_VAL, + /* d_exec_req */ EDYN_TAGREQ_OPTIONAL, + /* d_shared_req */ EDYN_TAGREQ_OPTIONAL + }, + + /* EDYN_TAG_PLTGOT */ + { + /* d_tag_name */ "DT_PLTGOT", + /* d_tag_value */ DT_PLTGOT, + /* d_untype */ EDYN_UNTYPE_PTR, + /* d_exec_req */ EDYN_TAGREQ_OPTIONAL, + /* d_shared_req */ EDYN_TAGREQ_OPTIONAL + }, + + /* EDYN_TAG_HASH */ + { + /* d_tag_name */ "DT_HASH", + /* d_tag_value */ DT_HASH, + /* d_untype */ EDYN_UNTYPE_PTR, + /* d_exec_req */ EDYN_TAGREQ_MANDATORY, + /* d_shared_req */ EDYN_TAGREQ_MANDATORY + }, + + /* EDYN_TAG_STRTAB */ + { + /* d_tag_name */ "DT_STRTAB", + /* d_tag_value */ DT_STRTAB, + /* d_untype */ EDYN_UNTYPE_PTR, + /* d_exec_req */ EDYN_TAGREQ_MANDATORY, + /* d_shared_req */ EDYN_TAGREQ_MANDATORY + }, + + /* EDYN_TAG_SYMTAB */ + { + /* d_tag_name */ "DT_SYMTAB", + /* d_tag_value */ DT_SYMTAB, + /* d_untype */ EDYN_UNTYPE_PTR, + /* d_exec_req */ EDYN_TAGREQ_MANDATORY, + /* d_shared_req */ EDYN_TAGREQ_MANDATORY + }, + + /* EDYN_TAG_RELA */ + { + /* d_tag_name */ "DT_RELA", + /* d_tag_value */ DT_RELA, + /* d_untype */ EDYN_UNTYPE_PTR, + /* d_exec_req */ EDYN_TAGREQ_MANDATORY, + /* d_shared_req */ EDYN_TAGREQ_OPTIONAL + }, + + /* EDYN_TAG_RELASZ */ + { + /* d_tag_name */ "DT_RELASZ", + /* d_tag_value */ DT_RELASZ, + /* d_untype */ EDYN_UNTYPE_VAL, + /* d_exec_req */ EDYN_TAGREQ_MANDATORY, + /* d_shared_req */ EDYN_TAGREQ_OPTIONAL + }, + + /* EDYN_TAG_RELAENT */ + { + /* d_tag_name */ "DT_RELAENT", + /* d_tag_value */ DT_RELAENT, + /* d_untype */ EDYN_UNTYPE_VAL, + /* d_exec_req */ EDYN_TAGREQ_MANDATORY, + /* d_shared_req */ EDYN_TAGREQ_OPTIONAL + }, + + /* EDYN_TAG_STRSZ */ + { + /* d_tag_name */ "DT_STRSZ", + /* d_tag_value */ DT_STRSZ, + /* d_untype */ EDYN_UNTYPE_VAL, + /* d_exec_req */ EDYN_TAGREQ_MANDATORY, + /* d_shared_req */ EDYN_TAGREQ_MANDATORY + }, + + /* EDYN_TAG_SYMENT */ + { + /* d_tag_name */ "DT_SYMENT", + /* d_tag_value */ DT_SYMENT, + /* d_untype */ EDYN_UNTYPE_VAL, + /* d_exec_req */ EDYN_TAGREQ_MANDATORY, + /* d_shared_req */ EDYN_TAGREQ_MANDATORY + }, + + /* EDYN_TAG_INIT */ + { + /* d_tag_name */ "DT_INIT", + /* d_tag_value */ DT_INIT, + /* d_untype */ EDYN_UNTYPE_PTR, + /* d_exec_req */ EDYN_TAGREQ_OPTIONAL, + /* d_shared_req */ EDYN_TAGREQ_OPTIONAL + }, + + /* EDYN_TAG_FINI */ + { + /* d_tag_name */ "DT_FINI", + /* d_tag_value */ DT_FINI, + /* d_untype */ EDYN_UNTYPE_PTR, + /* d_exec_req */ EDYN_TAGREQ_OPTIONAL, + /* d_shared_req */ EDYN_TAGREQ_OPTIONAL + }, + + /* EDYN_TAG_SONAME */ + { + /* d_tag_name */ "DT_SONAME", + /* d_tag_value */ DT_SONAME, + /* d_untype */ EDYN_UNTYPE_VAL, + /* d_exec_req */ EDYN_TAGREQ_IGNORED, + /* d_shared_req */ EDYN_TAGREQ_OPTIONAL + }, + + /* EDYN_TAG_RPATH */ + { + /* d_tag_name */ "DT_RPATH", + /* d_tag_value */ DT_RPATH, + /* d_untype */ EDYN_UNTYPE_VAL, + /* d_exec_req */ EDYN_TAGREQ_OPTIONAL, + /* d_shared_req */ EDYN_TAGREQ_IGNORED + }, + + /* EDYN_TAG_SYMBOLIC */ + { + /* d_tag_name */ "DT_SYMBOLIC", + /* d_tag_value */ DT_SYMBOLIC, + /* d_untype */ EDYN_UNTYPE_IGNORED, + /* d_exec_req */ EDYN_TAGREQ_IGNORED, + /* d_shared_req */ EDYN_TAGREQ_OPTIONAL + }, + + /* EDYN_TAG_REL */ + { + /* d_tag_name */ "DT_REL", + /* d_tag_value */ DT_REL, + /* d_untype */ EDYN_UNTYPE_PTR, + /* d_exec_req */ EDYN_TAGREQ_MANDATORY, + /* d_shared_req */ EDYN_TAGREQ_OPTIONAL + }, + + /* EDYN_TAG_RELSZ */ + { + /* d_tag_name */ "DT_RELSZ", + /* d_tag_value */ DT_RELSZ, + /* d_untype */ EDYN_UNTYPE_VAL, + /* d_exec_req */ EDYN_TAGREQ_MANDATORY, + /* d_shared_req */ EDYN_TAGREQ_OPTIONAL + }, + + /* EDYN_TAG_RELENT */ + { + /* d_tag_name */ "DT_RELENT", + /* d_tag_value */ DT_RELENT, + /* d_untype */ EDYN_UNTYPE_VAL, + /* d_exec_req */ EDYN_TAGREQ_MANDATORY, + /* d_shared_req */ EDYN_TAGREQ_OPTIONAL + }, + + /* EDYN_TAG_PLTREL */ + { + /* d_tag_name */ "DT_PLTREL", + /* d_tag_value */ DT_PLTREL, + /* d_untype */ EDYN_UNTYPE_VAL, + /* d_exec_req */ EDYN_TAGREQ_OPTIONAL, + /* d_shared_req */ EDYN_TAGREQ_OPTIONAL + }, + + /* EDYN_TAG_DEBUG */ + { + /* d_tag_name */ "DT_DEBUG", + /* d_tag_value */ DT_DEBUG, + /* d_untype */ EDYN_UNTYPE_PTR, + /* d_exec_req */ EDYN_TAGREQ_OPTIONAL, + /* d_shared_req */ EDYN_TAGREQ_IGNORED + }, + + /* EDYN_TAG_TEXTREL */ + { + /* d_tag_name */ "DT_TEXTREL", + /* d_tag_value */ DT_TEXTREL, + /* d_untype */ EDYN_UNTYPE_IGNORED, + /* d_exec_req */ EDYN_TAGREQ_OPTIONAL, + /* d_shared_req */ EDYN_TAGREQ_OPTIONAL + }, + + /* EDYN_TAG_JMPREL */ + { + /* d_tag_name */ "DT_JMPREL", + /* d_tag_value */ DT_JMPREL, + /* d_untype */ EDYN_UNTYPE_PTR, + /* d_exec_req */ EDYN_TAGREQ_OPTIONAL, + /* d_shared_req */ EDYN_TAGREQ_OPTIONAL + }, + + /* EDYN_TAG_BIND_NOW */ + { + /* d_tag_name */ "DT_BIND_NOW", + /* d_tag_value */ DT_BIND_NOW, + /* d_untype */ EDYN_UNTYPE_IGNORED, + /* d_exec_req */ EDYN_TAGREQ_OPTIONAL, + /* d_shared_req */ EDYN_TAGREQ_OPTIONAL + }, + + /* EDYN_TAG_INIT_ARRAY */ + { + /* d_tag_name */ "DT_INIT_ARRAY", + /* d_tag_value */ DT_INIT_ARRAY, + /* d_untype */ EDYN_UNTYPE_PTR, + /* d_exec_req */ EDYN_TAGREQ_OPTIONAL, + /* d_shared_req */ EDYN_TAGREQ_OPTIONAL + }, + + /* EDYN_TAG_FINI_ARRAY */ + { + /* d_tag_name */ "DT_FINI_ARRAY", + /* d_tag_value */ DT_FINI_ARRAY, + /* d_untype */ EDYN_UNTYPE_PTR, + /* d_exec_req */ EDYN_TAGREQ_OPTIONAL, + /* d_shared_req */ EDYN_TAGREQ_OPTIONAL + }, + + /* EDYN_TAG_INIT_ARRAYSZ */ + { + /* d_tag_name */ "DT_INIT_ARRAYSZ", + /* d_tag_value */ DT_INIT_ARRAYSZ, + /* d_untype */ EDYN_UNTYPE_VAL, + /* d_exec_req */ EDYN_TAGREQ_OPTIONAL, + /* d_shared_req */ EDYN_TAGREQ_OPTIONAL + }, + + /* EDYN_TAG_FINI_ARRAYSZ */ + { + /* d_tag_name */ "DT_FINI_ARRAYSZ", + /* d_tag_value */ DT_FINI_ARRAYSZ, + /* d_untype */ EDYN_UNTYPE_VAL, + /* d_exec_req */ EDYN_TAGREQ_OPTIONAL, + /* d_shared_req */ EDYN_TAGREQ_OPTIONAL + }, + + /* EDYN_TAG_RUNPATH */ + { + /* d_tag_name */ "DT_RUNPATH", + /* d_tag_value */ DT_RUNPATH, + /* d_untype */ EDYN_UNTYPE_VAL, + /* d_exec_req */ EDYN_TAGREQ_OPTIONAL, + /* d_shared_req */ EDYN_TAGREQ_OPTIONAL + }, + + /* EDYN_TAG_FLAGS */ + { + /* d_tag_name */ "DT_FLAGS", + /* d_tag_value */ DT_FLAGS, + /* d_untype */ EDYN_UNTYPE_VAL, + /* d_exec_req */ EDYN_TAGREQ_OPTIONAL, + /* d_shared_req */ EDYN_TAGREQ_OPTIONAL + }, + + /* EDYN_TAG_ENCODING */ + { + /* d_tag_name */ "DT_ENCODING", + /* d_tag_value */ DT_ENCODING, + /* d_untype */ EDYN_UNTYPE_UNSPECIFIED, + /* d_exec_req */ EDYN_TAGREQ_UNSPECIFIED, + /* d_shared_req */ EDYN_TAGREQ_UNSPECIFIED + }, + + /* EDYN_TAG_PREINIT_ARRAY */ + { + /* d_tag_name */ "DT_PREINIT_ARRAY", + /* d_tag_value */ DT_PREINIT_ARRAY, + /* d_untype */ EDYN_UNTYPE_PTR, + /* d_exec_req */ EDYN_TAGREQ_OPTIONAL, + /* d_shared_req */ EDYN_TAGREQ_IGNORED + }, + + /* EDYN_TAG_PREINIT_ARRAYSZ */ + { + /* d_tag_name */ "DT_PREINIT_ARRAYSZ", + /* d_tag_value */ DT_PREINIT_ARRAYSZ, + /* d_untype */ EDYN_UNTYPE_VAL, + /* d_exec_req */ EDYN_TAGREQ_OPTIONAL, + /* d_shared_req */ EDYN_TAGREQ_IGNORED + }, + + /* Terminate array with an id of -1 */ + { + /* d_tag_name */ "", + /* d_tag_value */ -1, + /* d_untype */ EDYN_UNTYPE_UNSPECIFIED, + /* d_exec_req */ EDYN_TAGREQ_OPTIONAL, + /* d_shared_req */ EDYN_TAGREQ_IGNORED + } +}; + +/*---------------------------------------------------------------------------*/ +/* Special Section Database */ +/*---------------------------------------------------------------------------*/ +const struct ESCN ESCN_DB[] = +{ + /* .bss */ + { + /* name */ ESCN_BSS_name, + /* sh_type */ SHT_NOBITS, + /* sh_entsize */ 0, + /* sh_flags */ SHF_ALLOC + SHF_WRITE + }, + + /* .comment */ + { + /* name */ ESCN_COMMENT_name, + /* sh_type */ SHT_PROGBITS, + /* sh_entsize */ 0, + /* sh_flags */ 0 + }, + + /* .data */ + { + /* name */ ESCN_DATA_name, + /* sh_type */ SHT_PROGBITS, + /* sh_entsize */ 0, + /* sh_flags */ SHF_ALLOC + SHF_WRITE + }, + + /* .data1 */ + { + /* name */ ESCN_DATA1_name, + /* sh_type */ SHT_PROGBITS, + /* sh_entsize */ 0, + /* sh_flags */ SHF_ALLOC + SHF_WRITE + }, + + /* .debug */ + { + /* name */ ESCN_DEBUG_name, + /* sh_type */ SHT_PROGBITS, + /* sh_entsize */ 0, + /* sh_flags */ 0 + }, + + /* .dynamic */ + { + /* name */ ESCN_DYNAMIC_name, + /* sh_type */ SHT_DYNAMIC, + /* sh_entsize */ sizeof(struct Elf32_Dyn), + /* sh_flags */ SHF_ALLOC + }, + + /* .dynstr */ + { + /* name */ ESCN_DYNSTR_name, + /* sh_type */ SHT_STRTAB, + /* sh_entsize */ sizeof(char), + /* sh_flags */ SHF_ALLOC + SHF_STRINGS + }, + + /* .dynsym */ + { + /* name */ ESCN_DYNSYM_name, + /* sh_type */ SHT_DYNSYM, + /* sh_entsize */ sizeof(struct Elf32_Sym), + /* sh_flags */ SHF_ALLOC + }, + + /* .fini */ + { + /* name */ ESCN_FINI_name, + /* sh_type */ SHT_PROGBITS, + /* sh_entsize */ 0, + /* sh_flags */ SHF_ALLOC + SHF_EXECINSTR + }, + + /* .fini_array */ + { + /* name */ ESCN_FINI_ARRAY_name, + /* sh_type */ SHT_FINI_ARRAY, + /* sh_entsize */ 0, + /* sh_flags */ SHF_ALLOC + SHF_WRITE + }, + + /* .got */ + { + /* name */ ESCN_GOT_name, + /* sh_type */ SHT_PROGBITS, + /* sh_entsize */ 0, + /* sh_flags */ 0 + }, + + /* .hash */ + { + /* name */ ESCN_HASH_name, + /* sh_type */ SHT_HASH, + /* sh_entsize */ 0, + /* sh_flags */ SHF_ALLOC + }, + + /* .init */ + { + /* name */ ESCN_INIT_name, + /* sh_type */ SHT_PROGBITS, + /* sh_entsize */ 0, + /* sh_flags */ SHF_ALLOC + SHF_EXECINSTR + }, + + /* .init_array */ + { + /* name */ ESCN_INIT_ARRAY_name, + /* sh_type */ SHT_INIT_ARRAY, + /* sh_entsize */ 0, + /* sh_flags */ SHF_ALLOC + SHF_WRITE + }, + + /* .interp */ + { + /* name */ ESCN_INTERP_name, + /* sh_type */ SHT_PROGBITS, + /* sh_entsize */ 0, + /* sh_flags */ 0 + }, + + /* .line */ + { + /* name */ ESCN_LINE_name, + /* sh_type */ SHT_PROGBITS, + /* sh_entsize */ 0, + /* sh_flags */ 0 + }, + + /* .note */ + { + /* name */ ESCN_NOTE_name, + /* sh_type */ SHT_NOTE, + /* sh_entsize */ 0, + /* sh_flags */ 0 + }, + + /* .plt */ + { + /* name */ ESCN_PLT_name, + /* sh_type */ SHT_PROGBITS, + /* sh_entsize */ 0, + /* sh_flags */ 0 + }, + + /* .preinit_array */ + { + /* name */ ESCN_PREINIT_ARRAY_name, + /* sh_type */ SHT_PREINIT_ARRAY, + /* sh_entsize */ 0, + /* sh_flags */ SHF_ALLOC + SHF_WRITE + }, + + /* .rel */ + { + /* name */ ESCN_REL_name, + /* sh_type */ SHT_REL, + /* sh_entsize */ sizeof(struct Elf32_Rel), + /* sh_flags */ 0 + }, + + /* .rela */ + { + /* name */ ESCN_RELA_name, + /* sh_type */ SHT_RELA, + /* sh_entsize */ sizeof(struct Elf32_Rela), + /* sh_flags */ 0 + }, + + /* .rodata */ + { + /* name */ ESCN_RODATA_name, + /* sh_type */ SHT_PROGBITS, + /* sh_entsize */ 0, + /* sh_flags */ SHF_ALLOC + }, + + /* .rodata1 */ + { + /* name */ ESCN_RODATA1_name, + /* sh_type */ SHT_PROGBITS, + /* sh_entsize */ 0, + /* sh_flags */ SHF_ALLOC + }, + + /* .shstrtab */ + { + /* name */ ESCN_SHSTRTAB_name, + /* sh_type */ SHT_STRTAB, + /* sh_entsize */ sizeof(char), + /* sh_flags */ SHF_STRINGS + }, + + /* .strtab */ + { + /* name */ ESCN_STRTAB_name, + /* sh_type */ SHT_STRTAB, + /* sh_entsize */ sizeof(char), + /* sh_flags */ SHF_STRINGS + }, + + /* .symtab */ + { + /* name */ ESCN_SYMTAB_name, + /* sh_type */ SHT_SYMTAB, + /* sh_entsize */ sizeof(struct Elf32_Sym), + /* sh_flags */ 0 + }, + + /* .symtab_shndx */ + { + /* name */ ESCN_SYMTAB_SHNDX_name, + /* sh_type */ SHT_SYMTAB_SHNDX, + /* sh_entsize */ sizeof(Elf32_Word), + /* sh_flags */ 0 + }, + + /* .tbss */ + { + /* name */ ESCN_TBSS_name, + /* sh_type */ SHT_NOBITS, + /* sh_entsize */ 0, + /* sh_flags */ SHF_ALLOC + SHF_WRITE + SHF_TLS + }, + + /* .tdata */ + { + /* name */ ESCN_TDATA_name, + /* sh_type */ SHT_PROGBITS, + /* sh_entsize */ 0, + /* sh_flags */ SHF_ALLOC + SHF_WRITE + SHF_TLS + }, + + /* .tdata1 */ + { + /* name */ ESCN_TDATA1_name, + /* sh_type */ SHT_PROGBITS, + /* sh_entsize */ 0, + /* sh_flags */ SHF_ALLOC + SHF_WRITE + SHF_TLS + }, + + /* .text */ + { + /* name */ ESCN_TEXT_name, + /* sh_type */ SHT_PROGBITS, + /* sh_entsize */ 0, + /* sh_flags */ SHF_ALLOC + SHF_EXECINSTR + }, +#if 0 + /* .build.attributes */ + { + /* name */ ESCN_ATTRIBUTES_name, + /* sh_type */ SHT_ATTRIBUTES, + /* sh_entsize */ 0, + /* sh_flags */ 0 + }, +#endif + /* Terminate array with a NULL name field */ + { + /* name */ (const char*)0, + /* sh_type */ 0, + /* sh_entsize */ 0, + /* sh_flags */ 0 + } +}; + diff --git a/src/core/dsp/ocl_load/DLOAD/elf32.h b/src/core/dsp/ocl_load/DLOAD/elf32.h new file mode 100644 index 0000000..67358d6 --- /dev/null +++ b/src/core/dsp/ocl_load/DLOAD/elf32.h @@ -0,0 +1,756 @@ +/* +* elf32.h +* +* Basic Data Structures for 32-bit ELF Object Format Files +* +* The data structures in this file come primarily from this specification: +* +* Tool Interface Standard (TIS) +* Executable and Linking Format (ELF) Specification +* Version 1.2 +* +* TIS Committee +* May 1995 +* +* Additions and enhancements from this specification are also included: +* +* System V Application Binary Interface +* DRAFT 17 +* December 2003 +* +* http://sco.com/developers/gabi/2003-12-17/contents.html +* +* +* Copyright (C) 2009-2014 Texas Instruments Incorporated - http://www.ti.com/ +* +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +*/ + +#ifndef ELF32_H +#define ELF32_H + +#include <inttypes.h> + +/*---------------------------------------------------------------------------*/ +/* 32-Bit Data Types (Figure 1-2, page 1-2) */ +/*---------------------------------------------------------------------------*/ +typedef uint32_t Elf32_Addr; +typedef uint16_t Elf32_Half; +typedef uint32_t Elf32_Off; +typedef int32_t Elf32_Sword; +typedef uint32_t Elf32_Word; + + +/*****************************************************************************/ +/* ELF Header */ +/* PP. 1-4 */ +/*****************************************************************************/ + +/*---------------------------------------------------------------------------*/ +/* ELF Identification Indexes (indexes into Elf32_Ehdr.e_ident[] below) */ +/*---------------------------------------------------------------------------*/ +enum +{ + EI_MAG0 = 0, /* File identification */ + EI_MAG1 = 1, /* File identification */ + EI_MAG2 = 2, /* File identification */ + EI_MAG3 = 3, /* File identification */ + EI_CLASS = 4, /* File class */ + EI_DATA = 5, /* Data encoding */ + EI_VERSION = 6, /* File version */ + EI_OSABI = 7, /* Operating system / ABI */ + EI_ABIVERSION = 8, /* ABI version */ + EI_PAD = 9, /* Start of padding bytes */ + EI_NIDENT = 16 /* Size of Elf32_Ehdr.e_ident[] */ +}; + + +/*---------------------------------------------------------------------------*/ +/* ELF Header Data Structure */ +/*---------------------------------------------------------------------------*/ +struct Elf32_Ehdr +{ + uint8_t e_ident[EI_NIDENT]; /* ELF Magic Number */ + Elf32_Half e_type; /* Object File Type */ + Elf32_Half e_machine; /* Target Processor */ + Elf32_Word e_version; /* Object File Version */ + Elf32_Addr e_entry; /* Entry Point */ + Elf32_Off e_phoff; /* Program Header Table Offset */ + Elf32_Off e_shoff; /* Section Header Table Offset */ + Elf32_Word e_flags; /* Processor-Specific Flags */ + Elf32_Half e_ehsize; /* Size of ELF header */ + Elf32_Half e_phentsize; /* Size of a Program Header */ + Elf32_Half e_phnum; /* # Entries in Program Header Table */ + Elf32_Half e_shentsize; /* Size of a Section Header */ + Elf32_Half e_shnum; /* # Entries in Section Header Table */ + Elf32_Half e_shstrndx; /* Section Name String Table Section */ +}; + + +/*---------------------------------------------------------------------------*/ +/* Object File Types (value of "e_type") */ +/*---------------------------------------------------------------------------*/ +enum +{ + ET_NONE = 0, /* No file type */ + ET_REL = 1, /* Relocatable file */ + ET_EXEC = 2, /* Executable file */ + ET_DYN = 3, /* Shared object file */ + ET_CORE = 4, /* Core file */ + ET_LOOS = 0xfe00, /* First OS-specific value */ + ET_HIPS = 0xfeff, /* Last OS-specific value */ + ET_LOPROC = 0xff00, /* First processor-specific value */ + ET_HIPROC = 0xffff /* Last processor-specific value */ +}; + + +/*---------------------------------------------------------------------------*/ +/* Target Processors (value of "e_machine") */ +/*---------------------------------------------------------------------------*/ +enum +{ + EM_NONE = 0, /* No machine */ + EM_M32 = 1, /* AT&T WE 32100 */ + EM_SPARC = 2, /* SPARC */ + EM_386 = 3, /* Intel 80386 */ + EM_68K = 4, /* Motorola 68000 */ + EM_88K = 5, /* Motorola 88000 */ + EM_860 = 7, /* Intel 80860 */ + EM_MIPS = 8, /* MIPS I Architecture */ + EM_S370 = 9, /* IBM System/370 Processor */ + EM_MIPS_RS3_LE = 10, /* MIPS RS3000 Little-endian */ + EM_PARISC = 15, /* Hewlett-Packard PA-RISC */ + EM_VPP500 = 17, /* Fujitsu VPP500 */ + EM_SPARC32PLUS = 18, /* Enhanced instruction set SPARC */ + EM_960 = 19, /* Intel 80960 */ + EM_PPC = 20, /* PowerPC */ + EM_PPC64 = 21, /* 64-bit PowerPC */ + EM_S390 = 22, /* IBM System/390 Processor */ + EM_V800 = 36, /* NEC V800 */ + EM_FR20 = 37, /* Fujitsu FR20 */ + EM_RH32 = 38, /* TRW RH-32 */ + EM_RCE = 39, /* Motorola RCE */ + EM_ARM = 40, /* Advanced RISC Machines ARM */ + EM_ALPHA = 41, /* Digital Alpha */ + EM_SH = 42, /* Hitachi SH */ + EM_SPARCV9 = 43, /* SPARC Version 9 */ + EM_TRICORE = 44, /* Siemens TriCore embedded processor */ + EM_ARC = 45, /* "Argonaut RISC Core, Argonaut Technologies Inc. */ + EM_H8_300 = 46, /* Hitachi H8/300 */ + EM_H8_300H = 47, /* Hitachi H8/300H */ + EM_H8S = 48, /* Hitachi H8S */ + EM_H8_500 = 49, /* Hitachi H8/500 */ + EM_IA_64 = 50, /* Intel IA-64 processor architecture */ + EM_MIPS_X = 51, /* Stanford MIPS-X */ + EM_COLDFIRE = 52, /* Motorola ColdFire */ + EM_68HC12 = 53, /* Motorola M68HC12 */ + EM_MMA = 54, /* Fujitsu MMA Multimedia Accelerator */ + EM_PCP = 55, /* Siemens PCP */ + EM_NCPU = 56, /* Sony nCPU embedded RISC processor */ + EM_NDR1 = 57, /* Denso NDR1 microprocessor */ + EM_STARCORE = 58, /* Motorola Star*Core processor */ + EM_ME16 = 59, /* Toyota ME16 processor */ + EM_ST100 = 60, /* STMicroelectronics ST100 processor */ + EM_TINYJ = 61, /* Advanced Logic Corp. TinyJ embedded processor f */ + EM_X86_64 = 62, /* AMD x86-64 architecture */ + EM_PDSP = 63, /* Sony DSP Processor */ + EM_PDP10 = 64, /* Digital Equipment Corp. PDP-10 */ + EM_PDP11 = 65, /* Digital Equipment Corp. PDP-11 */ + EM_FX66 = 66, /* Siemens FX66 microcontroller */ + EM_ST9PLUS = 67, /* STMicroelectronics ST9+ 8/16 bit microcontrolle */ + EM_ST7 = 68, /* STMicroelectronics ST7 8-bit microcontroller */ + EM_68HC16 = 69, /* Motorola MC68HC16 Microcontroller */ + EM_68HC11 = 70, /* Motorola MC68HC11 Microcontroller */ + EM_68HC08 = 71, /* Motorola MC68HC08 Microcontroller */ + EM_68HC05 = 72, /* Motorola MC68HC05 Microcontroller */ + EM_SVX = 73, /* Silicon Graphics SVx */ + EM_ST19 = 74, /* STMicroelectronics ST19 8-bit microcontroller */ + EM_VAX = 75, /* Digital VAX */ + EM_CRIS = 76, /* Axis Communications 32-bit embedded processor */ + EM_JAVELIN = 77, /* Infineon Technologies 32-bit embedded processor */ + EM_FIREPATH = 78, /* Element 14 64-bit DSP Processor */ + EM_ZSP = 79, /* LSI Logic 16-bit DSP Processor */ + EM_MMIX = 80, /* Donald Knuth's educational 64-bit processor */ + EM_HUANY = 81, /* Harvard University machine-independent object f */ + EM_PRISM = 82, /* SiTera Prism */ + EM_AVR = 83, /* Atmel AVR 8-bit microcontroller */ + EM_FR30 = 84, /* Fujitsu FR30 */ + EM_D10V = 85, /* Mitsubishi D10V */ + EM_D30V = 86, /* Mitsubishi D30V */ + EM_V850 = 87, /* NEC v850 */ + EM_M32R = 88, /* Mitsubishi M32R */ + EM_MN10300 = 89, /* Matsushita MN10300 */ + EM_MN10200 = 90, /* Matsushita MN10200 */ + EM_PJ = 91, /* picoJava */ + EM_OPENRISC = 92, /* OpenRISC 32-bit embedded processor */ + EM_ARC_A5 = 93, /* ARC Cores Tangent-A5 */ + EM_XTENSA = 94, /* Tensilica Xtensa Architecture */ + EM_VIDEOCORE = 95, /* Alphamosaic VideoCore processor */ + EM_TMM_GPP = 96, /* Thompson Multimedia General Purpose Processor */ + EM_NS32K = 97, /* National Semiconductor 32000 series */ + EM_TPC = 98, /* Tenor Network TPC processor */ + EM_SNP1K = 99, /* Trebia SNP 1000 processor */ + EM_ST200 = 100, /* STMicroelectronics (www.st.com) ST200 microcont */ + EM_IP2K = 101, /* Ubicom IP2xxx microcontroller family */ + EM_MAX = 102, /* MAX Processor */ + EM_CR = 103, /* National Semiconductor CompactRISC microprocess */ + EM_F2MC16 = 104, /* Fujitsu F2MC16 */ + EM_MSP430 = 105, /* Texas Instruments embedded microcontroller msp4 */ + EM_BLACKFIN = 106, /* Analog Devices Blackfin (DSP) processor */ + EM_SE_C33 = 107, /* S1C33 Family of Seiko Epson processors */ + EM_SEP = 108, /* Sharp embedded microprocessor */ + EM_ARCA = 109, /* Arca RISC Microprocessor */ + EM_UNICORE = 110, /* Microprocessor series from PKU-Unity Ltd. and M */ + + /*------------------------------------------------------------------------*/ + /* ELF Magic Numbers Reserved For Texas Instruments */ + /* */ + /* The magic numbers 140-159 were reserved through SCO to be included */ + /* in the official ELF specification. Please see Don Darling */ + /* regarding any changes or allocation of the numbers below. */ + /* */ + /* When we allocate a number for use, SCO needs to be notified so they */ + /* can update the ELF specification accordingly. */ + /*------------------------------------------------------------------------*/ + EM_TI_C6000 = 140, /* Reserved for Texas Instruments; unused */ + EM_TI_UNUSED02 = 141, /* Reserved for Texas Instruments; unused */ + EM_TI_UNUSED03 = 142, /* Reserved for Texas Instruments; unused */ + EM_TI_UNUSED04 = 143, /* Reserved for Texas Instruments; unused */ + EM_TI_UNUSED05 = 144, /* Reserved for Texas Instruments; unused */ + EM_TI_UNUSED06 = 145, /* Reserved for Texas Instruments; unused */ + EM_TI_UNUSED07 = 146, /* Reserved for Texas Instruments; unused */ + EM_TI_UNUSED08 = 147, /* Reserved for Texas Instruments; unused */ + EM_TI_UNUSED09 = 148, /* Reserved for Texas Instruments; unused */ + EM_TI_UNUSED10 = 149, /* Reserved for Texas Instruments; unused */ + EM_TI_UNUSED11 = 150, /* Reserved for Texas Instruments; unused */ + EM_TI_UNUSED12 = 151, /* Reserved for Texas Instruments; unused */ + EM_TI_UNUSED13 = 152, /* Reserved for Texas Instruments; unused */ + EM_TI_UNUSED14 = 153, /* Reserved for Texas Instruments; unused */ + EM_TI_UNUSED15 = 154, /* Reserved for Texas Instruments; unused */ + EM_TI_UNUSED16 = 155, /* Reserved for Texas Instruments; unused */ + EM_TI_UNUSED17 = 156, /* Reserved for Texas Instruments; unused */ + EM_TI_UNUSED18 = 157, /* Reserved for Texas Instruments; unused */ + EM_TI_UNUSED19 = 158, /* Reserved for Texas Instruments; unused */ + EM_TI_UNUSED20 = 159 /* Reserved for Texas Instruments; unused */ +}; + + +/*---------------------------------------------------------------------------*/ +/* Object File Version (value of "e_version") */ +/*---------------------------------------------------------------------------*/ +enum +{ + EV_NONE = 0, /* Invalid version */ + EV_CURRENT = 1 /* Current version */ +}; + + +/*****************************************************************************/ +/* ELF Identification */ +/* PP. 1-6 */ +/*****************************************************************************/ + +/*---------------------------------------------------------------------------*/ +/* Identification Values for ELF Files */ +/*---------------------------------------------------------------------------*/ + +/* EI_MAG0 to EI_MAG3 */ +enum +{ + ELFMAG0 = 0x7f, /* e_ident[EI_MAG0] */ + ELFMAG1 = 'E', /* e_ident[EI_MAG1] */ + ELFMAG2 = 'L', /* e_ident[EI_MAG2] */ + ELFMAG3 = 'F' /* e_ident[EI_MAG3] */ +}; + +/* EI_CLASS */ +enum +{ + ELFCLASSNONE = 0, /* Invalid class */ + ELFCLASS32 = 1, /* 32-bit objects */ + ELFCLASS64 = 2 /* 64-bit objects */ +}; + +/* EI_DATA */ +enum +{ + ELFDATANONE = 0, /* Invalid data encoding */ + ELFDATA2LSB = 1, /* Little-endian data */ + ELFDATA2MSB = 2 /* Big-endian data */ +}; + +/* EI_OSABI */ +enum +{ + ELFOSABI_NONE = 0, /* No extensions or unspecified */ + ELFOSABI_HPUX = 1, /* Hewlett-Packard HP-UX */ + ELFOSABI_NETBSD = 2, /* NetBSD */ + ELFOSABI_LINUX = 3, /* Linux */ + ELFOSABI_SOLARIS = 6, /* Sun Solaris */ + ELFOSABI_AIX = 7, /* AIX */ + ELFOSABI_IRIX = 8, /* IRIX */ + ELFOSABI_FREEBSD = 9, /* FreeBSD */ + ELFOSABI_TRU64 = 10, /* Compaq TRU64 UNIX */ + ELFOSABI_MODESTO = 11, /* Novell Modesto */ + ELFOSABI_OPENBSD = 12, /* Open BSD */ + ELFOSABI_OPENVMS = 13, /* Open VMS */ + ELFOSABI_NSK = 14, /* Hewlett-Packard Non-Stop Kernel */ + ELFOSABI_AROS = 15 /* Amiga Research OS */ +}; + +/*****************************************************************************/ +/* Program Header */ +/* PP. 2-2 */ +/*****************************************************************************/ + +/*---------------------------------------------------------------------------*/ +/* Program Header Data Structure */ +/*---------------------------------------------------------------------------*/ +struct Elf32_Phdr +{ + Elf32_Word p_type; /* Segment type */ + Elf32_Off p_offset; /* Segment file offset */ + Elf32_Addr p_vaddr; /* Segment virtual address */ + Elf32_Addr p_paddr; /* Segment physical address */ + Elf32_Word p_filesz; /* Segment file image size */ + Elf32_Word p_memsz; /* Segment memory image size */ + Elf32_Word p_flags; /* Segment flags */ + Elf32_Word p_align; /* Segment alignment */ +}; + +/*---------------------------------------------------------------------------*/ +/* Segment Types (value of "p_type") */ +/*---------------------------------------------------------------------------*/ +enum +{ + PT_NULL = 0, /* Unused table entry */ + PT_LOAD = 1, /* Loadable segment */ + PT_DYNAMIC = 2, /* Dynamic linking information */ + PT_INTERP = 3, /* Interpreter path string location */ + PT_NOTE = 4, /* Location and size of auxiliary information */ + PT_SHLIB = 5, /* Shared library information */ + PT_PHDR = 6, /* Location and size of program header table */ + PT_TLS = 7, /* Specifies the Thread-Local Storage template */ + PT_LOOS = 0x60000000, /* First OS-specific value */ + PT_HIOS = 0x6fffffff, /* Last OS-specific value */ + PT_LOPROC = 0x70000000, /* First processor-specific value */ + PT_HIPROC = 0x7fffffff /* Last processor-specific value */ +}; + +/*---------------------------------------------------------------------------*/ +/* Segment Permissions (value of "p_flags") */ +/*---------------------------------------------------------------------------*/ +enum +{ + PF_X = 0x1, /* Execute */ + PF_W = 0x2, /* Write */ + PF_R = 0x4, /* Read */ + PF_MASKOS = 0x0ff00000, /* OS-specific mask */ + PF_MASKPROC = 0xf0000000 /* Processor-specific mask */ +}; + +/*****************************************************************************/ +/* Sections */ +/* PP. 1-9 */ +/*****************************************************************************/ + +/*---------------------------------------------------------------------------*/ +/* Section Header Data Structure */ +/*---------------------------------------------------------------------------*/ +struct Elf32_Shdr +{ + Elf32_Word sh_name; /* Section name (offset into string section) */ + Elf32_Word sh_type; /* Section type */ + Elf32_Word sh_flags; /* Section flags */ + Elf32_Addr sh_addr; /* Address in memory image */ + Elf32_Off sh_offset; /* File offset of section data */ + Elf32_Word sh_size; /* Size of the section in bytes */ + Elf32_Word sh_link; /* Link to the section header table */ + Elf32_Word sh_info; /* Extra information depending on section type */ + Elf32_Word sh_addralign; /* Address alignment constraints */ + Elf32_Word sh_entsize; /* Size of fixed-size entries in section */ +}; + +/*---------------------------------------------------------------------------*/ +/* Special Section Indexes */ +/*---------------------------------------------------------------------------*/ +enum +{ + SHN_UNDEF = 0, /* Referenced by undefined values */ + SHN_LORESERVE = 0xff00, /* First reserved index */ + SHN_LOPROC = 0xff00, /* First processor-specific index */ + SHN_HIPROC = 0xff1f, /* Last processor-specific index */ + SHN_LOOS = 0xff20, /* First OS-specific index */ + SHN_HIOS = 0xff3f, /* Last OS-specific index */ + SHN_ABS = 0xfff1, /* Referenced by absolute values */ + SHN_COMMON = 0xfff2, /* Referenced by common values */ + SHN_XINDEX = 0xffff, /* Indirect index reference (escape value) */ + SHN_HIRESERVE = 0xffff /* Last reserved index */ +}; + +/*---------------------------------------------------------------------------*/ +/* Section Types (value of "sh_type") */ +/*---------------------------------------------------------------------------*/ +enum +{ + SHT_NULL = 0, /* Inactive section */ + SHT_PROGBITS = 1, /* Application-specific information */ + SHT_SYMTAB = 2, /* Symbol table */ + SHT_STRTAB = 3, /* String table */ + SHT_RELA = 4, /* Relocation entries (explicit addends) */ + SHT_HASH = 5, /* Symbol hash table */ + SHT_DYNAMIC = 6, /* Dynamic linking information */ + SHT_NOTE = 7, /* Miscellaneous information */ + SHT_NOBITS = 8, /* Contains no data in file */ + SHT_REL = 9, /* Relocation entries (no expl. addends) */ + SHT_SHLIB = 10, /* Shared library */ + SHT_DYNSYM = 11, /* Dynamic symbol table */ + SHT_INIT_ARRAY = 14, /* Pointers to initialization functions */ + SHT_FINI_ARRAY = 15, /* Pointers to termination functions */ + SHT_PREINIT_ARRAY = 16, /* Pointers to pre-init functions */ + SHT_GROUP = 17, /* Section group */ + SHT_SYMTAB_SHNDX = 18, /* Section indexes for SHN_XINDEX refs. */ + SHT_LOOS = 0x60000000, /* First OS-specific type */ + SHT_HIOS = 0x6fffffff, /* Last OS-specific type */ + SHT_LOPROC = 0x70000000, /* First processor-specific type */ + SHT_HIPROC = 0x7fffffff, /* Last processor-specific type */ + SHT_LOUSER = 0x80000000, /* First application-specific type */ + SHT_HIUSER = 0xffffffff /* Last application-specific type */ +}; + +/*---------------------------------------------------------------------------*/ +/* Section Attribute Flags (value of "sh_flags") */ +/*---------------------------------------------------------------------------*/ +enum +{ + SHF_WRITE = 0x1, /* Writable during process execution */ + SHF_ALLOC = 0x2, /* Loaded into processor memory */ + SHF_EXECINSTR = 0x4, /* Contains executable instructions */ + SHF_MERGE = 0x10, /* Can be merged */ + SHF_STRINGS = 0x20, /* Contains null-terminated strings */ + SHF_INFO_LINK = 0x40, /* sh_info contains a section index */ + SHF_LINK_ORDER = 0x80, /* Maintain section ordering */ + SHF_OS_NONCONFORMING = 0x100, /* OS-specific processing required */ + SHF_GROUP = 0x200, /* Member of a section group */ + SHF_TLS = 0x400, /* Contains Thread-Local Storage */ + SHF_MASKOS = 0x0ff00000, /* Mask of OS-specific flags */ + SHF_MASKPROC = 0xf0000000 /* Mask for processor-specific flags */ +}; + +/*---------------------------------------------------------------------------*/ +/* Section Group Flags */ +/*---------------------------------------------------------------------------*/ +enum +{ + GRP_COMDAT = 0x1, /* Common data; only one is kept by linker */ + GRP_MASKOS = 0x0ff00000, /* Mask for OS-specific group flags */ + GRP_MASKPROC = 0xf0000000 /* Mask for processor-specific group flags */ +}; + + +/*****************************************************************************/ +/* Symbol Table */ +/* PP. 1-18 */ +/*****************************************************************************/ + +/*---------------------------------------------------------------------------*/ +/* Symbol Table Entry Data Structure */ +/*---------------------------------------------------------------------------*/ +struct Elf32_Sym +{ + Elf32_Word st_name; /* String table offset for symbol name */ + Elf32_Addr st_value; /* Symbol value */ + Elf32_Word st_size; /* Symbol size */ + uint8_t st_info; /* Symbol type and binding */ + uint8_t st_other; /* Symbol visibility */ + Elf32_Half st_shndx; /* Symbol type / defining section */ +}; + +/*---------------------------------------------------------------------------*/ +/* Undefined Symbol Index */ +/*---------------------------------------------------------------------------*/ +enum +{ + STN_UNDEF = 0 /* First symbol table entry is always undefined */ +}; + +/*---------------------------------------------------------------------------*/ +/* Symbol Binding and Type Utility Functions. */ +/*---------------------------------------------------------------------------*/ +static inline uint8_t ELF32_ST_BIND(uint8_t i) { return (i >> 4); } +static inline uint8_t ELF32_ST_TYPE(uint8_t i) { return (i & 0xf); } +static inline uint8_t ELF32_ST_INFO(uint8_t b, uint8_t t) + { return ((b << 4) + (t & 0xf)); } +static inline uint8_t ELF32_ST_VISIBILITY(uint8_t o) { return (o & 0x3); } + + +/*---------------------------------------------------------------------------*/ +/* Symbol Binding (value returned by ELF32_ST_BIND()) */ +/*---------------------------------------------------------------------------*/ +enum +{ + STB_LOCAL = 0, /* Symbol does not have external linkage */ + STB_GLOBAL = 1, /* Symbol has external linkage */ + STB_WEAK = 2, /* Symbol has weak external linkage */ + STB_LOOS = 10, /* First OS-specific binding */ + STB_HIOS = 12, /* Last OS-specific binding */ + STB_LOPROC = 13, /* First processor-specific binding */ + STB_HIPROC = 15 /* Last processor-specific binding */ +}; + +/*---------------------------------------------------------------------------*/ +/* Symbol Types (value returned by ELF32_ST_TYPE()) */ +/*---------------------------------------------------------------------------*/ +enum +{ + STT_NOTYPE = 0, /* Unspecified type */ + STT_OBJECT = 1, /* Associated with a data object */ + STT_FUNC = 2, /* Associated with executable code */ + STT_SECTION = 3, /* Associated with a section */ + STT_FILE = 4, /* Associated with a source file */ + STT_COMMON = 5, /* Labels an uninitialized common block */ + STT_TLS = 6, /* Specifies a thread-local storage entity */ + STT_LOOS = 10, /* First OS-specific type */ + STT_HIOS = 12, /* Last OS-specific type */ + STT_LOPROC = 13, /* First processor-specific type */ + STT_HIPROC = 15 /* Last processor-specific type */ +}; + +/*---------------------------------------------------------------------------*/ +/* Symbol Visibility (value returned by ELF32_ST_VISIBILITY()) */ +/*---------------------------------------------------------------------------*/ +enum +{ + STV_DEFAULT = 0, /* Visibility specified by binding type */ + STV_INTERNAL = 1, /* Like STV_HIDDEN, with processor-specific semantics */ + STV_HIDDEN = 2, /* Not visible to other components */ + STV_PROTECTED = 3 /* Visible in other components but not preemptable */ +}; + +/*****************************************************************************/ +/* Relocation */ +/* PP. 1-22 */ +/*****************************************************************************/ + +/*---------------------------------------------------------------------------*/ +/* Relocation Entries Data Structures */ +/*---------------------------------------------------------------------------*/ +struct Elf32_Rel +{ + Elf32_Addr r_offset; /* Offset of the relocatable value in the section */ + Elf32_Word r_info; /* Symbol table index and relocation type */ +}; + +struct Elf32_Rela +{ + Elf32_Addr r_offset; /* Offset of the relocatable value in the section */ + Elf32_Word r_info; /* Symbol table index and relocation type */ + Elf32_Sword r_addend; /* Constant addend used to compute new value */ +}; + +/*---------------------------------------------------------------------------*/ +/* Relocation Symbol and Type Utility Functions. */ +/*---------------------------------------------------------------------------*/ +static inline uint32_t ELF32_R_SYM(uint32_t i) { return (i >> 8); } +static inline uint8_t ELF32_R_TYPE(uint32_t i) { return (i & 0xFF); } +static inline uint32_t ELF32_R_INFO(uint32_t s, uint8_t t) + { return ((s << 8) + t); } + + +/*****************************************************************************/ +/* Dynamic Section */ +/* PP. 2-8 */ +/*****************************************************************************/ +struct Elf32_Dyn +{ + Elf32_Sword d_tag; + union + { + Elf32_Word d_val; + Elf32_Addr d_ptr; + } d_un; +}; + +/* Name Value d_un Executable Shared Obj. */ +/* ---- ----- ---- ---------- ----------- */ +enum +{ + DT_NULL = 0, /* ignored mandatory mandatory */ + DT_NEEDED = 1, /* d_val optional optional */ + DT_PLTRELSZ = 2, /* d_val optional optional */ + DT_PLTGOT = 3, /* d_ptr optional optional */ + DT_HASH = 4, /* d_ptr mandatory mandatory */ + DT_STRTAB = 5, /* d_ptr mandatory mandatory */ + DT_SYMTAB = 6, /* d_ptr mandatory mandatory */ + DT_RELA = 7, /* d_ptr mandatory optional */ + DT_RELASZ = 8, /* d_val mandatory optional */ + DT_RELAENT = 9, /* d_val mandatory optional */ + DT_STRSZ = 10, /* d_val mandatory mandatory */ + DT_SYMENT = 11, /* d_val mandatory mandatory */ + DT_INIT = 12, /* d_ptr optional optional */ + DT_FINI = 13, /* d_ptr optional optional */ + DT_SONAME = 14, /* d_val ignored optional */ + DT_RPATH = 15, /* d_val optional ignored */ + DT_SYMBOLIC = 16, /* ignored ignored optional */ + DT_REL = 17, /* d_ptr mandatory optional */ + DT_RELSZ = 18, /* d_val mandatory optional */ + DT_RELENT = 19, /* d_val mandatory optional */ + DT_PLTREL = 20, /* d_val optional optional */ + DT_DEBUG = 21, /* d_ptr optional ignored */ + DT_TEXTREL = 22, /* ignored optional optional */ + DT_JMPREL = 23, /* d_ptr optional optional */ + DT_BIND_NOW = 24, /* ignored optional optional */ + DT_INIT_ARRAY = 25, /* d_ptr optional optional */ + DT_FINI_ARRAY = 26, /* d_ptr optional optional */ + DT_INIT_ARRAYSZ = 27, /* d_val optional optional */ + DT_FINI_ARRAYSZ = 28, /* d_val optional optional */ + DT_RUNPATH = 29, /* d_val optional optional */ + DT_FLAGS = 30, /* d_val optional optional */ + DT_ENCODING = 32, /* unspecified unspecified unspecified */ + DT_PREINIT_ARRAY = 32, /* d_ptr optional ignored */ + DT_PREINIT_ARRAYSZ = 33, /* d_val optional ignored */ + DT_LOOS = 0x60000000, /* unspecified unspecified unspecified */ + DT_HIOS = 0x6ffff000, /* unspecified unspecified unspecified */ + DT_LOPROC = 0x70000000, /* unspecified unspecified unspecified */ + DT_HIPROC = 0x7fffffff /* unspecified unspecified unspecified */ +}; + + +/*---------------------------------------------------------------------------*/ +/* DT_FLAGS values. */ +/*---------------------------------------------------------------------------*/ +enum +{ + DF_ORIGIN = 0x01, /* loaded object may reference $ORIGIN subst. string */ + DF_SYMBOLIC = 0x02, /* changes dynamic linker symbol resolution */ + DF_TEXTREL = 0x04, /* do not allow relocation of non-writable segments */ + DF_BIND_NOW = 0x08, /* don't use lazy binding */ + DF_STATIC_TLS = 0x10, /* do not load this file dynamically */ + DF_DIRECT_DEPENDENT = 0x20, /* limit global sym lookup to dependent list */ + DF_WORLD = 0x40 /* Linux style global sym lookup, breadth-first */ +}; + + +/*---------------------------------------------------------------------------*/ +/* Dynamic Tag Database. */ +/*---------------------------------------------------------------------------*/ + +/* Specifiers for which d_un union member to use */ + +enum +{ + EDYN_UNTYPE_IGNORED, + EDYN_UNTYPE_VAL, + EDYN_UNTYPE_PTR, + EDYN_UNTYPE_UNSPECIFIED +}; + + +/* Specifiers for executable/shared object file requirements */ + +enum +{ + EDYN_TAGREQ_IGNORED, + EDYN_TAGREQ_MANDATORY, + EDYN_TAGREQ_OPTIONAL, + EDYN_TAGREQ_UNSPECIFIED +}; + + +/* Data structure for one dynamic tag database entry */ + +struct EDYN_TAG +{ + const char* d_tag_name; /* tag name string */ + Elf32_Sword d_tag_value; /* DT_* tag value */ + Elf32_Word d_untype; /* which d_un union member to use */ + Elf32_Word d_exec_req; /* requirement for executable files */ + Elf32_Word d_shared_req; /* requirement for shared object files */ +}; + +extern const struct EDYN_TAG EDYN_TAG_DB[]; + +/*****************************************************************************/ +/* Special Section Database */ +/*****************************************************************************/ + +/*---------------------------------------------------------------------------*/ +/* Special Section Names */ +/*---------------------------------------------------------------------------*/ +#define ESCN_BSS_name ".bss" +#define ESCN_COMMENT_name ".comment" +#define ESCN_DATA1_name ".data1" +#define ESCN_DATA_name ".data" +#define ESCN_DEBUG_name ".debug" +#define ESCN_DYNAMIC_name ".dynamic" +#define ESCN_DYNSTR_name ".dynstr" +#define ESCN_DYNSYM_name ".dynsym" +#define ESCN_FINI_ARRAY_name ".fini_array" +#define ESCN_FINI_name ".fini" +#define ESCN_GOT_name ".got" +#define ESCN_HASH_name ".hash" +#define ESCN_INIT_ARRAY_name ".init_array" +#define ESCN_INIT_name ".init" +#define ESCN_INTERP_name ".interp" +#define ESCN_LINE_name ".line" +#define ESCN_NOTE_name ".note" +#define ESCN_PLT_name ".plt" +#define ESCN_PREINIT_ARRAY_name ".preinit_array" +#define ESCN_RELA_name ".rela" +#define ESCN_REL_name ".rel" +#define ESCN_RODATA1_name ".rodata1" +#define ESCN_RODATA_name ".rodata" +#define ESCN_SHSTRTAB_name ".shstrtab" +#define ESCN_STRTAB_name ".strtab" +#define ESCN_SYMTAB_SHNDX_name ".symtab_shndx" +#define ESCN_SYMTAB_name ".symtab" +#define ESCN_TBSS_name ".tbss" +#define ESCN_TDATA1_name ".tdata1" +#define ESCN_TDATA_name ".tdata" +#define ESCN_TEXT_name ".text" +#define ESCN_ATTRIBUTES_name "__TI_build_attributes" +#define ESCN_ICODE_name "__TI_ICODE" +#define ESCN_XREF_name "__TI_XREF" + +/*---------------------------------------------------------------------------*/ +/* Special Section Information Data Structure. */ +/*---------------------------------------------------------------------------*/ +struct ESCN +{ + const char *name; + Elf32_Word sh_type; + Elf32_Word sh_entsize; + Elf32_Word sh_flags; +}; + +extern const struct ESCN ESCN_DB[]; + +#endif /* ELF32_H */ diff --git a/src/core/dsp/ocl_load/DLOAD/relocate.h b/src/core/dsp/ocl_load/DLOAD/relocate.h new file mode 100644 index 0000000..ee21aa9 --- /dev/null +++ b/src/core/dsp/ocl_load/DLOAD/relocate.h @@ -0,0 +1,64 @@ +/* +* relocate.h +* +* Declare names and IDs of all C6x-specific relocation types supported +* in the dynamic loader. +* +* Copyright (C) 2009-2014 Texas Instruments Incorporated - http://www.ti.com/ +* +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +*/ + +#ifndef RELOCATE_H +#define RELOCATE_H + +#include <inttypes.h> +#include "elf32.h" +#include "dload.h" +#include "dload_api.h" + +/*---------------------------------------------------------------------------*/ +/* Declare some globals that are used for internal debugging and profiling. */ +/*---------------------------------------------------------------------------*/ +#if LOADER_DEBUG || LOADER_PROFILE +#include <time.h> +extern int DLREL_relocations; +extern time_t DLREL_total_reloc_time; +#endif + + +/*---------------------------------------------------------------------------*/ +/* Landing point for core loader's relocation processor. */ +/*---------------------------------------------------------------------------*/ +void DLREL_relocate(DLOAD_HANDLE handle, LOADER_FILE_DESC *fd, + DLIMP_Dynamic_Module *dyn_module); + +#endif diff --git a/src/core/dsp/ocl_load/DLOAD/symtab.h b/src/core/dsp/ocl_load/DLOAD/symtab.h new file mode 100644 index 0000000..1f06584 --- /dev/null +++ b/src/core/dsp/ocl_load/DLOAD/symtab.h @@ -0,0 +1,72 @@ +/* +* symtab.h +* +* Specification of functions used by the core loader to create, maintain, +* and destroy internal symbol tables. +* +* Copyright (C) 2009-2014 Texas Instruments Incorporated - http://www.ti.com/ +* +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +*/ + +#ifndef SYMTAB_H +#define SYMTAB_H + +#include "ArrayList.h" +#include "dload.h" + +/*****************************************************************************/ +/* This is the top-level application file handle. It should only be needed */ +/* under the Linux and DSBT models. */ +/*****************************************************************************/ +extern int32_t DLIMP_application_handle; + +/*---------------------------------------------------------------------------*/ +/* Core Loader Symbol Table Management Functions */ +/*---------------------------------------------------------------------------*/ +BOOL DLSYM_canonical_lookup(DLOAD_HANDLE handle, + int32_t sym_index, + DLIMP_Dynamic_Module *dyn_module, + Elf32_Addr *sym_value); + +BOOL DLSYM_global_lookup(DLOAD_HANDLE handle, + const char *sym_name, + DLIMP_Loaded_Module *pentry, + Elf32_Addr *sym_value); + +BOOL DLSYM_lookup_local_symtab(const char *sym_name, + struct Elf32_Sym *symtab, + Elf32_Word symnum, + Elf32_Addr *sym_value); + +void DLSYM_copy_globals(DLIMP_Dynamic_Module *dyn_module); + +#endif diff --git a/src/core/dsp/ocl_load/DLOAD/util.h b/src/core/dsp/ocl_load/DLOAD/util.h new file mode 100644 index 0000000..24c5b3f --- /dev/null +++ b/src/core/dsp/ocl_load/DLOAD/util.h @@ -0,0 +1,89 @@ +/* +* util.h +* +* Definition of some useful string comparison routines (not +* not provided on all platforms) and a few generic macros. +* +* Copyright (C) 2009-2014 Texas Instruments Incorporated - http://www.ti.com/ +* +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +*/ + +#ifndef UTIL_H +#define UTIL_H + +#include <ctype.h> + +#if !defined(__linux) + +/*****************************************************************************/ +/* STRCASECMP() - Case-insensitive strcmp. */ +/*****************************************************************************/ +static int strcasecmp(const char* s1, const char* s2) +{ + char c1, c2; + do { c1 = *s1++; c2 = *s2++; } + while (c1 && c2 && (tolower(c1) == tolower(c2))); + + return tolower(c1) - tolower(c2); +} + +/*****************************************************************************/ +/* STRNCASECMP() - Case-insensitive strncmp. */ +/*****************************************************************************/ +static int strncasecmp(const char* s1, const char* s2, size_t n) +{ + char c1, c2; + + if (!n) return 0; + + do { c1 = *s1++; c2 = *s2++; } + while (--n && c1 && c2 && (tolower(c1) == tolower(c2))); + + return tolower(c1) - tolower(c2); +} + +#endif + +/*****************************************************************************/ +/* Define MIN and MAX macros. */ +/*****************************************************************************/ +#define MIN(x,y) (((x) > (y)) ? (y) : (x)) +#define MAX(x,y) (((x) >= (y)) ? (x) : (y)) + +/*****************************************************************************/ +/* C implementation of 'bool' type. */ +/*****************************************************************************/ +typedef int BOOL; +#define TRUE 1 +#define FALSE 0 + +#endif diff --git a/src/core/dsp/ocl_load/DLOAD/version.h b/src/core/dsp/ocl_load/DLOAD/version.h new file mode 100644 index 0000000..e36d1a9 --- /dev/null +++ b/src/core/dsp/ocl_load/DLOAD/version.h @@ -0,0 +1,63 @@ +/* +* version.h +* +* Dynamic Loader source version identifictaion. +* +* Copyright (C) 2009-2014 Texas Instruments Incorporated - http://www.ti.com/ +* +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +*/ + +#ifndef _VERSION_H_ +#define _VERSION_H_ + +/*****************************************************************************/ +/* VERSION NUMBER COMPONENTS - ALWAYS INCREASING!! */ +/* Initial version ID is 1.0.0. Successive version ID's will be incremented */ +/* by automated processes during release port. */ +/*****************************************************************************/ +#define VERSION_MAJOR 1 +#define VERSION_MINOR 0 +#define VERSION_PATCH 0 + +/******************************************************************************/ +/* Macros used to convert version macros into strings. */ +/******************************************************************************/ +#define MKCSTR(_str) #_str +#define MKMSTR(_str) MKCSTR(_str) + +/******************************************************************************/ +/* VERSION string construction macros. */ +/******************************************************************************/ +#define VERSTR MKMSTR(VERSION_MAJOR) "." MKMSTR(VERSION_MINOR) "." MKMSTR(VERSION_PATCH) +#define VERSION "Texas Instruments Dynamic Loader API/Core v"VERSTR + +#endif diff --git a/src/core/dsp/ocl_load/DLOAD/virtual_targets.h b/src/core/dsp/ocl_load/DLOAD/virtual_targets.h new file mode 100644 index 0000000..1d44b4d --- /dev/null +++ b/src/core/dsp/ocl_load/DLOAD/virtual_targets.h @@ -0,0 +1,90 @@ +/****************************************************************************** + * Copyright (c) 2013-2014, Texas Instruments Incorporated - http://www.ti.com/ + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Texas Instruments Incorporated nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ +#include "dload.h" +#include "elf32.h" + +#ifdef C60_TARGET +#include "c60_dynamic.h" +#include "c60_reloc.h" +#endif + +#ifdef ARM_TARGET +#include "arm_dynamic.h" +#include "arm_reloc.h" +#endif + +/*****************************************************************************/ +/* Define a virtual target class to give access to target specific functions */ +/*****************************************************************************/ +typedef struct vtarget +{ + int machine_id; + + BOOL (*relocate_dynamic_tag_info)(DLIMP_Dynamic_Module *dyn_module, int i); + BOOL (*process_eiosabi)(DLIMP_Dynamic_Module* dyn_module); + BOOL (*process_dynamic_tag)(DLIMP_Dynamic_Module *dyn_module, int i); + void (*relocate)(DLOAD_HANDLE handle, LOADER_FILE_DESC *elf_file, + DLIMP_Dynamic_Module *dyn_module); + +} VIRTUAL_TARGET; + + + +/*****************************************************************************/ +/* Populate this for each target supported. */ +/*****************************************************************************/ +VIRTUAL_TARGET vt_arr[] = { + +#ifdef C60_TARGET + { + EM_TI_C6000, + DLDYN_c60_relocate_dynamic_tag_info, + DLDYN_c60_process_eiosabi, + DLDYN_c60_process_dynamic_tag, + DLREL_c60_relocate + }, +#endif +#ifdef ARM_TARGET + { + EM_ARM, + DLDYN_arm_relocate_dynamic_tag_info, + DLDYN_arm_process_eiosabi, + DLDYN_arm_process_dynamic_tag, + DLREL_arm_relocate + }, +#endif + { + EM_NONE, + 0, + 0, + 0, + 0 + } +}; + + diff --git a/src/core/dsp/ocl_load/DLOAD_API/api_version_change.log b/src/core/dsp/ocl_load/DLOAD_API/api_version_change.log new file mode 100644 index 0000000..689cfe6 --- /dev/null +++ b/src/core/dsp/ocl_load/DLOAD_API/api_version_change.log @@ -0,0 +1,33 @@ + + Dynamic Loader API and Loader Core - Version Number Change Log + ============================================================== + + Version Number Description + -------------------------- + + The version number associated with the Dynamic Loader API and the Loader Core + sources has three components: + + <major version>.<minor version>.<patch version> + + major version - is incremented if there is a change to the API that creates a + compatibility discontinuity. + + minor version - is incremented if functionality is added to the API without + causing a compatibility discontinuity. + + patch version - is incremented if a defect has been repaired, a performance + enhancement has been added, or the source code has been + refactored in some way. There should not be a compatibility + discontinuity created by an increment to the patch version. + + Version Number Change Log + ------------------------- + + 1.0.0 - 17 July 2009 - Initial release of dynamic loader API and loader + core sources. + + 2.0.0 - 1 Feb 2013 - Add client handle to several DLIF functions. + - Add DLIF_exit() for loader abort. + + diff --git a/src/core/dsp/ocl_load/DLOAD_API/dload_api.h b/src/core/dsp/ocl_load/DLOAD_API/dload_api.h new file mode 100644 index 0000000..95de10f --- /dev/null +++ b/src/core/dsp/ocl_load/DLOAD_API/dload_api.h @@ -0,0 +1,700 @@ +/* +* dload_api.h +* +* Dynamic Loader API Specification +* -------------------------------- +* +* Client-side of API is assumed to be platform dependent, but object file +* format independent. +* +* Core Loader side of API is assumed to be platform independent, but +* object file format dependent and target dependent. +* +* Copyright (C) 2009-2014 Texas Instruments Incorporated - http://www.ti.com/ +* +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +*/ + +#ifndef DLOAD_API_H +#define DLOAD_API_H + +#include <inttypes.h> +#include <stdio.h> +#include "util.h" + +extern int debugging_on; + +/*****************************************************************************/ +/* Specification of Loader File Descriptor. If client side of the loader */ +/* supports virtual memory, this may need to be updated to facilitate the */ +/* use of mmap(). */ +/*****************************************************************************/ +typedef FILE LOADER_FILE_DESC; + +static const int LOADER_SEEK_SET = SEEK_SET; +static const int LOADER_SEEK_CUR = SEEK_CUR; +static const int LOADER_SEEK_END = SEEK_END; + +/*****************************************************************************/ +/* TARGET_ADDRESS - type suitable for storing target memory address values. */ +/*****************************************************************************/ +typedef uint32_t TARGET_ADDRESS; + +/*****************************************************************************/ +/* Define DLOAD Object Handle */ +/*****************************************************************************/ +typedef void * DLOAD_HANDLE; + +/*****************************************************************************/ +/* Core Loader Provided API Functions (Core Loader Entry Points) */ +/*****************************************************************************/ + +/*---------------------------------------------------------------------------*/ +/* DLOAD_version() */ +/* */ +/* Return a string constant representation for the version ID of the */ +/* dynamic loader's core loader source code. */ +/* */ +/*---------------------------------------------------------------------------*/ +#include "version.h" +#define DLOAD_version() VERSION + +/*---------------------------------------------------------------------------*/ +/* DLOAD_create() */ +/* */ +/* Construct and initialize the dynamic loader core's handle. */ +/* */ +/*---------------------------------------------------------------------------*/ +DLOAD_HANDLE DLOAD_create(void * client_handle); + +/*---------------------------------------------------------------------------*/ +/* DLOAD_destroy() */ +/* */ +/* Destroy and finalize the dynamic loader core's handle. */ +/* */ +/*---------------------------------------------------------------------------*/ +void DLOAD_destroy(DLOAD_HANDLE handle); + +/*---------------------------------------------------------------------------*/ +/* DLOAD_initialize() */ +/* */ +/* Construct and initialize data structures internal to the dynamic */ +/* loader core. */ +/* */ +/*---------------------------------------------------------------------------*/ +void DLOAD_initialize(DLOAD_HANDLE handle); + +/*---------------------------------------------------------------------------*/ +/* DLOAD_finalize() */ +/* */ +/* Destroy and finalize data structures internal to the dynamic */ +/* loader core. */ +/* */ +/*---------------------------------------------------------------------------*/ +void DLOAD_finalize(DLOAD_HANDLE handle); + +/*---------------------------------------------------------------------------*/ +/* DLOAD_load_symbols() */ +/* */ +/* Load externally visible symbols from the specified file so that they */ +/* can be linked against when another object file is subsequntly loaded. */ +/* External symbols will be made available for global symbol linkage. */ +/* */ +/*---------------------------------------------------------------------------*/ +BOOL DLOAD_load_symbols(DLOAD_HANDLE handle, LOADER_FILE_DESC* fp); + +/*---------------------------------------------------------------------------*/ +/* DLOAD_load() */ +/* */ +/* Dynamically load the specified file and return a file handle for the */ +/* loaded file. If the load fails, this function will return a value */ +/* zero (0). */ +/* */ +/* The core loader must have read access to the file pointed by fp. */ +/* */ +/*---------------------------------------------------------------------------*/ +int DLOAD_load(DLOAD_HANDLE handle, LOADER_FILE_DESC* fp); + +/*---------------------------------------------------------------------------*/ +/* DLOAD_unload() */ +/* */ +/* Given a file handle ID, unload all object segments associated with */ +/* the identified file and any of its dependents that are not still in */ +/* use. */ +/* */ +/*---------------------------------------------------------------------------*/ +BOOL DLOAD_unload(DLOAD_HANDLE handle, uint32_t pseudopid); + +/*---------------------------------------------------------------------------*/ +/* DLOAD_get_entry_names_info() */ +/* */ +/* Given a file handle, return the number entry points that are */ +/* available in the specified file as well as the max name length. This */ +/* can then be used by the client to allocate the appropriate amount of */ +/* memory needed to call DLOAD_get_entry_names() */ +/* */ +/*---------------------------------------------------------------------------*/ +BOOL DLOAD_get_entry_names_info(DLOAD_HANDLE handle, uint32_t file_handle, + int32_t *entry_pt_cnt, + int32_t *entry_pt_max_name_len); + +/*---------------------------------------------------------------------------*/ +/* DLOAD_get_entry_names() */ +/* */ +/* Given a file handle, build a list of entry point names that are */ +/* available in the specified file. This can be used when querying */ +/* the list of global functions available in a shared library. */ +/* */ +/*---------------------------------------------------------------------------*/ +BOOL DLOAD_get_entry_names(DLOAD_HANDLE handle, uint32_t file_handle, + int32_t* entry_pt_cnt, char*** entry_pt_names); + +/*---------------------------------------------------------------------------*/ +/* DLOAD_query_symbol() */ +/* */ +/* Query the value of a symbol that is defined by an object file that */ +/* has previously been loaded. Boolean return value will be false if */ +/* the symbol is not found. */ +/* */ +/*---------------------------------------------------------------------------*/ +BOOL DLOAD_query_symbol(DLOAD_HANDLE handle, uint32_t file_handle, + const char *sym_name, TARGET_ADDRESS *sym_val); + +/*---------------------------------------------------------------------------*/ +/* DLOAD_get_entry_point() */ +/* */ +/* Given a file handle, return the entry point target address associated */ +/* with that object file. The entry point address value is written to */ +/* *sym_val. The return value of the function indicates whether the */ +/* file with the specified handle was found or not. */ +/* */ +/*---------------------------------------------------------------------------*/ +BOOL DLOAD_get_entry_point(DLOAD_HANDLE handle, uint32_t file_handle, + TARGET_ADDRESS *sym_val); + +/*---------------------------------------------------------------------------*/ +/* DLOAD_load_arguments() */ +/* */ +/* Given a file handle, find the object file assicated with that handle */ +/* and copy the argc/argv information from the client into that object */ +/* file's .args section. The return value indicates whether the operation */ +/* was successful. If there are no loaded object files which match the */ +/* handle or if there is insufficient space in the .args section to hold */ +/* the specified argc/argv information, the function will return false. */ +/* */ +/*---------------------------------------------------------------------------*/ +BOOL DLOAD_load_arguments(DLOAD_HANDLE handle, uint32_t file_handle, + int argc, char** argv); + +/*---------------------------------------------------------------------------*/ +/* DLOAD_prepare_for_execution() */ +/* */ +/* Given a file handle, prepare for execution : */ +/* - Return entry point associated with that module in the *sym_val */ +/* output parameter. */ +/* - Write out the given arguments to the .args section contained in the */ +/* same module. */ +/* - As a test (for the Reference implementation) read the arguments */ +/* using the DLIF_read_arguments() function and set global argc,argv. */ +/* */ +/* The return value of the function indicates whether the file with the */ +/* specified handle was found or not. */ +/* */ +/*---------------------------------------------------------------------------*/ +BOOL DLOAD_prepare_for_execution(DLOAD_HANDLE handle, uint32_t file_handle, + TARGET_ADDRESS *sym_val, + int argc, char** argv); + + +/*****************************************************************************/ +/* Client Provided API Functions */ +/*****************************************************************************/ + +/*---------------------------------------------------------------------------*/ +/* File I/O */ +/* */ +/* The client side of the dynamic loader must provide basic file I/O */ +/* capabilities so that the core loader has random access into any */ +/* object file that it is asked to load. */ +/* */ +/* The client side of the dynamic loader must provide a definition of */ +/* the LOADER_FILE_DESC in dload_filedefs.h. This allows the core loader */ +/* to be independent of how the client accesses raw data in an object */ +/* file. */ +/* */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* DLIF_fseek() */ +/* */ +/* Seek to a position in a file (accessed via 'stream') based on the */ +/* values for offset and origin. */ +/* */ +/*---------------------------------------------------------------------------*/ +int DLIF_fseek(LOADER_FILE_DESC *stream, int32_t offset, int origin); + +/*---------------------------------------------------------------------------*/ +/* DLIF_ftell() */ +/* */ +/* Return the current file position in the file identified in the */ +/* LOADER_FILE_DESC pointed to by 'stream'. */ +/* */ +/*---------------------------------------------------------------------------*/ +int32_t DLIF_ftell(LOADER_FILE_DESC *stream); + +/*---------------------------------------------------------------------------*/ +/* DLIF_fread() */ +/* */ +/* Read 'size' * 'nmemb' bytes of data from the file identified in the */ +/* LOADER_FILE_DESC object pointed to by 'stream', and write that data */ +/* into the memory accessed via 'ptr'. */ +/* */ +/*---------------------------------------------------------------------------*/ +size_t DLIF_fread(void *ptr, size_t size, size_t nmemb, + LOADER_FILE_DESC *stream); + +/*---------------------------------------------------------------------------*/ +/* DLIF_fclose() */ +/* */ +/* Close a file that was opened on behalf of the core loader. Ownership */ +/* of the file pointer in question belongs to the core loader, but the */ +/* client has exclusive access to the file system. */ +/* */ +/*---------------------------------------------------------------------------*/ +int DLIF_fclose(LOADER_FILE_DESC *fd); + +/*---------------------------------------------------------------------------*/ +/* Host Memory Management */ +/* */ +/* Allocate and free host memory as needed for the dynamic loader's */ +/* internal data structures. If the dynamic loader resides on the */ +/* target architecture, then this memory is allocated from a target */ +/* memory heap that must be managed separately from memory that is */ +/* allocated for a dynamically loaded object file. */ +/* */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* DLIF_malloc() */ +/* */ +/* Allocate 'size' bytes of memory space that is usable as scratch space */ +/* (appropriate for the loader's internal data structures) by the dynamic */ +/* loader. */ +/* */ +/* If allocation fails, this function must not return. */ +/* */ +/*---------------------------------------------------------------------------*/ +void* DLIF_malloc(size_t size); + +/*---------------------------------------------------------------------------*/ +/* DLIF_free() */ +/* */ +/* Free memory space that was previously allocated by DLIF_malloc(). */ +/* */ +/*---------------------------------------------------------------------------*/ +void DLIF_free(void* ptr); + +/*---------------------------------------------------------------------------*/ +/* Target Memory Allocator Interface */ +/* */ +/* The client side of the dynamic loader must create and maintain an */ +/* infrastructure to manage target memory. The client must keep track */ +/* of what target memory is associated with each object segment, */ +/* allocating target memory for newly loaded objects and release target */ +/* memory that is associated with objects that are being unloaded from */ +/* the target architecture. */ +/* */ +/* The two client-supplied functions, DLIF_allocate() and DLIF_release(), */ +/* are used by the core loader to interface into the client side's */ +/* target memory allocator infrastructure. */ +/* */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* DLOAD_SEGMENT_FLAGS - segment characteristics. */ +/*---------------------------------------------------------------------------*/ +typedef uint32_t DLOAD_SEGMENT_FLAGS; +static const int DLOAD_SF_executable = 0x1; /* Memory must be executable */ +static const int DLOAD_SF_relocatable = 0x2; /* Segment must be relocatable */ +static const int DLOAD_SF_writable = 0x4; /* Memory must be writable */ + +/*---------------------------------------------------------------------------*/ +/* DLOAD_MEMORY_SEGMENT - Define structure to represent placement and size */ +/* details of a segment to be loaded. */ +/*---------------------------------------------------------------------------*/ +struct DLOAD_MEMORY_SEGMENT +{ + uint32_t target_page; /* requested/returned memory page */ + TARGET_ADDRESS target_address; /* requested/returned address */ + uint32_t objsz_in_bytes; /* size of init'd part of segment */ + uint32_t memsz_in_bytes; /* size of memory block for segment */ +// DLOAD_SEGMENT_FLAGS flags; /* allocation request flags */ +}; + +/*---------------------------------------------------------------------------*/ +/* DLOAD_MEMORY_REQUEST - Define structure to represent a target memory */ +/* request made by the core loader on behalf of a segment that the */ +/* loader needs to relocate and write into target memory. */ +/*---------------------------------------------------------------------------*/ +struct DLOAD_MEMORY_REQUEST +{ + LOADER_FILE_DESC *fp; /* file being loaded */ + struct DLOAD_MEMORY_SEGMENT *segment; /* obj for req/ret alloc */ + void *host_address; /* ret hst ptr from DLIF_copy()*/ + BOOL is_loaded; /* returned as true if segment */ + /* is already in target memory */ + uint32_t offset; /* file offset of segment's */ + /* raw data */ + uint32_t flip_endian; /* endianness of trg opp host */ + DLOAD_SEGMENT_FLAGS flags; /* allocation request flags */ + uint32_t align; /* align of trg memory block */ +}; + +/*---------------------------------------------------------------------------*/ +/* DLIF_initMem() */ +/* */ +/* Given an address and size, initialize the memory used to load the */ +/* dynamic segments. This should be called by the client before */ +/* beginning dynamic loading. */ +/* */ +/*---------------------------------------------------------------------------*/ +BOOL DLIF_initMem(void* client_handle, uint32_t dynMemAddr, uint32_t size); + +/*---------------------------------------------------------------------------*/ +/* DLIF_deinitMem() */ +/* */ +/* De-initialize the memory used to load the dynamic segments. */ +/* */ +/*---------------------------------------------------------------------------*/ +BOOL DLIF_deinitMem(void* client_handle); + +/*---------------------------------------------------------------------------*/ +/* DLIF_allocate() */ +/* */ +/* Given a DLOAD_MEMORY_REQUEST created by the core loader, allocate */ +/* target memory to fulfill the request using the target memory */ +/* management infrastrucutre on the client side of the dynamic loader. */ +/* The contents of the DLOAD_MEMORY_REQUEST will be updated per the */ +/* details of a successful allocation. The allocated page and address */ +/* can be found in the DLOAD_MEMORY_SEGMENT attached to the request. */ +/* The boolean return value reflects whether the allocation was */ +/* successful or not. */ +/* */ +/*---------------------------------------------------------------------------*/ +BOOL DLIF_allocate(void* client_handle, struct DLOAD_MEMORY_REQUEST *req); + +/*---------------------------------------------------------------------------*/ +/* DLIF_release() */ +/* */ +/* Given a DLOAD_MEMORY_SEGMENT description, free the target memory */ +/* associated with the segment using the target memory management */ +/* infrastructure on the client side of the dynamic loader. */ +/* */ +/*---------------------------------------------------------------------------*/ +BOOL DLIF_release(void* client_handle, struct DLOAD_MEMORY_SEGMENT* ptr); + +/*---------------------------------------------------------------------------*/ +/* Target Memory Access / Write Services */ +/* */ +/* The client side's target memory allocator infrastructure communicates */ +/* with the core loader through the DLOAD_MEMORY_REQUEST and */ +/* DLOAD_MEMORY_SEGMENT data structures defined above. To complete the */ +/* loading of an object segment, the segment may need to be relocated */ +/* before it is actually written to target memory in the space that was */ +/* allocated for it by DLIF_allocate(). */ +/* */ +/* The client side of the dynamic loader provides two functions to help */ +/* complete the process of loading an object segment, DLIF_copy() and */ +/* DLIF_write(). */ +/* */ +/* These functions help to make the core loader truly independent of */ +/* whether it is running on the host or target architecture and how the */ +/* client provides for reading/writing from/to target memory. */ +/* */ +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ +/* DLIF_copy() */ +/* */ +/* Copy segment data from the object file described in the 'fp' and */ +/* 'offset' of the DLOAD_MEMORY_REQUEST into host accessible memory so */ +/* that it can relocated or otherwise manipulated by the core loader. */ +/* */ +/*---------------------------------------------------------------------------*/ +BOOL DLIF_copy(void* client_handle, struct DLOAD_MEMORY_REQUEST* req); + +/*---------------------------------------------------------------------------*/ +/* DLIF_write() */ +/* */ +/* Once the segment data described in the DLOAD_MEMORY_REQUEST is ready */ +/* (relocated, if needed), write the segment contents to the target */ +/* memory identified in the DLOAD_MEMORY_SEGMENT attached to the request. */ +/* */ +/* After the segment contents have been written to target memory, the */ +/* core loader should discard the DLOAD_MEMORY_REQUEST object, but retain */ +/* the DLOAD_MEMORY_SEGMENT object so that the target memory associated */ +/* with the segment can be releases when the segment is unloaded. */ +/* */ +/*---------------------------------------------------------------------------*/ +BOOL DLIF_write(void* client_handle, struct DLOAD_MEMORY_REQUEST* req); + +/*---------------------------------------------------------------------------*/ +/* DLIF_read() */ +/* */ +/* Given a host accessible buffer, read content of indicated target */ +/* memory address into the buffer. */ +/*---------------------------------------------------------------------------*/ +BOOL DLIF_read(void* client_handle, + void *ptr, size_t size, size_t nmemb, TARGET_ADDRESS src); + +/*---------------------------------------------------------------------------*/ +/* DLIF_memcpy() */ +/* */ +/* Given a host accessible buffer, copy content from specified buffer */ +/* into target memory. */ +/*---------------------------------------------------------------------------*/ +BOOL DLIF_memcpy(void* client_handle, void *to, void *from, size_t size); + +/*---------------------------------------------------------------------------*/ +/* DLIF_execute() */ +/* */ +/* Start execution on the target architecture from given 'exec_addr'. */ +/* If the dynamic loader is running on the target architecture, this can */ +/* be effected as a simple function call. */ +/* */ +/*---------------------------------------------------------------------------*/ +int32_t DLIF_execute(void* client_handle, TARGET_ADDRESS exec_addr); + +/*---------------------------------------------------------------------------*/ +/* Loading and Unloading of Dependent Files */ +/* */ +/* The dynamic loader core loader must coordinate loading and unloading */ +/* dependent object files with the client side of the dynamic loader. */ +/* This allows the client to keep its bookkeeping information up to date */ +/* with what is currently loaded on the target architecture. */ +/* */ +/* For instance, the client may need to interact with a file system or */ +/* registry. The client may also need to update debug information in */ +/* synch with the loading and unloading of shared objects. */ +/* */ +/*---------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ +/* DLIF_load_dependent() */ +/* */ +/* Ask client to find and open a dependent file identified by the */ +/* 'so_name' parameter, then, if necessary, initiate a DLOAD_load() */ +/* call to actually load the shared object onto the target. A */ +/* successful load will return a file handle ID that the client can */ +/* associate with the newly loaded file. */ +/* */ +/*---------------------------------------------------------------------------*/ +int DLIF_load_dependent(void* client_handle, const char* so_name); + +/*---------------------------------------------------------------------------*/ +/* DLIF_unload_dependent() */ +/* */ +/* Ask client to unload a dependent file identified by the 'file_handle' */ +/* parameter. Initiate a call to DLOAD_unload() to actually free up */ +/* the target memory that was occupied by the object file. */ +/* */ +/*---------------------------------------------------------------------------*/ +void DLIF_unload_dependent(void* client_handle, uint32_t file_handle); + +/*---------------------------------------------------------------------------*/ +/* Error/Warning Registration Functions */ +/* */ +/* The client will maintain an error/warning log. This will allow the */ +/* core loader to register errors and warnings in the load during a */ +/* given dynamic load. The client is required to check the log after */ +/* each load attempt to report any problems. */ +/* */ +/*---------------------------------------------------------------------------*/ + + +/*---------------------------------------------------------------------------*/ +/* Loader Warning Types */ +/*---------------------------------------------------------------------------*/ +typedef enum { + DLWT_MISC = 0, /* Miscellaneous warning */ + DLWT_FILE /* Warning missing/invalid file information */ +} LOADER_WARNING_TYPE; + +/*---------------------------------------------------------------------------*/ +/* DLIF_warning() */ +/* */ +/* Log a warning message with the client's error/warning handling */ +/* infrastructure. */ +/* */ +/*---------------------------------------------------------------------------*/ +void DLIF_warning(LOADER_WARNING_TYPE wtype, const char *fmt, ...); + +/*---------------------------------------------------------------------------*/ +/* Loader Error Types */ +/*---------------------------------------------------------------------------*/ +typedef enum { + DLET_MISC = 0, /* Miscellaneous error */ + DLET_FILE, /* Error reading/processing file */ + DLET_SYMBOL, /* Symbol resolution error */ + DLET_RELOC, /* Relocation error */ + DLET_MEMORY, /* Host memory allocation/free error */ + DLET_TRGMEM, /* Target memory allocation/free error */ + DLET_DEBUG /* Shared object or DLL debug error */ +} LOADER_ERROR_TYPE; + +/*---------------------------------------------------------------------------*/ +/* DLIF_error() */ +/* */ +/* Log an error message with the client's error/warning handling */ +/* infrastructure. */ +/* */ +/*---------------------------------------------------------------------------*/ +void DLIF_error(LOADER_ERROR_TYPE etype, const char *fmt, ...); + +/*---------------------------------------------------------------------------*/ +/* DLIF_exit() */ +/* */ +/* Abort the loader following a fatal error. */ +/* */ +/*---------------------------------------------------------------------------*/ +void DLIF_exit(int code); + +/*---------------------------------------------------------------------------*/ +/* DLIF_trace() */ +/* */ +/* Log a message with the client's trace handling infrastructure. */ +/* */ +/*---------------------------------------------------------------------------*/ +void DLIF_trace(const char *fmt, ...); + +/*---------------------------------------------------------------------------*/ +/* Dynamic Static Base Table (DSBT) Support Functions */ +/*---------------------------------------------------------------------------*/ +#define DSBT_INDEX_INVALID -1 +#define DSBT_DSBT_BASE_INVALID 0 +#define DSBT_STATIC_BASE_INVALID 0 + +/*****************************************************************************/ +/* Core Loader Side of DSBT Support */ +/*****************************************************************************/ + +/*---------------------------------------------------------------------------*/ +/* DLOAD_get_dsbt_size() */ +/* */ +/* Query the size of the DSBT associated with a specified file. The */ +/* client will check the size of a module's DSBT before it writes a copy */ +/* of the master DSBT to the module's DSBT. If the module's DSBT is not */ +/* big enough, an error will be emitted and the load will fail. */ +/* */ +/*---------------------------------------------------------------------------*/ +uint32_t DLOAD_get_dsbt_size(DLOAD_HANDLE handle, int32_t file_handle); + +/*---------------------------------------------------------------------------*/ +/* DLOAD_get_dsbt_base() */ +/* */ +/* Find DSBT address for specified file. The client will query for this */ +/* address after allocation and symbol relocation has been completed. */ +/* The client will write a copy of the master DSBT to the returned DSBT */ +/* address if the module's DSBT size is big enough. */ +/* */ +/*---------------------------------------------------------------------------*/ +BOOL DLOAD_get_dsbt_base(DLOAD_HANDLE handle, int32_t file_handle, + TARGET_ADDRESS *dsbt_base); + +/*---------------------------------------------------------------------------*/ +/* DLOAD_get_static_base() */ +/* */ +/* Find static base for a specified file. The client will query for this */ +/* address after allocation and symbol relocation has been completed. */ +/* The client will use the returned static base value to fill the slot */ +/* in the master DSBT that is associated with this module. */ +/* */ +/*---------------------------------------------------------------------------*/ +BOOL DLOAD_get_static_base(DLOAD_HANDLE handle, int32_t file_handle, + TARGET_ADDRESS *static_base); + + +/*****************************************************************************/ +/* Client Side of DSBT Support */ +/*****************************************************************************/ + +/*---------------------------------------------------------------------------*/ +/* DLIF_register_dsbt_index_request() */ +/* */ +/* Register a request for a DSBT index with the client. A module can */ +/* make a specific DSBT index request or it can allow the client to */ +/* assign a DSBT index on its behalf (requested_dsbt_index == -1). The */ +/* client implementation of this function must check that a specific DSBT */ +/* index request does not conflict with a previous specific DSBT index */ +/* request. */ +/* */ +/*---------------------------------------------------------------------------*/ +BOOL DLIF_register_dsbt_index_request(DLOAD_HANDLE handle, + const char *requestor_name, + int32_t requestor_file_handle, + int32_t requested_dsbt_index); + +/*---------------------------------------------------------------------------*/ +/* DLIF_assign_dsbt_indices() */ +/* */ +/* Bind each module that registered a request for a DSBT index to a */ +/* specific slot in the DSBT. Specific requests for DSBT indices will be */ +/* honored first. Any general requests that remain will be assigned to */ +/* the first available slot in the DSBT. */ +/* */ +/*---------------------------------------------------------------------------*/ +void DLIF_assign_dsbt_indices(void); + +/*---------------------------------------------------------------------------*/ +/* DLIF_get_dsbt_index() */ +/* */ +/* Given a module that uses the DSBT model, return the identity of the */ +/* DSBT slot that was assigned to it by the client. This function can */ +/* only be called after the client has assigned DSBT indices to all */ +/* loaded object modules that use the DSBT model. The implementation of */ +/* this function will check that a proper DSBT index has been assigned to */ +/* the specified module and an invalid index (-1) if there is a problem. */ +/* */ +/*---------------------------------------------------------------------------*/ +int32_t DLIF_get_dsbt_index(int32_t file_handle); + +/*---------------------------------------------------------------------------*/ +/* DLIF_update_all_dsbts() */ +/* */ +/* Populate the client's model of the master DSBT with the static base */ +/* for each assigned slot in the DSBT, then write a copy of the master */ +/* DSBT to each module's DSBT location. The implementation of this */ +/* function must check the size of each module's DSBT to make sure that */ +/* it is large enough to hold a copy of the master DSBT. The function */ +/* will return FALSE if there is a problem. */ +/* */ +/*---------------------------------------------------------------------------*/ +BOOL DLIF_update_all_dsbts(void); + +#endif diff --git a/src/core/dsp/ocl_load/DLOAD_SYM/symtab.c b/src/core/dsp/ocl_load/DLOAD_SYM/symtab.c new file mode 100644 index 0000000..fbcdbeb --- /dev/null +++ b/src/core/dsp/ocl_load/DLOAD_SYM/symtab.c @@ -0,0 +1,417 @@ +/* +* symtab.c +* +* Symbol table creation, maintenance, and management. This module also +* contains implementations of local and global symbol table lookup +* algorithms, as appropriate for the platform that we are running on +* (assumed to be DSP Bridge or Linux model, indicated by +* direct_dependent_only flag in a given Module). +* +* Copyright (C) 2009-2014 Texas Instruments Incorporated - http://www.ti.com/ +* +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +*/ + +#include "elf32.h" +#include "ArrayList.h" + +/*---------------------------------------------------------------------------*/ +/* Set up a Queue of Int32 type data objects. */ +/*---------------------------------------------------------------------------*/ +#include "Queue.h" +TYPE_QUEUE_DEFINITION(int32_t, Int32) +TYPE_QUEUE_IMPLEMENTATION(int32_t, Int32) + +#include "symtab.h" +#include "dload_api.h" +#include <string.h> + +/*---------------------------------------------------------------------------*/ +/* Holds the handle of the ET_EXEC-type mmodule loaded, if any. */ +/*---------------------------------------------------------------------------*/ +int32_t DLIMP_application_handle = 0; + +/*---------------------------------------------------------------------------*/ +/* Function prototypes */ +/*---------------------------------------------------------------------------*/ +BOOL DLSYM_lookup_global_symtab(const char *sym_name, struct Elf32_Sym *symtab, + Elf32_Word symnum, Elf32_Addr *sym_value); + +/*****************************************************************************/ +/* DLSYM_COPY_GLOBALS() - Copy global symbols from the dynamic module's */ +/* symbol table to the loader's global symbol table. */ +/*****************************************************************************/ +void DLSYM_copy_globals(DLIMP_Dynamic_Module *dyn_module) +{ + Elf32_Word i, global_index, global_symnum; + DLIMP_Loaded_Module *module = dyn_module->loaded_module; + +#if LOADER_DEBUG + if (debugging_on) + DLIF_trace("DLSYM_copy_globals:\n"); +#endif + + /*------------------------------------------------------------------------*/ + /* The dynamic symbol table is sorted so that the local symbols come */ + /* before the global symbols. gsymtab_offset points to the address where */ + /* the first global symbol starts. Only the global symbols need to be */ + /* copied into the persistent info. */ + /*------------------------------------------------------------------------*/ + global_index = dyn_module->gsymtab_offset / sizeof(struct Elf32_Sym); + global_symnum = dyn_module->symnum - global_index; + + /*------------------------------------------------------------------------*/ + /* Create space for the new global symbol table. */ + /*------------------------------------------------------------------------*/ + if (module->gsymtab) + { + DLIF_free(module->gsymtab); + module->gsymtab = NULL; + } + + if (global_symnum > 0) + { + module->gsymtab = DLIF_malloc(sizeof(struct Elf32_Sym) * global_symnum); + + memcpy(module->gsymtab, + &dyn_module->symtab[global_index], + sizeof(struct Elf32_Sym) * global_symnum); + } + module->gsymnum = global_symnum; + + /*------------------------------------------------------------------------*/ + /* Copy the string table part that contains the global symbol names. */ + /*------------------------------------------------------------------------*/ + if (module->gstrtab) + { + DLIF_free(module->gstrtab); + module->gstrtab = NULL; + } + + module->gstrsz = dyn_module->strsz - dyn_module->gstrtab_offset; + if (module->gstrsz) + { + module->gstrtab = DLIF_malloc(module->gstrsz); + + memcpy(module->gstrtab, + dyn_module->strtab + dyn_module->gstrtab_offset, + module->gstrsz); + } + + /*------------------------------------------------------------------------*/ + /* Update the symbol names of the global symbol entries to point to */ + /* the symbol names in the string table. */ + /* NOTE: Note that we don't set the offset into the string table. We */ + /* instead set the full address so that the st_name field can be accessed */ + /* as char *. */ + /*------------------------------------------------------------------------*/ + for (i = 0; i < global_symnum; i++) + { + + Elf32_Word old_offset = dyn_module->symtab[i + global_index].st_name - + (Elf32_Addr) dyn_module->strtab; + Elf32_Word new_offset = old_offset - dyn_module->gstrtab_offset; + struct Elf32_Sym *sym = &((struct Elf32_Sym*)(module->gsymtab))[i]; + sym->st_name = new_offset + (Elf32_Addr)module->gstrtab; + +#if LOADER_DEBUG + if (debugging_on) DLIF_trace("Copying symbol: %s\n", + (char*)dyn_module->symtab[i + global_index].st_name); +#endif + } +} + +/*****************************************************************************/ +/* BREADTH_FIRST_LOOKUP() - Perform a breadth-first search of the Module */ +/* dependency graph to find specified symbol name (sym_name). */ +/*****************************************************************************/ +static BOOL breadth_first_lookup(DLOAD_HANDLE phandle, + const char* sym_name, + int handle, + Elf32_Addr *sym_value) +{ + /*------------------------------------------------------------------------*/ + /* We start this function by putting the specified file handle on the */ + /* file_handle_queue. */ + /*------------------------------------------------------------------------*/ + LOADER_OBJECT *dHandle = (LOADER_OBJECT *)phandle; + Int32_Queue file_handle_queue = TYPE_QUEUE_INITIALIZER; + Int32_enqueue(&file_handle_queue, handle); + + /*------------------------------------------------------------------------*/ + /* While the queue is not empty, keep looking for the symbol. */ + /*------------------------------------------------------------------------*/ + while(file_handle_queue.size) + { + int i; + + /*---------------------------------------------------------------------*/ + /* Set up a pointer to front of the list of loaded files so that we */ + /* can be sure that dependent files will be searched in load order. */ + /*---------------------------------------------------------------------*/ + loaded_module_ptr_Queue_Node* mod_node = + dHandle->DLIMP_loaded_objects.front_ptr; + int* dependencies = (int*)(mod_node->value->dependencies.buf); + + /*---------------------------------------------------------------------*/ + /* Pluck off the file handle at the front of the file_handle_queue. */ + /* We will search this file next. */ + /*---------------------------------------------------------------------*/ + handle = Int32_dequeue(&file_handle_queue); + + /*---------------------------------------------------------------------*/ + /* Locate the Module associated with the current file handle. */ + /*---------------------------------------------------------------------*/ + while (mod_node->value->file_handle != handle) mod_node++; + + /*---------------------------------------------------------------------*/ + /* Search the symbol table of the current file handle's Module. */ + /* If the symbol was found, then we're finished. */ + /*---------------------------------------------------------------------*/ + if (DLSYM_lookup_global_symtab(sym_name, + mod_node->value->gsymtab, + mod_node->value->gsymnum, + sym_value)) + return TRUE; + + /*---------------------------------------------------------------------*/ + /* If our symbol was not in the current Module, then add this Module's */ + /* dependents to the end of the file_handle_queue. */ + /*---------------------------------------------------------------------*/ + for (i = 0; i < mod_node->value->dependencies.size; i++) + Int32_enqueue(&file_handle_queue, dependencies[i]); + } + + /*------------------------------------------------------------------------*/ + /* We didn't find our symbol; return FALSE. */ + /*------------------------------------------------------------------------*/ + return FALSE; +} + +/*****************************************************************************/ +/* DLSYM_global_lookup() - Search the global symbol table to find the */ +/* definition of the given symbol name. */ +/*****************************************************************************/ +BOOL DLSYM_global_lookup(DLOAD_HANDLE handle, + const char *sym_name, + DLIMP_Loaded_Module *loaded_module, + Elf32_Addr *sym_value) +{ + int i = 0; + loaded_module_ptr_Queue_Node* node; + LOADER_OBJECT *dHandle = (LOADER_OBJECT *)handle; + +#if LOADER_DEBUG + if (debugging_on) + DLIF_trace("DLSYM_global_lookup: %s\n", sym_name); +#endif + + /*------------------------------------------------------------------------*/ + /* We will choose a different lookup algorithm based on what kind of */ + /* platform we are supporting. In the Braveheart case, the global symbol */ + /* lookup algorithm searches the base image first, followed by the */ + /* explicit children of the specified Module. */ + /*------------------------------------------------------------------------*/ + if (loaded_module->direct_dependent_only) + { + int* child_handle = (int*)(loaded_module->dependencies.buf); + + /*---------------------------------------------------------------------*/ + /* Spin through list of this Module's dependencies (anything on its */ + /* DT_NEEDED list), searching through each dependent's symbol table */ + /* to find the symbol we are after. */ + /*---------------------------------------------------------------------*/ + for (i = 0; i < loaded_module->dependencies.size; i++) + { + for (node = dHandle->DLIMP_loaded_objects.front_ptr; + node->value->file_handle != child_handle[i]; + node=node->next_ptr); + + /*------------------------------------------------------------------*/ + /* Return true if we find the symbol. */ + /*------------------------------------------------------------------*/ + if (DLSYM_lookup_global_symtab(sym_name, + node->value->gsymtab, + node->value->gsymnum, + sym_value)) + return TRUE; + } + } + + /*------------------------------------------------------------------------*/ + /* In the LINUX model, we will use a breadth-first global symbol lookup */ + /* algorithm. First, the application's global symbol table is searched, */ + /* followed by its children, followed by their children, and so on. */ + /* It is up to the client of this module to set the application handle. */ + /*------------------------------------------------------------------------*/ + else + { + if (breadth_first_lookup(handle, sym_name, DLIMP_application_handle, + sym_value)) + return TRUE; + } + + /*------------------------------------------------------------------------*/ + /* If we got this far, then symbol was not found. */ + /*------------------------------------------------------------------------*/ + DLIF_error(DLET_SYMBOL, "Could not resolve symbol %s!\n", sym_name); + + return FALSE; +} + +/*****************************************************************************/ +/* DLSYM_lookup_symtab() - Lookup the symbol name in the given symbol table. */ +/* Symbol must have specified binding. Return the */ +/* value in sym_value and return TRUE if the lookup */ +/* succeeds. */ +/*****************************************************************************/ +static BOOL DLSYM_lookup_symtab(const char *sym_name, struct Elf32_Sym *symtab, + Elf32_Word symnum, Elf32_Addr *sym_value, + BOOL require_local_binding) +{ + Elf32_Addr sym_idx; + +#if LOADER_DEBUG + if (debugging_on) + DLIF_trace("DLSYM_lookup_symtab, sym to find : %s\n", sym_name); +#endif + + for (sym_idx = 0; sym_idx < symnum; sym_idx++) + { +#if LOADER_DEBUG + if (debugging_on) + DLIF_trace("\tPotential symbol match : %s\n", + (char*)symtab[sym_idx].st_name); +#endif + + if ((symtab[sym_idx].st_shndx != SHN_UNDEF) && ((require_local_binding && + (ELF32_ST_BIND(symtab[sym_idx].st_info) == STB_LOCAL)) || + (!require_local_binding && + (ELF32_ST_BIND(symtab[sym_idx].st_info) != STB_LOCAL))) && + !strcmp(sym_name,(char*)(symtab[sym_idx].st_name))) + { + if (sym_value) *sym_value = symtab[sym_idx].st_value; + return TRUE; + } + } + if (sym_value) *sym_value = 0; + return FALSE; +} + +/*****************************************************************************/ +/* DLSYM_lookup_global_symtab() - Lookup the symbol name in the given symbol */ +/* table. Symbol must have global binding. */ +/* Return the value in sym_value and return */ +/* TRUE if the lookup succeeds. */ +/*****************************************************************************/ +BOOL DLSYM_lookup_global_symtab(const char *sym_name, struct Elf32_Sym *symtab, + Elf32_Word symnum, Elf32_Addr *sym_value) +{ + return DLSYM_lookup_symtab(sym_name, symtab, symnum, sym_value, FALSE); +} + +/*****************************************************************************/ +/* DLSYM_lookup_local_symtab() - Lookup the symbol name in the given symbol */ +/* table. Symbol must have local binding. */ +/* Return the value in sym_value and return */ +/* TRUE if the lookup succeeds. */ +/*****************************************************************************/ +BOOL DLSYM_lookup_local_symtab(const char *sym_name, struct Elf32_Sym *symtab, + Elf32_Word symnum, Elf32_Addr *sym_value) +{ + return DLSYM_lookup_symtab(sym_name, symtab, symnum, sym_value, TRUE); +} + +/*****************************************************************************/ +/* CANONICAL_SYMBOL_LOOKUP() - Find the symbol definition. Look up the local */ +/* symbol table to find the symbol. If it is a */ +/* definition and cannot be pre-empted, return */ +/* it. Otherwise, do a look up in the global */ +/* symbol table that contains the symbol tables */ +/* from all the necessary modules. */ +/*****************************************************************************/ +BOOL DLSYM_canonical_lookup(DLOAD_HANDLE handle, int sym_index, + DLIMP_Dynamic_Module *dyn_module, + Elf32_Addr *sym_value) +{ + /*------------------------------------------------------------------------*/ + /* Lookup the symbol table to get the symbol characteristics. */ + /*------------------------------------------------------------------------*/ + struct Elf32_Sym *sym = &dyn_module->symtab[sym_index]; + int32_t st_bind = ELF32_ST_BIND(sym->st_info); + int32_t st_vis = ELF32_ST_VISIBILITY(sym->st_other); + BOOL is_def = (sym->st_shndx != SHN_UNDEF && + (sym->st_shndx < SHN_LORESERVE || + sym->st_shndx == SHN_ABS || + sym->st_shndx == SHN_COMMON || + sym->st_shndx == SHN_XINDEX)); + const char *sym_name = (char *)sym->st_name; + +#if LOADER_DEBUG + if (debugging_on) + DLIF_trace("DLSYM_canonical_lookup: %d, %s\n", sym_index, sym_name); +#endif + + /*------------------------------------------------------------------------*/ + /* Local symbols and symbol definitions that cannot be pre-empted */ + /* are resolved by the definition in the same module. */ + /*------------------------------------------------------------------------*/ + if (st_bind == STB_LOCAL || st_vis != STV_DEFAULT) + { + /*---------------------------------------------------------------------*/ + /* If it is a local symbol or non-local that cannot be preempted, */ + /* the definition should be found in the same module. If we don't */ + /* find the definition it is an error. */ + /*---------------------------------------------------------------------*/ + if (!is_def) + { + DLIF_error(DLET_SYMBOL, + "Local/non-imported symbol %s definition is not found " + "in module %s!\n", sym_name, dyn_module->name); + return FALSE; + } + else + { + if (sym_value) *sym_value = sym->st_value; + return TRUE; + } + } + /*------------------------------------------------------------------------*/ + /* Else we have either pre-emptable defintion or undef symbol. We need */ + /* to do global look up. */ + /*------------------------------------------------------------------------*/ + else + { + return DLSYM_global_lookup(handle, sym_name, dyn_module->loaded_module, + sym_value); + } +} + diff --git a/src/core/dsp/ocl_load/README b/src/core/dsp/ocl_load/README new file mode 100644 index 0000000..19165f6 --- /dev/null +++ b/src/core/dsp/ocl_load/README @@ -0,0 +1,8 @@ + +This program is dependent on these Standard CVS modules + +C60_DLOAD_DYN: +C60_DLOAD_REL: +DLOAD: +DLOAD_API: +DLOAD_SYM: diff --git a/src/core/dsp/ocl_load/Stack.h b/src/core/dsp/ocl_load/Stack.h new file mode 100644 index 0000000..e958674 --- /dev/null +++ b/src/core/dsp/ocl_load/Stack.h @@ -0,0 +1,182 @@ +/****************************************************************************** + * Copyright (c) 2013-2014, Texas Instruments Incorporated - http://www.ti.com/ + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Texas Instruments Incorporated nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ +/* +* Stack.h +* +* Interface to Stack +* ------------------ +* +* This is an implementation of a type-independent stack implemented as +* a signly linked list class for C. It's basically a template class, but +* uses macros instead, so that it can be compiled with a C-only compiler. +* +* To define a Stack class: +* #include "Stack.h" +* TYPE_STACK_DEFINITION(object_type,Class_Identifier) +* +* In a separate C file: +* #include "Stack.h" +* TYPE_STACK_DEFINITION(object_type,Class_Identifier) +* TYPE_STACK_IMPLEMENTATION(object_type,Class_Identifier) +* +* Now, to create a stack: +* struct Class_Identifier_Stack name; +* Get it initialized to zero everywhere somehow, maybe like this: +* initialize_stack_Class_Identifier(&name); +* +* To add to the stack: +* push_Class_Identifier(&name, object); +* +* To access the top of the stack: +* Class_Identifier_Stack_Node *tos = name.top_ptr; +* do_something_to_(tos->value); +* +* To delete from the stack: +* if (name.size > 0) pop_Class_Identifier(&name); +* +* Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ +* +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the +* distribution. +* +* Neither the name of Texas Instruments Incorporated nor the names of +* its contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +*/ + +#ifndef STACK_H +#define STACK_H + +#include <inttypes.h> +#include "dload_api.h" + +/*****************************************************************************/ +/* TYPE_STACK_DEFINITION() - Define structure specifications for a last-in, */ +/* first-out linked list of t_name objects. */ +/*****************************************************************************/ +#define TYPE_STACK_DEFINITION(t, t_name) \ +struct t_name##_Stack_Node_ \ +{ \ + t value; \ + struct t_name##_Stack_Node_* next_ptr; \ +}; \ +typedef struct t_name##_Stack_Node_ t_name##_Stack_Node; \ + \ +typedef struct \ +{ \ + t_name##_Stack_Node* top_ptr; \ + t_name##_Stack_Node* bottom_ptr; \ + int size; \ +} t_name##_Stack; \ + \ +extern void t_name##_initialize_stack(t_name##_Stack* stack); \ +extern void t_name##_push(t_name##_Stack* stack, t to_push); \ +extern t t_name##_pop(t_name##_Stack* stack); + +/*****************************************************************************/ +/* TYPE_STACK_DEFINITION() - Define the initializer to initalize Stacks. */ +/*****************************************************************************/ +#define TYPE_STACK_INITIALIZER {NULL, NULL, 0 } + +/*****************************************************************************/ +/* TYPE_STACK_IMPLEMENTATION() - Define member functions of new LIFO linked */ +/* list "class" of t_name objects. */ +/* */ +/* <type>_initialize_stack() - clears the stack */ +/* <type>_push() - pushes a <t> type object to the top of the stack */ +/* <type>_pop() - pop a <t> type object from the top of the stack */ +/* and provide access to it to the caller */ +/*****************************************************************************/ +#define TYPE_STACK_IMPLEMENTATION(t, t_name) \ +void t_name##_initialize_stack (t_name##_Stack* stack) \ +{ \ + stack->top_ptr = stack->bottom_ptr = NULL; \ + stack->size = 0; \ +} \ +void t_name##_push(t_name##_Stack* stack, t to_push) \ +{ \ + stack->size++; \ + \ + if(!stack->top_ptr) \ + { \ + stack->bottom_ptr = stack->top_ptr = \ + (t_name##_Stack_Node*)(DLIF_malloc(sizeof(t_name##_Stack_Node))); \ + stack->top_ptr->next_ptr = NULL; \ + } \ + else \ + { \ + t_name##_Stack_Node* next_ptr = stack->top_ptr; \ + stack->top_ptr = \ + (t_name##_Stack_Node*)(DLIF_malloc(sizeof(t_name##_Stack_Node))); \ + stack->top_ptr->next_ptr = next_ptr; \ + } \ + \ + stack->top_ptr->value = to_push; \ +} \ + \ +t t_name##_pop(t_name##_Stack* stack) \ +{ \ + t to_ret; \ + t_name##_Stack_Node* next_ptr = stack->top_ptr->next_ptr; \ + \ + stack->size--; \ + to_ret = stack->top_ptr->value; \ + DLIF_free((void*)(stack->top_ptr)); \ + \ + if(!stack->size) \ + stack->top_ptr = stack->bottom_ptr = NULL; \ + else \ + stack->top_ptr = next_ptr; \ + \ + return to_ret; \ +} + +#endif diff --git a/src/core/dsp/ocl_load/ocl_load.c b/src/core/dsp/ocl_load/ocl_load.c new file mode 100644 index 0000000..c53a137 --- /dev/null +++ b/src/core/dsp/ocl_load/ocl_load.c @@ -0,0 +1,139 @@ +/****************************************************************************** + * Copyright (c) 2013-2014, Texas Instruments Incorporated - http://www.ti.com/ + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Texas Instruments Incorporated nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +#include "dload_api.h" + +#define TYPE_STACK_DEFINITION(t, t_name) +#define TYPE_STACK_IMPLEMENTATION(t, t_name) + +int debugging_on = FALSE; +int profiling_on = FALSE; + +int global_argc; +char **global_argv; + +int DLIF_fseek(LOADER_FILE_DESC *stream, int32_t offset, int origin) + { return fseek(stream, offset, origin); } + + +size_t DLIF_fread(void *ptr, size_t size, size_t nmemb, + LOADER_FILE_DESC *stream) + { return fread(ptr, size, nmemb, stream); } + +int32_t DLIF_ftell (LOADER_FILE_DESC *stream) { return ftell(stream); } +int32_t DLIF_fclose(LOADER_FILE_DESC *fd) { return fclose(fd); } +void* DLIF_malloc(size_t size) { return malloc(size); } +void DLIF_free (void* ptr) { free(ptr); } + +/*****************************************************************************/ +/* DLIF_COPY() - Copy data from file to host-accessible memory. */ +/* Returns a host pointer to the data in the host_address field of the */ +/* DLOAD_MEMORY_REQUEST object. */ +/*****************************************************************************/ +BOOL DLIF_copy(void* client_handle, struct DLOAD_MEMORY_REQUEST* targ_req) +{ + struct DLOAD_MEMORY_SEGMENT* obj_desc = targ_req->segment; + LOADER_FILE_DESC* f = targ_req->fp; + void *buf = calloc(obj_desc->memsz_in_bytes, 1); + + fseek(f, targ_req->offset, SEEK_SET); + + int result = 1; + if (obj_desc->objsz_in_bytes) + result = fread(buf, obj_desc->objsz_in_bytes, 1, f); + + assert(result == 1); + + targ_req->host_address = buf; + + return 1; +} + +BOOL DLIF_read(void* client_handle, + void *ptr, size_t size, size_t nmemb, TARGET_ADDRESS src) + { assert(0); } + +BOOL DLIF_memcpy(void* client_handle, + void *to, void *from, size_t size) + { return (!memcpy(to, from, size)) ? 0 : 1; } + +int32_t DLIF_execute(void* client_handle, + TARGET_ADDRESS exec_addr) { assert(0); return 1; } + + + + +BOOL DLIF_register_dsbt_index_request(DLOAD_HANDLE handle, + const char *requestor_name, + int32_t requestor_file_handle, + int32_t requested_dsbt_index) + { assert(0); } + +void DLIF_assign_dsbt_indices(void) { assert(0); } + +int32_t DLIF_get_dsbt_index(int32_t file_handle) + { assert(0); return DSBT_INDEX_INVALID; } + +BOOL DLIF_update_all_dsbts() { assert(0); return TRUE; } + +void DLIF_warning(LOADER_WARNING_TYPE wtype, const char *fmt, ...) +{ + va_list ap; + va_start(ap,fmt); + printf("<< D L O A D >> WARNING: "); + vprintf(fmt,ap); + va_end(ap); +} + +void DLIF_error(LOADER_ERROR_TYPE etype, const char *fmt, ...) +{ + va_list ap; + va_start(ap,fmt); + printf("<< D L O A D >> ERROR: "); + vprintf(fmt,ap); + va_end(ap); +} + +void DLIF_trace(const char *fmt, ...) +{ + va_list ap; + va_start(ap,fmt); + vprintf(fmt,ap); + va_end(ap); +} + +void DLIF_exit(ecode) +{ + exit(ecode); +} + |