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