]> git.saurik.com Git - apple/icu.git/blame - icuSources/tools/genccode/genccode.c
ICU-400.42.tar.gz
[apple/icu.git] / icuSources / tools / genccode / genccode.c
CommitLineData
b75a7d8f 1/*
46f4442e
A
2 *******************************************************************************
3 * Copyright (C) 1999-2007, International Business Machines
4 * Corporation and others. All Rights Reserved.
5 *******************************************************************************
6 * file name: gennames.c
7 * encoding: US-ASCII
8 * tab size: 8 (not used)
9 * indentation:4
10 *
11 * created on: 1999nov01
12 * created by: Markus W. Scherer
13 *
14 * This program reads a binary file and creates a C source code file
15 * with a byte array that contains the data of the binary file.
16 *
17 * 12/09/1999 weiv Added multiple file handling
18 */
b75a7d8f 19
73c04bcf
A
20#include "unicode/utypes.h"
21
22#ifdef U_WINDOWS
b75a7d8f
A
23# define VC_EXTRALEAN
24# define WIN32_LEAN_AND_MEAN
b75a7d8f
A
25# define NOUSER
26# define NOSERVICE
27# define NOIME
28# define NOMCX
29#include <windows.h>
30#include <time.h>
46f4442e 31#endif
b75a7d8f 32
46f4442e
A
33#ifdef U_LINUX
34# define U_ELF
b75a7d8f
A
35#endif
36
46f4442e
A
37#ifdef U_ELF
38# include <elf.h>
39# if defined(ELFCLASS64)
40# define U_ELF64
41# endif
42 /* Old elf.h headers may not have EM_X86_64, or have EM_X8664 instead. */
43# ifndef EM_X86_64
44# define EM_X86_64 62
45# endif
46# define ICU_ENTRY_OFFSET 0
b75a7d8f
A
47#endif
48
49#include <stdio.h>
50#include <stdlib.h>
b75a7d8f
A
51#include "unicode/putil.h"
52#include "cmemory.h"
53#include "cstring.h"
54#include "filestrm.h"
55#include "toolutil.h"
374ca955 56#include "unicode/uclean.h"
b75a7d8f
A
57#include "uoptions.h"
58
59#define MAX_COLUMN ((uint32_t)(0xFFFFFFFFU))
60
61static uint32_t column=MAX_COLUMN;
62
46f4442e 63#if defined(U_WINDOWS) || defined(U_ELF)
b75a7d8f
A
64#define CAN_GENERATE_OBJECTS
65#endif
66
67/* prototypes --------------------------------------------------------------- */
68
69static void
70writeCCode(const char *filename, const char *destdir);
71
374ca955
A
72static void
73writeAssemblyCode(const char *filename, const char *destdir);
74
b75a7d8f
A
75#ifdef CAN_GENERATE_OBJECTS
76static void
77writeObjectCode(const char *filename, const char *destdir);
78#endif
79
80static void
81getOutFilename(const char *inFilename, const char *destdir, char *outFilename, char *entryName, const char *newSuffix);
82
83static void
84write8(FileStream *out, uint8_t byte);
85
374ca955
A
86static void
87write32(FileStream *out, uint32_t byte);
88
b75a7d8f
A
89#ifdef OS400
90static void
91write8str(FileStream *out, uint8_t byte);
92#endif
93/* -------------------------------------------------------------------------- */
94
374ca955
A
95enum {
96 kOptHelpH = 0,
97 kOptHelpQuestionMark,
98 kOptDestDir,
99 kOptName,
100 kOptEntryPoint,
101#ifdef CAN_GENERATE_OBJECTS
102 kOptObject,
46f4442e 103 kOptMatchArch,
374ca955
A
104#endif
105 kOptFilename,
106 kOptAssembly
107};
108
109/*
110Creating Template Files for New Platforms
111
112Let the cc compiler help you get started.
113Compile this program
114 const unsigned int x[5] = {1, 2, 0xdeadbeef, 0xffffffff, 16};
115with the -S option to produce assembly output.
116
117For example, this will generate array.s:
118gcc -S array.c
119
120This will produce a .s file that may look like this:
121
122 .file "array.c"
123 .version "01.01"
124gcc2_compiled.:
125 .globl x
126 .section .rodata
127 .align 4
128 .type x,@object
129 .size x,20
130x:
131 .long 1
132 .long 2
133 .long -559038737
134 .long -1
135 .long 16
136 .ident "GCC: (GNU) 2.96 20000731 (Red Hat Linux 7.1 2.96-85)"
137
138which gives a starting point that will compile, and can be transformed
139to become the template, generally with some consulting of as docs and
140some experimentation.
141
142If you want ICU to automatically use this assembly, you should
143specify "GENCCODE_ASSEMBLY=-a name" in the specific config/mh-* file,
144where the name is the compiler or platform that you used in this
145assemblyHeader data structure.
146*/
147static const struct AssemblyType {
148 const char *name;
149 const char *header;
150 const char *beginLine;
151} assemblyHeader[] = {
152 {"gcc",
153 ".globl %s\n"
73c04bcf 154 "\t.section .note.GNU-stack,\"\",@progbits\n"
374ca955
A
155 "\t.section .rodata\n"
156 "\t.align 8\n" /* Either align 8 bytes or 2^8 (256) bytes. 8 bytes is needed. */
73c04bcf 157 "\t.type %s,@object\n"
374ca955
A
158 "%s:\n\n",
159
160 ".long "
161 },
162 {"gcc-darwin",
163 /*"\t.section __TEXT,__text,regular,pure_instructions\n"
164 "\t.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32\n"*/
165 ".globl _%s\n"
166 "\t.data\n"
167 "\t.const\n"
168 "\t.align 4\n" /* 1<<4 = 16 */
169 "_%s:\n\n",
170
171 ".long "
172 },
173 {"gcc-cygwin",
174 ".globl _%s\n"
175 "\t.section .rodata\n"
176 "\t.align 8\n" /* Either align 8 bytes or 2^8 (256) bytes. 8 bytes is needed. */
177 "_%s:\n\n",
178
179 ".long "
180 },
181 {"sun",
182 "\t.section \".rodata\"\n"
183 "\t.align 8\n"
184 ".globl %s\n"
185 "%s:\n",
186
187 ".word "
188 },
46f4442e
A
189 {"sun-x86",
190 "Drodata.rodata:\n"
191 "\t.type Drodata.rodata,@object\n"
192 "\t.size Drodata.rodata,0\n"
193 "\t.globl %s\n"
194 "\t.align 8\n"
195 "%s:\n",
196
197 ".4byte "
198 },
374ca955
A
199 {"xlc",
200 ".globl %s{RO}\n"
201 "\t.toc\n"
202 "%s:\n"
203 "\t.csect %s{RO}, 4\n",
204
205 ".long "
206 },
46f4442e
A
207 {"aCC-ia64",
208 "\t.file \"%s.s\"\n"
209 "\t.type %s,@object\n"
210 "\t.global %s\n"
211 "\t.secalias .abe$0.rodata, \".rodata\"\n"
212 "\t.section .abe$0.rodata = \"a\", \"progbits\"\n"
213 "\t.align 16\n"
214 "%s::\t",
215
216 "data4 "
217 },
218 {"aCC-parisc",
374ca955
A
219 "\t.SPACE $TEXT$\n"
220 "\t.SUBSPA $LIT$\n"
221 "%s\n"
222 "\t.EXPORT %s\n"
223 "\t.ALIGN 16\n",
224
225 ".WORD "
226 }
227};
228
229static int32_t assemblyHeaderIndex = -1;
230
b75a7d8f
A
231static UOption options[]={
232/*0*/UOPTION_HELP_H,
233 UOPTION_HELP_QUESTION_MARK,
234 UOPTION_DESTDIR,
235 UOPTION_DEF("name", 'n', UOPT_REQUIRES_ARG),
374ca955 236 UOPTION_DEF("entrypoint", 'e', UOPT_REQUIRES_ARG),
b75a7d8f 237#ifdef CAN_GENERATE_OBJECTS
374ca955 238/*5*/UOPTION_DEF("object", 'o', UOPT_NO_ARG),
46f4442e 239 UOPTION_DEF("match-arch", 'm', UOPT_REQUIRES_ARG),
b75a7d8f 240#endif
374ca955
A
241 UOPTION_DEF("filename", 'f', UOPT_REQUIRES_ARG),
242 UOPTION_DEF("assembly", 'a', UOPT_REQUIRES_ARG)
b75a7d8f
A
243};
244
b75a7d8f
A
245extern int
246main(int argc, char* argv[]) {
247 UBool verbose = TRUE;
374ca955 248 int32_t idx;
b75a7d8f
A
249
250 U_MAIN_INIT_ARGS(argc, argv);
251
374ca955 252 options[kOptDestDir].value = ".";
b75a7d8f
A
253
254 /* read command line options */
255 argc=u_parseArgs(argc, argv, sizeof(options)/sizeof(options[0]), options);
46f4442e 256
b75a7d8f
A
257 /* error handling, printing usage message */
258 if(argc<0) {
259 fprintf(stderr,
260 "error in command line argument \"%s\"\n",
261 argv[-argc]);
262 }
374ca955 263 if(argc<0 || options[kOptHelpH].doesOccur || options[kOptHelpQuestionMark].doesOccur) {
b75a7d8f
A
264 fprintf(stderr,
265 "usage: %s [-options] filename1 filename2 ...\n"
266 "\tread each binary input file and \n"
267 "\tcreate a .c file with a byte array that contains the input file's data\n"
268 "options:\n"
269 "\t-h or -? or --help this usage text\n"
270 "\t-d or --destdir destination directory, followed by the path\n"
271 "\t-n or --name symbol prefix, followed by the prefix\n"
46f4442e 272 "\t-e or --entrypoint entry point name, followed by the name (_dat will be appended)\n"
b75a7d8f 273 "\t-r or --revision Specify a version\n"
46f4442e 274 , argv[0]);
b75a7d8f 275#ifdef CAN_GENERATE_OBJECTS
46f4442e 276 fprintf(stderr,
b75a7d8f 277 "\t-o or --object write a .obj file instead of .c\n"
46f4442e
A
278 "\t-m or --match-arch file.o match the architecture (CPU, 32/64 bits) of the specified .o\n"
279 "\t ELF format defaults to i386. Windows defaults to the native platform.\n");
b75a7d8f 280#endif
374ca955 281 fprintf(stderr,
46f4442e 282 "\t-f or --filename Specify an alternate base filename. (default: symbolname_typ)\n"
374ca955
A
283 "\t-a or --assembly Create assembly file. (possible values are: ");
284
285 fprintf(stderr, "%s", assemblyHeader[0].name);
286 for (idx = 1; idx < (int32_t)(sizeof(assemblyHeader)/sizeof(assemblyHeader[0])); idx++) {
287 fprintf(stderr, ", %s", assemblyHeader[idx].name);
288 }
289 fprintf(stderr,
290 ")\n");
b75a7d8f
A
291 } else {
292 const char *message, *filename;
293 void (*writeCode)(const char *, const char *);
374ca955
A
294
295 if(options[kOptAssembly].doesOccur) {
296 message="generating assembly code for %s\n";
297 writeCode=&writeAssemblyCode;
298 for (idx = 0; idx < (int32_t)(sizeof(assemblyHeader)/sizeof(assemblyHeader[0])); idx++) {
299 if (uprv_strcmp(options[kOptAssembly].value, assemblyHeader[idx].name) == 0) {
300 assemblyHeaderIndex = idx;
301 break;
302 }
303 }
304 if (assemblyHeaderIndex < 0) {
305 fprintf(stderr,
306 "Assembly type \"%s\" is unknown.\n", options[kOptAssembly].value);
307 return -1;
308 }
309 }
b75a7d8f 310#ifdef CAN_GENERATE_OBJECTS
374ca955 311 else if(options[kOptObject].doesOccur) {
b75a7d8f
A
312 message="generating object code for %s\n";
313 writeCode=&writeObjectCode;
374ca955 314 }
b75a7d8f 315#endif
374ca955 316 else
b75a7d8f
A
317 {
318 message="generating C code for %s\n";
319 writeCode=&writeCCode;
320 }
321 while(--argc) {
322 filename=getLongPathname(argv[argc]);
323 if (verbose) {
324 fprintf(stdout, message, filename);
325 }
326 column=MAX_COLUMN;
374ca955 327 writeCode(filename, options[kOptDestDir].value);
b75a7d8f
A
328 }
329 }
330
331 return 0;
332}
333
374ca955
A
334static void
335writeAssemblyCode(const char *filename, const char *destdir) {
336 char entry[64];
337 uint32_t buffer[1024];
338 char *bufferStr = (char *)buffer;
339 FileStream *in, *out;
340 size_t i, length;
341
342 in=T_FileStream_open(filename, "rb");
343 if(in==NULL) {
344 fprintf(stderr, "genccode: unable to open input file %s\n", filename);
345 exit(U_FILE_ACCESS_ERROR);
346 }
347
348 getOutFilename(filename, destdir, bufferStr, entry, ".s");
349 out=T_FileStream_open(bufferStr, "w");
350 if(out==NULL) {
351 fprintf(stderr, "genccode: unable to open output file %s\n", bufferStr);
352 exit(U_FILE_ACCESS_ERROR);
353 }
354
355 if(options[kOptEntryPoint].doesOccur) {
356 uprv_strcpy(entry, options[kOptEntryPoint].value);
357 uprv_strcat(entry, "_dat");
358 }
359
360 /* turn dashes or dots in the entry name into underscores */
361 length=uprv_strlen(entry);
362 for(i=0; i<length; ++i) {
363 if(entry[i]=='-' || entry[i]=='.') {
364 entry[i]='_';
365 }
366 }
367
368 sprintf(bufferStr, assemblyHeader[assemblyHeaderIndex].header,
369 entry, entry, entry, entry,
370 entry, entry, entry, entry);
371 T_FileStream_writeLine(out, bufferStr);
372 T_FileStream_writeLine(out, assemblyHeader[assemblyHeaderIndex].beginLine);
373
374 for(;;) {
375 length=T_FileStream_read(in, buffer, sizeof(buffer));
376 if(length==0) {
377 break;
378 }
379 if (length != sizeof(buffer)) {
380 /* pad with extra 0's when at the end of the file */
381 for(i=0; i < (length % sizeof(uint32_t)); ++i) {
382 buffer[length+i] = 0;
383 }
384 }
385 for(i=0; i<(length/sizeof(buffer[0])); i++) {
386 write32(out, buffer[i]);
387 }
388 }
389
390 T_FileStream_writeLine(out, "\n");
391
392 if(T_FileStream_error(in)) {
393 fprintf(stderr, "genccode: file read error while generating from file %s\n", filename);
394 exit(U_FILE_ACCESS_ERROR);
395 }
396
397 if(T_FileStream_error(out)) {
398 fprintf(stderr, "genccode: file write error while generating from file %s\n", filename);
399 exit(U_FILE_ACCESS_ERROR);
400 }
401
402 T_FileStream_close(out);
403 T_FileStream_close(in);
404}
405
b75a7d8f
A
406static void
407writeCCode(const char *filename, const char *destdir) {
374ca955 408 char buffer[4096], entry[64];
b75a7d8f
A
409 FileStream *in, *out;
410 size_t i, length;
411
412 in=T_FileStream_open(filename, "rb");
413 if(in==NULL) {
414 fprintf(stderr, "genccode: unable to open input file %s\n", filename);
415 exit(U_FILE_ACCESS_ERROR);
416 }
417
374ca955
A
418 if(options[kOptName].doesOccur) { /* prepend 'icudt28_' */
419 strcpy(entry, options[kOptName].value);
420 strcat(entry, "_");
421 } else {
422 entry[0] = 0;
423 }
424
425 getOutFilename(filename, destdir, buffer, entry+uprv_strlen(entry), ".c");
b75a7d8f
A
426 out=T_FileStream_open(buffer, "w");
427 if(out==NULL) {
428 fprintf(stderr, "genccode: unable to open output file %s\n", buffer);
429 exit(U_FILE_ACCESS_ERROR);
430 }
431
432 /* turn dashes or dots in the entry name into underscores */
433 length=uprv_strlen(entry);
434 for(i=0; i<length; ++i) {
435 if(entry[i]=='-' || entry[i]=='.') {
436 entry[i]='_';
437 }
438 }
374ca955 439
b75a7d8f
A
440#ifdef OS400
441 /*
442 TODO: Fix this once the compiler implements this feature. Keep in sync with udatamem.c
443
444 This is here because this platform can't currently put
445 const data into the read-only pages of an object or
446 shared library (service program). Only strings are allowed in read-only
447 pages, so we use char * strings to store the data.
448
449 In order to prevent the beginning of the data from ever matching the
450 magic numbers we must still use the initial double.
451 [grhoten 4/24/2003]
452 */
453 sprintf(buffer,
454 "#define U_DISABLE_RENAMING 1\n"
455 "#include \"unicode/umachine.h\"\n"
456 "U_CDECL_BEGIN\n"
457 "const struct {\n"
458 " double bogus;\n"
459 " const char *bytes; \n"
374ca955
A
460 "} %s={ 0.0, \n",
461 entry);
b75a7d8f
A
462 T_FileStream_writeLine(out, buffer);
463
464 for(;;) {
465 length=T_FileStream_read(in, buffer, sizeof(buffer));
466 if(length==0) {
467 break;
468 }
469 for(i=0; i<length; ++i) {
470 write8str(out, (uint8_t)buffer[i]);
471 }
472 }
473
474 T_FileStream_writeLine(out, "\"\n};\nU_CDECL_END\n");
475#else
476 /* Function renaming shouldn't be done in data */
477 sprintf(buffer,
478 "#define U_DISABLE_RENAMING 1\n"
479 "#include \"unicode/umachine.h\"\n"
480 "U_CDECL_BEGIN\n"
481 "const struct {\n"
482 " double bogus;\n"
483 " uint8_t bytes[%ld]; \n"
374ca955
A
484 "} %s={ 0.0, {\n",
485 (long)T_FileStream_size(in), entry);
b75a7d8f
A
486 T_FileStream_writeLine(out, buffer);
487
488 for(;;) {
489 length=T_FileStream_read(in, buffer, sizeof(buffer));
490 if(length==0) {
491 break;
492 }
493 for(i=0; i<length; ++i) {
494 write8(out, (uint8_t)buffer[i]);
495 }
496 }
497
498 T_FileStream_writeLine(out, "\n}\n};\nU_CDECL_END\n");
499#endif
500
501 if(T_FileStream_error(in)) {
502 fprintf(stderr, "genccode: file read error while generating from file %s\n", filename);
503 exit(U_FILE_ACCESS_ERROR);
504 }
505
506 if(T_FileStream_error(out)) {
507 fprintf(stderr, "genccode: file write error while generating from file %s\n", filename);
508 exit(U_FILE_ACCESS_ERROR);
509 }
510
511 T_FileStream_close(out);
512 T_FileStream_close(in);
513}
514
515#ifdef CAN_GENERATE_OBJECTS
46f4442e
A
516static void
517getArchitecture(uint16_t *pCPU, uint16_t *pBits, UBool *pIsBigEndian) {
518 int64_t buffer[256];
519 const char *filename;
520 FileStream *in;
521 int32_t length;
522
523#ifdef U_ELF
524 /* Pointer to ELF header. Elf32_Ehdr and ELF64_Ehdr are identical for the necessary fields. */
525 const Elf32_Ehdr *pHeader32;
526#elif defined(U_WINDOWS)
527 const IMAGE_FILE_HEADER *pHeader;
528#else
529# error "Unknown platform for CAN_GENERATE_OBJECTS."
530#endif
531
532 if(options[kOptMatchArch].doesOccur) {
533 filename=options[kOptMatchArch].value;
534 } else {
535 /* set defaults */
536#ifdef U_ELF
537 /* set EM_386 because elf.h does not provide better defaults */
538 *pCPU=EM_386;
539 *pBits=32;
540 *pIsBigEndian=(UBool)(U_IS_BIG_ENDIAN ? ELFDATA2MSB : ELFDATA2LSB);
541#elif defined(U_WINDOWS)
542/* _M_IA64 should be defined in windows.h */
543# if defined(_M_IA64)
544 *pCPU=IMAGE_FILE_MACHINE_IA64;
545# elif defined(_M_AMD64)
546 *pCPU=IMAGE_FILE_MACHINE_AMD64;
547# else
548 *pCPU=IMAGE_FILE_MACHINE_I386;
549# endif
550 *pBits= *pCPU==IMAGE_FILE_MACHINE_I386 ? 32 : 64;
551 *pIsBigEndian=FALSE;
552#else
553# error "Unknown platform for CAN_GENERATE_OBJECTS."
554#endif
555 return;
556 }
557
558 in=T_FileStream_open(filename, "rb");
559 if(in==NULL) {
560 fprintf(stderr, "genccode: unable to open match-arch file %s\n", filename);
561 exit(U_FILE_ACCESS_ERROR);
562 }
563 length=T_FileStream_read(in, buffer, sizeof(buffer));
564
565#ifdef U_ELF
566 if(length<sizeof(Elf32_Ehdr)) {
567 fprintf(stderr, "genccode: match-arch file %s is too short\n", filename);
568 exit(U_UNSUPPORTED_ERROR);
569 }
570 pHeader32=(const Elf32_Ehdr *)buffer;
571 if(
572 pHeader32->e_ident[0]!=ELFMAG0 ||
573 pHeader32->e_ident[1]!=ELFMAG1 ||
574 pHeader32->e_ident[2]!=ELFMAG2 ||
575 pHeader32->e_ident[3]!=ELFMAG3 ||
576 pHeader32->e_ident[EI_CLASS]<ELFCLASS32 || pHeader32->e_ident[EI_CLASS]>ELFCLASS64
577 ) {
578 fprintf(stderr, "genccode: match-arch file %s is not an ELF object file, or not supported\n", filename);
579 exit(U_UNSUPPORTED_ERROR);
580 }
581
582 *pBits= pHeader32->e_ident[EI_CLASS]==ELFCLASS32 ? 32 : 64; /* only 32 or 64: see check above */
583#ifdef U_ELF64
584 if(*pBits!=32 && *pBits!=64) {
585 fprintf(stderr, "genccode: currently only supports 32-bit and 64-bit ELF format\n");
586 exit(U_UNSUPPORTED_ERROR);
587 }
588#else
589 if(*pBits!=32) {
590 fprintf(stderr, "genccode: built with elf.h missing 64-bit definitions\n");
591 exit(U_UNSUPPORTED_ERROR);
592 }
593#endif
594
595 *pIsBigEndian=(UBool)(pHeader32->e_ident[EI_DATA]==ELFDATA2MSB);
596 if(*pIsBigEndian!=U_IS_BIG_ENDIAN) {
597 fprintf(stderr, "genccode: currently only same-endianness ELF formats are supported\n");
598 exit(U_UNSUPPORTED_ERROR);
599 }
600 /* TODO: Support byte swapping */
601
602 *pCPU=pHeader32->e_machine;
603#elif defined(U_WINDOWS)
604 if(length<sizeof(IMAGE_FILE_HEADER)) {
605 fprintf(stderr, "genccode: match-arch file %s is too short\n", filename);
606 exit(U_UNSUPPORTED_ERROR);
607 }
608 pHeader=(const IMAGE_FILE_HEADER *)buffer;
609 *pCPU=pHeader->Machine;
610 /*
611 * The number of bits is implicit with the Machine value.
612 * *pBits is ignored in the calling code, so this need not be precise.
613 */
614 *pBits= *pCPU==IMAGE_FILE_MACHINE_I386 ? 32 : 64;
615 /* Windows always runs on little-endian CPUs. */
616 *pIsBigEndian=FALSE;
617#else
618# error "Unknown platform for CAN_GENERATE_OBJECTS."
619#endif
620
621 T_FileStream_close(in);
622}
623
b75a7d8f
A
624static void
625writeObjectCode(const char *filename, const char *destdir) {
46f4442e
A
626 /* common variables */
627 char buffer[4096], entry[40]={ 0 };
628 FileStream *in, *out;
629 const char *newSuffix;
630 int32_t i, entryLength, length, size, entryOffset=0, entryLengthOffset=0;
631
632 uint16_t cpu, bits;
633 UBool makeBigEndian;
634
635 /* platform-specific variables and initialization code */
636#ifdef U_ELF
637 /* 32-bit Elf file header */
638 static Elf32_Ehdr header32={
639 {
640 /* e_ident[] */
641 ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3,
642 ELFCLASS32,
643 U_IS_BIG_ENDIAN ? ELFDATA2MSB : ELFDATA2LSB,
644 EV_CURRENT /* EI_VERSION */
645 },
646 ET_REL,
647 EM_386,
648 EV_CURRENT, /* e_version */
649 0, /* e_entry */
650 0, /* e_phoff */
651 (Elf32_Off)sizeof(Elf32_Ehdr), /* e_shoff */
652 0, /* e_flags */
653 (Elf32_Half)sizeof(Elf32_Ehdr), /* eh_size */
654 0, /* e_phentsize */
655 0, /* e_phnum */
656 (Elf32_Half)sizeof(Elf32_Shdr), /* e_shentsize */
657 5, /* e_shnum */
658 2 /* e_shstrndx */
659 };
660
661 /* 32-bit Elf section header table */
662 static Elf32_Shdr sectionHeaders32[5]={
663 { /* SHN_UNDEF */
664 0
665 },
666 { /* .symtab */
667 1, /* sh_name */
668 SHT_SYMTAB,
669 0, /* sh_flags */
670 0, /* sh_addr */
671 (Elf32_Off)(sizeof(header32)+sizeof(sectionHeaders32)), /* sh_offset */
672 (Elf32_Word)(2*sizeof(Elf32_Sym)), /* sh_size */
673 3, /* sh_link=sect hdr index of .strtab */
674 1, /* sh_info=One greater than the symbol table index of the last
675 * local symbol (with STB_LOCAL). */
676 4, /* sh_addralign */
677 (Elf32_Word)(sizeof(Elf32_Sym)) /* sh_entsize */
678 },
679 { /* .shstrtab */
680 9, /* sh_name */
681 SHT_STRTAB,
682 0, /* sh_flags */
683 0, /* sh_addr */
684 (Elf32_Off)(sizeof(header32)+sizeof(sectionHeaders32)+2*sizeof(Elf32_Sym)), /* sh_offset */
685 40, /* sh_size */
686 0, /* sh_link */
687 0, /* sh_info */
688 1, /* sh_addralign */
689 0 /* sh_entsize */
690 },
691 { /* .strtab */
692 19, /* sh_name */
693 SHT_STRTAB,
694 0, /* sh_flags */
695 0, /* sh_addr */
696 (Elf32_Off)(sizeof(header32)+sizeof(sectionHeaders32)+2*sizeof(Elf32_Sym)+40), /* sh_offset */
697 (Elf32_Word)sizeof(entry), /* sh_size */
698 0, /* sh_link */
699 0, /* sh_info */
700 1, /* sh_addralign */
701 0 /* sh_entsize */
702 },
703 { /* .rodata */
704 27, /* sh_name */
705 SHT_PROGBITS,
706 SHF_ALLOC, /* sh_flags */
707 0, /* sh_addr */
708 (Elf32_Off)(sizeof(header32)+sizeof(sectionHeaders32)+2*sizeof(Elf32_Sym)+40+sizeof(entry)), /* sh_offset */
709 0, /* sh_size */
710 0, /* sh_link */
711 0, /* sh_info */
712 16, /* sh_addralign */
713 0 /* sh_entsize */
714 }
715 };
716
717 /* symbol table */
718 static Elf32_Sym symbols32[2]={
719 { /* STN_UNDEF */
720 0
721 },
722 { /* data entry point */
723 1, /* st_name */
724 0, /* st_value */
725 0, /* st_size */
726 ELF64_ST_INFO(STB_GLOBAL, STT_OBJECT),
727 0, /* st_other */
728 4 /* st_shndx=index of related section table entry */
729 }
730 };
731
732 /* section header string table, with decimal string offsets */
733 static const char sectionStrings[40]=
734 /* 0 */ "\0"
735 /* 1 */ ".symtab\0"
736 /* 9 */ ".shstrtab\0"
737 /* 19 */ ".strtab\0"
738 /* 27 */ ".rodata\0"
739 /* 35 */ "\0\0\0\0"; /* contains terminating NUL */
740 /* 40: padded to multiple of 8 bytes */
741
742 /*
743 * Use entry[] for the string table which will contain only the
744 * entry point name.
745 * entry[0] must be 0 (NUL)
746 * The entry point name can be up to 38 characters long (sizeof(entry)-2).
747 */
748
749 /* 16-align .rodata in the .o file, just in case */
750 static const char padding[16]={ 0 };
751 int32_t paddingSize;
752
753#ifdef U_ELF64
754 /* 64-bit Elf file header */
755 static Elf64_Ehdr header64={
756 {
757 /* e_ident[] */
758 ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3,
759 ELFCLASS64,
760 U_IS_BIG_ENDIAN ? ELFDATA2MSB : ELFDATA2LSB,
761 EV_CURRENT /* EI_VERSION */
762 },
763 ET_REL,
764 EM_X86_64,
765 EV_CURRENT, /* e_version */
766 0, /* e_entry */
767 0, /* e_phoff */
768 (Elf64_Off)sizeof(Elf64_Ehdr), /* e_shoff */
769 0, /* e_flags */
770 (Elf64_Half)sizeof(Elf64_Ehdr), /* eh_size */
771 0, /* e_phentsize */
772 0, /* e_phnum */
773 (Elf64_Half)sizeof(Elf64_Shdr), /* e_shentsize */
774 5, /* e_shnum */
775 2 /* e_shstrndx */
776 };
777
778 /* 64-bit Elf section header table */
779 static Elf64_Shdr sectionHeaders64[5]={
780 { /* SHN_UNDEF */
781 0
782 },
783 { /* .symtab */
784 1, /* sh_name */
785 SHT_SYMTAB,
786 0, /* sh_flags */
787 0, /* sh_addr */
788 (Elf64_Off)(sizeof(header64)+sizeof(sectionHeaders64)), /* sh_offset */
789 (Elf64_Xword)(2*sizeof(Elf64_Sym)), /* sh_size */
790 3, /* sh_link=sect hdr index of .strtab */
791 1, /* sh_info=One greater than the symbol table index of the last
792 * local symbol (with STB_LOCAL). */
793 4, /* sh_addralign */
794 (Elf64_Xword)(sizeof(Elf64_Sym)) /* sh_entsize */
795 },
796 { /* .shstrtab */
797 9, /* sh_name */
798 SHT_STRTAB,
799 0, /* sh_flags */
800 0, /* sh_addr */
801 (Elf64_Off)(sizeof(header64)+sizeof(sectionHeaders64)+2*sizeof(Elf64_Sym)), /* sh_offset */
802 40, /* sh_size */
803 0, /* sh_link */
804 0, /* sh_info */
805 1, /* sh_addralign */
806 0 /* sh_entsize */
807 },
808 { /* .strtab */
809 19, /* sh_name */
810 SHT_STRTAB,
811 0, /* sh_flags */
812 0, /* sh_addr */
813 (Elf64_Off)(sizeof(header64)+sizeof(sectionHeaders64)+2*sizeof(Elf64_Sym)+40), /* sh_offset */
814 (Elf64_Xword)sizeof(entry), /* sh_size */
815 0, /* sh_link */
816 0, /* sh_info */
817 1, /* sh_addralign */
818 0 /* sh_entsize */
819 },
820 { /* .rodata */
821 27, /* sh_name */
822 SHT_PROGBITS,
823 SHF_ALLOC, /* sh_flags */
824 0, /* sh_addr */
825 (Elf64_Off)(sizeof(header64)+sizeof(sectionHeaders64)+2*sizeof(Elf64_Sym)+40+sizeof(entry)), /* sh_offset */
826 0, /* sh_size */
827 0, /* sh_link */
828 0, /* sh_info */
829 16, /* sh_addralign */
830 0 /* sh_entsize */
831 }
832 };
833
834 /*
835 * 64-bit symbol table
836 * careful: different order of items compared with Elf32_sym!
837 */
838 static Elf64_Sym symbols64[2]={
839 { /* STN_UNDEF */
840 0
841 },
842 { /* data entry point */
843 1, /* st_name */
844 ELF64_ST_INFO(STB_GLOBAL, STT_OBJECT),
845 0, /* st_other */
846 4, /* st_shndx=index of related section table entry */
847 0, /* st_value */
848 0 /* st_size */
849 }
850 };
851
852#endif /* U_ELF64 */
853
854 /* entry[] have a leading NUL */
855 entryOffset=1;
856
857 /* in the common code, count entryLength from after the NUL */
858 entryLengthOffset=1;
859
860 newSuffix=".o";
861
862#elif defined(U_WINDOWS)
b75a7d8f
A
863 struct {
864 IMAGE_FILE_HEADER fileHeader;
865 IMAGE_SECTION_HEADER sections[2];
866 char linkerOptions[100];
867 } objHeader;
868 IMAGE_SYMBOL symbols[1];
869 struct {
870 DWORD sizeofLongNames;
871 char longNames[100];
872 } symbolNames;
46f4442e
A
873
874 /*
875 * entry sometimes have a leading '_'
876 * overwritten if entryOffset==0 depending on the target platform
877 * see check for cpu below
878 */
879 entry[0]='_';
880
881 newSuffix=".obj";
882#else
883# error "Unknown platform for CAN_GENERATE_OBJECTS."
884#endif
885
886 /* deal with options, files and the entry point name */
887 getArchitecture(&cpu, &bits, &makeBigEndian);
888 printf("genccode: --match-arch cpu=%hu bits=%hu big-endian=%hu\n", cpu, bits, makeBigEndian);
889#ifdef U_WINDOWS
890 if(cpu==IMAGE_FILE_MACHINE_I386) {
891 entryOffset=1;
892 }
893#endif
b75a7d8f
A
894
895 in=T_FileStream_open(filename, "rb");
896 if(in==NULL) {
897 fprintf(stderr, "genccode: unable to open input file %s\n", filename);
898 exit(U_FILE_ACCESS_ERROR);
899 }
46f4442e 900 size=T_FileStream_size(in);
b75a7d8f 901
46f4442e 902 getOutFilename(filename, destdir, buffer, entry+entryOffset, newSuffix);
b75a7d8f 903
374ca955 904 if(options[kOptEntryPoint].doesOccur) {
46f4442e
A
905 uprv_strcpy(entry+entryOffset, options[kOptEntryPoint].value);
906 uprv_strcat(entry+entryOffset, "_dat");
b75a7d8f
A
907 }
908 /* turn dashes in the entry name into underscores */
46f4442e 909 entryLength=(int32_t)uprv_strlen(entry+entryLengthOffset);
b75a7d8f 910 for(i=0; i<entryLength; ++i) {
46f4442e
A
911 if(entry[entryLengthOffset+i]=='-') {
912 entry[entryLengthOffset+i]='_';
b75a7d8f
A
913 }
914 }
915
916 /* open the output file */
917 out=T_FileStream_open(buffer, "wb");
918 if(out==NULL) {
919 fprintf(stderr, "genccode: unable to open output file %s\n", buffer);
920 exit(U_FILE_ACCESS_ERROR);
921 }
922
46f4442e
A
923#ifdef U_ELF
924 if(bits==32) {
925 header32.e_ident[EI_DATA]= makeBigEndian ? ELFDATA2MSB : ELFDATA2LSB;
926 header32.e_machine=cpu;
927
928 /* 16-align .rodata in the .o file, just in case */
929 paddingSize=sectionHeaders32[4].sh_offset & 0xf;
930 if(paddingSize!=0) {
931 paddingSize=0x10-paddingSize;
932 sectionHeaders32[4].sh_offset+=paddingSize;
933 }
934
935 sectionHeaders32[4].sh_size=(Elf32_Word)size;
936
937 symbols32[1].st_size=(Elf32_Word)size;
938
939 /* write .o headers */
940 T_FileStream_write(out, &header32, (int32_t)sizeof(header32));
941 T_FileStream_write(out, sectionHeaders32, (int32_t)sizeof(sectionHeaders32));
942 T_FileStream_write(out, symbols32, (int32_t)sizeof(symbols32));
943 } else /* bits==64 */ {
944#ifdef U_ELF64
945 header64.e_ident[EI_DATA]= makeBigEndian ? ELFDATA2MSB : ELFDATA2LSB;
946 header64.e_machine=cpu;
947
948 /* 16-align .rodata in the .o file, just in case */
949 paddingSize=sectionHeaders64[4].sh_offset & 0xf;
950 if(paddingSize!=0) {
951 paddingSize=0x10-paddingSize;
952 sectionHeaders64[4].sh_offset+=paddingSize;
953 }
954
955 sectionHeaders64[4].sh_size=(Elf64_Xword)size;
956
957 symbols64[1].st_size=(Elf64_Xword)size;
958
959 /* write .o headers */
960 T_FileStream_write(out, &header64, (int32_t)sizeof(header64));
961 T_FileStream_write(out, sectionHeaders64, (int32_t)sizeof(sectionHeaders64));
962 T_FileStream_write(out, symbols64, (int32_t)sizeof(symbols64));
963#endif
964 }
965
966 T_FileStream_write(out, sectionStrings, (int32_t)sizeof(sectionStrings));
967 T_FileStream_write(out, entry, (int32_t)sizeof(entry));
968 if(paddingSize!=0) {
969 T_FileStream_write(out, padding, paddingSize);
970 }
971#elif defined(U_WINDOWS)
b75a7d8f
A
972 /* populate the .obj headers */
973 uprv_memset(&objHeader, 0, sizeof(objHeader));
974 uprv_memset(&symbols, 0, sizeof(symbols));
975 uprv_memset(&symbolNames, 0, sizeof(symbolNames));
b75a7d8f
A
976
977 /* write the linker export directive */
978 uprv_strcpy(objHeader.linkerOptions, "-export:");
979 length=8;
980 uprv_strcpy(objHeader.linkerOptions+length, entry);
981 length+=entryLength;
982 uprv_strcpy(objHeader.linkerOptions+length, ",data ");
983 length+=6;
984
985 /* set the file header */
46f4442e 986 objHeader.fileHeader.Machine=cpu;
b75a7d8f 987 objHeader.fileHeader.NumberOfSections=2;
46f4442e 988 objHeader.fileHeader.TimeDateStamp=(DWORD)time(NULL);
b75a7d8f
A
989 objHeader.fileHeader.PointerToSymbolTable=IMAGE_SIZEOF_FILE_HEADER+2*IMAGE_SIZEOF_SECTION_HEADER+length+size; /* start of symbol table */
990 objHeader.fileHeader.NumberOfSymbols=1;
991
992 /* set the section for the linker options */
993 uprv_strncpy((char *)objHeader.sections[0].Name, ".drectve", 8);
994 objHeader.sections[0].SizeOfRawData=length;
995 objHeader.sections[0].PointerToRawData=IMAGE_SIZEOF_FILE_HEADER+2*IMAGE_SIZEOF_SECTION_HEADER;
996 objHeader.sections[0].Characteristics=IMAGE_SCN_LNK_INFO|IMAGE_SCN_LNK_REMOVE|IMAGE_SCN_ALIGN_1BYTES;
997
998 /* set the data section */
999 uprv_strncpy((char *)objHeader.sections[1].Name, ".rdata", 6);
1000 objHeader.sections[1].SizeOfRawData=size;
1001 objHeader.sections[1].PointerToRawData=IMAGE_SIZEOF_FILE_HEADER+2*IMAGE_SIZEOF_SECTION_HEADER+length;
1002 objHeader.sections[1].Characteristics=IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_ALIGN_16BYTES|IMAGE_SCN_MEM_READ;
1003
1004 /* set the symbol table */
1005 if(entryLength<=8) {
1006 uprv_strncpy((char *)symbols[0].N.ShortName, entry, entryLength);
1007 symbolNames.sizeofLongNames=4;
1008 } else {
1009 symbols[0].N.Name.Short=0;
1010 symbols[0].N.Name.Long=4;
1011 symbolNames.sizeofLongNames=4+entryLength+1;
1012 uprv_strcpy(symbolNames.longNames, entry);
1013 }
1014 symbols[0].SectionNumber=2;
1015 symbols[0].StorageClass=IMAGE_SYM_CLASS_EXTERNAL;
1016
1017 /* write the file header and the linker options section */
1018 T_FileStream_write(out, &objHeader, objHeader.sections[1].PointerToRawData);
46f4442e
A
1019#else
1020# error "Unknown platform for CAN_GENERATE_OBJECTS."
1021#endif
b75a7d8f
A
1022
1023 /* copy the data file into section 2 */
1024 for(;;) {
1025 length=T_FileStream_read(in, buffer, sizeof(buffer));
1026 if(length==0) {
1027 break;
1028 }
374ca955 1029 T_FileStream_write(out, buffer, (int32_t)length);
b75a7d8f
A
1030 }
1031
46f4442e 1032#ifdef U_WINDOWS
b75a7d8f
A
1033 /* write the symbol table */
1034 T_FileStream_write(out, symbols, IMAGE_SIZEOF_SYMBOL);
1035 T_FileStream_write(out, &symbolNames, symbolNames.sizeofLongNames);
46f4442e 1036#endif
b75a7d8f
A
1037
1038 if(T_FileStream_error(in)) {
1039 fprintf(stderr, "genccode: file read error while generating from file %s\n", filename);
1040 exit(U_FILE_ACCESS_ERROR);
1041 }
1042
1043 if(T_FileStream_error(out)) {
1044 fprintf(stderr, "genccode: file write error while generating from file %s\n", filename);
1045 exit(U_FILE_ACCESS_ERROR);
1046 }
1047
1048 T_FileStream_close(out);
1049 T_FileStream_close(in);
b75a7d8f
A
1050}
1051#endif
1052
1053static void
1054getOutFilename(const char *inFilename, const char *destdir, char *outFilename, char *entryName, const char *newSuffix) {
1055 const char *basename=findBasename(inFilename), *suffix=uprv_strrchr(basename, '.');
1056
1057 /* copy path */
1058 if(destdir!=NULL && *destdir!=0) {
1059 do {
1060 *outFilename++=*destdir++;
1061 } while(*destdir!=0);
1062 if(*(outFilename-1)!=U_FILE_SEP_CHAR) {
1063 *outFilename++=U_FILE_SEP_CHAR;
1064 }
1065 inFilename=basename;
1066 } else {
1067 while(inFilename<basename) {
1068 *outFilename++=*inFilename++;
1069 }
1070 }
1071
1072 if(suffix==NULL) {
1073 /* the filename does not have a suffix */
1074 uprv_strcpy(entryName, inFilename);
374ca955
A
1075 if(options[kOptFilename].doesOccur) {
1076 uprv_strcpy(outFilename, options[kOptFilename].value);
1077 } else {
1078 uprv_strcpy(outFilename, inFilename);
1079 }
b75a7d8f
A
1080 uprv_strcat(outFilename, newSuffix);
1081 } else {
374ca955 1082 char *saveOutFilename = outFilename;
b75a7d8f
A
1083 /* copy basename */
1084 while(inFilename<suffix) {
1085 if(*inFilename=='-') {
1086 /* iSeries cannot have '-' in the .o objects. */
1087 *outFilename++=*entryName++='_';
1088 inFilename++;
1089 }
1090 else {
1091 *outFilename++=*entryName++=*inFilename++;
1092 }
1093 }
1094
1095 /* replace '.' by '_' */
1096 *outFilename++=*entryName++='_';
1097 ++inFilename;
1098
1099 /* copy suffix */
1100 while(*inFilename!=0) {
1101 *outFilename++=*entryName++=*inFilename++;
1102 }
1103
1104 *entryName=0;
1105
374ca955
A
1106 if(options[kOptFilename].doesOccur) {
1107 uprv_strcpy(saveOutFilename, options[kOptFilename].value);
1108 uprv_strcat(saveOutFilename, newSuffix);
1109 } else {
1110 /* add ".c" */
1111 uprv_strcpy(outFilename, newSuffix);
1112 }
b75a7d8f
A
1113 }
1114}
1115
374ca955
A
1116static void
1117write32(FileStream *out, uint32_t bitField) {
1118 int32_t i;
1119 char bitFieldStr[64]; /* This is more bits than needed for a 32-bit number */
1120 char *s = bitFieldStr;
1121 uint8_t *ptrIdx = (uint8_t *)&bitField;
1122 static const char hexToStr[16] = {
1123 '0','1','2','3',
1124 '4','5','6','7',
1125 '8','9','A','B',
1126 'C','D','E','F'
1127 };
1128
1129 /* write the value, possibly with comma and newline */
1130 if(column==MAX_COLUMN) {
1131 /* first byte */
1132 column=1;
1133 } else if(column<32) {
1134 *(s++)=',';
1135 ++column;
1136 } else {
1137 *(s++)='\n';
1138 uprv_strcpy(s, assemblyHeader[assemblyHeaderIndex].beginLine);
1139 s+=uprv_strlen(s);
1140 column=1;
1141 }
1142
1143 if (bitField < 10) {
1144 /* It's a small number. Don't waste the space for 0x */
1145 *(s++)=hexToStr[bitField];
1146 }
1147 else {
1148 int seenNonZero = 0; /* This is used to remove leading zeros */
1149
1150 *(s++)='0';
1151 *(s++)='x';
1152
1153 /* This creates a 32-bit field */
1154#if U_IS_BIG_ENDIAN
1155 for (i = 0; i < sizeof(uint32_t); i++)
1156#else
1157 for (i = sizeof(uint32_t)-1; i >= 0 ; i--)
1158#endif
1159 {
1160 uint8_t value = ptrIdx[i];
1161 if (value || seenNonZero) {
1162 *(s++)=hexToStr[value>>4];
1163 *(s++)=hexToStr[value&0xF];
1164 seenNonZero = 1;
1165 }
1166 }
1167 }
1168
1169 *(s++)=0;
1170 T_FileStream_writeLine(out, bitFieldStr);
1171}
1172
b75a7d8f
A
1173static void
1174write8(FileStream *out, uint8_t byte) {
1175 char s[4];
1176 int i=0;
1177
1178 /* convert the byte value to a string */
1179 if(byte>=100) {
1180 s[i++]=(char)('0'+byte/100);
1181 byte%=100;
1182 }
1183 if(i>0 || byte>=10) {
1184 s[i++]=(char)('0'+byte/10);
1185 byte%=10;
1186 }
1187 s[i++]=(char)('0'+byte);
1188 s[i]=0;
1189
1190 /* write the value, possibly with comma and newline */
1191 if(column==MAX_COLUMN) {
1192 /* first byte */
1193 column=1;
1194 } else if(column<16) {
1195 T_FileStream_writeLine(out, ",");
1196 ++column;
1197 } else {
1198 T_FileStream_writeLine(out, ",\n");
1199 column=1;
1200 }
1201 T_FileStream_writeLine(out, s);
1202}
1203
1204#ifdef OS400
1205static void
1206write8str(FileStream *out, uint8_t byte) {
1207 char s[8];
1208
374ca955
A
1209 if (byte > 7)
1210 sprintf(s, "\\x%X", byte);
1211 else
1212 sprintf(s, "\\%X", byte);
b75a7d8f
A
1213
1214 /* write the value, possibly with comma and newline */
1215 if(column==MAX_COLUMN) {
1216 /* first byte */
1217 column=1;
1218 T_FileStream_writeLine(out, "\"");
374ca955 1219 } else if(column<24) {
b75a7d8f
A
1220 ++column;
1221 } else {
1222 T_FileStream_writeLine(out, "\"\n\"");
1223 column=1;
1224 }
1225 T_FileStream_writeLine(out, s);
1226}
1227#endif