diff options
author | Amaury Pouly <pamaury@rockbox.org> | 2011-07-02 02:12:01 +0000 |
---|---|---|
committer | Amaury Pouly <pamaury@rockbox.org> | 2011-07-02 02:12:01 +0000 |
commit | fed77808c5b3efa1a8e6ac10647845da6847f48a (patch) | |
tree | a3ebe987b86806d270032937eb1a9eb563174d9d /utils | |
parent | 337e922685d11f80fa9e7b164511e043044b6302 (diff) | |
download | rockbox-fed77808c5b3efa1a8e6ac10647845da6847f48a.tar.gz rockbox-fed77808c5b3efa1a8e6ac10647845da6847f48a.zip |
elftosb: support 'strings' in section id, support load binary at address, support call/jump at address
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30110 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'utils')
-rw-r--r-- | utils/sbtools/elftosb.c | 211 |
1 files changed, 182 insertions, 29 deletions
diff --git a/utils/sbtools/elftosb.c b/utils/sbtools/elftosb.c index 58665da16d..38ac0ae32a 100644 --- a/utils/sbtools/elftosb.c +++ b/utils/sbtools/elftosb.c | |||
@@ -164,28 +164,48 @@ static key_array_t read_keys(const char *key_file, int *num_keys) | |||
164 | * Command file parsing | 164 | * Command file parsing |
165 | */ | 165 | */ |
166 | 166 | ||
167 | enum cmd_source_type_t | ||
168 | { | ||
169 | CMD_SRC_UNK, | ||
170 | CMD_SRC_ELF, | ||
171 | CMD_SRC_BIN | ||
172 | }; | ||
173 | |||
174 | struct bin_param_t | ||
175 | { | ||
176 | uint32_t size; | ||
177 | void *data; | ||
178 | }; | ||
179 | |||
167 | struct cmd_source_t | 180 | struct cmd_source_t |
168 | { | 181 | { |
169 | char *identifier; | 182 | char *identifier; |
170 | char *filename; | 183 | char *filename; |
171 | struct cmd_source_t *next; | 184 | struct cmd_source_t *next; |
172 | /* for later use */ | 185 | /* for later use */ |
186 | enum cmd_source_type_t type; | ||
187 | bool bin_loaded; | ||
173 | bool elf_loaded; | 188 | bool elf_loaded; |
174 | struct elf_params_t elf; | 189 | struct elf_params_t elf; |
190 | struct bin_param_t bin; | ||
175 | }; | 191 | }; |
176 | 192 | ||
177 | enum cmd_inst_type_t | 193 | enum cmd_inst_type_t |
178 | { | 194 | { |
179 | CMD_LOAD, | 195 | CMD_LOAD, /* load image */ |
180 | CMD_JUMP, | 196 | CMD_JUMP, /* jump at image */ |
181 | CMD_CALL | 197 | CMD_CALL, /* call image */ |
198 | CMD_LOAD_AT, /* load binary at */ | ||
199 | CMD_CALL_AT, /* call at address */ | ||
200 | CMD_JUMP_AT, /* jump at address */ | ||
182 | }; | 201 | }; |
183 | 202 | ||
184 | struct cmd_inst_t | 203 | struct cmd_inst_t |
185 | { | 204 | { |
186 | enum cmd_inst_type_t type; | 205 | enum cmd_inst_type_t type; |
187 | char *identifier; | 206 | char *identifier; |
188 | uint32_t argument; | 207 | uint32_t argument; // for jump, call |
208 | uint32_t addr; // for 'at' | ||
189 | struct cmd_inst_t *next; | 209 | struct cmd_inst_t *next; |
190 | }; | 210 | }; |
191 | 211 | ||
@@ -213,6 +233,7 @@ enum lexem_type_t | |||
213 | LEX_SEMICOLON, | 233 | LEX_SEMICOLON, |
214 | LEX_LBRACE, | 234 | LEX_LBRACE, |
215 | LEX_RBRACE, | 235 | LEX_RBRACE, |
236 | LEX_RANGLE, | ||
216 | LEX_EOF | 237 | LEX_EOF |
217 | }; | 238 | }; |
218 | 239 | ||
@@ -276,6 +297,34 @@ static void parse_string(char **ptr, char *end, struct lexem_t *lexem) | |||
276 | __parse_string(ptr, end, (void *)&pstr, __parse_string_emit); | 297 | __parse_string(ptr, end, (void *)&pstr, __parse_string_emit); |
277 | } | 298 | } |
278 | 299 | ||
300 | static void parse_ascii_number(char **ptr, char *end, struct lexem_t *lexem) | ||
301 | { | ||
302 | /* skip ' */ | ||
303 | (*ptr)++; | ||
304 | /* we expect 4 character and then ' */ | ||
305 | int len = 0; | ||
306 | uint32_t value = 0; | ||
307 | while(*ptr != end) | ||
308 | { | ||
309 | if(**ptr != '\'') | ||
310 | { | ||
311 | value = value << 8 | **ptr; | ||
312 | len++; | ||
313 | (*ptr)++; | ||
314 | } | ||
315 | else | ||
316 | break; | ||
317 | } | ||
318 | if(*ptr == end || **ptr != '\'') | ||
319 | bug("Unterminated ascii number literal"); | ||
320 | if(len != 1 && len != 2 && len != 4) | ||
321 | bug("Invalid ascii number literal length: only 1, 2 or 4 are valid"); | ||
322 | /* skip ' */ | ||
323 | (*ptr)++; | ||
324 | lexem->type = LEX_NUMBER; | ||
325 | lexem->num = value; | ||
326 | } | ||
327 | |||
279 | static void parse_number(char **ptr, char *end, struct lexem_t *lexem) | 328 | static void parse_number(char **ptr, char *end, struct lexem_t *lexem) |
280 | { | 329 | { |
281 | int base = 10; | 330 | int base = 10; |
@@ -337,9 +386,11 @@ static void next_lexem(char **ptr, char *end, struct lexem_t *lexem) | |||
337 | if(**ptr == ')') ret_simple(LEX_RPAREN, 1); | 386 | if(**ptr == ')') ret_simple(LEX_RPAREN, 1); |
338 | if(**ptr == '{') ret_simple(LEX_LBRACE, 1); | 387 | if(**ptr == '{') ret_simple(LEX_LBRACE, 1); |
339 | if(**ptr == '}') ret_simple(LEX_RBRACE, 1); | 388 | if(**ptr == '}') ret_simple(LEX_RBRACE, 1); |
389 | if(**ptr == '>') ret_simple(LEX_RANGLE, 1); | ||
340 | if(**ptr == '=') ret_simple(LEX_EQUAL, 1); | 390 | if(**ptr == '=') ret_simple(LEX_EQUAL, 1); |
341 | if(**ptr == ';') ret_simple(LEX_SEMICOLON, 1); | 391 | if(**ptr == ';') ret_simple(LEX_SEMICOLON, 1); |
342 | if(**ptr == '"') return parse_string(ptr, end, lexem); | 392 | if(**ptr == '"') return parse_string(ptr, end, lexem); |
393 | if(**ptr == '\'') return parse_ascii_number(ptr, end, lexem); | ||
343 | if(isdigit(**ptr)) return parse_number(ptr, end, lexem); | 394 | if(isdigit(**ptr)) return parse_number(ptr, end, lexem); |
344 | if(isalpha(**ptr) || **ptr == '_') return parse_identifier(ptr, end, lexem); | 395 | if(isalpha(**ptr) || **ptr == '_') return parse_identifier(ptr, end, lexem); |
345 | bug("Unexpected character '%c' in command file\n", **ptr); | 396 | bug("Unexpected character '%c' in command file\n", **ptr); |
@@ -433,6 +484,8 @@ static struct cmd_file_t *read_command_file(const char *file) | |||
433 | bug("invalid command file: ';' expected after string"); | 484 | bug("invalid command file: ';' expected after string"); |
434 | if(find_source_by_id(cmd_file, src->identifier) != NULL) | 485 | if(find_source_by_id(cmd_file, src->identifier) != NULL) |
435 | bug("invalid command file: duplicated source identifier"); | 486 | bug("invalid command file: duplicated source identifier"); |
487 | /* type filled later */ | ||
488 | src->type = CMD_SRC_UNK; | ||
436 | cmd_file->source_list = src; | 489 | cmd_file->source_list = src; |
437 | } | 490 | } |
438 | 491 | ||
@@ -452,9 +505,14 @@ static struct cmd_file_t *read_command_file(const char *file) | |||
452 | if(lexem.type != LEX_LPAREN) | 505 | if(lexem.type != LEX_LPAREN) |
453 | bug("invalid command file: '(' expected after 'section'"); | 506 | bug("invalid command file: '(' expected after 'section'"); |
454 | next(); | 507 | next(); |
455 | if(lexem.type != LEX_NUMBER) | 508 | /* can be a number or a 4 character long string */ |
509 | if(lexem.type == LEX_NUMBER) | ||
510 | { | ||
511 | sec->identifier = lexem.num; | ||
512 | } | ||
513 | else | ||
456 | bug("invalid command file: number expected as section identifier"); | 514 | bug("invalid command file: number expected as section identifier"); |
457 | sec->identifier = lexem.num; | 515 | |
458 | next(); | 516 | next(); |
459 | if(lexem.type != LEX_RPAREN) | 517 | if(lexem.type != LEX_RPAREN) |
460 | bug("invalid command file: ')' expected after section identifier"); | 518 | bug("invalid command file: ')' expected after section identifier"); |
@@ -480,26 +538,62 @@ static struct cmd_file_t *read_command_file(const char *file) | |||
480 | else | 538 | else |
481 | bug("invalid command file: instruction expected in section"); | 539 | bug("invalid command file: instruction expected in section"); |
482 | next(); | 540 | next(); |
483 | if(lexem.type != LEX_IDENTIFIER) | 541 | |
484 | bug("invalid command file: identifier expected after instruction"); | 542 | if(inst->type == CMD_LOAD) |
485 | inst->identifier = lexem.str; | ||
486 | if(find_source_by_id(cmd_file, inst->identifier) == NULL) | ||
487 | bug("invalid command file: undefined reference to source '%s'", inst->identifier); | ||
488 | next(); | ||
489 | if((inst->type == CMD_CALL || inst->type == CMD_JUMP) && lexem.type == LEX_LPAREN) | ||
490 | { | 543 | { |
544 | if(lexem.type != LEX_IDENTIFIER) | ||
545 | bug("invalid command file: identifier expected after instruction"); | ||
546 | inst->identifier = lexem.str; | ||
547 | if(find_source_by_id(cmd_file, inst->identifier) == NULL) | ||
548 | bug("invalid command file: undefined reference to source '%s'", inst->identifier); | ||
491 | next(); | 549 | next(); |
492 | if(lexem.type != LEX_NUMBER) | 550 | if(lexem.type == LEX_RANGLE) |
493 | bug("invalid command file: expected numeral expression after ("); | 551 | { |
494 | inst->argument = lexem.num; | 552 | // load at |
495 | next(); | 553 | inst->type = CMD_LOAD_AT; |
496 | if(lexem.type != LEX_RPAREN) | 554 | next(); |
497 | bug("invalid command file: expected closing brace"); | 555 | if(lexem.type != LEX_NUMBER) |
498 | next(); | 556 | bug("invalid command file: number expected for loading address"); |
557 | inst->addr = lexem.num; | ||
558 | next(); | ||
559 | } | ||
560 | if(lexem.type != LEX_SEMICOLON) | ||
561 | bug("invalid command file: expected ';' after command"); | ||
499 | } | 562 | } |
500 | if(lexem.type != LEX_SEMICOLON) | 563 | else if(inst->type == CMD_CALL || inst->type == CMD_JUMP) |
501 | bug("invalid command file: expected ';' after command"); | 564 | { |
502 | 565 | if(lexem.type == LEX_IDENTIFIER) | |
566 | { | ||
567 | inst->identifier = lexem.str; | ||
568 | if(find_source_by_id(cmd_file, inst->identifier) == NULL) | ||
569 | bug("invalid command file: undefined reference to source '%s'", inst->identifier); | ||
570 | next(); | ||
571 | } | ||
572 | else if(lexem.type == LEX_NUMBER) | ||
573 | { | ||
574 | inst->type = (inst->type == CMD_CALL) ? CMD_CALL_AT : CMD_JUMP_AT; | ||
575 | inst->addr = lexem.num; | ||
576 | next(); | ||
577 | } | ||
578 | else | ||
579 | bug("invalid command file: identifier or number expected after jump/load"); | ||
580 | |||
581 | if(lexem.type == LEX_LPAREN) | ||
582 | { | ||
583 | next(); | ||
584 | if(lexem.type != LEX_NUMBER) | ||
585 | bug("invalid command file: expected numeral expression after ("); | ||
586 | inst->argument = lexem.num; | ||
587 | next(); | ||
588 | if(lexem.type != LEX_RPAREN) | ||
589 | bug("invalid command file: expected closing brace"); | ||
590 | next(); | ||
591 | } | ||
592 | if(lexem.type != LEX_SEMICOLON) | ||
593 | bug("invalid command file: expected ';' after command"); | ||
594 | } | ||
595 | else | ||
596 | bug("die"); | ||
503 | if(end_list == NULL) | 597 | if(end_list == NULL) |
504 | { | 598 | { |
505 | sec->inst_list = inst; | 599 | sec->inst_list = inst; |
@@ -589,8 +683,11 @@ static void load_elf_by_id(struct cmd_file_t *cmd_file, const char *id) | |||
589 | if(src == NULL) | 683 | if(src == NULL) |
590 | bug("undefined reference to source '%s'\n", id); | 684 | bug("undefined reference to source '%s'\n", id); |
591 | /* avoid reloading */ | 685 | /* avoid reloading */ |
592 | if(src->elf_loaded) | 686 | if(src->type == CMD_SRC_ELF && src->elf_loaded) |
593 | return; | 687 | return; |
688 | if(src->type != CMD_SRC_UNK) | ||
689 | bug("source '%s' seen both as elf and binary file", id); | ||
690 | src->type = CMD_SRC_ELF; | ||
594 | int fd = open(src->filename, O_RDONLY); | 691 | int fd = open(src->filename, O_RDONLY); |
595 | if(fd < 0) | 692 | if(fd < 0) |
596 | bug("cannot open '%s' (id '%s')\n", src->filename, id); | 693 | bug("cannot open '%s' (id '%s')\n", src->filename, id); |
@@ -603,6 +700,32 @@ static void load_elf_by_id(struct cmd_file_t *cmd_file, const char *id) | |||
603 | bug("error loading elf file '%s' (id '%s')\n", src->filename, id); | 700 | bug("error loading elf file '%s' (id '%s')\n", src->filename, id); |
604 | } | 701 | } |
605 | 702 | ||
703 | static void load_bin_by_id(struct cmd_file_t *cmd_file, const char *id) | ||
704 | { | ||
705 | struct cmd_source_t *src = find_source_by_id(cmd_file, id); | ||
706 | if(src == NULL) | ||
707 | bug("undefined reference to source '%s'\n", id); | ||
708 | if(src == NULL) | ||
709 | bug("undefined reference to source '%s'\n", id); | ||
710 | /* avoid reloading */ | ||
711 | if(src->type == CMD_SRC_BIN && src->bin_loaded) | ||
712 | return; | ||
713 | if(src->type != CMD_SRC_UNK) | ||
714 | bug("source '%s' seen both as elf and binary file", id); | ||
715 | src->type = CMD_SRC_BIN; | ||
716 | int fd = open(src->filename, O_RDONLY); | ||
717 | if(fd < 0) | ||
718 | bug("cannot open '%s' (id '%s')\n", src->filename, id); | ||
719 | if(g_debug) | ||
720 | printf("Loading BIN file '%s'...\n", src->filename); | ||
721 | src->bin.size = lseek(fd, 0, SEEK_END); | ||
722 | lseek(fd, 0, SEEK_SET); | ||
723 | src->bin.data = xmalloc(src->bin.size); | ||
724 | read(fd, src->bin.data, src->bin.size); | ||
725 | close(fd); | ||
726 | src->bin_loaded = true; | ||
727 | } | ||
728 | |||
606 | static struct sb_file_t *apply_cmd_file(struct cmd_file_t *cmd_file) | 729 | static struct sb_file_t *apply_cmd_file(struct cmd_file_t *cmd_file) |
607 | { | 730 | { |
608 | struct sb_file_t *sb = xmalloc(sizeof(struct sb_file_t)); | 731 | struct sb_file_t *sb = xmalloc(sizeof(struct sb_file_t)); |
@@ -630,17 +753,31 @@ static struct sb_file_t *apply_cmd_file(struct cmd_file_t *cmd_file) | |||
630 | struct cmd_inst_t *cinst = csec->inst_list; | 753 | struct cmd_inst_t *cinst = csec->inst_list; |
631 | while(cinst) | 754 | while(cinst) |
632 | { | 755 | { |
633 | load_elf_by_id(cmd_file, cinst->identifier); | ||
634 | struct elf_params_t *elf = &find_source_by_id(cmd_file, cinst->identifier)->elf; | ||
635 | |||
636 | if(cinst->type == CMD_LOAD) | 756 | if(cinst->type == CMD_LOAD) |
757 | { | ||
758 | load_elf_by_id(cmd_file, cinst->identifier); | ||
759 | struct elf_params_t *elf = &find_source_by_id(cmd_file, cinst->identifier)->elf; | ||
637 | sec->nr_insts += elf_get_nr_sections(elf); | 760 | sec->nr_insts += elf_get_nr_sections(elf); |
761 | } | ||
638 | else if(cinst->type == CMD_JUMP || cinst->type == CMD_CALL) | 762 | else if(cinst->type == CMD_JUMP || cinst->type == CMD_CALL) |
639 | { | 763 | { |
764 | load_elf_by_id(cmd_file, cinst->identifier); | ||
765 | struct elf_params_t *elf = &find_source_by_id(cmd_file, cinst->identifier)->elf; | ||
640 | if(!elf_get_start_addr(elf, NULL)) | 766 | if(!elf_get_start_addr(elf, NULL)) |
641 | bug("cannot jump/call '%s' because it has no starting point !\n", cinst->identifier); | 767 | bug("cannot jump/call '%s' because it has no starting point !\n", cinst->identifier); |
642 | sec->nr_insts++; | 768 | sec->nr_insts++; |
643 | } | 769 | } |
770 | else if(cinst->type == CMD_CALL_AT || cinst->type == CMD_JUMP_AT) | ||
771 | { | ||
772 | sec->nr_insts++; | ||
773 | } | ||
774 | else if(cinst->type == CMD_LOAD_AT) | ||
775 | { | ||
776 | load_bin_by_id(cmd_file, cinst->identifier); | ||
777 | sec->nr_insts++; | ||
778 | } | ||
779 | else | ||
780 | bug("die"); | ||
644 | 781 | ||
645 | cinst = cinst->next; | 782 | cinst = cinst->next; |
646 | } | 783 | } |
@@ -652,10 +789,9 @@ static struct sb_file_t *apply_cmd_file(struct cmd_file_t *cmd_file) | |||
652 | cinst = csec->inst_list; | 789 | cinst = csec->inst_list; |
653 | while(cinst) | 790 | while(cinst) |
654 | { | 791 | { |
655 | struct elf_params_t *elf = &find_source_by_id(cmd_file, cinst->identifier)->elf; | ||
656 | |||
657 | if(cinst->type == CMD_LOAD) | 792 | if(cinst->type == CMD_LOAD) |
658 | { | 793 | { |
794 | struct elf_params_t *elf = &find_source_by_id(cmd_file, cinst->identifier)->elf; | ||
659 | struct elf_section_t *esec = elf->first_section; | 795 | struct elf_section_t *esec = elf->first_section; |
660 | while(esec) | 796 | while(esec) |
661 | { | 797 | { |
@@ -678,10 +814,27 @@ static struct sb_file_t *apply_cmd_file(struct cmd_file_t *cmd_file) | |||
678 | } | 814 | } |
679 | else if(cinst->type == CMD_JUMP || cinst->type == CMD_CALL) | 815 | else if(cinst->type == CMD_JUMP || cinst->type == CMD_CALL) |
680 | { | 816 | { |
817 | struct elf_params_t *elf = &find_source_by_id(cmd_file, cinst->identifier)->elf; | ||
681 | sec->insts[idx].argument = cinst->argument; | 818 | sec->insts[idx].argument = cinst->argument; |
682 | sec->insts[idx].inst = (cinst->type == CMD_JUMP) ? SB_INST_JUMP : SB_INST_CALL; | 819 | sec->insts[idx].inst = (cinst->type == CMD_JUMP) ? SB_INST_JUMP : SB_INST_CALL; |
683 | sec->insts[idx++].addr = elf->start_addr; | 820 | sec->insts[idx++].addr = elf->start_addr; |
684 | } | 821 | } |
822 | else if(cinst->type == CMD_JUMP_AT || cinst->type == CMD_CALL_AT) | ||
823 | { | ||
824 | sec->insts[idx].argument = cinst->argument; | ||
825 | sec->insts[idx].inst = (cinst->type == CMD_JUMP_AT) ? SB_INST_JUMP : SB_INST_CALL; | ||
826 | sec->insts[idx++].addr = cinst->addr; | ||
827 | } | ||
828 | else if(cinst->type == CMD_LOAD_AT) | ||
829 | { | ||
830 | struct bin_param_t *bin = &find_source_by_id(cmd_file, cinst->identifier)->bin; | ||
831 | sec->insts[idx].inst = SB_INST_LOAD; | ||
832 | sec->insts[idx].addr = cinst->addr; | ||
833 | sec->insts[idx].data = bin->data; | ||
834 | sec->insts[idx++].size = bin->size; | ||
835 | } | ||
836 | else | ||
837 | bug("die"); | ||
685 | 838 | ||
686 | cinst = cinst->next; | 839 | cinst = cinst->next; |
687 | } | 840 | } |