/*---------------------------------------------------------------------------* Project: TwlSDK - bin2obj File: cookargs.c Copyright 2005-2008 Nintendo. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Date:: 2008-09-17#$ $Rev: 8556 $ $Author: okubata_ryoma $ *---------------------------------------------------------------------------*/ #include "bin2obj.h" extern const unsigned long SDK_DATE_OF_LATEST_FILE; /*---------------------------------------------------------------------------* Name: cook_args Description: bin2obj main. *---------------------------------------------------------------------------*/ void cook_args(Bin2ObjArgs * t, int argc, char *argv[]) { u16 default_machine; u8 default_endian; int c; static struct option long_options[] = { {"begin", 1, 0, 'b'}, {"end", 1, 0, 'e'}, {"compatible", 0, 0, 'C'}, {"section", 1, 0, 's'}, {"align", 1, 0, 'a'}, {"readonly", 0, 0, 'r'}, {"big-endian", 0, 0, 'B'}, {"little-endian", 0, 0, 'L'}, {"machine", 0, 0, 'm'}, {0, 0, 0, 0} }; memset(t, 0, sizeof(Bin2ObjArgs)); UnpackFileName(argv[0], NULL, &t->app_name, NULL); t->align = DEFAULT_ALIGN; t->writable = DEFALUT_WRITABLE; t->symbol_begin = StrDup(DEFAULT_SYMBOL_BEGIN); t->symbol_end = StrDup(DEFAULT_SYMBOL_END); t->section_rodata = StrDup(DEFAULT_SECTION_RODATA); t->section_rwdata = StrDup(DEFAULT_SECTION_RWDATA); t->machine = 0; t->endian = ELFDATA2UNDEF; default_machine = EM_ARM; default_endian = ELFDATA2LSB; while ((c = getopt_long(argc, argv, "b:e:Cs:a:rBLm:", long_options, NULL)) != -1) { switch (c) { case 'b': if (t->symbol_begin) free(t->symbol_begin); t->symbol_begin = StrDup(optarg); break; case 'e': if (t->symbol_end) free(t->symbol_end); t->symbol_end = StrDup(optarg); break; case 'C': // For Compatibility with CodeWarrior BinToElf if (t->symbol_begin) free(t->symbol_begin); if (t->symbol_end) free(t->symbol_end); t->symbol_begin = StrDup(COMPATIBLE_SYMBOL_BEGIN); t->symbol_end = StrDup(COMPATIBLE_SYMBOL_END); break; case 's': if (t->section_rodata) free(t->section_rodata); if (t->section_rwdata) free(t->section_rwdata); t->section_rodata = StrDup(optarg); t->section_rwdata = StrDup(optarg); break; case 'a': t->align = atoi(optarg); if (t->align < 1) t->align = 1; break; case 'r': t->writable = FALSE; break; case 'B': t->endian = ELFDATA2MSB; // Big Endian default_machine = EM_PPC; break; case 'L': t->endian = ELFDATA2LSB; // Little Endian default_machine = EM_ARM; break; case 'm': if (!strcmp(optarg, "arm")) { t->machine = EM_ARM; default_endian = ELFDATA2LSB; } else if (!strcmp(optarg, "ppc")) { t->machine = EM_PPC; default_endian = ELFDATA2MSB; } break; case '?': case ':': default: goto usage; } } if (optind + 2 != argc) { goto usage; } t->binary_filename = StrDup(argv[optind + 0]); t->object_filename = StrDup(argv[optind + 1]); // Default endian & machine if (t->machine == 0) { t->machine = default_machine; } if (t->endian == ELFDATA2UNDEF) { t->endian = default_endian; } return; usage: { fprintf(stderr, "NITRO/RevoEX Software Development Tool - %s - Binary to Object converter \n" "Build %lu\n\n" "Usage: %s [-b|--begin SYMBOL_BEGIN]\n" " [-e|--end SYMBOL_END]\n" " [-C|--compatible]\n" " [-a|--align ALIGNMENT]\n" " [-r|--readonly]\n" " [-s|--section SECTION]\n" " [-m|--machine [arm|ppc]]\n" " [-B|--big-endian]\n" " [-L|--little-endian] BINARY_FILE OBJECT_FILE\n\n" " -b or --begin Set symbol name for top of binary. (*)\n" " -e or --end Set symbol name for bottom of binary. (*)\n" " -C or --compatible Use compatible symbols with BinToElf.exe.\n" " Same as \"-b _binary_%%f -e _binary_%%f_end\".\n" " -a or --align Set binary data alignment in bytes.\n" " -r or --readonly Handle binary data as readonly.\n" " -s or --section Set section name.\n" " -m or --machine [arm|ppc] Machine arch [arm|ppc].(default=arm)\n" " -B or --big-endian Output in big endian format.\n" " -L or --little-endian Output in little endian format.\n\n" " (*) special %% rules for symbols (ex. binary_file = \"filename.dat\")\n" " %%f,%%t replaced to file name of binary (%%f = \"filename.dat\")\n" " %%b replaced to base name of binary (%%b = \"filename\")\n" " %%e replaced to extension of binary (%%e = \"dat\")\n\n", t->app_name, SDK_DATE_OF_LATEST_FILE, t->app_name); free_args(t); exit(-1); } } /*---------------------------------------------------------------------------* Name: create_symbol_string Description: Creates the symbol name from the binary file name. *---------------------------------------------------------------------------*/ char *create_symbol_string(const char *filename, const char *symbol_format) { char *symbol; char *file_base; char *file_ext; int i; // Analyze the filename and divide into its elements UnpackFileName(filename, NULL, &file_base, &file_ext); // Determine if %f, %b, %e characters are in the format specification, and replace them with the corresponding filename data (main filename, file extension, etc.) // symbol = StrDup(symbol_format); for (i = 0; symbol[i] != '\0'; i++) { if (symbol[i] == '%') { switch (symbol[i + 1]) { case 'b': i = replace_word(&symbol, i, 2, file_base); break; case 'e': i = replace_word(&symbol, i, 2, file_ext); break; case 'f': case 't': i = replace_word(&symbol, i, 2, file_base); i = replace_word(&symbol, i, 0, "."); i = replace_word(&symbol, i, 0, file_ext); break; } } } // If characters that cannot be used as symbols are included, change them to "_" for (i = 0; symbol[i] != '\0'; i++) { if (!isalnum(symbol[i]) && symbol[i] != '_') { symbol[i] = '_'; } } if (isdigit(symbol[i])) { symbol[i] = '_'; // First character cannot be a numeral, either } free(file_base); free(file_ext); return symbol; } /*---------------------------------------------------------------------------* Name: replace_word Description: Replaces string. Arguments: *symbol: String to be replaced (realloc-ed) pos: Replacement position len: String size to be deleted through replacement str: String to be inserted in the replacement position Characters from symbol[pos] to symbol[pos+len-1] are replaced by str. If the size of str is different from len, the length of the entire string will change. Returns: The end position of the inserted string. *---------------------------------------------------------------------------*/ int replace_word(char **str, int pos, int len, const char *substr) { int new_len, str_len, substr_len; char *new_str; // Calculate the size of the string after replacement str_len = strlen(*str); assert(str_len >= pos + len); if (!substr) substr = ""; substr_len = strlen(substr); new_len = str_len - len + substr_len; // Create the string after replacement new_str = Calloc(new_len + 1); // +1 for '\0' strncpy(new_str, *str, pos); strcat(new_str, substr); strcat(new_str, *str + pos + len); // realloc processing free(*str); *str = new_str; // Return the new position return pos + substr_len; } /*---------------------------------------------------------------------------* Name: free_args Description: Clears the Bin2ObjArgs region. *---------------------------------------------------------------------------*/ void free_args(Bin2ObjArgs * t) { if (t->app_name) free(t->app_name); if (t->binary_filename) free(t->binary_filename); if (t->object_filename) free(t->object_filename); if (t->section_rodata) free(t->section_rodata); if (t->section_rwdata) free(t->section_rwdata); if (t->symbol_begin) free(t->symbol_begin); if (t->symbol_end) free(t->symbol_end); memset(t, 0, sizeof(Bin2ObjArgs)); } /*---------------------------------------------------------------------------* Name: StrDup Description: Error handling version of strdup Arguments: str String to copy Returns: String that was copied *---------------------------------------------------------------------------*/ char *StrDup(const char *str) { char *cp; if (NULL == (cp = strdup(str ? str : ""))) { fprintf(stderr, "Error: No memory."); exit(2); } return cp; } /*---------------------------------------------------------------------------* Name: StrNDup Description: Error-handling version of strdup with character length specification. Arguments: str String to copy len String to copy (Not including '\0') Returns: String that was copied *---------------------------------------------------------------------------*/ char *StrNDup(const char *str, int len) { char *cp; cp = Calloc(len + 1); if (str && len) (void)strncpy(cp, str, len); return cp; // Area having len+1 bytes was allocated with malloc, so there is no need to add '\0' after strncpy. // // Can also support cases where str is NULL } /*---------------------------------------------------------------------------* Name: StrCatDup Description: Allocates room for a concatenated string from the heap area. Arguments: str1 String 1 (When str1 == NULL, treated as " ") str2 String 2 (When str2 == NULL, treated as " ") Returns: Concatenated string *---------------------------------------------------------------------------*/ char *StrCatDup(const char *str1, const char *str2) { int len1, len2; char *cp; len1 = str1 ? strlen(str1) : 0; len2 = str2 ? strlen(str2) : 0; cp = Calloc(len1 + len2 + 1); if (str1) (void)strcpy(cp, str1); if (str2) (void)strcat(cp, str2); return cp; } /*---------------------------------------------------------------------------* Name: Calloc Description: Error-handling version of calloc (only one argument) Arguments: size Length of area to allocate Returns: Allocated area *---------------------------------------------------------------------------*/ void *Calloc(int size) { void *cp; if (NULL == (cp = calloc(1, size))) { fprintf(stderr, "Error: No memory."); exit(2); } return cp; } /*---------------------------------------------------------------------------* Name: UnpackFileName Description: Analyzes the file name and divides it into parts: (directory, file base name, file extension) Arguments: path Full path name dir Directory base File's base name ext File extension (not including '.') * * Because dir, base, and ext are allocated from the heap, they must be freed * * When dir, base or ext is NULL, no value is assigned Returns: None. *---------------------------------------------------------------------------*/ void UnpackFileName(const char *path, char **dir, char **base, char **ext) { int i, base_top, ext_top; int path_len = strlen(path); // Search for the position of the final '.' and the path delimiters ext_top = path_len; for (i = path_len - 1; i >= 0; i--) { if (path[i] == '.' && ext_top == path_len) { ext_top = i + 1; } if (path[i] == '/' || path[i] == '\\' || path[i] == ':') { break; } } base_top = i + 1; // Assign if (dir) *dir = StrNDup(path, base_top); if (base) *base = StrNDup(path + base_top, ext_top - base_top - 1); if (ext) *ext = StrDup(path + ext_top); return; }