diff options
Diffstat (limited to 'utils/rknanoutils/rkboottool/elf.c')
-rw-r--r-- | utils/rknanoutils/rkboottool/elf.c | 73 |
1 files changed, 43 insertions, 30 deletions
diff --git a/utils/rknanoutils/rkboottool/elf.c b/utils/rknanoutils/rkboottool/elf.c index 481ab98dd6..78b29506a2 100644 --- a/utils/rknanoutils/rkboottool/elf.c +++ b/utils/rknanoutils/rkboottool/elf.c | |||
@@ -21,6 +21,14 @@ | |||
21 | #include "elf.h" | 21 | #include "elf.h" |
22 | #include "misc.h" | 22 | #include "misc.h" |
23 | 23 | ||
24 | static char *strdup(const char *str) | ||
25 | { | ||
26 | int len = strlen(str); | ||
27 | char *s = malloc(len + 1); | ||
28 | memcpy(s, str, len + 1); | ||
29 | return s; | ||
30 | } | ||
31 | |||
24 | /** | 32 | /** |
25 | * Definitions | 33 | * Definitions |
26 | * taken from elf.h linux header | 34 | * taken from elf.h linux header |
@@ -189,43 +197,55 @@ static struct elf_segment_t *elf_add_segment(struct elf_params_t *params) | |||
189 | } | 197 | } |
190 | 198 | ||
191 | void elf_add_load_section(struct elf_params_t *params, | 199 | void elf_add_load_section(struct elf_params_t *params, |
192 | uint32_t load_addr, uint32_t size, const void *section) | 200 | uint32_t load_addr, uint32_t size, const void *section, const char *name) |
193 | { | 201 | { |
194 | struct elf_section_t *sec = elf_add_section(params); | 202 | struct elf_section_t *sec = elf_add_section(params); |
203 | char buffer[32]; | ||
204 | if(name == NULL) | ||
205 | { | ||
206 | sprintf(buffer, ".text%d", params->unique_index++); | ||
207 | name = buffer; | ||
208 | } | ||
195 | 209 | ||
196 | sec->type = EST_LOAD; | 210 | sec->type = EST_LOAD; |
197 | sec->addr = load_addr; | 211 | sec->addr = load_addr; |
198 | sec->size = size; | 212 | sec->size = size; |
199 | sec->section = xmalloc(size); | 213 | sec->section = xmalloc(size); |
214 | sec->name = strdup(name); | ||
200 | memcpy(sec->section, section, size); | 215 | memcpy(sec->section, section, size); |
201 | } | 216 | } |
202 | 217 | ||
203 | void elf_add_fill_section(struct elf_params_t *params, | 218 | void elf_add_fill_section(struct elf_params_t *params, |
204 | uint32_t fill_addr, uint32_t size, uint32_t pattern) | 219 | uint32_t fill_addr, uint32_t size, uint32_t pattern) |
205 | { | 220 | { |
221 | char buffer[32]; | ||
222 | sprintf(buffer, ".bss%d", params->unique_index++); | ||
223 | |||
206 | if(pattern != 0x00) | 224 | if(pattern != 0x00) |
207 | { | 225 | { |
208 | printf("oops, non-zero filling, ignore fill section\n"); | 226 | printf("oops, non-zero filling, ignore fill section\n"); |
209 | return; | 227 | return; |
210 | } | 228 | } |
211 | 229 | ||
212 | struct elf_section_t *sec = elf_add_section(params); | 230 | struct elf_section_t *sec = elf_add_section(params); |
213 | 231 | ||
214 | sec->type = EST_FILL; | 232 | sec->type = EST_FILL; |
215 | sec->addr = fill_addr; | 233 | sec->addr = fill_addr; |
216 | sec->size = size; | 234 | sec->size = size; |
217 | sec->pattern = pattern; | 235 | sec->pattern = pattern; |
236 | sec->name = strdup(buffer); | ||
218 | } | 237 | } |
219 | 238 | ||
220 | void elf_write_file(struct elf_params_t *params, elf_write_fn_t write, | 239 | void elf_write_file(struct elf_params_t *params, elf_write_fn_t write, |
221 | elf_printf_fn_t printf, void *user) | 240 | elf_printf_fn_t printf, void *user) |
222 | { | 241 | { |
223 | (void) printf; | 242 | (void) printf; |
224 | 243 | ||
225 | Elf32_Ehdr ehdr; | 244 | Elf32_Ehdr ehdr; |
226 | uint32_t phnum = 0; | 245 | uint32_t phnum = 0; |
227 | struct elf_section_t *sec = params->first_section; | 246 | struct elf_section_t *sec = params->first_section; |
228 | uint32_t offset = 0; | 247 | uint32_t offset = 0; |
248 | uint32_t strtbl_size = 1; /* offset 0 is for the NULL name */ | ||
229 | Elf32_Phdr phdr; | 249 | Elf32_Phdr phdr; |
230 | Elf32_Shdr shdr; | 250 | Elf32_Shdr shdr; |
231 | memset(&ehdr, 0, EI_NIDENT); | 251 | memset(&ehdr, 0, EI_NIDENT); |
@@ -241,7 +261,9 @@ void elf_write_file(struct elf_params_t *params, elf_write_fn_t write, | |||
241 | { | 261 | { |
242 | sec->offset = 0; | 262 | sec->offset = 0; |
243 | } | 263 | } |
244 | 264 | sec->name_offset = strtbl_size; | |
265 | strtbl_size += strlen(sec->name) + 1; | ||
266 | |||
245 | phnum++; | 267 | phnum++; |
246 | sec = sec->next; | 268 | sec = sec->next; |
247 | } | 269 | } |
@@ -275,16 +297,14 @@ void elf_write_file(struct elf_params_t *params, elf_write_fn_t write, | |||
275 | 297 | ||
276 | write(user, 0, &ehdr, sizeof ehdr); | 298 | write(user, 0, &ehdr, sizeof ehdr); |
277 | 299 | ||
278 | /* allocate enough size to hold any combinaison of .text/.bss in the string table: | 300 | /* the last name offset gives the size of the section, we need to add a small |
279 | * - one empty name ("\0") | 301 | * amount of .shstrtab name */ |
280 | * - at most N names of the form ".textXXXX\0" or ".bssXXXX\0" | 302 | uint32_t shstrtab_index = strtbl_size; |
281 | * - one name ".shstrtab\0" */ | 303 | strtbl_size += strlen(".shstrtab") + 1; |
282 | char *strtbl_content = malloc(1 + strlen(".shstrtab") + 1 + | 304 | char *strtbl_content = malloc(strtbl_size); |
283 | phnum * (strlen(".textXXXX") + 1)); | 305 | /* create NULL and shstrtab names */ |
284 | |||
285 | strtbl_content[0] = '\0'; | 306 | strtbl_content[0] = '\0'; |
286 | strcpy(&strtbl_content[1], ".shstrtab"); | 307 | strcpy(&strtbl_content[shstrtab_index], ".shstrtab"); |
287 | uint32_t strtbl_index = 1 + strlen(".shstrtab") + 1; | ||
288 | 308 | ||
289 | uint32_t data_offset = ehdr.e_ehsize + ehdr.e_phnum * ehdr.e_phentsize + | 309 | uint32_t data_offset = ehdr.e_ehsize + ehdr.e_phnum * ehdr.e_phentsize + |
290 | ehdr.e_shnum * ehdr.e_shentsize; | 310 | ehdr.e_shnum * ehdr.e_shentsize; |
@@ -294,7 +314,8 @@ void elf_write_file(struct elf_params_t *params, elf_write_fn_t write, | |||
294 | while(sec) | 314 | while(sec) |
295 | { | 315 | { |
296 | sec->offset += data_offset; | 316 | sec->offset += data_offset; |
297 | 317 | strcpy(&strtbl_content[sec->name_offset], sec->name); | |
318 | |||
298 | phdr.p_type = PT_LOAD; | 319 | phdr.p_type = PT_LOAD; |
299 | if(sec->type == EST_LOAD) | 320 | if(sec->type == EST_LOAD) |
300 | phdr.p_offset = sec->offset; | 321 | phdr.p_offset = sec->offset; |
@@ -336,21 +357,13 @@ void elf_write_file(struct elf_params_t *params, elf_write_fn_t write, | |||
336 | offset += sizeof(Elf32_Shdr); | 357 | offset += sizeof(Elf32_Shdr); |
337 | } | 358 | } |
338 | 359 | ||
339 | uint32_t text_idx = 0; | ||
340 | uint32_t bss_idx = 0; | ||
341 | while(sec) | 360 | while(sec) |
342 | { | 361 | { |
343 | shdr.sh_name = strtbl_index; | 362 | shdr.sh_name = sec->name_offset; |
344 | if(sec->type == EST_LOAD) | 363 | if(sec->type == EST_LOAD) |
345 | { | ||
346 | strtbl_index += 1 + sprintf(&strtbl_content[strtbl_index], ".text%d", text_idx++); | ||
347 | shdr.sh_type = SHT_PROGBITS; | 364 | shdr.sh_type = SHT_PROGBITS; |
348 | } | ||
349 | else | 365 | else |
350 | { | ||
351 | strtbl_index += 1 + sprintf(&strtbl_content[strtbl_index], ".bss%d", bss_idx++); | ||
352 | shdr.sh_type = SHT_NOBITS; | 366 | shdr.sh_type = SHT_NOBITS; |
353 | } | ||
354 | shdr.sh_flags = SHF_ALLOC | SHF_EXECINSTR; | 367 | shdr.sh_flags = SHF_ALLOC | SHF_EXECINSTR; |
355 | shdr.sh_addr = sec->addr; | 368 | shdr.sh_addr = sec->addr; |
356 | shdr.sh_offset = sec->offset; | 369 | shdr.sh_offset = sec->offset; |
@@ -367,12 +380,12 @@ void elf_write_file(struct elf_params_t *params, elf_write_fn_t write, | |||
367 | } | 380 | } |
368 | 381 | ||
369 | { | 382 | { |
370 | shdr.sh_name = 1; | 383 | shdr.sh_name = shstrtab_index; |
371 | shdr.sh_type = SHT_STRTAB; | 384 | shdr.sh_type = SHT_STRTAB; |
372 | shdr.sh_flags = 0; | 385 | shdr.sh_flags = 0; |
373 | shdr.sh_addr = 0; | 386 | shdr.sh_addr = 0; |
374 | shdr.sh_offset = strtbl_offset + data_offset; | 387 | shdr.sh_offset = strtbl_offset + data_offset; |
375 | shdr.sh_size = strtbl_index; | 388 | shdr.sh_size = strtbl_size; |
376 | shdr.sh_link = SHN_UNDEF; | 389 | shdr.sh_link = SHN_UNDEF; |
377 | shdr.sh_info = 0; | 390 | shdr.sh_info = 0; |
378 | shdr.sh_addralign = 1; | 391 | shdr.sh_addralign = 1; |
@@ -391,7 +404,7 @@ void elf_write_file(struct elf_params_t *params, elf_write_fn_t write, | |||
391 | sec = sec->next; | 404 | sec = sec->next; |
392 | } | 405 | } |
393 | 406 | ||
394 | write(user, strtbl_offset + data_offset, strtbl_content, strtbl_index); | 407 | write(user, strtbl_offset + data_offset, strtbl_content, strtbl_size); |
395 | free(strtbl_content); | 408 | free(strtbl_content); |
396 | } | 409 | } |
397 | 410 | ||
@@ -399,7 +412,7 @@ bool elf_read_file(struct elf_params_t *params, elf_read_fn_t read, | |||
399 | elf_printf_fn_t printf, void *user) | 412 | elf_printf_fn_t printf, void *user) |
400 | { | 413 | { |
401 | #define error_printf(...) ({printf(user, true, __VA_ARGS__); return false;}) | 414 | #define error_printf(...) ({printf(user, true, __VA_ARGS__); return false;}) |
402 | 415 | ||
403 | /* read header */ | 416 | /* read header */ |
404 | Elf32_Ehdr ehdr; | 417 | Elf32_Ehdr ehdr; |
405 | if(!read(user, 0, &ehdr, sizeof(ehdr))) | 418 | if(!read(user, 0, &ehdr, sizeof(ehdr))) |
@@ -459,7 +472,7 @@ bool elf_read_file(struct elf_params_t *params, elf_read_fn_t read, | |||
459 | void *data = xmalloc(shdr.sh_size); | 472 | void *data = xmalloc(shdr.sh_size); |
460 | if(!read(user, shdr.sh_offset, data, shdr.sh_size)) | 473 | if(!read(user, shdr.sh_offset, data, shdr.sh_size)) |
461 | error_printf("error read self section data\n"); | 474 | error_printf("error read self section data\n"); |
462 | elf_add_load_section(params, shdr.sh_addr, shdr.sh_size, data); | 475 | elf_add_load_section(params, shdr.sh_addr, shdr.sh_size, data, NULL); |
463 | free(data); | 476 | free(data); |
464 | 477 | ||
465 | if(strtab) | 478 | if(strtab) |
@@ -476,7 +489,6 @@ bool elf_read_file(struct elf_params_t *params, elf_read_fn_t read, | |||
476 | if(strtab) | 489 | if(strtab) |
477 | printf(user, false, "filter out %s\n", &strtab[shdr.sh_name], shdr.sh_type); | 490 | printf(user, false, "filter out %s\n", &strtab[shdr.sh_name], shdr.sh_type); |
478 | } | 491 | } |
479 | |||
480 | } | 492 | } |
481 | free(strtab); | 493 | free(strtab); |
482 | /* run through segments */ | 494 | /* run through segments */ |
@@ -562,6 +574,7 @@ void elf_release(struct elf_params_t *params) | |||
562 | struct elf_section_t *next_sec = sec->next; | 574 | struct elf_section_t *next_sec = sec->next; |
563 | if(sec->type == EST_LOAD) | 575 | if(sec->type == EST_LOAD) |
564 | free(sec->section); | 576 | free(sec->section); |
577 | free(sec->name); | ||
565 | free(sec); | 578 | free(sec); |
566 | sec = next_sec; | 579 | sec = next_sec; |
567 | } | 580 | } |