Annotation of prex-old/boot/common/elf.c, Revision 1.1.1.1.2.1
1.1 nbrk 1: /*-
2: * Copyright (c) 2005-2006, 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 co-contributors
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 <prex/bootinfo.h>
36: #include <sys/elf.h>
37: #include <platform.h>
38:
1.1.1.1.2.1! nbrk 39: #ifdef DEBUG_ELF
! 40: #define DPRINTF(a) printf a
! 41: #else
! 42: #define DPRINTF(a) do {} while (0)
! 43: #endif
! 44:
1.1 nbrk 45: extern int nr_img; /* number of images */
46:
47: #define SHF_VALID (SHF_ALLOC | SHF_EXECINSTR | SHF_ALLOC | SHF_WRITE)
48:
49: static char *sect_addr[32]; /* array of section address */
50:
51: static int
52: load_executable(char *img, struct module *m)
53: {
54: Elf32_Ehdr *ehdr;
55: Elf32_Phdr *phdr;
1.1.1.1.2.1! nbrk 56: paddr_t phys_base;
1.1 nbrk 57: int i;
58:
59: phys_base = load_base;
60: ehdr = (Elf32_Ehdr *)img;
1.1.1.1.2.1! nbrk 61: phdr = (Elf32_Phdr *)((paddr_t)ehdr + ehdr->e_phoff);
1.1 nbrk 62: m->phys = load_base;
63: phys_base = load_base;
1.1.1.1.2.1! nbrk 64: DPRINTF(("phys addr=%x\n", phys_base));
1.1 nbrk 65:
66: for (i = 0; i < (int)ehdr->e_phnum; i++, phdr++) {
67: if (phdr->p_type != PT_LOAD)
68: continue;
69:
1.1.1.1.2.1! nbrk 70: DPRINTF(("p_flags=%x\n", (int)phdr->p_flags));
! 71: DPRINTF(("p_align=%x\n", (int)phdr->p_align));
! 72: DPRINTF(("p_paddr=%x\n", (int)phdr->p_paddr));
1.1 nbrk 73:
74: if (i >= 2) {
1.1.1.1.2.1! nbrk 75: DPRINTF(("skipping extra phdr\n"));
1.1 nbrk 76: continue;
77: }
78: if (phdr->p_flags & PF_X) {
79: /* Text */
80: m->text = phdr->p_vaddr;
81: m->textsz = (size_t)phdr->p_memsz;
82: } else {
83: /* Data & BSS */
84: m->data = phdr->p_vaddr;
85: m->datasz = (size_t)phdr->p_filesz;
86: m->bsssz =
87: (size_t)(phdr->p_memsz - phdr->p_filesz);
88: load_base = phys_base + (m->data - m->text);
89: }
90: if (phdr->p_filesz > 0) {
91: memcpy((char *)load_base, img + phdr->p_offset,
92: (size_t)phdr->p_filesz);
1.1.1.1.2.1! nbrk 93: DPRINTF(("load: offset=%x size=%x\n",
! 94: load_base, (int)phdr->p_filesz));
1.1 nbrk 95: }
96: if (!(phdr->p_flags & PF_X)) {
97: if (m->bsssz > 0) {
98: /* Zero fill BSS */
99: memset((char *)load_base + m->datasz,
100: 0, m->bsssz);
101: }
102: load_base += phdr->p_memsz;
103: }
104: }
105: /* workaround for data/bss size is 0 */
106: if (m->data == 0)
107: load_base = phys_base + m->textsz;
108:
109: load_base = PAGE_ALIGN(load_base);
110: m->size = (size_t)(load_base - m->phys);
111: m->entry = ehdr->e_entry;
1.1.1.1.2.1! nbrk 112: DPRINTF(("module size=%x entry=%x\n", m->size, m->entry));
1.1 nbrk 113: return 0;
114: }
115:
116: static int
117: relocate_section_rela(Elf32_Sym *sym_table, Elf32_Rela *rela,
118: char *target_sect, int nr_reloc)
119: {
120: Elf32_Sym *sym;
121: Elf32_Addr sym_val;
122: int i;
123:
124: for (i = 0; i < nr_reloc; i++) {
125: sym = &sym_table[ELF32_R_SYM(rela->r_info)];
126: if (sym->st_shndx != STN_UNDEF) {
127: sym_val = (Elf32_Addr)sect_addr[sym->st_shndx]
128: + sym->st_value;
129: if (relocate_rela(rela, sym_val, target_sect) != 0)
130: return -1;
131: } else if (ELF32_ST_BIND(sym->st_info) != STB_WEAK) {
1.1.1.1.2.1! nbrk 132: DPRINTF(("Undefined symbol for rela[%x] sym=%x\n",
! 133: i, sym));
1.1 nbrk 134: return -1;
135: } else {
1.1.1.1.2.1! nbrk 136: DPRINTF(("Undefined weak symbol for rela[%x]\n", i));
1.1 nbrk 137: }
138: rela++;
139: }
140: return 0;
141: }
142:
143: static int
144: relocate_section_rel(Elf32_Sym *sym_table, Elf32_Rel *rel,
145: char *target_sect, int nr_reloc)
146: {
147: Elf32_Sym *sym;
148: Elf32_Addr sym_val;
149: int i;
150:
151: for (i = 0; i < nr_reloc; i++) {
152: sym = &sym_table[ELF32_R_SYM(rel->r_info)];
153: if (sym->st_shndx != STN_UNDEF) {
154: sym_val = (Elf32_Addr)sect_addr[sym->st_shndx]
155: + sym->st_value;
156: if (relocate_rel(rel, sym_val, target_sect) != 0)
157: return -1;
158: } else if (ELF32_ST_BIND(sym->st_info) != STB_WEAK) {
1.1.1.1.2.1! nbrk 159: DPRINTF(("Undefined symbol for rel[%x] sym=%x\n",
! 160: i, sym));
1.1 nbrk 161: return -1;
162: } else {
1.1.1.1.2.1! nbrk 163: DPRINTF(("Undefined weak symbol for rel[%x]\n", i));
1.1 nbrk 164: }
165: rel++;
166: }
167: return 0;
168: }
169:
170: static int
171: relocate_section(char *img, Elf32_Shdr *shdr)
172: {
173: Elf32_Sym *sym_table;
174: char *target_sect;
175: int nr_reloc, err;
176:
177: if (shdr->sh_entsize == 0)
178: return 0;
179: if ((target_sect = sect_addr[shdr->sh_info]) == 0)
180: return -1;
181: if ((sym_table = (Elf32_Sym *)sect_addr[shdr->sh_link]) == 0)
182: return -1;
183:
184: nr_reloc = (int)(shdr->sh_size / shdr->sh_entsize);
185: switch (shdr->sh_type) {
186: case SHT_REL:
187: err = relocate_section_rel(sym_table,
188: (Elf32_Rel *)(img + shdr->sh_offset),
189: target_sect, nr_reloc);
190: break;
191:
192: case SHT_RELA:
193: err = relocate_section_rela(sym_table,
194: (Elf32_Rela *)(img + shdr->sh_offset),
195: target_sect, nr_reloc);
196: break;
197:
198: default:
199: err = -1;
200: break;
201: }
202: return err;
203: }
204:
205: static int
206: load_relocatable(char *img, struct module *m)
207: {
208: Elf32_Ehdr *ehdr;
209: Elf32_Shdr *shdr;
1.1.1.1.2.1! nbrk 210: paddr_t sect_base, bss_base;
1.1 nbrk 211: int i;
212:
213: ehdr = (Elf32_Ehdr *)img;
1.1.1.1.2.1! nbrk 214: shdr = (Elf32_Shdr *)((paddr_t)ehdr + ehdr->e_shoff);
1.1 nbrk 215: bss_base = 0;
216: m->phys = load_base;
1.1.1.1.2.1! nbrk 217: DPRINTF(("phys addr=%x\n", load_base));
1.1 nbrk 218:
219: /* Copy sections */
220: for (i = 0; i < (int)ehdr->e_shnum; i++, shdr++) {
221: sect_addr[i] = 0;
222: if (shdr->sh_type == SHT_PROGBITS) {
223:
1.1.1.1.2.1! nbrk 224: DPRINTF(("sh_addr=%x\n", shdr->sh_addr));
! 225: DPRINTF(("sh_size=%x\n", shdr->sh_size));
! 226: DPRINTF(("sh_offset=%x\n", shdr->sh_offset));
! 227: DPRINTF(("sh_flags=%x\n", shdr->sh_flags));
1.1 nbrk 228:
229: switch (shdr->sh_flags & SHF_VALID) {
230: case (SHF_ALLOC | SHF_EXECINSTR):
231: /* Text */
1.1.1.1.2.1! nbrk 232: m->text = (vaddr_t)phys_to_virt(load_base);
1.1 nbrk 233: break;
234: case (SHF_ALLOC | SHF_WRITE):
235: /* Data */
236: if (m->data == 0)
237: m->data =
1.1.1.1.2.1! nbrk 238: (vaddr_t)phys_to_virt(load_base + shdr->sh_addr);
1.1 nbrk 239: break;
240: case SHF_ALLOC:
241: /* rodata */
242: /* Note: rodata is treated as text. */
243: break;
244: default:
245: continue;
246: }
247: sect_base = load_base + shdr->sh_addr;
248: memcpy((char *)sect_base, img + shdr->sh_offset,
249: (size_t)shdr->sh_size);
1.1.1.1.2.1! nbrk 250: DPRINTF(("load: offset=%x size=%x\n",
! 251: sect_base, (int)shdr->sh_size));
1.1 nbrk 252:
253: sect_addr[i] = (char *)sect_base;
254: } else if (shdr->sh_type == SHT_NOBITS) {
255: /* BSS */
256: m->bsssz = (size_t)shdr->sh_size;
257: sect_base = load_base + shdr->sh_addr;
258: bss_base = sect_base;
259:
260: /* Zero fill BSS */
261: memset((char *)sect_base, 0, (size_t)shdr->sh_size);
262:
263: sect_addr[i] = (char *)sect_base;
264: } else if (shdr->sh_type == SHT_SYMTAB) {
265: /* Symbol table */
266: sect_addr[i] = img + shdr->sh_offset;
267: }
268: }
269: m->textsz = (size_t)(m->data - m->text);
270: m->datasz = (size_t)(bss_base - m->data);
271:
272: load_base = bss_base + m->bsssz;
273: load_base = PAGE_ALIGN(load_base);
274:
1.1.1.1.2.1! nbrk 275: DPRINTF(("module load_base=%x text=%x\n", load_base, m->text));
! 276: m->size = (size_t)(load_base - (paddr_t)virt_to_phys(m->text));
! 277: m->entry = (vaddr_t)phys_to_virt(ehdr->e_entry + m->phys);
! 278: DPRINTF(("module size=%x entry=%x\n", m->size, m->entry));
1.1 nbrk 279:
280: /* Process relocation */
1.1.1.1.2.1! nbrk 281: shdr = (Elf32_Shdr *)((paddr_t)ehdr + ehdr->e_shoff);
1.1 nbrk 282: for (i = 0; i < (int)ehdr->e_shnum; i++, shdr++) {
283: if (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA) {
284: if (relocate_section(img, shdr) != 0)
285: return -1;
286: }
287: }
288: return 0;
289: }
290:
291: /*
292: * Load the program from specified ELF image data stored in memory.
293: * The boot information is filled after loading the program.
294: */
295: int
296: elf_load(char *img, struct module *m)
297: {
298: Elf32_Ehdr *ehdr;
299: Elf32_Phdr *phdr;
300:
1.1.1.1.2.1! nbrk 301: DPRINTF(("\nelf_load\n"));
1.1 nbrk 302:
303: ehdr = (Elf32_Ehdr *)img;
304:
305: /* Check ELF header */
306: if ((ehdr->e_ident[EI_MAG0] != ELFMAG0) ||
307: (ehdr->e_ident[EI_MAG1] != ELFMAG1) ||
308: (ehdr->e_ident[EI_MAG2] != ELFMAG2) ||
309: (ehdr->e_ident[EI_MAG3] != ELFMAG3))
310: return -1;
311:
1.1.1.1.2.1! nbrk 312: phdr = (Elf32_Phdr *)((paddr_t)ehdr + ehdr->e_ehsize);
1.1 nbrk 313:
314: if (nr_img == 0) {
315: /* Initialize the load address */
1.1.1.1.2.1! nbrk 316: load_base = (vaddr_t)phys_to_virt(phdr->p_paddr);
1.1 nbrk 317: if (load_base == 0)
318: return -1;
1.1.1.1.2.1! nbrk 319: DPRINTF(("kernel base=%x\n", load_base));
1.1 nbrk 320: load_start = load_base;
321: }
322: else if (nr_img == 1) {
323: /* Second image => Driver */
1.1.1.1.2.1! nbrk 324: DPRINTF(("driver base=%x\n", load_base));
1.1 nbrk 325: }
326: else {
327: /* Other images => Boot tasks */
1.1.1.1.2.1! nbrk 328: DPRINTF(("task base=%x\n", load_base));
1.1 nbrk 329: }
330:
331: switch (ehdr->e_type) {
332: case ET_EXEC:
333: if (load_executable(img, m) != 0)
334: return -1;
335: break;
336: case ET_REL:
337: if (load_relocatable(img, m) != 0)
338: return -1;
339: break;
340: default:
1.1.1.1.2.1! nbrk 341: DPRINTF(("Unsupported file type\n"));
1.1 nbrk 342: return -1;
343: }
344: nr_img++;
345: return 0;
346: }
CVSweb