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