~ubuntu-branches/ubuntu/wily/slof/wily

« back to all changes in this revision

Viewing changes to lib/libelf/elf32.c

  • Committer: Package Import Robot
  • Author(s): Aurelien Jarno
  • Date: 2012-09-16 23:05:23 UTC
  • Revision ID: package-import@ubuntu.com-20120916230523-r2ynulqmp2tyu2e5
Tags: upstream-20120217+dfsg
ImportĀ upstreamĀ versionĀ 20120217+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
}