6 static int fixup_rela(struct dyld_info
*info
, const Elf32_Rela
*rela
,
7 Elf32_Addr (*resolve_import
)(const char *),
8 const char **error_out
)
10 const Elf32_Sym
*sym
= NULL
;
11 if(ELF32_R_SYM(rela
->r_info
) != 0)
12 sym
= &info
->symtab
[ELF32_R_SYM(rela
->r_info
)];
15 switch(ELF32_R_TYPE(rela
->r_info
)) {
17 return 1; // Does nothing.
20 value
= info
->base
+ rela
->r_addend
;
26 value
= (Elf32_Addr
)dyld_lookup(&info
->strtab
[sym
->st_name
], info
);
30 value
= resolve_import(&info
->strtab
[sym
->st_name
]);
32 static char error
[256];
33 snprintf(error
, sizeof(error
),
34 "ELF object has an unresolved symbol: %s",
35 &info
->strtab
[sym
->st_name
]);
42 *error_out
= "ELF object uses an unsupported relocation type";
46 memcpy((Elf32_Addr
*)(info
->base
+ rela
->r_offset
), &value
,
52 int dyld_load(const void *shlib
, Elf32_Addr base
,
53 Elf32_Addr (*resolve_import
)(const char *),
54 struct dyld_info
*info
, const char **error_out
)
56 const Elf32_Ehdr
*ehdr
= (const Elf32_Ehdr
*)shlib
;
58 const unsigned char expected_ident
[EI_NIDENT
] = {
59 ELFMAG0
, ELFMAG1
, ELFMAG2
, ELFMAG3
,
60 ELFCLASS32
, ELFDATA2MSB
, EV_CURRENT
,
61 ELFOSABI_NONE
, /* ABI version */ 0
63 if(memcmp(ehdr
->e_ident
, expected_ident
, EI_NIDENT
) ||
64 ehdr
->e_type
!= ET_DYN
) {
65 *error_out
= "ELF object is not a shared library";
70 if(ehdr
->e_machine
!= EM_OPENRISC
) {
71 *error_out
= "ELF object does not contain OpenRISC machine code";
75 #error Unsupported architecture
78 const Elf32_Phdr
*phdr
= (const Elf32_Phdr
*)((intptr_t)shlib
+ ehdr
->e_phoff
);
79 const Elf32_Dyn
*dyn
= NULL
;
80 for(int i
= 0; i
< ehdr
->e_phnum
; i
++) {
81 if(phdr
[i
].p_type
== PT_DYNAMIC
)
82 dyn
= (const Elf32_Dyn
*)((intptr_t)shlib
+ phdr
[i
].p_offset
);
84 memcpy((void*)(base
+ phdr
[i
].p_vaddr
),
85 (const void*)((intptr_t)shlib
+ phdr
[i
].p_offset
),
90 *error_out
= "ELF object does not have a PT_DYNAMIC header";
94 const char *strtab
= NULL
;
95 const Elf32_Sym
*symtab
= NULL
;
96 const Elf32_Rela
*rela
= NULL
, *pltrel
= NULL
;
97 const Elf32_Word
*hash
= NULL
;
99 size_t syment
= sizeof(Elf32_Sym
), relaent
= sizeof(Elf32_Rela
),
100 relanum
= 0, pltrelnum
= 0;
101 while(dyn
->d_tag
!= DT_NULL
) {
103 case DT_STRTAB
: strtab
= (const char *)(base
+ dyn
->d_un
.d_ptr
); break;
104 case DT_SYMTAB
: symtab
= (const Elf32_Sym
*)(base
+ dyn
->d_un
.d_ptr
); break;
105 case DT_SYMENT
: syment
= dyn
->d_un
.d_val
; break;
106 case DT_RELA
: rela
= (const Elf32_Rela
*)(base
+ dyn
->d_un
.d_ptr
); break;
107 case DT_RELAENT
: relaent
= dyn
->d_un
.d_val
; break;
108 case DT_RELASZ
: relanum
= dyn
->d_un
.d_val
/ sizeof(Elf32_Rela
); break;
109 case DT_JMPREL
: pltrel
= (const Elf32_Rela
*)(base
+ dyn
->d_un
.d_ptr
); break;
110 case DT_PLTRELSZ
: pltrelnum
= dyn
->d_un
.d_val
/ sizeof(Elf32_Rela
); break;
111 case DT_HASH
: hash
= (const Elf32_Word
*)(base
+ dyn
->d_un
.d_ptr
); break;
112 case DT_INIT
: init
= dyn
->d_un
.d_val
; break;
115 *error_out
= "ELF object uses Rel relocations, which are not supported";
122 if(symtab
== NULL
|| syment
== 0 || strtab
== NULL
) {
123 *error_out
= "ELF object must contain a symbol table";
127 if(syment
!= sizeof(Elf32_Sym
) || relaent
!= sizeof(Elf32_Rela
)) {
128 *error_out
= "ELF object uses an unknown format for symbols and relocations";
133 info
->init
= (void*)(base
+ init
);
134 info
->strtab
= strtab
;
135 info
->symtab
= symtab
;
136 info
->hash
.nbucket
= hash
[0];
137 info
->hash
.nchain
= hash
[1];
138 info
->hash
.bucket
= &hash
[2];
139 info
->hash
.chain
= &hash
[2 + info
->hash
.nbucket
];
141 for(int i
= 0; i
< relanum
; i
++) {
142 if(!fixup_rela(info
, &rela
[i
], resolve_import
, error_out
))
146 for(int i
= 0; i
< pltrelnum
; i
++) {
147 if(!fixup_rela(info
, &pltrel
[i
], resolve_import
, error_out
))
154 static unsigned long elf_hash(const unsigned char *name
)
156 unsigned long h
= 0, g
;
158 h
= (h
<< 4) + *name
++;
159 if((g
= h
& 0xf0000000)) {
167 void *dyld_lookup(const char *symbol
, struct dyld_info
*info
)
169 unsigned hash
= elf_hash((const unsigned char*) symbol
);
170 unsigned index
= info
->hash
.bucket
[hash
% info
->hash
.nbucket
];
171 while(strcmp(&info
->strtab
[info
->symtab
[index
].st_name
], symbol
)) {
172 if(index
== STN_UNDEF
)
174 index
= info
->hash
.chain
[index
];
177 Elf32_Addr value
= info
->symtab
[index
].st_value
;
179 return (void*)(info
->base
+ value
);