1 /*---------------------------------------------------------------------------*
2 Project: TwlSDK - bin2obj
3 File: cookargs.c
4
5 Copyright 2005-2008 Nintendo. All rights reserved.
6
7 These coded instructions, statements, and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12
13 $Date:: 2008-09-17#$
14 $Rev: 8556 $
15 $Author: okubata_ryoma $
16 *---------------------------------------------------------------------------*/
17 #include "bin2obj.h"
18
19 extern const unsigned long SDK_DATE_OF_LATEST_FILE;
20
21 /*---------------------------------------------------------------------------*
22 Name: cook_args
23
24 Description: bin2obj main.
25 *---------------------------------------------------------------------------*/
cook_args(Bin2ObjArgs * t,int argc,char * argv[])26 void cook_args(Bin2ObjArgs * t, int argc, char *argv[])
27 {
28 u16 default_machine;
29 u8 default_endian;
30 int c;
31 static struct option long_options[] = {
32 {"begin", 1, 0, 'b'},
33 {"end", 1, 0, 'e'},
34 {"compatible", 0, 0, 'C'},
35 {"section", 1, 0, 's'},
36 {"align", 1, 0, 'a'},
37 {"readonly", 0, 0, 'r'},
38 {"big-endian", 0, 0, 'B'},
39 {"little-endian", 0, 0, 'L'},
40 {"machine", 0, 0, 'm'},
41 {0, 0, 0, 0}
42 };
43
44 memset(t, 0, sizeof(Bin2ObjArgs));
45 UnpackFileName(argv[0], NULL, &t->app_name, NULL);
46 t->align = DEFAULT_ALIGN;
47 t->writable = DEFALUT_WRITABLE;
48 t->symbol_begin = StrDup(DEFAULT_SYMBOL_BEGIN);
49 t->symbol_end = StrDup(DEFAULT_SYMBOL_END);
50 t->section_rodata = StrDup(DEFAULT_SECTION_RODATA);
51 t->section_rwdata = StrDup(DEFAULT_SECTION_RWDATA);
52
53 t->machine = 0;
54 t->endian = ELFDATA2UNDEF;
55
56 default_machine = EM_ARM;
57 default_endian = ELFDATA2LSB;
58
59 while ((c = getopt_long(argc, argv, "b:e:Cs:a:rBLm:", long_options, NULL)) != -1)
60 {
61 switch (c)
62 {
63 case 'b':
64 if (t->symbol_begin)
65 free(t->symbol_begin);
66 t->symbol_begin = StrDup(optarg);
67 break;
68
69 case 'e':
70 if (t->symbol_end)
71 free(t->symbol_end);
72 t->symbol_end = StrDup(optarg);
73 break;
74
75 case 'C':
76 // For Compatibility with CodeWarrior BinToElf
77 if (t->symbol_begin)
78 free(t->symbol_begin);
79 if (t->symbol_end)
80 free(t->symbol_end);
81 t->symbol_begin = StrDup(COMPATIBLE_SYMBOL_BEGIN);
82 t->symbol_end = StrDup(COMPATIBLE_SYMBOL_END);
83 break;
84
85 case 's':
86 if (t->section_rodata)
87 free(t->section_rodata);
88 if (t->section_rwdata)
89 free(t->section_rwdata);
90 t->section_rodata = StrDup(optarg);
91 t->section_rwdata = StrDup(optarg);
92 break;
93
94 case 'a':
95 t->align = atoi(optarg);
96 if (t->align < 1)
97 t->align = 1;
98 break;
99
100 case 'r':
101 t->writable = FALSE;
102 break;
103
104 case 'B':
105 t->endian = ELFDATA2MSB; // Big Endian
106 default_machine = EM_PPC;
107 break;
108
109 case 'L':
110 t->endian = ELFDATA2LSB; // Little Endian
111 default_machine = EM_ARM;
112 break;
113
114 case 'm':
115 if (!strcmp(optarg, "arm"))
116 {
117 t->machine = EM_ARM;
118 default_endian = ELFDATA2LSB;
119 }
120 else if (!strcmp(optarg, "ppc"))
121 {
122 t->machine = EM_PPC;
123 default_endian = ELFDATA2MSB;
124 }
125 break;
126
127 case '?':
128 case ':':
129 default:
130 goto usage;
131 }
132 }
133
134 if (optind + 2 != argc)
135 {
136 goto usage;
137 }
138
139 t->binary_filename = StrDup(argv[optind + 0]);
140 t->object_filename = StrDup(argv[optind + 1]);
141
142 // Default endian & machine
143 if (t->machine == 0)
144 {
145 t->machine = default_machine;
146 }
147 if (t->endian == ELFDATA2UNDEF)
148 {
149 t->endian = default_endian;
150 }
151
152 return;
153
154 usage:
155 {
156 fprintf(stderr,
157 "NITRO/RevoEX Software Development Tool - %s - Binary to Object converter \n"
158 "Build %lu\n\n"
159 "Usage: %s [-b|--begin SYMBOL_BEGIN]\n"
160 " [-e|--end SYMBOL_END]\n"
161 " [-C|--compatible]\n"
162 " [-a|--align ALIGNMENT]\n"
163 " [-r|--readonly]\n"
164 " [-s|--section SECTION]\n"
165 " [-m|--machine [arm|ppc]]\n"
166 " [-B|--big-endian]\n"
167 " [-L|--little-endian] BINARY_FILE OBJECT_FILE\n\n"
168 " -b or --begin Set symbol name for top of binary. (*)\n"
169 " -e or --end Set symbol name for bottom of binary. (*)\n"
170 " -C or --compatible Use compatible symbols with BinToElf.exe.\n"
171 " Same as \"-b _binary_%%f -e _binary_%%f_end\".\n"
172 " -a or --align Set binary data alignment in bytes.\n"
173 " -r or --readonly Handle binary data as readonly.\n"
174 " -s or --section Set section name.\n"
175 " -m or --machine [arm|ppc] Machine arch [arm|ppc].(default=arm)\n"
176 " -B or --big-endian Output in big endian format.\n"
177 " -L or --little-endian Output in little endian format.\n\n"
178 " (*) special %% rules for symbols (ex. binary_file = \"filename.dat\")\n"
179 " %%f,%%t replaced to file name of binary (%%f = \"filename.dat\")\n"
180 " %%b replaced to base name of binary (%%b = \"filename\")\n"
181 " %%e replaced to extension of binary (%%e = \"dat\")\n\n",
182 t->app_name, SDK_DATE_OF_LATEST_FILE, t->app_name);
183 free_args(t);
184 exit(-1);
185 }
186 }
187
188 /*---------------------------------------------------------------------------*
189 Name: create_symbol_string
190
191 Description: Creates the symbol name from the binary file name.
192 *---------------------------------------------------------------------------*/
create_symbol_string(const char * filename,const char * symbol_format)193 char *create_symbol_string(const char *filename, const char *symbol_format)
194 {
195 char *symbol;
196 char *file_base;
197 char *file_ext;
198 int i;
199
200 // Analyze the filename and divide into its elements
201 UnpackFileName(filename, NULL, &file_base, &file_ext);
202
203 // Determine if %f, %b, %e characters are in the format specification, and replace them with the corresponding filename data (main filename, file extension, etc.)
204 //
205 symbol = StrDup(symbol_format);
206 for (i = 0; symbol[i] != '\0'; i++)
207 {
208 if (symbol[i] == '%')
209 {
210 switch (symbol[i + 1])
211 {
212 case 'b':
213 i = replace_word(&symbol, i, 2, file_base);
214 break;
215
216 case 'e':
217 i = replace_word(&symbol, i, 2, file_ext);
218 break;
219
220 case 'f':
221 case 't':
222 i = replace_word(&symbol, i, 2, file_base);
223 i = replace_word(&symbol, i, 0, ".");
224 i = replace_word(&symbol, i, 0, file_ext);
225 break;
226 }
227 }
228 }
229
230 // If characters that cannot be used as symbols are included, change them to "_"
231 for (i = 0; symbol[i] != '\0'; i++)
232 {
233 if (!isalnum(symbol[i]) && symbol[i] != '_')
234 {
235 symbol[i] = '_';
236 }
237 }
238 if (isdigit(symbol[i]))
239 {
240 symbol[i] = '_'; // First character cannot be a numeral, either
241 }
242
243 free(file_base);
244 free(file_ext);
245
246 return symbol;
247 }
248
249 /*---------------------------------------------------------------------------*
250 Name: replace_word
251
252 Description: Replaces string.
253
254 Arguments: *symbol: String to be replaced (realloc-ed)
255 pos: Replacement position
256 len: String size to be deleted through replacement
257 str: String to be inserted in the replacement position
258
259 Characters from symbol[pos] to symbol[pos+len-1] are replaced by str.
260 If the size of str is different from len, the length of the entire string will change.
261
262
263 Returns: The end position of the inserted string.
264 *---------------------------------------------------------------------------*/
replace_word(char ** str,int pos,int len,const char * substr)265 int replace_word(char **str, int pos, int len, const char *substr)
266 {
267 int new_len, str_len, substr_len;
268 char *new_str;
269
270 // Calculate the size of the string after replacement
271 str_len = strlen(*str);
272 assert(str_len >= pos + len);
273
274 if (!substr)
275 substr = "";
276 substr_len = strlen(substr);
277 new_len = str_len - len + substr_len;
278
279 // Create the string after replacement
280 new_str = Calloc(new_len + 1); // +1 for '\0'
281 strncpy(new_str, *str, pos);
282 strcat(new_str, substr);
283 strcat(new_str, *str + pos + len);
284
285 // realloc processing
286 free(*str);
287 *str = new_str;
288
289 // Return the new position
290 return pos + substr_len;
291 }
292
293 /*---------------------------------------------------------------------------*
294 Name: free_args
295
296 Description: Clears the Bin2ObjArgs region.
297 *---------------------------------------------------------------------------*/
free_args(Bin2ObjArgs * t)298 void free_args(Bin2ObjArgs * t)
299 {
300 if (t->app_name)
301 free(t->app_name);
302 if (t->binary_filename)
303 free(t->binary_filename);
304 if (t->object_filename)
305 free(t->object_filename);
306 if (t->section_rodata)
307 free(t->section_rodata);
308 if (t->section_rwdata)
309 free(t->section_rwdata);
310 if (t->symbol_begin)
311 free(t->symbol_begin);
312 if (t->symbol_end)
313 free(t->symbol_end);
314 memset(t, 0, sizeof(Bin2ObjArgs));
315 }
316
317
318 /*---------------------------------------------------------------------------*
319 Name: StrDup
320
321 Description: Error handling version of strdup
322
323 Arguments: str String to copy
324
325 Returns: String that was copied
326 *---------------------------------------------------------------------------*/
StrDup(const char * str)327 char *StrDup(const char *str)
328 {
329 char *cp;
330
331 if (NULL == (cp = strdup(str ? str : "")))
332 {
333 fprintf(stderr, "Error: No memory.");
334 exit(2);
335 }
336 return cp;
337 }
338
339 /*---------------------------------------------------------------------------*
340 Name: StrNDup
341
342 Description: Error-handling version of strdup with character length specification.
343
344 Arguments: str String to copy
345 len String to copy (Not including '\0')
346
347 Returns: String that was copied
348 *---------------------------------------------------------------------------*/
StrNDup(const char * str,int len)349 char *StrNDup(const char *str, int len)
350 {
351 char *cp;
352
353 cp = Calloc(len + 1);
354 if (str && len)
355 (void)strncpy(cp, str, len);
356 return cp;
357
358 // Area having len+1 bytes was allocated with malloc, so there is no need to add '\0' after strncpy.
359 //
360 // Can also support cases where str is NULL
361 }
362
363 /*---------------------------------------------------------------------------*
364 Name: StrCatDup
365
366 Description: Allocates room for a concatenated string from the heap area.
367
368 Arguments: str1 String 1 (When str1 == NULL, treated as " ")
369 str2 String 2 (When str2 == NULL, treated as " ")
370
371 Returns: Concatenated string
372 *---------------------------------------------------------------------------*/
StrCatDup(const char * str1,const char * str2)373 char *StrCatDup(const char *str1, const char *str2)
374 {
375 int len1, len2;
376 char *cp;
377
378 len1 = str1 ? strlen(str1) : 0;
379 len2 = str2 ? strlen(str2) : 0;
380
381 cp = Calloc(len1 + len2 + 1);
382
383 if (str1)
384 (void)strcpy(cp, str1);
385 if (str2)
386 (void)strcat(cp, str2);
387
388 return cp;
389 }
390
391 /*---------------------------------------------------------------------------*
392 Name: Calloc
393
394 Description: Error-handling version of calloc (only one argument)
395
396 Arguments: size Length of area to allocate
397
398 Returns: Allocated area
399 *---------------------------------------------------------------------------*/
Calloc(int size)400 void *Calloc(int size)
401 {
402 void *cp;
403
404 if (NULL == (cp = calloc(1, size)))
405 {
406 fprintf(stderr, "Error: No memory.");
407 exit(2);
408 }
409 return cp;
410 }
411
412 /*---------------------------------------------------------------------------*
413 Name: UnpackFileName
414
415 Description: Analyzes the file name and divides it into parts: (directory, file base name, file extension)
416
417
418 Arguments: path Full path name
419 dir Directory
420 base File's base name
421 ext File extension (not including '.')
422
423 * * Because dir, base, and ext are allocated from the heap, they must be freed
424 * * When dir, base or ext is NULL, no value is assigned
425
426 Returns: None.
427 *---------------------------------------------------------------------------*/
UnpackFileName(const char * path,char ** dir,char ** base,char ** ext)428 void UnpackFileName(const char *path, char **dir, char **base, char **ext)
429 {
430 int i, base_top, ext_top;
431 int path_len = strlen(path);
432
433 // Search for the position of the final '.' and the path delimiters
434 ext_top = path_len;
435 for (i = path_len - 1; i >= 0; i--)
436 {
437 if (path[i] == '.' && ext_top == path_len)
438 {
439 ext_top = i + 1;
440 }
441 if (path[i] == '/' || path[i] == '\\' || path[i] == ':')
442 {
443 break;
444 }
445 }
446 base_top = i + 1;
447
448 // Assign
449 if (dir)
450 *dir = StrNDup(path, base_top);
451 if (base)
452 *base = StrNDup(path + base_top, ext_top - base_top - 1);
453 if (ext)
454 *ext = StrDup(path + ext_top);
455 return;
456 }
457