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