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 *******************************************************************************
8 #include "unicode/utypes.h"
10 #if U_PLATFORM_HAS_WIN32_API
12 # define WIN32_LEAN_AND_MEAN
20 # define WINDOWS_WITH_GNUC
24 #if U_PLATFORM_IS_LINUX_BASED && U_HAVE_ELF_H
30 # if defined(ELFCLASS64)
33 /* Old elf.h headers may not have EM_X86_64, or have EM_X8664 instead. */
37 # define ICU_ENTRY_OFFSET 0
42 #include "unicode/putil.h"
47 #include "unicode/uclean.h"
50 #include "filetools.h"
52 #include "unicode/errorcode.h"
54 #define MAX_COLUMN ((uint32_t)(0xFFFFFFFFU))
56 #define HEX_0X 0 /* 0x1234 */
57 #define HEX_0H 1 /* 01234h */
59 /* prototypes --------------------------------------------------------------- */
62 const char *inFilename
,
65 int32_t outFilenameCapacity
,
67 int32_t entryNameCapacity
,
68 const char *newSuffix
,
69 const char *optFilename
);
72 write8(FileStream
*out
, uint8_t byte
, uint32_t column
);
75 write32(FileStream
*out
, uint32_t byte
, uint32_t column
);
77 #if U_PLATFORM == U_PF_OS400
79 write8str(FileStream
*out
, uint8_t byte
, uint32_t column
);
81 /* -------------------------------------------------------------------------- */
84 Creating Template Files for New Platforms
86 Let the cc compiler help you get started.
88 const unsigned int x[5] = {1, 2, 0xdeadbeef, 0xffffffff, 16};
89 with the -S option to produce assembly output.
91 For example, this will generate array.s:
94 This will produce a .s file that may look like this:
110 .ident "GCC: (GNU) 2.96 20000731 (Red Hat Linux 7.1 2.96-85)"
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.
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.
121 static const struct AssemblyType
{
124 const char *beginLine
;
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 */
133 "\t.section .note.GNU-stack,\"\",%%progbits\n"
134 "\t.section .rodata\n"
136 "#ifdef U_HIDE_DATA_SYMBOL\n"
139 "\t.type %s,%%object\n"
142 ".long ",".size %s, .-%s\n",HEX_0X
145 /*"\t.section __TEXT,__text,regular,pure_instructions\n"
146 "\t.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32\n"*/
148 "#ifdef U_HIDE_DATA_SYMBOL\n"
149 "\t.private_extern _%s\n"
160 "\t.section .rodata\n"
168 "\t.section .rodata\n"
174 /* 16 bytes alignment. */
175 /* http://docs.oracle.com/cd/E19641-01/802-1947/802-1947.pdf */
177 "\t.section \".rodata\"\n"
184 /* 16 bytes alignment for sun-x86. */
185 /* http://docs.oracle.com/cd/E19963-01/html/821-1608/eoiyg.html */
188 "\t.type Drodata.rodata,@object\n"
189 "\t.size Drodata.rodata,0\n"
196 /* 1<<4 bit alignment for aix. */
197 /* http://pic.dhe.ibm.com/infocenter/aix/v6r1/index.jsp?topic=%2Fcom.ibm.aix.aixassem%2Fdoc%2Falangref%2Fidalangref_csect_pseudoop.htm */
202 "\t.csect %s{RO}, 4\n",
208 "\t.type %s,@object\n"
210 "\t.secalias .abe$0.rodata, \".rodata\"\n"
211 "\t.section .abe$0.rodata = \"a\", \"progbits\"\n"
227 /* http://msdn.microsoft.com/en-us/library/dwa9fwef.aspx */
230 "; generated by genccode\n"
234 "ICUDATA_%s\tSEGMENT READONLY PARA PUBLIC FLAT 'DATA'\n"
236 "_%s\tLABEL DWORD\n",
237 "\tDWORD ","\nICUDATA_%s\tENDS\n\tEND\n",HEX_0H
241 static int32_t assemblyHeaderIndex
= -1;
242 static int32_t hexType
= HEX_0X
;
244 U_CAPI UBool U_EXPORT2
245 checkAssemblyHeaderName(const char* optAssembly
) {
247 assemblyHeaderIndex
= -1;
248 for (idx
= 0; idx
< UPRV_LENGTHOF(assemblyHeader
); idx
++) {
249 if (uprv_strcmp(optAssembly
, assemblyHeader
[idx
].name
) == 0) {
250 assemblyHeaderIndex
= idx
;
251 hexType
= assemblyHeader
[idx
].hexType
; /* set the hex type */
260 U_CAPI
void U_EXPORT2
261 printAssemblyHeadersToStdErr(void) {
263 fprintf(stderr
, "%s", assemblyHeader
[0].name
);
264 for (idx
= 1; idx
< UPRV_LENGTHOF(assemblyHeader
); idx
++) {
265 fprintf(stderr
, ", %s", assemblyHeader
[idx
].name
);
271 U_CAPI
void U_EXPORT2
273 const char *filename
,
275 const char *optEntryPoint
,
276 const char *optFilename
,
278 size_t outFilePathCapacity
) {
279 uint32_t column
= MAX_COLUMN
;
282 uint32_t uint32s
[1024];
285 FileStream
*in
, *out
;
286 size_t i
, length
, count
;
288 in
=T_FileStream_open(filename
, "rb");
290 fprintf(stderr
, "genccode: unable to open input file %s\n", filename
);
291 exit(U_FILE_ACCESS_ERROR
);
298 sizeof(buffer
.chars
),
303 out
=T_FileStream_open(buffer
.chars
, "w");
305 fprintf(stderr
, "genccode: unable to open output file %s\n", buffer
.chars
);
306 exit(U_FILE_ACCESS_ERROR
);
309 if (outFilePath
!= NULL
) {
310 if (uprv_strlen(buffer
.chars
) >= outFilePathCapacity
) {
311 fprintf(stderr
, "genccode: filename too long\n");
312 exit(U_ILLEGAL_ARGUMENT_ERROR
);
314 uprv_strcpy(outFilePath
, buffer
.chars
);
317 #if defined (WINDOWS_WITH_GNUC) && U_PLATFORM != U_PF_CYGWIN
318 /* Need to fix the file separator character when using MinGW. */
319 swapFileSepChar(outFilePath
, U_FILE_SEP_CHAR
, '/');
322 if(optEntryPoint
!= NULL
) {
323 uprv_strcpy(entry
, optEntryPoint
);
324 uprv_strcat(entry
, "_dat");
327 /* turn dashes or dots in the entry name into underscores */
328 length
=uprv_strlen(entry
);
329 for(i
=0; i
<length
; ++i
) {
330 if(entry
[i
]=='-' || entry
[i
]=='.') {
336 buffer
.chars
, sizeof(buffer
.chars
),
337 assemblyHeader
[assemblyHeaderIndex
].header
,
338 entry
, entry
, entry
, entry
,
339 entry
, entry
, entry
, entry
);
340 if (count
>= sizeof(buffer
.chars
)) {
341 fprintf(stderr
, "genccode: entry name too long (long filename?)\n");
342 exit(U_ILLEGAL_ARGUMENT_ERROR
);
344 T_FileStream_writeLine(out
, buffer
.chars
);
345 T_FileStream_writeLine(out
, assemblyHeader
[assemblyHeaderIndex
].beginLine
);
348 memset(buffer
.uint32s
, 0, sizeof(buffer
.uint32s
));
349 length
=T_FileStream_read(in
, buffer
.uint32s
, sizeof(buffer
.uint32s
));
353 for(i
=0; i
<(length
/sizeof(buffer
.uint32s
[0])); i
++) {
354 // TODO: What if the last read sees length not as a multiple of 4?
355 column
= write32(out
, buffer
.uint32s
[i
], column
);
359 T_FileStream_writeLine(out
, "\n");
362 buffer
.chars
, sizeof(buffer
.chars
),
363 assemblyHeader
[assemblyHeaderIndex
].footer
,
364 entry
, entry
, entry
, entry
,
365 entry
, entry
, entry
, entry
);
366 if (count
>= sizeof(buffer
.chars
)) {
367 fprintf(stderr
, "genccode: entry name too long (long filename?)\n");
368 exit(U_ILLEGAL_ARGUMENT_ERROR
);
370 T_FileStream_writeLine(out
, buffer
.chars
);
372 if(T_FileStream_error(in
)) {
373 fprintf(stderr
, "genccode: file read error while generating from file %s\n", filename
);
374 exit(U_FILE_ACCESS_ERROR
);
377 if(T_FileStream_error(out
)) {
378 fprintf(stderr
, "genccode: file write error while generating from file %s\n", filename
);
379 exit(U_FILE_ACCESS_ERROR
);
382 T_FileStream_close(out
);
383 T_FileStream_close(in
);
386 U_CAPI
void U_EXPORT2
388 const char *filename
,
391 const char *optFilename
,
393 size_t outFilePathCapacity
) {
394 uint32_t column
= MAX_COLUMN
;
395 char buffer
[4096], entry
[96];
396 FileStream
*in
, *out
;
397 size_t i
, length
, count
;
399 in
=T_FileStream_open(filename
, "rb");
401 fprintf(stderr
, "genccode: unable to open input file %s\n", filename
);
402 exit(U_FILE_ACCESS_ERROR
);
405 if(optName
!= NULL
) { /* prepend 'icudt28_' */
406 // +2 includes the _ and the NUL
407 if (uprv_strlen(optName
) + 2 > sizeof(entry
)) {
408 fprintf(stderr
, "genccode: entry name too long (long filename?)\n");
409 exit(U_ILLEGAL_ARGUMENT_ERROR
);
411 strcpy(entry
, optName
);
421 static_cast<int32_t>(sizeof(buffer
)),
422 entry
+ uprv_strlen(entry
),
423 static_cast<int32_t>(sizeof(entry
) - uprv_strlen(entry
)),
427 if (outFilePath
!= NULL
) {
428 if (uprv_strlen(buffer
) >= outFilePathCapacity
) {
429 fprintf(stderr
, "genccode: filename too long\n");
430 exit(U_ILLEGAL_ARGUMENT_ERROR
);
432 uprv_strcpy(outFilePath
, buffer
);
435 out
=T_FileStream_open(buffer
, "w");
437 fprintf(stderr
, "genccode: unable to open output file %s\n", buffer
);
438 exit(U_FILE_ACCESS_ERROR
);
441 /* turn dashes or dots in the entry name into underscores */
442 length
=uprv_strlen(entry
);
443 for(i
=0; i
<length
; ++i
) {
444 if(entry
[i
]=='-' || entry
[i
]=='.') {
449 #if U_PLATFORM == U_PF_OS400
451 TODO: Fix this once the compiler implements this feature. Keep in sync with udatamem.c
453 This is here because this platform can't currently put
454 const data into the read-only pages of an object or
455 shared library (service program). Only strings are allowed in read-only
456 pages, so we use char * strings to store the data.
458 In order to prevent the beginning of the data from ever matching the
459 magic numbers we must still use the initial double.
462 count
= snprintf(buffer
, sizeof(buffer
),
463 "#ifndef IN_GENERATED_CCODE\n"
464 "#define IN_GENERATED_CCODE\n"
465 "#define U_DISABLE_RENAMING 1\n"
466 "#include \"unicode/umachine.h\"\n"
471 " const char *bytes; \n"
474 if (count
>= sizeof(buffer
)) {
475 fprintf(stderr
, "genccode: entry name too long (long filename?)\n");
476 exit(U_ILLEGAL_ARGUMENT_ERROR
);
478 T_FileStream_writeLine(out
, buffer
);
481 length
=T_FileStream_read(in
, buffer
, sizeof(buffer
));
485 for(i
=0; i
<length
; ++i
) {
486 column
= write8str(out
, (uint8_t)buffer
[i
], column
);
490 T_FileStream_writeLine(out
, "\"\n};\nU_CDECL_END\n");
492 /* Function renaming shouldn't be done in data */
493 count
= snprintf(buffer
, sizeof(buffer
),
494 "#ifndef IN_GENERATED_CCODE\n"
495 "#define IN_GENERATED_CCODE\n"
496 "#define U_DISABLE_RENAMING 1\n"
497 "#include \"unicode/umachine.h\"\n"
502 " uint8_t bytes[%ld]; \n"
504 (long)T_FileStream_size(in
), entry
);
505 if (count
>= sizeof(buffer
)) {
506 fprintf(stderr
, "genccode: entry name too long (long filename?)\n");
507 exit(U_ILLEGAL_ARGUMENT_ERROR
);
509 T_FileStream_writeLine(out
, buffer
);
512 length
=T_FileStream_read(in
, buffer
, sizeof(buffer
));
516 for(i
=0; i
<length
; ++i
) {
517 column
= write8(out
, (uint8_t)buffer
[i
], column
);
521 T_FileStream_writeLine(out
, "\n}\n};\nU_CDECL_END\n");
524 if(T_FileStream_error(in
)) {
525 fprintf(stderr
, "genccode: file read error while generating from file %s\n", filename
);
526 exit(U_FILE_ACCESS_ERROR
);
529 if(T_FileStream_error(out
)) {
530 fprintf(stderr
, "genccode: file write error while generating from file %s\n", filename
);
531 exit(U_FILE_ACCESS_ERROR
);
534 T_FileStream_close(out
);
535 T_FileStream_close(in
);
539 write32(FileStream
*out
, uint32_t bitField
, uint32_t column
) {
541 char bitFieldStr
[64]; /* This is more bits than needed for a 32-bit number */
542 char *s
= bitFieldStr
;
543 uint8_t *ptrIdx
= (uint8_t *)&bitField
;
544 static const char hexToStr
[16] = {
551 /* write the value, possibly with comma and newline */
552 if(column
==MAX_COLUMN
) {
555 } else if(column
<32) {
560 uprv_strcpy(s
, assemblyHeader
[assemblyHeaderIndex
].beginLine
);
566 /* It's a small number. Don't waste the space for 0x */
567 *(s
++)=hexToStr
[bitField
];
570 int seenNonZero
= 0; /* This is used to remove leading zeros */
572 if(hexType
==HEX_0X
) {
575 } else if(hexType
==HEX_0H
) {
579 /* This creates a 32-bit field */
581 for (i
= 0; i
< sizeof(uint32_t); i
++)
583 for (i
= sizeof(uint32_t)-1; i
>= 0 ; i
--)
586 uint8_t value
= ptrIdx
[i
];
587 if (value
|| seenNonZero
) {
588 *(s
++)=hexToStr
[value
>>4];
589 *(s
++)=hexToStr
[value
&0xF];
593 if(hexType
==HEX_0H
) {
599 T_FileStream_writeLine(out
, bitFieldStr
);
604 write8(FileStream
*out
, uint8_t byte
, uint32_t column
) {
608 /* convert the byte value to a string */
610 s
[i
++]=(char)('0'+byte
/100);
613 if(i
>0 || byte
>=10) {
614 s
[i
++]=(char)('0'+byte
/10);
617 s
[i
++]=(char)('0'+byte
);
620 /* write the value, possibly with comma and newline */
621 if(column
==MAX_COLUMN
) {
624 } else if(column
<16) {
625 T_FileStream_writeLine(out
, ",");
628 T_FileStream_writeLine(out
, ",\n");
631 T_FileStream_writeLine(out
, s
);
635 #if U_PLATFORM == U_PF_OS400
637 write8str(FileStream
*out
, uint8_t byte
, uint32_t column
) {
641 sprintf(s
, "\\x%X", byte
);
643 sprintf(s
, "\\%X", byte
);
645 /* write the value, possibly with comma and newline */
646 if(column
==MAX_COLUMN
) {
649 T_FileStream_writeLine(out
, "\"");
650 } else if(column
<24) {
653 T_FileStream_writeLine(out
, "\"\n\"");
656 T_FileStream_writeLine(out
, s
);
663 const char *inFilename
,
666 int32_t outFilenameCapacity
,
668 int32_t entryNameCapacity
,
669 const char *newSuffix
,
670 const char *optFilename
) {
671 const char *basename
=findBasename(inFilename
), *suffix
=uprv_strrchr(basename
, '.');
673 icu::CharString outFilenameBuilder
;
674 icu::CharString entryNameBuilder
;
675 icu::ErrorCode status
;
678 if(destdir
!=NULL
&& *destdir
!=0) {
679 outFilenameBuilder
.append(destdir
, status
);
680 outFilenameBuilder
.ensureEndsWithFileSeparator(status
);
682 outFilenameBuilder
.append(inFilename
, static_cast<int32_t>(basename
- inFilename
), status
);
687 /* the filename does not have a suffix */
688 entryNameBuilder
.append(inFilename
, status
);
689 if(optFilename
!= NULL
) {
690 outFilenameBuilder
.append(optFilename
, status
);
692 outFilenameBuilder
.append(inFilename
, status
);
694 outFilenameBuilder
.append(newSuffix
, status
);
696 int32_t saveOutFilenameLength
= outFilenameBuilder
.length();
698 while(inFilename
<suffix
) {
699 // iSeries cannot have '-' in the .o objects.
700 char c
= (*inFilename
=='-') ? '_' : *inFilename
;
701 outFilenameBuilder
.append(c
, status
);
702 entryNameBuilder
.append(c
, status
);
706 /* replace '.' by '_' */
707 outFilenameBuilder
.append('_', status
);
708 entryNameBuilder
.append('_', status
);
712 outFilenameBuilder
.append(inFilename
, status
);
713 entryNameBuilder
.append(inFilename
, status
);
715 if(optFilename
!= NULL
) {
716 outFilenameBuilder
.truncate(saveOutFilenameLength
);
717 outFilenameBuilder
.append(optFilename
, status
);
720 outFilenameBuilder
.append(newSuffix
, status
);
723 if (status
.isFailure()) {
724 fprintf(stderr
, "genccode: error building filename or entrypoint\n");
728 if (outFilenameBuilder
.length() >= outFilenameCapacity
) {
729 fprintf(stderr
, "genccode: output filename too long\n");
730 exit(U_ILLEGAL_ARGUMENT_ERROR
);
733 if (entryNameBuilder
.length() >= entryNameCapacity
) {
734 fprintf(stderr
, "genccode: entry name too long (long filename?)\n");
735 exit(U_ILLEGAL_ARGUMENT_ERROR
);
738 uprv_strcpy(outFilename
, outFilenameBuilder
.data());
739 uprv_strcpy(entryName
, entryNameBuilder
.data());
742 #ifdef CAN_GENERATE_OBJECTS
744 getArchitecture(uint16_t *pCPU
, uint16_t *pBits
, UBool
*pIsBigEndian
, const char *optMatchArch
) {
749 /* Elf32_Ehdr and ELF64_Ehdr are identical for the necessary fields. */
750 #elif U_PLATFORM_HAS_WIN32_API
751 IMAGE_FILE_HEADER header
;
755 const char *filename
;
761 #elif U_PLATFORM_HAS_WIN32_API
762 const IMAGE_FILE_HEADER
*pHeader
;
764 # error "Unknown platform for CAN_GENERATE_OBJECTS."
767 if(optMatchArch
!= NULL
) {
768 filename
=optMatchArch
;
772 /* set EM_386 because elf.h does not provide better defaults */
775 *pIsBigEndian
=(UBool
)(U_IS_BIG_ENDIAN
? ELFDATA2MSB
: ELFDATA2LSB
);
776 #elif U_PLATFORM_HAS_WIN32_API
777 // Windows always runs in little-endian mode.
778 *pIsBigEndian
= FALSE
;
780 // Note: The various _M_<arch> macros are predefined by the MSVC compiler based
781 // on the target compilation architecture.
782 // https://docs.microsoft.com/cpp/preprocessor/predefined-macros
784 // link.exe will link an IMAGE_FILE_MACHINE_UNKNOWN data-only .obj file
785 // no matter what architecture it is targeting (though other values are
786 // required to match). Unfortunately, the variable name decoration/mangling
787 // is slightly different on x86, which means we can't use the UNKNOWN type
788 // for all architectures though.
789 # if defined(_M_IX86)
790 *pCPU
= IMAGE_FILE_MACHINE_I386
;
792 *pCPU
= IMAGE_FILE_MACHINE_UNKNOWN
;
794 # if defined(_M_IA64) || defined(_M_AMD64) || defined (_M_ARM64)
795 *pBits
= 64; // Doesn't seem to be used for anything interesting though?
796 # elif defined(_M_IX86) || defined(_M_ARM)
799 # error "Unknown platform for CAN_GENERATE_OBJECTS."
802 # error "Unknown platform for CAN_GENERATE_OBJECTS."
807 in
=T_FileStream_open(filename
, "rb");
809 fprintf(stderr
, "genccode: unable to open match-arch file %s\n", filename
);
810 exit(U_FILE_ACCESS_ERROR
);
812 length
=T_FileStream_read(in
, buffer
.bytes
, sizeof(buffer
.bytes
));
815 if(length
<(int32_t)sizeof(Elf32_Ehdr
)) {
816 fprintf(stderr
, "genccode: match-arch file %s is too short\n", filename
);
817 exit(U_UNSUPPORTED_ERROR
);
820 buffer
.header32
.e_ident
[0]!=ELFMAG0
||
821 buffer
.header32
.e_ident
[1]!=ELFMAG1
||
822 buffer
.header32
.e_ident
[2]!=ELFMAG2
||
823 buffer
.header32
.e_ident
[3]!=ELFMAG3
||
824 buffer
.header32
.e_ident
[EI_CLASS
]<ELFCLASS32
|| buffer
.header32
.e_ident
[EI_CLASS
]>ELFCLASS64
826 fprintf(stderr
, "genccode: match-arch file %s is not an ELF object file, or not supported\n", filename
);
827 exit(U_UNSUPPORTED_ERROR
);
830 *pBits
= buffer
.header32
.e_ident
[EI_CLASS
]==ELFCLASS32
? 32 : 64; /* only 32 or 64: see check above */
832 if(*pBits
!=32 && *pBits
!=64) {
833 fprintf(stderr
, "genccode: currently only supports 32-bit and 64-bit ELF format\n");
834 exit(U_UNSUPPORTED_ERROR
);
838 fprintf(stderr
, "genccode: built with elf.h missing 64-bit definitions\n");
839 exit(U_UNSUPPORTED_ERROR
);
843 *pIsBigEndian
=(UBool
)(buffer
.header32
.e_ident
[EI_DATA
]==ELFDATA2MSB
);
844 if(*pIsBigEndian
!=U_IS_BIG_ENDIAN
) {
845 fprintf(stderr
, "genccode: currently only same-endianness ELF formats are supported\n");
846 exit(U_UNSUPPORTED_ERROR
);
848 /* TODO: Support byte swapping */
850 *pCPU
=buffer
.header32
.e_machine
;
851 #elif U_PLATFORM_HAS_WIN32_API
852 if(length
<sizeof(IMAGE_FILE_HEADER
)) {
853 fprintf(stderr
, "genccode: match-arch file %s is too short\n", filename
);
854 exit(U_UNSUPPORTED_ERROR
);
856 /* TODO: Use buffer.header. Keep aliasing legal. */
857 pHeader
=(const IMAGE_FILE_HEADER
*)buffer
.bytes
;
858 *pCPU
=pHeader
->Machine
;
860 * The number of bits is implicit with the Machine value.
861 * *pBits is ignored in the calling code, so this need not be precise.
863 *pBits
= *pCPU
==IMAGE_FILE_MACHINE_I386
? 32 : 64;
864 /* Windows always runs on little-endian CPUs. */
867 # error "Unknown platform for CAN_GENERATE_OBJECTS."
870 T_FileStream_close(in
);
873 U_CAPI
void U_EXPORT2
875 const char *filename
,
877 const char *optEntryPoint
,
878 const char *optMatchArch
,
879 const char *optFilename
,
881 size_t outFilePathCapacity
) {
882 /* common variables */
883 char buffer
[4096], entry
[96]={ 0 };
884 FileStream
*in
, *out
;
885 const char *newSuffix
;
886 int32_t i
, entryLength
, length
, size
, entryOffset
=0, entryLengthOffset
=0;
891 /* platform-specific variables and initialization code */
893 /* 32-bit Elf file header */
894 static Elf32_Ehdr header32
={
897 ELFMAG0
, ELFMAG1
, ELFMAG2
, ELFMAG3
,
899 U_IS_BIG_ENDIAN
? ELFDATA2MSB
: ELFDATA2LSB
,
900 EV_CURRENT
/* EI_VERSION */
904 EV_CURRENT
, /* e_version */
907 (Elf32_Off
)sizeof(Elf32_Ehdr
), /* e_shoff */
909 (Elf32_Half
)sizeof(Elf32_Ehdr
), /* eh_size */
912 (Elf32_Half
)sizeof(Elf32_Shdr
), /* e_shentsize */
917 /* 32-bit Elf section header table */
918 static Elf32_Shdr sectionHeaders32
[5]={
920 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
927 (Elf32_Off
)(sizeof(header32
)+sizeof(sectionHeaders32
)), /* sh_offset */
928 (Elf32_Word
)(2*sizeof(Elf32_Sym
)), /* sh_size */
929 3, /* sh_link=sect hdr index of .strtab */
930 1, /* sh_info=One greater than the symbol table index of the last
931 * local symbol (with STB_LOCAL). */
932 4, /* sh_addralign */
933 (Elf32_Word
)(sizeof(Elf32_Sym
)) /* sh_entsize */
940 (Elf32_Off
)(sizeof(header32
)+sizeof(sectionHeaders32
)+2*sizeof(Elf32_Sym
)), /* sh_offset */
944 1, /* sh_addralign */
952 (Elf32_Off
)(sizeof(header32
)+sizeof(sectionHeaders32
)+2*sizeof(Elf32_Sym
)+40), /* sh_offset */
953 (Elf32_Word
)sizeof(entry
), /* sh_size */
956 1, /* sh_addralign */
962 SHF_ALLOC
, /* sh_flags */
964 (Elf32_Off
)(sizeof(header32
)+sizeof(sectionHeaders32
)+2*sizeof(Elf32_Sym
)+40+sizeof(entry
)), /* sh_offset */
968 16, /* sh_addralign */
974 static Elf32_Sym symbols32
[2]={
978 { /* data entry point */
982 ELF64_ST_INFO(STB_GLOBAL
, STT_OBJECT
),
984 4 /* st_shndx=index of related section table entry */
988 /* section header string table, with decimal string offsets */
989 static const char sectionStrings
[40]=
992 /* 9 */ ".shstrtab\0"
995 /* 35 */ "\0\0\0\0"; /* contains terminating NUL */
996 /* 40: padded to multiple of 8 bytes */
999 * Use entry[] for the string table which will contain only the
1001 * entry[0] must be 0 (NUL)
1002 * The entry point name can be up to 38 characters long (sizeof(entry)-2).
1005 /* 16-align .rodata in the .o file, just in case */
1006 static const char padding
[16]={ 0 };
1007 int32_t paddingSize
;
1010 /* 64-bit Elf file header */
1011 static Elf64_Ehdr header64
={
1014 ELFMAG0
, ELFMAG1
, ELFMAG2
, ELFMAG3
,
1016 U_IS_BIG_ENDIAN
? ELFDATA2MSB
: ELFDATA2LSB
,
1017 EV_CURRENT
/* EI_VERSION */
1021 EV_CURRENT
, /* e_version */
1024 (Elf64_Off
)sizeof(Elf64_Ehdr
), /* e_shoff */
1026 (Elf64_Half
)sizeof(Elf64_Ehdr
), /* eh_size */
1027 0, /* e_phentsize */
1029 (Elf64_Half
)sizeof(Elf64_Shdr
), /* e_shentsize */
1034 /* 64-bit Elf section header table */
1035 static Elf64_Shdr sectionHeaders64
[5]={
1037 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1044 (Elf64_Off
)(sizeof(header64
)+sizeof(sectionHeaders64
)), /* sh_offset */
1045 (Elf64_Xword
)(2*sizeof(Elf64_Sym
)), /* sh_size */
1046 3, /* sh_link=sect hdr index of .strtab */
1047 1, /* sh_info=One greater than the symbol table index of the last
1048 * local symbol (with STB_LOCAL). */
1049 4, /* sh_addralign */
1050 (Elf64_Xword
)(sizeof(Elf64_Sym
)) /* sh_entsize */
1057 (Elf64_Off
)(sizeof(header64
)+sizeof(sectionHeaders64
)+2*sizeof(Elf64_Sym
)), /* sh_offset */
1061 1, /* sh_addralign */
1069 (Elf64_Off
)(sizeof(header64
)+sizeof(sectionHeaders64
)+2*sizeof(Elf64_Sym
)+40), /* sh_offset */
1070 (Elf64_Xword
)sizeof(entry
), /* sh_size */
1073 1, /* sh_addralign */
1079 SHF_ALLOC
, /* sh_flags */
1081 (Elf64_Off
)(sizeof(header64
)+sizeof(sectionHeaders64
)+2*sizeof(Elf64_Sym
)+40+sizeof(entry
)), /* sh_offset */
1085 16, /* sh_addralign */
1091 * 64-bit symbol table
1092 * careful: different order of items compared with Elf32_sym!
1094 static Elf64_Sym symbols64
[2]={
1098 { /* data entry point */
1100 ELF64_ST_INFO(STB_GLOBAL
, STT_OBJECT
),
1102 4, /* st_shndx=index of related section table entry */
1108 #endif /* U_ELF64 */
1110 /* entry[] have a leading NUL */
1113 /* in the common code, count entryLength from after the NUL */
1114 entryLengthOffset
=1;
1118 #elif U_PLATFORM_HAS_WIN32_API
1120 IMAGE_FILE_HEADER fileHeader
;
1121 IMAGE_SECTION_HEADER sections
[2];
1122 char linkerOptions
[100];
1124 IMAGE_SYMBOL symbols
[1];
1126 DWORD sizeofLongNames
;
1127 char longNames
[100];
1131 * entry sometimes have a leading '_'
1132 * overwritten if entryOffset==0 depending on the target platform
1133 * see check for cpu below
1139 # error "Unknown platform for CAN_GENERATE_OBJECTS."
1142 /* deal with options, files and the entry point name */
1143 getArchitecture(&cpu
, &bits
, &makeBigEndian
, optMatchArch
);
1146 printf("genccode: --match-arch cpu=%hu bits=%hu big-endian=%d\n", cpu
, bits
, makeBigEndian
);
1150 printf("genccode: using architecture cpu=%hu bits=%hu big-endian=%d\n", cpu
, bits
, makeBigEndian
);
1152 #if U_PLATFORM_HAS_WIN32_API
1153 if(cpu
==IMAGE_FILE_MACHINE_I386
) {
1158 in
=T_FileStream_open(filename
, "rb");
1160 fprintf(stderr
, "genccode: unable to open input file %s\n", filename
);
1161 exit(U_FILE_ACCESS_ERROR
);
1163 size
=T_FileStream_size(in
);
1170 entry
+ entryOffset
,
1171 sizeof(entry
) - entryOffset
,
1175 if (outFilePath
!= NULL
) {
1176 if (uprv_strlen(buffer
) >= outFilePathCapacity
) {
1177 fprintf(stderr
, "genccode: filename too long\n");
1178 exit(U_ILLEGAL_ARGUMENT_ERROR
);
1180 uprv_strcpy(outFilePath
, buffer
);
1183 if(optEntryPoint
!= NULL
) {
1184 uprv_strcpy(entry
+entryOffset
, optEntryPoint
);
1185 uprv_strcat(entry
+entryOffset
, "_dat");
1187 /* turn dashes in the entry name into underscores */
1188 entryLength
=(int32_t)uprv_strlen(entry
+entryLengthOffset
);
1189 for(i
=0; i
<entryLength
; ++i
) {
1190 if(entry
[entryLengthOffset
+i
]=='-') {
1191 entry
[entryLengthOffset
+i
]='_';
1195 /* open the output file */
1196 out
=T_FileStream_open(buffer
, "wb");
1198 fprintf(stderr
, "genccode: unable to open output file %s\n", buffer
);
1199 exit(U_FILE_ACCESS_ERROR
);
1204 header32
.e_ident
[EI_DATA
]= makeBigEndian
? ELFDATA2MSB
: ELFDATA2LSB
;
1205 header32
.e_machine
=cpu
;
1207 /* 16-align .rodata in the .o file, just in case */
1208 paddingSize
=sectionHeaders32
[4].sh_offset
& 0xf;
1209 if(paddingSize
!=0) {
1210 paddingSize
=0x10-paddingSize
;
1211 sectionHeaders32
[4].sh_offset
+=paddingSize
;
1214 sectionHeaders32
[4].sh_size
=(Elf32_Word
)size
;
1216 symbols32
[1].st_size
=(Elf32_Word
)size
;
1218 /* write .o headers */
1219 T_FileStream_write(out
, &header32
, (int32_t)sizeof(header32
));
1220 T_FileStream_write(out
, sectionHeaders32
, (int32_t)sizeof(sectionHeaders32
));
1221 T_FileStream_write(out
, symbols32
, (int32_t)sizeof(symbols32
));
1222 } else /* bits==64 */ {
1224 header64
.e_ident
[EI_DATA
]= makeBigEndian
? ELFDATA2MSB
: ELFDATA2LSB
;
1225 header64
.e_machine
=cpu
;
1227 /* 16-align .rodata in the .o file, just in case */
1228 paddingSize
=sectionHeaders64
[4].sh_offset
& 0xf;
1229 if(paddingSize
!=0) {
1230 paddingSize
=0x10-paddingSize
;
1231 sectionHeaders64
[4].sh_offset
+=paddingSize
;
1234 sectionHeaders64
[4].sh_size
=(Elf64_Xword
)size
;
1236 symbols64
[1].st_size
=(Elf64_Xword
)size
;
1238 /* write .o headers */
1239 T_FileStream_write(out
, &header64
, (int32_t)sizeof(header64
));
1240 T_FileStream_write(out
, sectionHeaders64
, (int32_t)sizeof(sectionHeaders64
));
1241 T_FileStream_write(out
, symbols64
, (int32_t)sizeof(symbols64
));
1245 T_FileStream_write(out
, sectionStrings
, (int32_t)sizeof(sectionStrings
));
1246 T_FileStream_write(out
, entry
, (int32_t)sizeof(entry
));
1247 if(paddingSize
!=0) {
1248 T_FileStream_write(out
, padding
, paddingSize
);
1250 #elif U_PLATFORM_HAS_WIN32_API
1251 /* populate the .obj headers */
1252 uprv_memset(&objHeader
, 0, sizeof(objHeader
));
1253 uprv_memset(&symbols
, 0, sizeof(symbols
));
1254 uprv_memset(&symbolNames
, 0, sizeof(symbolNames
));
1256 /* write the linker export directive */
1257 uprv_strcpy(objHeader
.linkerOptions
, "-export:");
1259 uprv_strcpy(objHeader
.linkerOptions
+length
, entry
);
1260 length
+=entryLength
;
1261 uprv_strcpy(objHeader
.linkerOptions
+length
, ",data ");
1264 /* set the file header */
1265 objHeader
.fileHeader
.Machine
=cpu
;
1266 objHeader
.fileHeader
.NumberOfSections
=2;
1267 objHeader
.fileHeader
.TimeDateStamp
=(DWORD
)time(NULL
);
1268 objHeader
.fileHeader
.PointerToSymbolTable
=IMAGE_SIZEOF_FILE_HEADER
+2*IMAGE_SIZEOF_SECTION_HEADER
+length
+size
; /* start of symbol table */
1269 objHeader
.fileHeader
.NumberOfSymbols
=1;
1271 /* set the section for the linker options */
1272 uprv_strncpy((char *)objHeader
.sections
[0].Name
, ".drectve", 8);
1273 objHeader
.sections
[0].SizeOfRawData
=length
;
1274 objHeader
.sections
[0].PointerToRawData
=IMAGE_SIZEOF_FILE_HEADER
+2*IMAGE_SIZEOF_SECTION_HEADER
;
1275 objHeader
.sections
[0].Characteristics
=IMAGE_SCN_LNK_INFO
|IMAGE_SCN_LNK_REMOVE
|IMAGE_SCN_ALIGN_1BYTES
;
1277 /* set the data section */
1278 uprv_strncpy((char *)objHeader
.sections
[1].Name
, ".rdata", 6);
1279 objHeader
.sections
[1].SizeOfRawData
=size
;
1280 objHeader
.sections
[1].PointerToRawData
=IMAGE_SIZEOF_FILE_HEADER
+2*IMAGE_SIZEOF_SECTION_HEADER
+length
;
1281 objHeader
.sections
[1].Characteristics
=IMAGE_SCN_CNT_INITIALIZED_DATA
|IMAGE_SCN_ALIGN_16BYTES
|IMAGE_SCN_MEM_READ
;
1283 /* set the symbol table */
1284 if(entryLength
<=8) {
1285 uprv_strncpy((char *)symbols
[0].N
.ShortName
, entry
, entryLength
);
1286 symbolNames
.sizeofLongNames
=4;
1288 symbols
[0].N
.Name
.Short
=0;
1289 symbols
[0].N
.Name
.Long
=4;
1290 symbolNames
.sizeofLongNames
=4+entryLength
+1;
1291 uprv_strcpy(symbolNames
.longNames
, entry
);
1293 symbols
[0].SectionNumber
=2;
1294 symbols
[0].StorageClass
=IMAGE_SYM_CLASS_EXTERNAL
;
1296 /* write the file header and the linker options section */
1297 T_FileStream_write(out
, &objHeader
, objHeader
.sections
[1].PointerToRawData
);
1299 # error "Unknown platform for CAN_GENERATE_OBJECTS."
1302 /* copy the data file into section 2 */
1304 length
=T_FileStream_read(in
, buffer
, sizeof(buffer
));
1308 T_FileStream_write(out
, buffer
, (int32_t)length
);
1311 #if U_PLATFORM_HAS_WIN32_API
1312 /* write the symbol table */
1313 T_FileStream_write(out
, symbols
, IMAGE_SIZEOF_SYMBOL
);
1314 T_FileStream_write(out
, &symbolNames
, symbolNames
.sizeofLongNames
);
1317 if(T_FileStream_error(in
)) {
1318 fprintf(stderr
, "genccode: file read error while generating from file %s\n", filename
);
1319 exit(U_FILE_ACCESS_ERROR
);
1322 if(T_FileStream_error(out
)) {
1323 fprintf(stderr
, "genccode: file write error while generating from file %s\n", filename
);
1324 exit(U_FILE_ACCESS_ERROR
);
1327 T_FileStream_close(out
);
1328 T_FileStream_close(in
);