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