|
|
1.1 root 1: /******************************************************************************
2: * Copyright (c) 2004, 2011 IBM Corporation
3: * All rights reserved.
4: * This program and the accompanying materials
5: * are made available under the terms of the BSD License
6: * which accompanies this distribution, and is available at
7: * http://www.opensource.org/licenses/bsd-license.php
8: *
9: * Contributors:
10: * IBM Corporation - initial implementation
11: *****************************************************************************/
12:
13: /*
14: * 32-bit ELF loader
15: */
16:
17: #include <string.h>
18: #include <libelf.h>
19:
20: struct ehdr32 {
21: uint32_t ei_ident;
22: uint8_t ei_class;
23: uint8_t ei_data;
24: uint8_t ei_version;
25: uint8_t ei_pad[9];
26: uint16_t e_type;
27: uint16_t e_machine;
28: uint32_t e_version;
29: uint32_t e_entry;
30: uint32_t e_phoff;
31: uint32_t e_shoff;
32: uint32_t e_flags;
33: uint16_t e_ehsize;
34: uint16_t e_phentsize;
35: uint16_t e_phnum;
36: uint16_t e_shentsize;
37: uint16_t e_shnum;
38: uint16_t e_shstrndx;
39: };
40:
41: struct phdr32 {
42: uint32_t p_type;
43: uint32_t p_offset;
44: uint32_t p_vaddr;
45: uint32_t p_paddr;
46: uint32_t p_filesz;
47: uint32_t p_memsz;
48: uint32_t p_flags;
49: uint32_t p_align;
50: };
51:
52:
53: static struct phdr32*
54: get_phdr32(void *file_addr)
55: {
56: return (struct phdr32 *) (((unsigned char *)file_addr)
57: + ((struct ehdr32 *)file_addr)->e_phoff);
58: }
59:
60: static void
61: load_segment(void *file_addr, struct phdr32 *phdr, signed long offset,
62: int (*pre_load)(void*, long),
63: void (*post_load)(void*, long))
64: {
65: unsigned long src = phdr->p_offset + (unsigned long) file_addr;
66: unsigned long destaddr;
67:
68: destaddr = (unsigned long)phdr->p_paddr;
69: destaddr = destaddr + offset;
70:
71: /* check if we're allowed to copy */
72: if (pre_load != NULL) {
73: if (pre_load((void*)destaddr, phdr->p_memsz) != 0)
74: return;
75: }
76:
77: /* copy into storage */
78: memmove((void *)destaddr, (void *)src, phdr->p_filesz);
79:
80: /* clear bss */
81: memset((void *)(destaddr + phdr->p_filesz), 0,
82: phdr->p_memsz - phdr->p_filesz);
83:
84: if (phdr->p_memsz && post_load) {
85: post_load((void*)destaddr, phdr->p_memsz);
86: }
87: }
88:
89: unsigned int
90: elf_load_segments32(void *file_addr, signed long offset,
91: int (*pre_load)(void*, long),
92: void (*post_load)(void*, long))
93: {
94: struct ehdr32 *ehdr = (struct ehdr32 *) file_addr;
95: /* Calculate program header address */
96: struct phdr32 *phdr = get_phdr32(file_addr);
97: int i;
98: signed int virt2phys = 0; /* Offset between virtual and physical */
99:
100: /* loop e_phnum times */
101: for (i = 0; i <= ehdr->e_phnum; i++) {
102: /* PT_LOAD ? */
103: if (phdr->p_type == 1) {
104: if (!virt2phys) {
105: virt2phys = phdr->p_paddr - phdr->p_vaddr;
106: }
107: /* copy segment */
108: load_segment(file_addr, phdr, offset, pre_load,
109: post_load);
110: }
111: /* step to next header */
112: phdr = (struct phdr32 *)(((uint8_t *)phdr) + ehdr->e_phentsize);
113: }
114:
115: /* Entry point is always a virtual address, so translate it
116: * to physical before returning it */
117: return ehdr->e_entry + virt2phys;
118: }
119:
120: /**
121: * Return the base address for loading (i.e. the address of the first PT_LOAD
122: * segment)
123: * @param file_addr pointer to the ELF file in memory
124: * @return the base address
125: */
126: long
127: elf_get_base_addr32(void *file_addr)
128: {
129: struct ehdr32 *ehdr = (struct ehdr32 *) file_addr;
130: struct phdr32 *phdr = get_phdr32(file_addr);
131: int i;
132:
133: /* loop e_phnum times */
134: for (i = 0; i <= ehdr->e_phnum; i++) {
135: /* PT_LOAD ? */
136: if (phdr->p_type == 1) {
137: return phdr->p_paddr;
138: }
139: /* step to next header */
140: phdr = (struct phdr32 *)(((uint8_t *)phdr) + ehdr->e_phentsize);
141: }
142:
143: return 0;
144: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.