• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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