#define R_TILEGX_NUM 130
+/* OR1K relocations */
+#define R_OR1K_NONE 0
+#define R_OR1K_32 1
+#define R_OR1K_16 2
+#define R_OR1K_8 3
+#define R_OR1K_LO_16_IN_INSN 4
+#define R_OR1K_HI_16_IN_INSN 5
+#define R_OR1K_INSN_REL_26 6
+#define R_OR1K_GNU_VTENTRY 7
+#define R_OR1K_GNU_VTINHERIT 8
+#define R_OR1K_32_PCREL 9
+#define R_OR1K_16_PCREL 10
+#define R_OR1K_8_PCREL 11
+#define R_OR1K_GOTPC_HI16 12
+#define R_OR1K_GOTPC_LO16 13
+#define R_OR1K_GOT16 14
+#define R_OR1K_PLT26 15
+#define R_OR1K_GOTOFF_HI16 16
+#define R_OR1K_GOTOFF_LO16 17
+#define R_OR1K_COPY 18
+#define R_OR1K_GLOB_DAT 19
+#define R_OR1K_JMP_SLOT 20
+#define R_OR1K_RELATIVE 21
+#define R_OR1K_TLS_GD_HI16 22
+#define R_OR1K_TLS_GD_LO16 23
+#define R_OR1K_TLS_LDM_HI16 24
+#define R_OR1K_TLS_LDM_LO16 25
+#define R_OR1K_TLS_LDO_HI16 26
+#define R_OR1K_TLS_LDO_LO16 27
+#define R_OR1K_TLS_IE_HI16 28
+#define R_OR1K_TLS_IE_LO16 29
+#define R_OR1K_TLS_LE_HI16 30
+#define R_OR1K_TLS_LE_LO16 31
+#define R_OR1K_TLS_TPOFF 32
+#define R_OR1K_TLS_DTPOFF 33
+#define R_OR1K_TLS_DTPMOD 34
+
+#define R_OR1K_NUM 35
#ifdef __cplusplus
}
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dyld.h>
+
+static int fixup_rela(Elf32_Addr base, Elf32_Rela *rela,
+ const char *strtab, Elf32_Sym *symtab,
+ Elf32_Addr (*resolve_import)(const char *),
+ const char **error_out) {
+ Elf32_Sym *sym = NULL;
+ if(ELF32_R_SYM(rela->r_info) != 0)
+ sym = &symtab[ELF32_R_SYM(rela->r_info)];
+ Elf32_Addr value;
+
+ switch(ELF32_R_TYPE(rela->r_info)) {
+ case R_OR1K_RELATIVE:
+ value = base + (sym ? sym->st_value : 0) + rela->r_addend;
+ break;
+
+ case R_OR1K_JMP_SLOT:
+ value = resolve_import(&strtab[sym->st_name]);
+ if(value == 0) {
+ static char error[256];
+ error[scnprintf(error, sizeof(error), "ELF object has an unresolved symbol: %s",
+ &strtab[sym->st_name])] = 0;
+ *error_out = error;
+ return 0;
+ }
+ break;
+
+ default:
+ *error_out = "ELF object uses an unsupported relocation type";
+ return 0;
+ }
+
+ *(Elf32_Addr*)(base + rela->r_offset) = value;
+
+ return 1;
+}
+
+int dyld_load(void *shlib, Elf32_Addr base,
+ Elf32_Addr (*resolve_import)(const char *),
+ struct dyld_info *info, const char **error_out) {
+ Elf32_Ehdr *ehdr = (Elf32_Ehdr *)shlib;
+
+ const unsigned char expected_ident[EI_NIDENT] = {
+ ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3,
+ ELFCLASS32, ELFDATA2MSB, EV_CURRENT,
+ ELFOSABI_NONE, /* ABI version */ 0
+ };
+ if(memcmp(ehdr->e_ident, expected_ident, EI_NIDENT) ||
+ ehdr->e_type != ET_DYN) {
+ *error_out = "ELF object is not a shared library";
+ return 0;
+ }
+
+#ifdef __or1k__
+ if(ehdr->e_machine != EM_OPENRISC) {
+ *error_out = "ELF object does not contain OpenRISC machine code";
+ return 0;
+ }
+#else
+#error Unsupported architecture
+#endif
+
+ Elf32_Phdr *phdr = (Elf32_Phdr *)((intptr_t)shlib + ehdr->e_phoff);
+ Elf32_Dyn *dyn = NULL;
+ for(int i = 0; i < ehdr->e_phnum; i++) {
+ if(phdr[i].p_type == PT_DYNAMIC)
+ dyn = (Elf32_Dyn *)((intptr_t)shlib + phdr[i].p_offset);
+
+ memcpy((void*)(base + phdr[i].p_vaddr),
+ (void*)((intptr_t)shlib + phdr[i].p_offset),
+ phdr[i].p_filesz);
+ }
+
+ if(dyn == NULL) {
+ *error_out = "ELF object does not have a PT_DYNAMIC header";
+ return 0;
+ }
+
+ char *strtab = NULL;
+ Elf32_Sym *symtab = NULL;
+ Elf32_Rela *rela = NULL, *pltrel = NULL;
+ Elf32_Word *hash = NULL, init = 0;
+ size_t syment = sizeof(Elf32_Sym), relaent = sizeof(Elf32_Rela),
+ relanum = 0, pltrelnum = 0;
+ while(dyn->d_tag != DT_NULL) {
+ switch(dyn->d_tag) {
+ case DT_STRTAB: strtab = (char *)(base + dyn->d_un.d_ptr); break;
+ case DT_SYMTAB: symtab = (Elf32_Sym *)(base + dyn->d_un.d_ptr); break;
+ case DT_SYMENT: syment = dyn->d_un.d_val; break;
+ case DT_RELA: rela = (Elf32_Rela *)(base + dyn->d_un.d_ptr); break;
+ case DT_RELAENT: relaent = dyn->d_un.d_val; break;
+ case DT_RELASZ: relanum = dyn->d_un.d_val / sizeof(Elf32_Rela); break;
+ case DT_JMPREL: pltrel = (Elf32_Rela *)(base + dyn->d_un.d_ptr); break;
+ case DT_PLTRELSZ: pltrelnum = dyn->d_un.d_val / sizeof(Elf32_Rela); break;
+ case DT_HASH: hash = (Elf32_Word *)dyn->d_un.d_val; break;
+ case DT_INIT: init = dyn->d_un.d_val; break;
+
+ case DT_REL:
+ *error_out = "ELF object uses Rel relocations, which are not supported";
+ return 0;
+ }
+
+ ++dyn;
+ }
+
+ if(symtab == NULL || syment == 0 || strtab == NULL) {
+ *error_out = "ELF object must contain a symbol table";
+ return 0;
+ }
+
+ if(syment != sizeof(Elf32_Sym) || relaent != sizeof(Elf32_Rela)) {
+ *error_out = "ELF object uses an unknown format for symbols and relocations";
+ return 0;
+ }
+
+ for(int i = 0; i < relanum; i++) {
+ if(!fixup_rela(base, &rela[i], strtab, symtab, resolve_import, error_out))
+ return 0;
+ }
+
+ for(int i = 0; i < pltrelnum; i++) {
+ if(!fixup_rela(base, &pltrel[i], strtab, symtab, resolve_import, error_out))
+ return 0;
+ }
+
+ info->base = base;
+ info->init = (void*)(base + init);
+ info->strtab = strtab;
+ info->symtab = symtab;
+ info->hash.nbucket = hash[0];
+ info->hash.nchain = hash[1];
+ info->hash.bucket = &hash[2];
+ info->hash.chain = &hash[2 + info->hash.nbucket];
+
+ return 1;
+}
+
+static unsigned long elf_hash(const unsigned char *name)
+{
+ unsigned long h = 0, g;
+ while(*name) {
+ h = (h << 4) + *name++;
+ if((g = h & 0xf0000000)) {
+ h ^= g >> 24;
+ h &= ~g;
+ }
+ }
+ return h;
+}
+
+void *dyld_lookup(const char *symbol, struct dyld_info *info) {
+ unsigned hash = elf_hash((const unsigned char*) symbol);
+ unsigned index = info->hash.bucket[hash % info->hash.nbucket];
+ while(strcmp(&info->strtab[info->symtab[index].st_name], symbol) &&
+ info->hash.chain[index] != STN_UNDEF)
+ index = info->hash.chain[index];
+
+ if(info->hash.chain[index] != STN_UNDEF) {
+ return (void*)(info->base + info->symtab[index].st_value);
+ } else {
+ return NULL;
+ }
+}