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