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