Subversion Repositories HelenOS

Rev

Rev 2949 | Rev 2962 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 2949 Rev 2961
1
/*
1
/*
2
 * Copyright (c) 2006 Sergey Bondari
2
 * Copyright (c) 2006 Sergey Bondari
3
 * Copyright (c) 2006 Jakub Jermar
3
 * Copyright (c) 2006 Jakub Jermar
4
 * Copyright (c) 2008 Jiri Svoboda
4
 * Copyright (c) 2008 Jiri Svoboda
5
 * All rights reserved.
5
 * All rights reserved.
6
 *
6
 *
7
 * Redistribution and use in source and binary forms, with or without
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
8
 * modification, are permitted provided that the following conditions
9
 * are met:
9
 * are met:
10
 *
10
 *
11
 * - Redistributions of source code must retain the above copyright
11
 * - Redistributions of source code must retain the above copyright
12
 *   notice, this list of conditions and the following disclaimer.
12
 *   notice, this list of conditions and the following disclaimer.
13
 * - Redistributions in binary form must reproduce the above copyright
13
 * - Redistributions in binary form must reproduce the above copyright
14
 *   notice, this list of conditions and the following disclaimer in the
14
 *   notice, this list of conditions and the following disclaimer in the
15
 *   documentation and/or other materials provided with the distribution.
15
 *   documentation and/or other materials provided with the distribution.
16
 * - The name of the author may not be used to endorse or promote products
16
 * - The name of the author may not be used to endorse or promote products
17
 *   derived from this software without specific prior written permission.
17
 *   derived from this software without specific prior written permission.
18
 *
18
 *
19
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
 */
29
 */
30
 
30
 
31
/** @addtogroup generic
31
/** @addtogroup generic
32
 * @{
32
 * @{
33
 */
33
 */
34
 
34
 
35
/**
35
/**
36
 * @file
36
 * @file
37
 * @brief   Kernel ELF loader.
37
 * @brief   Kernel ELF loader.
38
 */
38
 */
39
 
39
 
40
#include <stdio.h>
40
#include <stdio.h>
41
#include <sys/types.h>
41
#include <sys/types.h>
42
#include <align.h>
42
#include <align.h>
43
#include <assert.h>
43
#include <assert.h>
44
#include <as.h>
44
#include <as.h>
45
#include "elf.h"
45
#include "elf.h"
46
 
46
 
47
#define RTLD_BIAS 0x80000
47
#define RTLD_BIAS 0x80000
48
//#define RTLD_BIAS 0
48
//#define RTLD_BIAS 0
49
 
49
 
50
static char *error_codes[] = {
50
static char *error_codes[] = {
51
    "no error",
51
    "no error",
52
    "invalid image",
52
    "invalid image",
53
    "address space error",
53
    "address space error",
54
    "incompatible image",
54
    "incompatible image",
55
    "unsupported image type",
55
    "unsupported image type",
56
    "irrecoverable error"
56
    "irrecoverable error"
57
};
57
};
58
 
58
 
59
static int segment_header(int fd, elf_header_t *elf);
59
static int segment_header(int fd, elf_header_t *elf);
60
static int section_header(elf_section_header_t *entry, elf_header_t *elf);
60
static int section_header(int fd, elf_header_t *elf);
61
static int load_segment(int fd, elf_segment_header_t *entry, elf_header_t *elf);
61
static int load_segment(int fd, elf_segment_header_t *entry, elf_header_t *elf);
62
 
62
 
63
typedef void (*epoint_t)(void);
63
typedef void (*epoint_t)(void);
64
 
64
 
65
/** ELF loader
65
/** ELF loader
66
 *
66
 *
67
 * @param header Pointer to ELF header in memory
67
 * @param header Pointer to ELF header in memory
68
 * @return EE_OK on success
68
 * @return EE_OK on success
69
 */
69
 */
70
unsigned int elf_load(int fd, elf_header_t *header)
70
unsigned int elf_load(int fd, elf_header_t *header)
71
{
71
{
72
    int i, rc;
72
    int i, rc;
73
 
73
 
74
    rc = read(fd, header, sizeof(elf_header_t));
74
    rc = read(fd, header, sizeof(elf_header_t));
75
    if (rc < 0) {
75
    if (rc < 0) {
76
        printf("read error\n");
76
        printf("read error\n");
77
        return EE_INVALID;
77
        return EE_INVALID;
78
    }
78
    }
79
 
79
 
80
    printf("ELF-load:");
80
    printf("ELF-load:");
81
    /* Identify ELF */
81
    /* Identify ELF */
82
    if (header->e_ident[EI_MAG0] != ELFMAG0 ||
82
    if (header->e_ident[EI_MAG0] != ELFMAG0 ||
83
        header->e_ident[EI_MAG1] != ELFMAG1 ||
83
        header->e_ident[EI_MAG1] != ELFMAG1 ||
84
        header->e_ident[EI_MAG2] != ELFMAG2 ||
84
        header->e_ident[EI_MAG2] != ELFMAG2 ||
85
        header->e_ident[EI_MAG3] != ELFMAG3) {
85
        header->e_ident[EI_MAG3] != ELFMAG3) {
86
        printf("invalid header\n");
86
        printf("invalid header\n");
87
        return EE_INVALID;
87
        return EE_INVALID;
88
    }
88
    }
89
   
89
   
90
    /* Identify ELF compatibility */
90
    /* Identify ELF compatibility */
91
    if (header->e_ident[EI_DATA] != ELF_DATA_ENCODING ||
91
    if (header->e_ident[EI_DATA] != ELF_DATA_ENCODING ||
92
        header->e_machine != ELF_MACHINE ||
92
        header->e_machine != ELF_MACHINE ||
93
        header->e_ident[EI_VERSION] != EV_CURRENT ||
93
        header->e_ident[EI_VERSION] != EV_CURRENT ||
94
        header->e_version != EV_CURRENT ||
94
        header->e_version != EV_CURRENT ||
95
        header->e_ident[EI_CLASS] != ELF_CLASS) {
95
        header->e_ident[EI_CLASS] != ELF_CLASS) {
96
        printf("incompatible data/version/class\n");
96
        printf("incompatible data/version/class\n");
97
        return EE_INCOMPATIBLE;
97
        return EE_INCOMPATIBLE;
98
    }
98
    }
99
 
99
 
100
    if (header->e_phentsize != sizeof(elf_segment_header_t))
100
    if (header->e_phentsize != sizeof(elf_segment_header_t))
101
        return EE_INCOMPATIBLE;
101
        return EE_INCOMPATIBLE;
102
 
102
 
103
    if (header->e_shentsize != sizeof(elf_section_header_t))
103
    if (header->e_shentsize != sizeof(elf_section_header_t))
104
        return EE_INCOMPATIBLE;
104
        return EE_INCOMPATIBLE;
105
 
105
 
106
    /* Check if the object type is supported. */
106
    /* Check if the object type is supported. */
107
    if (header->e_type != ET_EXEC && header->e_type != ET_DYN) {
107
    if (header->e_type != ET_EXEC && header->e_type != ET_DYN) {
108
        printf("Object type %d is not supported\n", header->e_type);
108
        printf("Object type %d is not supported\n", header->e_type);
109
        return EE_UNSUPPORTED;
109
        return EE_UNSUPPORTED;
110
    }
110
    }
111
    if (header->e_type == ET_DYN) header->e_entry += RTLD_BIAS;
111
    if (header->e_type == ET_DYN) header->e_entry += RTLD_BIAS;
112
 
112
 
113
    printf("parse segments\n");
113
    printf("parse segments\n");
114
 
114
 
115
    /* Walk through all segment headers and process them. */
115
    /* Walk through all segment headers and process them. */
116
    for (i = 0; i < header->e_phnum; i++) {
116
    for (i = 0; i < header->e_phnum; i++) {
117
 
117
 
118
        /* Seek to start of header */
118
        /* Seek to start of segment header */
119
        lseek(fd, header->e_phoff + i * sizeof(elf_segment_header_t), SEEK_SET);
119
        lseek(fd, header->e_phoff + i * sizeof(elf_segment_header_t),
-
 
120
            SEEK_SET);
120
 
121
 
121
        rc = segment_header(fd, header);
122
        rc = segment_header(fd, header);
122
        if (rc != EE_OK)
123
        if (rc != EE_OK)
123
            return rc;
124
            return rc;
124
    }
125
    }
125
 
126
 
126
    printf("parse sections\n");
127
    printf("parse sections\n");
127
 
128
 
128
    /* Inspect all section headers and proccess them. */
129
    /* Inspect all section headers and proccess them. */
129
    for (i = 0; i < header->e_shnum; i++) {
130
    for (i = 0; i < header->e_shnum; i++) {
130
/*      elf_section_header_t *sechdr;
-
 
131
 
131
 
-
 
132
        /* Seek to start of section header */
132
        sechdr = &((elf_section_header_t *)(((uint8_t *) header) +
133
        lseek(fd, header->e_shoff + i * sizeof(elf_section_header_t),
133
            header->e_shoff))[i];
134
            SEEK_SET);
-
 
135
 
134
        rc = section_header(sechdr, header);
136
        rc = section_header(fd, header);
135
        if (rc != EE_OK)
137
        if (rc != EE_OK)
136
            return rc;*/
138
            return rc;
137
    }
139
    }
138
 
140
 
139
    printf("done\n");
141
    printf("done\n");
140
 
142
 
141
    return EE_OK;
143
    return EE_OK;
142
}
144
}
143
 
145
 
144
/** Print error message according to error code.
146
/** Print error message according to error code.
145
 *
147
 *
146
 * @param rc Return code returned by elf_load().
148
 * @param rc Return code returned by elf_load().
147
 *
149
 *
148
 * @return NULL terminated description of error.
150
 * @return NULL terminated description of error.
149
 */
151
 */
150
char *elf_error(unsigned int rc)
152
char *elf_error(unsigned int rc)
151
{
153
{
152
    assert(rc < sizeof(error_codes) / sizeof(char *));
154
    assert(rc < sizeof(error_codes) / sizeof(char *));
153
 
155
 
154
    return error_codes[rc];
156
    return error_codes[rc];
155
}
157
}
156
 
158
 
157
/** Process segment header.
159
/** Process segment header.
158
 *
160
 *
159
 * @param entry Segment header.
161
 * @param entry Segment header.
160
 * @param elf ELF header.
162
 * @param elf ELF header.
161
 *
163
 *
162
 * @return EE_OK on success, error code otherwise.
164
 * @return EE_OK on success, error code otherwise.
163
 */
165
 */
164
static int segment_header(int fd, elf_header_t *elf)
166
static int segment_header(int fd, elf_header_t *elf)
165
{
167
{
166
    static elf_segment_header_t entry_buf;
168
    static elf_segment_header_t entry_buf;
167
    elf_segment_header_t *entry = &entry_buf;
169
    elf_segment_header_t *entry = &entry_buf;
168
    int rc;
170
    int rc;
169
 
171
 
170
    rc = read(fd, entry, sizeof(elf_segment_header_t));
172
    rc = read(fd, entry, sizeof(elf_segment_header_t));
171
    if (rc < 0) { printf("read error\n"); return EE_INVALID; }
173
    if (rc < 0) { printf("read error\n"); return EE_INVALID; }
172
 
174
 
173
    switch (entry->p_type) {
175
    switch (entry->p_type) {
174
    case PT_NULL:
176
    case PT_NULL:
175
    case PT_PHDR:
177
    case PT_PHDR:
176
        break;
178
        break;
177
    case PT_LOAD:
179
    case PT_LOAD:
178
        return load_segment(fd, entry, elf);
180
        return load_segment(fd, entry, elf);
179
        break;
181
        break;
180
    case PT_DYNAMIC:
182
    case PT_DYNAMIC:
181
    case PT_INTERP:
183
    case PT_INTERP:
182
    case PT_SHLIB:
184
    case PT_SHLIB:
183
    case PT_NOTE:
185
    case PT_NOTE:
184
    case PT_LOPROC:
186
    case PT_LOPROC:
185
    case PT_HIPROC:
187
    case PT_HIPROC:
186
    default:
188
    default:
187
        printf("segment p_type %d unknown\n", entry->p_type);
189
        printf("segment p_type %d unknown\n", entry->p_type);
188
        return EE_UNSUPPORTED;
190
        return EE_UNSUPPORTED;
189
        break;
191
        break;
190
    }
192
    }
191
    return EE_OK;
193
    return EE_OK;
192
}
194
}
193
 
195
 
194
/** Load segment described by program header entry.
196
/** Load segment described by program header entry.
195
 *
197
 *
196
 * @param entry Program header entry describing segment to be loaded.
198
 * @param entry Program header entry describing segment to be loaded.
197
 * @param elf ELF header.
199
 * @param elf ELF header.
198
 *
200
 *
199
 * @return EE_OK on success, error code otherwise.
201
 * @return EE_OK on success, error code otherwise.
200
 */
202
 */
201
int load_segment(int fd, elf_segment_header_t *entry, elf_header_t *elf)
203
int load_segment(int fd, elf_segment_header_t *entry, elf_header_t *elf)
202
{
204
{
203
    void *a;
205
    void *a;
204
    int flags = 0;
206
    int flags = 0;
205
    uintptr_t bias;
207
    uintptr_t bias;
206
    int rc;
208
    int rc;
207
 
209
 
208
    printf("load segment at addr 0x%x, size 0x%x\n", entry->p_vaddr,
210
    printf("load segment at addr 0x%x, size 0x%x\n", entry->p_vaddr,
209
        entry->p_memsz);
211
        entry->p_memsz);
210
   
212
   
211
    bias = (elf->e_type == ET_DYN) ? RTLD_BIAS : 0;
213
    bias = (elf->e_type == ET_DYN) ? RTLD_BIAS : 0;
212
 
214
 
213
    if (entry->p_align > 1) {
215
    if (entry->p_align > 1) {
214
        if ((entry->p_offset % entry->p_align) !=
216
        if ((entry->p_offset % entry->p_align) !=
215
            (entry->p_vaddr % entry->p_align)) {
217
            (entry->p_vaddr % entry->p_align)) {
216
            printf("align check 1 failed offset%%align=%d, vaddr%%align=%d\n",
218
            printf("align check 1 failed offset%%align=%d, vaddr%%align=%d\n",
217
            entry->p_offset % entry->p_align,
219
            entry->p_offset % entry->p_align,
218
            entry->p_vaddr % entry->p_align
220
            entry->p_vaddr % entry->p_align
219
            );
221
            );
220
            return EE_INVALID;
222
            return EE_INVALID;
221
        }
223
        }
222
    }
224
    }
223
 
225
 
224
/*  if (entry->p_flags & PF_X)
226
/*  if (entry->p_flags & PF_X)
225
        flags |= AS_AREA_EXEC;
227
        flags |= AS_AREA_EXEC;
226
    if (entry->p_flags & PF_W)
228
    if (entry->p_flags & PF_W)
227
        flags |= AS_AREA_WRITE;
229
        flags |= AS_AREA_WRITE;
228
    if (entry->p_flags & PF_R)
230
    if (entry->p_flags & PF_R)
229
        flags |= AS_AREA_READ;
231
        flags |= AS_AREA_READ;
230
    flags |= AS_AREA_CACHEABLE;
232
    flags |= AS_AREA_CACHEABLE;
231
*/
233
*/
232
    /* FIXME: Kernel won't normally allow this, unless you "patch" it */
234
    /* FIXME: Kernel won't normally allow this, unless you "patch" it */
233
//  flags = AS_AREA_READ | AS_AREA_WRITE | AS_AREA_EXEC | AS_AREA_CACHEABLE;
235
//  flags = AS_AREA_READ | AS_AREA_WRITE | AS_AREA_EXEC | AS_AREA_CACHEABLE;
234
    flags = AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE;
236
    flags = AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE;
235
 
237
 
236
    /*
238
    /*
237
     * Check if the virtual address starts on page boundary.
239
     * Check if the virtual address starts on page boundary.
238
     */
240
     */
239
    if (ALIGN_UP(entry->p_vaddr, PAGE_SIZE) != entry->p_vaddr) {
241
    if (ALIGN_UP(entry->p_vaddr, PAGE_SIZE) != entry->p_vaddr) {
240
        printf("align check 2 failed - not page-aligned\n");
242
        printf("align check 2 failed - not page-aligned\n");
241
        printf("vaddr = 0x%x, should be 0x%x\n",
243
        printf("vaddr = 0x%x, should be 0x%x\n",
242
            entry->p_vaddr, ALIGN_UP(entry->p_vaddr, PAGE_SIZE));
244
            entry->p_vaddr, ALIGN_UP(entry->p_vaddr, PAGE_SIZE));
243
        return EE_UNSUPPORTED;
245
        return EE_UNSUPPORTED;
244
    }
246
    }
245
   
247
   
246
    printf("map to p_vaddr=0x%x-0x%x...\n", entry->p_vaddr + bias,
248
    printf("map to p_vaddr=0x%x-0x%x...\n", entry->p_vaddr + bias,
247
    entry->p_vaddr + bias + ALIGN_UP(entry->p_memsz, PAGE_SIZE));
249
    entry->p_vaddr + bias + ALIGN_UP(entry->p_memsz, PAGE_SIZE));
248
 
250
 
249
    a = as_area_create((uint8_t *)entry->p_vaddr + bias,
251
    a = as_area_create((uint8_t *)entry->p_vaddr + bias,
250
        entry->p_memsz, flags);
252
        entry->p_memsz, flags);
251
    if (a == (void *)(-1)) {
253
    if (a == (void *)(-1)) {
252
        printf("memory mapping failed\n");
254
        printf("memory mapping failed\n");
253
        return EE_MEMORY;
255
        return EE_MEMORY;
254
    }
256
    }
255
 
257
 
256
    printf("as_area_create(0x%x, 0x%x, %d) -> 0x%x\n",
258
    printf("as_area_create(0x%x, 0x%x, %d) -> 0x%x\n",
257
        entry->p_vaddr+bias, entry->p_memsz, flags, (unsigned)a);
259
        entry->p_vaddr+bias, entry->p_memsz, flags, (unsigned)a);
258
 
260
 
259
    /*
261
    /*
260
     * Load segment data
262
     * Load segment data
261
     */
263
     */
262
    printf("seek to %d\n", entry->p_offset);
264
    printf("seek to %d\n", entry->p_offset);
263
    rc = lseek(fd, entry->p_offset, SEEK_SET);
265
    rc = lseek(fd, entry->p_offset, SEEK_SET);
264
    if (rc < 0) { printf("seek error\n"); return EE_INVALID; }
266
    if (rc < 0) { printf("seek error\n"); return EE_INVALID; }
265
 
267
 
266
    printf("read 0x%x bytes to address 0x%x\n", entry->p_filesz, entry->p_vaddr+bias);
268
    printf("read 0x%x bytes to address 0x%x\n", entry->p_filesz, entry->p_vaddr+bias);
267
/*  rc = read(fd, (void *)(entry->p_vaddr + bias), entry->p_filesz);
269
/*  rc = read(fd, (void *)(entry->p_vaddr + bias), entry->p_filesz);
268
    if (rc < 0) { printf("read error\n"); return EE_INVALID; }*/
270
    if (rc < 0) { printf("read error\n"); return EE_INVALID; }*/
269
    unsigned left, now;
271
    unsigned left, now;
270
    uint8_t *dp;
272
    uint8_t *dp;
271
 
273
 
272
    left = entry->p_filesz;
274
    left = entry->p_filesz;
273
    dp = (uint8_t *)(entry->p_vaddr + bias);
275
    dp = (uint8_t *)(entry->p_vaddr + bias);
274
 
276
 
275
    while (left > 0) {
277
    while (left > 0) {
276
        now = 4096;
278
        now = 4096;
277
        if (now > left) now=left;
279
        if (now > left) now=left;
278
        printf("read %d...", now);
280
        printf("read %d...", now);
279
        rc = read(fd, dp, now);
281
        rc = read(fd, dp, now);
280
        if (rc < 0) { printf("read error\n"); return EE_INVALID; }
282
        if (rc < 0) { printf("read error\n"); return EE_INVALID; }
281
        printf("->%d\n", rc);
283
        printf("->%d\n", rc);
282
        left -= now;
284
        left -= now;
283
        dp += now;
285
        dp += now;
284
    }
286
    }
285
 
287
 
286
    return EE_OK;
288
    return EE_OK;
287
}
289
}
288
 
290
 
289
/** Process section header.
291
/** Process section header.
290
 *
292
 *
291
 * @param entry Segment header.
293
 * @param entry Segment header.
292
 * @param elf ELF header.
294
 * @param elf ELF header.
293
 *
295
 *
294
 * @return EE_OK on success, error code otherwise.
296
 * @return EE_OK on success, error code otherwise.
295
 */
297
 */
296
static int section_header(elf_section_header_t *entry, elf_header_t *elf)
298
static int section_header(int fd, elf_header_t *elf)
297
{
299
{
-
 
300
    static elf_section_header_t entry_buf;
-
 
301
    elf_section_header_t *entry = &entry_buf;
-
 
302
    int rc;
-
 
303
 
-
 
304
    rc = read(fd, entry, sizeof(elf_section_header_t));
-
 
305
    if (rc < 0) { printf("read error\n"); return EE_INVALID; }
-
 
306
 
298
    switch (entry->sh_type) {
307
    switch (entry->sh_type) {
299
    case SHT_PROGBITS:
308
    case SHT_PROGBITS:
300
        if (entry->sh_flags & SHF_TLS) {
309
        if (entry->sh_flags & SHF_TLS) {
301
            /* .tdata */
310
            /* .tdata */
302
        }
311
        }
303
        break;
312
        break;
304
    case SHT_NOBITS:
313
    case SHT_NOBITS:
305
        if (entry->sh_flags & SHF_TLS) {
314
        if (entry->sh_flags & SHF_TLS) {
306
            /* .tbss */
315
            /* .tbss */
307
        }
316
        }
308
        break;
317
        break;
-
 
318
    case SHT_DYNAMIC:
-
 
319
        printf("dynamic section found\n");
-
 
320
        break;
309
    default:
321
    default:
310
        break;
322
        break;
311
    }
323
    }
312
   
324
   
313
    return EE_OK;
325
    return EE_OK;
314
}
326
}
315
 
327
 
316
/** @}
328
/** @}
317
 */
329
 */
318
 
330