scoutos / prex0.9.0 / bsp / boot / common / elf.c @ 03e9c04a
History  View  Annotate  Download (9.78 KB)
1 
/*


2 
* Copyright (c) 20052006, Kohsuke Ohtani

3 
* All rights reserved.

4 
*

5 
* Redistribution and use in source and binary forms, with or without

6 
* modification, are permitted provided that the following conditions

7 
* are met:

8 
* 1. Redistributions of source code must retain the above copyright

9 
* notice, this list of conditions and the following disclaimer.

10 
* 2. Redistributions in binary form must reproduce the above copyright

11 
* notice, this list of conditions and the following disclaimer in the

12 
* documentation and/or other materials provided with the distribution.

13 
* 3. Neither the name of the author nor the names of any cocontributors

14 
* may be used to endorse or promote products derived from this software

15 
* without specific prior written permission.

16 
*

17 
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND

18 
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE

19 
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE

20 
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE

21 
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL

22 
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS

23 
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)

24 
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT

25 
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY

26 
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF

27 
* SUCH DAMAGE.

28 
*/

29  
30 
/*

31 
* elf.c  ELF file format support

32 
*/

33  
34 
#include <boot.h> 
35 
#include <load.h> 
36 
#include <sys/elf.h> 
37 
#include <elf_reloc.h> 
38  
39 
/* forward declarations */

40 
static int load_executable(char *, struct module *); 
41 
static int load_relocatable(char *, struct module *); 
42  
43 
#define SHF_VALID (SHF_ALLOC  SHF_EXECINSTR  SHF_ALLOC  SHF_WRITE)

44  
45 
static char *sect_addr[32]; /* array of section address */ 
46 
static int strshndx; /* index of string section */ 
47  
48 
/*

49 
* Load the program from specified ELF image stored in memory.

50 
* The boot information is filled after loading the program.

51 
*/

52 
int

53 
load_elf(char *img, struct module *m) 
54 
{ 
55 
Elf32_Ehdr *ehdr; 
56 
Elf32_Phdr *phdr; 
57  
58 
ELFDBG(("\nelf_load\n"));

59  
60 
ehdr = (Elf32_Ehdr *)img; 
61  
62 
/* Check ELF header */

63 
if ((ehdr>e_ident[EI_MAG0] != ELFMAG0) 

64 
(ehdr>e_ident[EI_MAG1] != ELFMAG1)  
65 
(ehdr>e_ident[EI_MAG2] != ELFMAG2)  
66 
(ehdr>e_ident[EI_MAG3] != ELFMAG3)) { 
67 
DPRINTF(("Invalid ELF image\n"));

68 
return 1; 
69 
} 
70  
71 
phdr = (Elf32_Phdr *)((paddr_t)ehdr + ehdr>e_ehsize); 
72  
73 
if (nr_img == 0) { 
74 
/* Initialize the load address */

75 
load_base = (vaddr_t)ptokv(phdr>p_paddr); 
76 
if (load_base == 0) { 
77 
DPRINTF(("Invalid load address\n"));

78 
return 1; 
79 
} 
80 
ELFDBG(("kernel base=%lx\n", load_base));

81 
load_start = load_base; 
82 
} 
83 
else if (nr_img == 1) { 
84 
/* 2nd image => Driver */

85 
ELFDBG(("driver base=%lx\n", load_base));

86 
} 
87 
else {

88 
/* Other images => Boot tasks */

89 
ELFDBG(("task base=%lx\n", load_base));

90 
} 
91  
92 
switch (ehdr>e_type) {

93 
case ET_EXEC:

94 
if (load_executable(img, m) != 0) 
95 
return 1; 
96 
break;

97 
case ET_REL:

98 
if (load_relocatable(img, m) != 0) 
99 
return 1; 
100 
break;

101 
default:

102 
ELFDBG(("Unsupported file type\n"));

103 
return 1; 
104 
} 
105 
nr_img++; 
106 
return 0; 
107 
} 
108  
109 
static int 
110 
load_executable(char *img, struct module *m) 
111 
{ 
112 
Elf32_Ehdr *ehdr; 
113 
Elf32_Phdr *phdr; 
114 
paddr_t phys_base; 
115 
int i;

116  
117 
phys_base = load_base; 
118 
ehdr = (Elf32_Ehdr *)img; 
119 
phdr = (Elf32_Phdr *)((paddr_t)ehdr + ehdr>e_phoff); 
120 
m>phys = load_base; 
121 
phys_base = load_base; 
122 
ELFDBG(("phys addr=%lx\n", phys_base));

123  
124 
for (i = 0; i < (int)ehdr>e_phnum; i++, phdr++) { 
125 
if (phdr>p_type != PT_LOAD)

126 
continue;

127  
128 
ELFDBG(("p_flags=%x\n", (int)phdr>p_flags)); 
129 
ELFDBG(("p_align=%x\n", (int)phdr>p_align)); 
130 
ELFDBG(("p_paddr=%x\n", phdr>p_paddr));

131  
132 
if (i >= 2) { 
133 
ELFDBG(("skipping extra phdr\n"));

134 
continue;

135 
} 
136 
if (phdr>p_flags & PF_X) {

137 
/* Text */

138 
m>text = phdr>p_vaddr; 
139 
m>textsz = (size_t)phdr>p_memsz; 
140 
} else {

141 
/* Data & BSS */

142 
m>data = phdr>p_vaddr; 
143 
m>datasz = (size_t)phdr>p_filesz; 
144 
m>bsssz = 
145 
(size_t)(phdr>p_memsz  phdr>p_filesz); 
146 
load_base = phys_base + (m>data  m>text); 
147 
} 
148 
if (phdr>p_filesz > 0) { 
149 
memcpy((char *)load_base, img + phdr>p_offset,

150 
(size_t)phdr>p_filesz); 
151 
ELFDBG(("load: offset=%lx size=%x\n",

152 
load_base, (int)phdr>p_filesz));

153 
} 
154 
if (!(phdr>p_flags & PF_X)) {

155 
if (m>bsssz > 0) { 
156 
/* Zero fill BSS */

157 
memset((char *)load_base + m>datasz,

158 
0, m>bsssz);

159 
} 
160 
load_base += phdr>p_memsz; 
161 
} 
162 
} 
163 
/* workaround for data/bss size is 0 */

164 
if (m>data == 0) 
165 
load_base = phys_base + m>textsz; 
166  
167 
load_base = round_page(load_base); 
168 
m>size = (size_t)(load_base  m>phys); 
169 
m>entry = ehdr>e_entry; 
170 
ELFDBG(("module size=%x entry=%lx\n", m>size, m>entry));

171  
172 
if (m>size == 0) 
173 
panic("Module size is 0!");

174 
return 0; 
175 
} 
176  
177 
static int 
178 
relocate_section_rela(Elf32_Sym *sym_table, Elf32_Rela *rela, 
179 
char *target_sect, int nr_reloc, char *strtab) 
180 
{ 
181 
Elf32_Sym *sym; 
182 
Elf32_Addr sym_val; 
183 
int i;

184  
185 
for (i = 0; i < nr_reloc; i++) { 
186 
sym = &sym_table[ELF32_R_SYM(rela>r_info)]; 
187 
ELFDBG(("%s\n", strtab + sym>st_name));

188 
if (sym>st_shndx != STN_UNDEF) {

189 
sym_val = (Elf32_Addr)sect_addr[sym>st_shndx] 
190 
+ sym>st_value; 
191 
if (relocate_rela(rela, sym_val, target_sect) != 0) 
192 
return 1; 
193 
} else if (ELF32_ST_BIND(sym>st_info) != STB_WEAK) { 
194 
DPRINTF(("Undefined symbol for rela[%x] sym=%lx\n",

195 
i, (long)sym));

196 
return 1; 
197 
} else {

198 
DPRINTF(("Undefined weak symbol for rela[%x]\n", i));

199 
} 
200 
rela++; 
201 
} 
202 
return 0; 
203 
} 
204  
205 
static int 
206 
relocate_section_rel(Elf32_Sym *sym_table, Elf32_Rel *rel, 
207 
char *target_sect, int nr_reloc, char *strtab) 
208 
{ 
209 
Elf32_Sym *sym; 
210 
Elf32_Addr sym_val; 
211 
int i;

212  
213 
for (i = 0; i < nr_reloc; i++) { 
214 
sym = &sym_table[ELF32_R_SYM(rel>r_info)]; 
215 
ELFDBG(("%s\n", strtab + sym>st_name));

216 
if (sym>st_shndx != STN_UNDEF) {

217 
sym_val = (Elf32_Addr)sect_addr[sym>st_shndx] 
218 
+ sym>st_value; 
219 
if (relocate_rel(rel, sym_val, target_sect) != 0) 
220 
return 1; 
221 
} else if (ELF32_ST_BIND(sym>st_info) != STB_WEAK) { 
222 
DPRINTF(("Undefined symbol for rel[%x] sym=%lx\n",

223 
i, (long)sym));

224 
return 1; 
225 
} else {

226 
DPRINTF(("Undefined weak symbol for rel[%x]\n", i));

227 
} 
228 
rel++; 
229 
} 
230 
return 0; 
231 
} 
232  
233 
static int 
234 
relocate_section(char *img, Elf32_Shdr *shdr)

235 
{ 
236 
Elf32_Sym *symtab; 
237 
char *target_sect;

238 
int nr_reloc, error;

239 
char *strtab;

240  
241 
ELFDBG(("relocate_section\n"));

242  
243 
if (shdr>sh_entsize == 0) 
244 
return 0; 
245 
if ((target_sect = sect_addr[shdr>sh_info]) == 0) 
246 
return 1; 
247 
if ((symtab = (Elf32_Sym *)sect_addr[shdr>sh_link]) == 0) 
248 
return 1; 
249 
if ((strtab = sect_addr[strshndx]) == 0) 
250 
return 1; 
251 
ELFDBG(("strtab=%x\n", strtab));

252  
253 
nr_reloc = (int)(shdr>sh_size / shdr>sh_entsize);

254 
switch (shdr>sh_type) {

255 
case SHT_REL:

256 
error = relocate_section_rel(symtab, 
257 
(Elf32_Rel *)(img + shdr>sh_offset), 
258 
target_sect, nr_reloc, strtab); 
259 
break;

260  
261 
case SHT_RELA:

262 
error = relocate_section_rela(symtab, 
263 
(Elf32_Rela *)(img + shdr>sh_offset), 
264 
target_sect, nr_reloc, strtab); 
265 
break;

266  
267 
default:

268 
error = 1;

269 
break;

270 
} 
271 
return error;

272 
} 
273  
274 
static int 
275 
load_relocatable(char *img, struct module *m) 
276 
{ 
277 
Elf32_Ehdr *ehdr; 
278 
Elf32_Shdr *shdr; 
279 
paddr_t sect_base, bss_base; 
280 
int i;

281  
282 
strshndx = 0;

283 
ehdr = (Elf32_Ehdr *)img; 
284 
shdr = (Elf32_Shdr *)((paddr_t)ehdr + ehdr>e_shoff); 
285 
bss_base = 0;

286 
m>phys = load_base; 
287 
ELFDBG(("phys addr=%lx\n", load_base));

288  
289 
/* Copy sections */

290 
for (i = 0; i < (int)ehdr>e_shnum; i++, shdr++) { 
291 
sect_addr[i] = 0;

292 
if (shdr>sh_type == SHT_PROGBITS) {

293  
294 
ELFDBG(("sh_addr=%x\n", shdr>sh_addr));

295 
ELFDBG(("sh_size=%x\n", shdr>sh_size));

296 
ELFDBG(("sh_offset=%x\n", shdr>sh_offset));

297 
ELFDBG(("sh_flags=%x\n", shdr>sh_flags));

298  
299 
switch (shdr>sh_flags & SHF_VALID) {

300 
case (SHF_ALLOC  SHF_EXECINSTR):

301 
/* Text */

302 
m>text = (vaddr_t)ptokv(load_base); 
303 
break;

304 
case (SHF_ALLOC  SHF_WRITE):

305 
/* Data */

306 
if (m>data == 0) { 
307 
m>data = (vaddr_t)ptokv(load_base + 
308 
shdr>sh_addr); 
309 
} 
310 
break;

311 
case SHF_ALLOC:

312 
/* rodata */

313 
/* Note: rodata is treated as text. */

314 
break;

315 
default:

316 
continue;

317 
} 
318 
sect_base = load_base + shdr>sh_addr; 
319 
memcpy((char *)sect_base, img + shdr>sh_offset,

320 
(size_t)shdr>sh_size); 
321 
ELFDBG(("load: offset=%lx size=%x\n",

322 
sect_base, (int)shdr>sh_size));

323  
324 
sect_addr[i] = (char *)sect_base;

325 
} else if (shdr>sh_type == SHT_NOBITS) { 
326 
/* BSS */

327 
m>bsssz = (size_t)shdr>sh_size; 
328 
sect_base = load_base + shdr>sh_addr; 
329 
bss_base = sect_base; 
330  
331 
/* Zero fill BSS */

332 
memset((char *)bss_base, 0, (size_t)shdr>sh_size); 
333  
334 
sect_addr[i] = (char *)sect_base;

335 
} else if (shdr>sh_type == SHT_SYMTAB) { 
336 
/* Symbol table */

337 
ELFDBG(("load: symtab index=%d link=%d\n",

338 
i, shdr>sh_link)); 
339 
sect_addr[i] = img + shdr>sh_offset; 
340 
if (strshndx != 0) 
341 
panic("Multiple symtab found!");

342 
strshndx = (int)shdr>sh_link;

343 
} else if (shdr>sh_type == SHT_STRTAB) { 
344 
/* String table */

345 
sect_addr[i] = img + shdr>sh_offset; 
346 
ELFDBG(("load: strtab index=%d addr=%x\n",

347 
i, sect_addr[i])); 
348 
} 
349 
} 
350 
m>textsz = (size_t)(m>data  m>text); 
351 
m>datasz = (size_t)((char *)ptokv(bss_base)  m>data);

352  
353 
load_base = bss_base + m>bsssz; 
354 
load_base = round_page(load_base); 
355  
356 
ELFDBG(("module load_base=%lx text=%lx\n", load_base, m>text));

357 
m>size = (size_t)(load_base  kvtop(m>text)); 
358 
m>entry = (vaddr_t)ptokv(ehdr>e_entry + m>phys); 
359 
ELFDBG(("module size=%x entry=%lx\n", m>size, m>entry));

360  
361 
/* Process relocation */

362 
shdr = (Elf32_Shdr *)((paddr_t)ehdr + ehdr>e_shoff); 
363 
for (i = 0; i < (int)ehdr>e_shnum; i++, shdr++) { 
364 
if (shdr>sh_type == SHT_REL  shdr>sh_type == SHT_RELA) {

365 
if (relocate_section(img, shdr) != 0) { 
366 
DPRINTF(("Relocation error: module=%s\n", m>name));

367 
return 1; 
368 
} 
369 
} 
370 
} 
371 
return 0; 
372 
} 