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 #define MAX_COLUMN ((uint32_t)(0xFFFFFFFFU))
54 #define HEX_0X 0 /* 0x1234 */
55 #define HEX_0H 1 /* 01234h */
57 /* prototypes --------------------------------------------------------------- */
59 getOutFilename(const char *inFilename
, const char *destdir
, char *outFilename
, char *entryName
, const char *newSuffix
, const char *optFilename
);
62 write8(FileStream
*out
, uint8_t byte
, uint32_t column
);
65 write32(FileStream
*out
, uint32_t byte
, uint32_t column
);
67 #if U_PLATFORM == U_PF_OS400
69 write8str(FileStream
*out
, uint8_t byte
, uint32_t column
);
71 /* -------------------------------------------------------------------------- */
74 Creating Template Files for New Platforms
76 Let the cc compiler help you get started.
78 const unsigned int x[5] = {1, 2, 0xdeadbeef, 0xffffffff, 16};
79 with the -S option to produce assembly output.
81 For example, this will generate array.s:
84 This will produce a .s file that may look like this:
100 .ident "GCC: (GNU) 2.96 20000731 (Red Hat Linux 7.1 2.96-85)"
102 which gives a starting point that will compile, and can be transformed
103 to become the template, generally with some consulting of as docs and
104 some experimentation.
106 If you want ICU to automatically use this assembly, you should
107 specify "GENCCODE_ASSEMBLY=-a name" in the specific config/mh-* file,
108 where the name is the compiler or platform that you used in this
109 assemblyHeader data structure.
111 static const struct AssemblyType
{
114 const char *beginLine
;
116 int8_t hexType
; /* HEX_0X or HEX_0h */
117 } assemblyHeader
[] = {
118 /* For gcc assemblers, the meaning of .align changes depending on the */
119 /* hardware, so we use .balign 16 which always means 16 bytes. */
120 /* https://sourceware.org/binutils/docs/as/Pseudo-Ops.html */
123 "\t.section .note.GNU-stack,\"\",%%progbits\n"
124 "\t.section .rodata\n"
126 "#ifdef U_HIDE_DATA_SYMBOL\n"
129 "\t.type %s,%%object\n"
132 ".long ",".size %s, .-%s\n",HEX_0X
135 /*"\t.section __TEXT,__text,regular,pure_instructions\n"
136 "\t.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32\n"*/
138 "#ifdef U_HIDE_DATA_SYMBOL\n"
139 "\t.private_extern _%s\n"
150 "\t.section .rodata\n"
158 "\t.section .rodata\n"
164 /* 16 bytes alignment. */
165 /* http://docs.oracle.com/cd/E19641-01/802-1947/802-1947.pdf */
167 "\t.section \".rodata\"\n"
174 /* 16 bytes alignment for sun-x86. */
175 /* http://docs.oracle.com/cd/E19963-01/html/821-1608/eoiyg.html */
178 "\t.type Drodata.rodata,@object\n"
179 "\t.size Drodata.rodata,0\n"
186 /* 1<<4 bit alignment for aix. */
187 /* http://pic.dhe.ibm.com/infocenter/aix/v6r1/index.jsp?topic=%2Fcom.ibm.aix.aixassem%2Fdoc%2Falangref%2Fidalangref_csect_pseudoop.htm */
192 "\t.csect %s{RO}, 4\n",
198 "\t.type %s,@object\n"
200 "\t.secalias .abe$0.rodata, \".rodata\"\n"
201 "\t.section .abe$0.rodata = \"a\", \"progbits\"\n"
217 /* http://msdn.microsoft.com/en-us/library/dwa9fwef.aspx */
220 "; generated by genccode\n"
224 "ICUDATA_%s\tSEGMENT READONLY PARA PUBLIC FLAT 'DATA'\n"
226 "_%s\tLABEL DWORD\n",
227 "\tDWORD ","\nICUDATA_%s\tENDS\n\tEND\n",HEX_0H
231 static int32_t assemblyHeaderIndex
= -1;
232 static int32_t hexType
= HEX_0X
;
234 U_CAPI UBool U_EXPORT2
235 checkAssemblyHeaderName(const char* optAssembly
) {
237 assemblyHeaderIndex
= -1;
238 for (idx
= 0; idx
< UPRV_LENGTHOF(assemblyHeader
); idx
++) {
239 if (uprv_strcmp(optAssembly
, assemblyHeader
[idx
].name
) == 0) {
240 assemblyHeaderIndex
= idx
;
241 hexType
= assemblyHeader
[idx
].hexType
; /* set the hex type */
250 U_CAPI
void U_EXPORT2
251 printAssemblyHeadersToStdErr(void) {
253 fprintf(stderr
, "%s", assemblyHeader
[0].name
);
254 for (idx
= 1; idx
< UPRV_LENGTHOF(assemblyHeader
); idx
++) {
255 fprintf(stderr
, ", %s", assemblyHeader
[idx
].name
);
261 U_CAPI
void U_EXPORT2
262 writeAssemblyCode(const char *filename
, const char *destdir
, const char *optEntryPoint
, const char *optFilename
, char *outFilePath
) {
263 uint32_t column
= MAX_COLUMN
;
265 uint32_t buffer
[1024];
266 char *bufferStr
= (char *)buffer
;
267 FileStream
*in
, *out
;
270 in
=T_FileStream_open(filename
, "rb");
272 fprintf(stderr
, "genccode: unable to open input file %s\n", filename
);
273 exit(U_FILE_ACCESS_ERROR
);
276 getOutFilename(filename
, destdir
, bufferStr
, entry
, ".S", optFilename
);
277 out
=T_FileStream_open(bufferStr
, "w");
279 fprintf(stderr
, "genccode: unable to open output file %s\n", bufferStr
);
280 exit(U_FILE_ACCESS_ERROR
);
283 if (outFilePath
!= NULL
) {
284 uprv_strcpy(outFilePath
, bufferStr
);
287 #if defined (WINDOWS_WITH_GNUC) && U_PLATFORM != U_PF_CYGWIN
288 /* Need to fix the file separator character when using MinGW. */
289 swapFileSepChar(outFilePath
, U_FILE_SEP_CHAR
, '/');
292 if(optEntryPoint
!= NULL
) {
293 uprv_strcpy(entry
, optEntryPoint
);
294 uprv_strcat(entry
, "_dat");
297 /* turn dashes or dots in the entry name into underscores */
298 length
=uprv_strlen(entry
);
299 for(i
=0; i
<length
; ++i
) {
300 if(entry
[i
]=='-' || entry
[i
]=='.') {
305 sprintf(bufferStr
, assemblyHeader
[assemblyHeaderIndex
].header
,
306 entry
, entry
, entry
, entry
,
307 entry
, entry
, entry
, entry
);
308 T_FileStream_writeLine(out
, bufferStr
);
309 T_FileStream_writeLine(out
, assemblyHeader
[assemblyHeaderIndex
].beginLine
);
312 memset(buffer
, 0, sizeof(buffer
));
313 length
=T_FileStream_read(in
, buffer
, sizeof(buffer
));
317 for(i
=0; i
<(length
/sizeof(buffer
[0])); i
++) {
318 column
= write32(out
, buffer
[i
], column
);
322 T_FileStream_writeLine(out
, "\n");
324 sprintf(bufferStr
, assemblyHeader
[assemblyHeaderIndex
].footer
,
325 entry
, entry
, entry
, entry
,
326 entry
, entry
, entry
, entry
);
327 T_FileStream_writeLine(out
, bufferStr
);
329 if(T_FileStream_error(in
)) {
330 fprintf(stderr
, "genccode: file read error while generating from file %s\n", filename
);
331 exit(U_FILE_ACCESS_ERROR
);
334 if(T_FileStream_error(out
)) {
335 fprintf(stderr
, "genccode: file write error while generating from file %s\n", filename
);
336 exit(U_FILE_ACCESS_ERROR
);
339 T_FileStream_close(out
);
340 T_FileStream_close(in
);
343 U_CAPI
void U_EXPORT2
344 writeCCode(const char *filename
, const char *destdir
, const char *optName
, const char *optFilename
, char *outFilePath
) {
345 uint32_t column
= MAX_COLUMN
;
346 char buffer
[4096], entry
[64];
347 FileStream
*in
, *out
;
350 in
=T_FileStream_open(filename
, "rb");
352 fprintf(stderr
, "genccode: unable to open input file %s\n", filename
);
353 exit(U_FILE_ACCESS_ERROR
);
356 if(optName
!= NULL
) { /* prepend 'icudt28_' */
357 strcpy(entry
, optName
);
363 getOutFilename(filename
, destdir
, buffer
, entry
+uprv_strlen(entry
), ".c", optFilename
);
364 if (outFilePath
!= NULL
) {
365 uprv_strcpy(outFilePath
, buffer
);
367 out
=T_FileStream_open(buffer
, "w");
369 fprintf(stderr
, "genccode: unable to open output file %s\n", buffer
);
370 exit(U_FILE_ACCESS_ERROR
);
373 /* turn dashes or dots in the entry name into underscores */
374 length
=uprv_strlen(entry
);
375 for(i
=0; i
<length
; ++i
) {
376 if(entry
[i
]=='-' || entry
[i
]=='.') {
381 #if U_PLATFORM == U_PF_OS400
383 TODO: Fix this once the compiler implements this feature. Keep in sync with udatamem.c
385 This is here because this platform can't currently put
386 const data into the read-only pages of an object or
387 shared library (service program). Only strings are allowed in read-only
388 pages, so we use char * strings to store the data.
390 In order to prevent the beginning of the data from ever matching the
391 magic numbers we must still use the initial double.
395 "#ifndef IN_GENERATED_CCODE\n"
396 "#define IN_GENERATED_CCODE\n"
397 "#define U_DISABLE_RENAMING 1\n"
398 "#include \"unicode/umachine.h\"\n"
403 " const char *bytes; \n"
406 T_FileStream_writeLine(out
, buffer
);
409 length
=T_FileStream_read(in
, buffer
, sizeof(buffer
));
413 for(i
=0; i
<length
; ++i
) {
414 column
= write8str(out
, (uint8_t)buffer
[i
], column
);
418 T_FileStream_writeLine(out
, "\"\n};\nU_CDECL_END\n");
420 /* Function renaming shouldn't be done in data */
422 "#ifndef IN_GENERATED_CCODE\n"
423 "#define IN_GENERATED_CCODE\n"
424 "#define U_DISABLE_RENAMING 1\n"
425 "#include \"unicode/umachine.h\"\n"
430 " uint8_t bytes[%ld]; \n"
432 (long)T_FileStream_size(in
), entry
);
433 T_FileStream_writeLine(out
, buffer
);
436 length
=T_FileStream_read(in
, buffer
, sizeof(buffer
));
440 for(i
=0; i
<length
; ++i
) {
441 column
= write8(out
, (uint8_t)buffer
[i
], column
);
445 T_FileStream_writeLine(out
, "\n}\n};\nU_CDECL_END\n");
448 if(T_FileStream_error(in
)) {
449 fprintf(stderr
, "genccode: file read error while generating from file %s\n", filename
);
450 exit(U_FILE_ACCESS_ERROR
);
453 if(T_FileStream_error(out
)) {
454 fprintf(stderr
, "genccode: file write error while generating from file %s\n", filename
);
455 exit(U_FILE_ACCESS_ERROR
);
458 T_FileStream_close(out
);
459 T_FileStream_close(in
);
463 write32(FileStream
*out
, uint32_t bitField
, uint32_t column
) {
465 char bitFieldStr
[64]; /* This is more bits than needed for a 32-bit number */
466 char *s
= bitFieldStr
;
467 uint8_t *ptrIdx
= (uint8_t *)&bitField
;
468 static const char hexToStr
[16] = {
475 /* write the value, possibly with comma and newline */
476 if(column
==MAX_COLUMN
) {
479 } else if(column
<32) {
484 uprv_strcpy(s
, assemblyHeader
[assemblyHeaderIndex
].beginLine
);
490 /* It's a small number. Don't waste the space for 0x */
491 *(s
++)=hexToStr
[bitField
];
494 int seenNonZero
= 0; /* This is used to remove leading zeros */
496 if(hexType
==HEX_0X
) {
499 } else if(hexType
==HEX_0H
) {
503 /* This creates a 32-bit field */
505 for (i
= 0; i
< sizeof(uint32_t); i
++)
507 for (i
= sizeof(uint32_t)-1; i
>= 0 ; i
--)
510 uint8_t value
= ptrIdx
[i
];
511 if (value
|| seenNonZero
) {
512 *(s
++)=hexToStr
[value
>>4];
513 *(s
++)=hexToStr
[value
&0xF];
517 if(hexType
==HEX_0H
) {
523 T_FileStream_writeLine(out
, bitFieldStr
);
528 write8(FileStream
*out
, uint8_t byte
, uint32_t column
) {
532 /* convert the byte value to a string */
534 s
[i
++]=(char)('0'+byte
/100);
537 if(i
>0 || byte
>=10) {
538 s
[i
++]=(char)('0'+byte
/10);
541 s
[i
++]=(char)('0'+byte
);
544 /* write the value, possibly with comma and newline */
545 if(column
==MAX_COLUMN
) {
548 } else if(column
<16) {
549 T_FileStream_writeLine(out
, ",");
552 T_FileStream_writeLine(out
, ",\n");
555 T_FileStream_writeLine(out
, s
);
559 #if U_PLATFORM == U_PF_OS400
561 write8str(FileStream
*out
, uint8_t byte
, uint32_t column
) {
565 sprintf(s
, "\\x%X", byte
);
567 sprintf(s
, "\\%X", byte
);
569 /* write the value, possibly with comma and newline */
570 if(column
==MAX_COLUMN
) {
573 T_FileStream_writeLine(out
, "\"");
574 } else if(column
<24) {
577 T_FileStream_writeLine(out
, "\"\n\"");
580 T_FileStream_writeLine(out
, s
);
586 getOutFilename(const char *inFilename
, const char *destdir
, char *outFilename
, char *entryName
, const char *newSuffix
, const char *optFilename
) {
587 const char *basename
=findBasename(inFilename
), *suffix
=uprv_strrchr(basename
, '.');
590 if(destdir
!=NULL
&& *destdir
!=0) {
592 *outFilename
++=*destdir
++;
593 } while(*destdir
!=0);
594 if(*(outFilename
-1)!=U_FILE_SEP_CHAR
) {
595 *outFilename
++=U_FILE_SEP_CHAR
;
599 while(inFilename
<basename
) {
600 *outFilename
++=*inFilename
++;
605 /* the filename does not have a suffix */
606 uprv_strcpy(entryName
, inFilename
);
607 if(optFilename
!= NULL
) {
608 uprv_strcpy(outFilename
, optFilename
);
610 uprv_strcpy(outFilename
, inFilename
);
612 uprv_strcat(outFilename
, newSuffix
);
614 char *saveOutFilename
= outFilename
;
616 while(inFilename
<suffix
) {
617 if(*inFilename
=='-') {
618 /* iSeries cannot have '-' in the .o objects. */
619 *outFilename
++=*entryName
++='_';
623 *outFilename
++=*entryName
++=*inFilename
++;
627 /* replace '.' by '_' */
628 *outFilename
++=*entryName
++='_';
632 while(*inFilename
!=0) {
633 *outFilename
++=*entryName
++=*inFilename
++;
638 if(optFilename
!= NULL
) {
639 uprv_strcpy(saveOutFilename
, optFilename
);
640 uprv_strcat(saveOutFilename
, newSuffix
);
643 uprv_strcpy(outFilename
, newSuffix
);
648 #ifdef CAN_GENERATE_OBJECTS
650 getArchitecture(uint16_t *pCPU
, uint16_t *pBits
, UBool
*pIsBigEndian
, const char *optMatchArch
) {
655 /* Elf32_Ehdr and ELF64_Ehdr are identical for the necessary fields. */
656 #elif U_PLATFORM_HAS_WIN32_API
657 IMAGE_FILE_HEADER header
;
661 const char *filename
;
667 #elif U_PLATFORM_HAS_WIN32_API
668 const IMAGE_FILE_HEADER
*pHeader
;
670 # error "Unknown platform for CAN_GENERATE_OBJECTS."
673 if(optMatchArch
!= NULL
) {
674 filename
=optMatchArch
;
678 /* set EM_386 because elf.h does not provide better defaults */
681 *pIsBigEndian
=(UBool
)(U_IS_BIG_ENDIAN
? ELFDATA2MSB
: ELFDATA2LSB
);
682 #elif U_PLATFORM_HAS_WIN32_API
683 // Windows always runs in little-endian mode.
684 *pIsBigEndian
= FALSE
;
686 // Note: The various _M_<arch> macros are predefined by the MSVC compiler based
687 // on the target compilation architecture.
688 // https://docs.microsoft.com/cpp/preprocessor/predefined-macros
690 // link.exe will link an IMAGE_FILE_MACHINE_UNKNOWN data-only .obj file
691 // no matter what architecture it is targeting (though other values are
692 // required to match). Unfortunately, the variable name decoration/mangling
693 // is slightly different on x86, which means we can't use the UNKNOWN type
694 // for all architectures though.
695 # if defined(_M_IX86)
696 *pCPU
= IMAGE_FILE_MACHINE_I386
;
698 *pCPU
= IMAGE_FILE_MACHINE_UNKNOWN
;
700 # if defined(_M_IA64) || defined(_M_AMD64) || defined (_M_ARM64)
701 *pBits
= 64; // Doesn't seem to be used for anything interesting though?
702 # elif defined(_M_IX86) || defined(_M_ARM)
705 # error "Unknown platform for CAN_GENERATE_OBJECTS."
708 # error "Unknown platform for CAN_GENERATE_OBJECTS."
713 in
=T_FileStream_open(filename
, "rb");
715 fprintf(stderr
, "genccode: unable to open match-arch file %s\n", filename
);
716 exit(U_FILE_ACCESS_ERROR
);
718 length
=T_FileStream_read(in
, buffer
.bytes
, sizeof(buffer
.bytes
));
721 if(length
<(int32_t)sizeof(Elf32_Ehdr
)) {
722 fprintf(stderr
, "genccode: match-arch file %s is too short\n", filename
);
723 exit(U_UNSUPPORTED_ERROR
);
726 buffer
.header32
.e_ident
[0]!=ELFMAG0
||
727 buffer
.header32
.e_ident
[1]!=ELFMAG1
||
728 buffer
.header32
.e_ident
[2]!=ELFMAG2
||
729 buffer
.header32
.e_ident
[3]!=ELFMAG3
||
730 buffer
.header32
.e_ident
[EI_CLASS
]<ELFCLASS32
|| buffer
.header32
.e_ident
[EI_CLASS
]>ELFCLASS64
732 fprintf(stderr
, "genccode: match-arch file %s is not an ELF object file, or not supported\n", filename
);
733 exit(U_UNSUPPORTED_ERROR
);
736 *pBits
= buffer
.header32
.e_ident
[EI_CLASS
]==ELFCLASS32
? 32 : 64; /* only 32 or 64: see check above */
738 if(*pBits
!=32 && *pBits
!=64) {
739 fprintf(stderr
, "genccode: currently only supports 32-bit and 64-bit ELF format\n");
740 exit(U_UNSUPPORTED_ERROR
);
744 fprintf(stderr
, "genccode: built with elf.h missing 64-bit definitions\n");
745 exit(U_UNSUPPORTED_ERROR
);
749 *pIsBigEndian
=(UBool
)(buffer
.header32
.e_ident
[EI_DATA
]==ELFDATA2MSB
);
750 if(*pIsBigEndian
!=U_IS_BIG_ENDIAN
) {
751 fprintf(stderr
, "genccode: currently only same-endianness ELF formats are supported\n");
752 exit(U_UNSUPPORTED_ERROR
);
754 /* TODO: Support byte swapping */
756 *pCPU
=buffer
.header32
.e_machine
;
757 #elif U_PLATFORM_HAS_WIN32_API
758 if(length
<sizeof(IMAGE_FILE_HEADER
)) {
759 fprintf(stderr
, "genccode: match-arch file %s is too short\n", filename
);
760 exit(U_UNSUPPORTED_ERROR
);
762 /* TODO: Use buffer.header. Keep aliasing legal. */
763 pHeader
=(const IMAGE_FILE_HEADER
*)buffer
.bytes
;
764 *pCPU
=pHeader
->Machine
;
766 * The number of bits is implicit with the Machine value.
767 * *pBits is ignored in the calling code, so this need not be precise.
769 *pBits
= *pCPU
==IMAGE_FILE_MACHINE_I386
? 32 : 64;
770 /* Windows always runs on little-endian CPUs. */
773 # error "Unknown platform for CAN_GENERATE_OBJECTS."
776 T_FileStream_close(in
);
779 U_CAPI
void U_EXPORT2
780 writeObjectCode(const char *filename
, const char *destdir
, const char *optEntryPoint
, const char *optMatchArch
, const char *optFilename
, char *outFilePath
) {
781 /* common variables */
782 char buffer
[4096], entry
[96]={ 0 };
783 FileStream
*in
, *out
;
784 const char *newSuffix
;
785 int32_t i
, entryLength
, length
, size
, entryOffset
=0, entryLengthOffset
=0;
790 /* platform-specific variables and initialization code */
792 /* 32-bit Elf file header */
793 static Elf32_Ehdr header32
={
796 ELFMAG0
, ELFMAG1
, ELFMAG2
, ELFMAG3
,
798 U_IS_BIG_ENDIAN
? ELFDATA2MSB
: ELFDATA2LSB
,
799 EV_CURRENT
/* EI_VERSION */
803 EV_CURRENT
, /* e_version */
806 (Elf32_Off
)sizeof(Elf32_Ehdr
), /* e_shoff */
808 (Elf32_Half
)sizeof(Elf32_Ehdr
), /* eh_size */
811 (Elf32_Half
)sizeof(Elf32_Shdr
), /* e_shentsize */
816 /* 32-bit Elf section header table */
817 static Elf32_Shdr sectionHeaders32
[5]={
819 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
826 (Elf32_Off
)(sizeof(header32
)+sizeof(sectionHeaders32
)), /* sh_offset */
827 (Elf32_Word
)(2*sizeof(Elf32_Sym
)), /* sh_size */
828 3, /* sh_link=sect hdr index of .strtab */
829 1, /* sh_info=One greater than the symbol table index of the last
830 * local symbol (with STB_LOCAL). */
831 4, /* sh_addralign */
832 (Elf32_Word
)(sizeof(Elf32_Sym
)) /* sh_entsize */
839 (Elf32_Off
)(sizeof(header32
)+sizeof(sectionHeaders32
)+2*sizeof(Elf32_Sym
)), /* sh_offset */
843 1, /* sh_addralign */
851 (Elf32_Off
)(sizeof(header32
)+sizeof(sectionHeaders32
)+2*sizeof(Elf32_Sym
)+40), /* sh_offset */
852 (Elf32_Word
)sizeof(entry
), /* sh_size */
855 1, /* sh_addralign */
861 SHF_ALLOC
, /* sh_flags */
863 (Elf32_Off
)(sizeof(header32
)+sizeof(sectionHeaders32
)+2*sizeof(Elf32_Sym
)+40+sizeof(entry
)), /* sh_offset */
867 16, /* sh_addralign */
873 static Elf32_Sym symbols32
[2]={
877 { /* data entry point */
881 ELF64_ST_INFO(STB_GLOBAL
, STT_OBJECT
),
883 4 /* st_shndx=index of related section table entry */
887 /* section header string table, with decimal string offsets */
888 static const char sectionStrings
[40]=
891 /* 9 */ ".shstrtab\0"
894 /* 35 */ "\0\0\0\0"; /* contains terminating NUL */
895 /* 40: padded to multiple of 8 bytes */
898 * Use entry[] for the string table which will contain only the
900 * entry[0] must be 0 (NUL)
901 * The entry point name can be up to 38 characters long (sizeof(entry)-2).
904 /* 16-align .rodata in the .o file, just in case */
905 static const char padding
[16]={ 0 };
909 /* 64-bit Elf file header */
910 static Elf64_Ehdr header64
={
913 ELFMAG0
, ELFMAG1
, ELFMAG2
, ELFMAG3
,
915 U_IS_BIG_ENDIAN
? ELFDATA2MSB
: ELFDATA2LSB
,
916 EV_CURRENT
/* EI_VERSION */
920 EV_CURRENT
, /* e_version */
923 (Elf64_Off
)sizeof(Elf64_Ehdr
), /* e_shoff */
925 (Elf64_Half
)sizeof(Elf64_Ehdr
), /* eh_size */
928 (Elf64_Half
)sizeof(Elf64_Shdr
), /* e_shentsize */
933 /* 64-bit Elf section header table */
934 static Elf64_Shdr sectionHeaders64
[5]={
936 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
943 (Elf64_Off
)(sizeof(header64
)+sizeof(sectionHeaders64
)), /* sh_offset */
944 (Elf64_Xword
)(2*sizeof(Elf64_Sym
)), /* sh_size */
945 3, /* sh_link=sect hdr index of .strtab */
946 1, /* sh_info=One greater than the symbol table index of the last
947 * local symbol (with STB_LOCAL). */
948 4, /* sh_addralign */
949 (Elf64_Xword
)(sizeof(Elf64_Sym
)) /* sh_entsize */
956 (Elf64_Off
)(sizeof(header64
)+sizeof(sectionHeaders64
)+2*sizeof(Elf64_Sym
)), /* sh_offset */
960 1, /* sh_addralign */
968 (Elf64_Off
)(sizeof(header64
)+sizeof(sectionHeaders64
)+2*sizeof(Elf64_Sym
)+40), /* sh_offset */
969 (Elf64_Xword
)sizeof(entry
), /* sh_size */
972 1, /* sh_addralign */
978 SHF_ALLOC
, /* sh_flags */
980 (Elf64_Off
)(sizeof(header64
)+sizeof(sectionHeaders64
)+2*sizeof(Elf64_Sym
)+40+sizeof(entry
)), /* sh_offset */
984 16, /* sh_addralign */
990 * 64-bit symbol table
991 * careful: different order of items compared with Elf32_sym!
993 static Elf64_Sym symbols64
[2]={
997 { /* data entry point */
999 ELF64_ST_INFO(STB_GLOBAL
, STT_OBJECT
),
1001 4, /* st_shndx=index of related section table entry */
1007 #endif /* U_ELF64 */
1009 /* entry[] have a leading NUL */
1012 /* in the common code, count entryLength from after the NUL */
1013 entryLengthOffset
=1;
1017 #elif U_PLATFORM_HAS_WIN32_API
1019 IMAGE_FILE_HEADER fileHeader
;
1020 IMAGE_SECTION_HEADER sections
[2];
1021 char linkerOptions
[100];
1023 IMAGE_SYMBOL symbols
[1];
1025 DWORD sizeofLongNames
;
1026 char longNames
[100];
1030 * entry sometimes have a leading '_'
1031 * overwritten if entryOffset==0 depending on the target platform
1032 * see check for cpu below
1038 # error "Unknown platform for CAN_GENERATE_OBJECTS."
1041 /* deal with options, files and the entry point name */
1042 getArchitecture(&cpu
, &bits
, &makeBigEndian
, optMatchArch
);
1045 printf("genccode: --match-arch cpu=%hu bits=%hu big-endian=%d\n", cpu
, bits
, makeBigEndian
);
1049 printf("genccode: using architecture cpu=%hu bits=%hu big-endian=%d\n", cpu
, bits
, makeBigEndian
);
1051 #if U_PLATFORM_HAS_WIN32_API
1052 if(cpu
==IMAGE_FILE_MACHINE_I386
) {
1057 in
=T_FileStream_open(filename
, "rb");
1059 fprintf(stderr
, "genccode: unable to open input file %s\n", filename
);
1060 exit(U_FILE_ACCESS_ERROR
);
1062 size
=T_FileStream_size(in
);
1064 getOutFilename(filename
, destdir
, buffer
, entry
+entryOffset
, newSuffix
, optFilename
);
1065 if (outFilePath
!= NULL
) {
1066 uprv_strcpy(outFilePath
, buffer
);
1069 if(optEntryPoint
!= NULL
) {
1070 uprv_strcpy(entry
+entryOffset
, optEntryPoint
);
1071 uprv_strcat(entry
+entryOffset
, "_dat");
1073 /* turn dashes in the entry name into underscores */
1074 entryLength
=(int32_t)uprv_strlen(entry
+entryLengthOffset
);
1075 for(i
=0; i
<entryLength
; ++i
) {
1076 if(entry
[entryLengthOffset
+i
]=='-') {
1077 entry
[entryLengthOffset
+i
]='_';
1081 /* open the output file */
1082 out
=T_FileStream_open(buffer
, "wb");
1084 fprintf(stderr
, "genccode: unable to open output file %s\n", buffer
);
1085 exit(U_FILE_ACCESS_ERROR
);
1090 header32
.e_ident
[EI_DATA
]= makeBigEndian
? ELFDATA2MSB
: ELFDATA2LSB
;
1091 header32
.e_machine
=cpu
;
1093 /* 16-align .rodata in the .o file, just in case */
1094 paddingSize
=sectionHeaders32
[4].sh_offset
& 0xf;
1095 if(paddingSize
!=0) {
1096 paddingSize
=0x10-paddingSize
;
1097 sectionHeaders32
[4].sh_offset
+=paddingSize
;
1100 sectionHeaders32
[4].sh_size
=(Elf32_Word
)size
;
1102 symbols32
[1].st_size
=(Elf32_Word
)size
;
1104 /* write .o headers */
1105 T_FileStream_write(out
, &header32
, (int32_t)sizeof(header32
));
1106 T_FileStream_write(out
, sectionHeaders32
, (int32_t)sizeof(sectionHeaders32
));
1107 T_FileStream_write(out
, symbols32
, (int32_t)sizeof(symbols32
));
1108 } else /* bits==64 */ {
1110 header64
.e_ident
[EI_DATA
]= makeBigEndian
? ELFDATA2MSB
: ELFDATA2LSB
;
1111 header64
.e_machine
=cpu
;
1113 /* 16-align .rodata in the .o file, just in case */
1114 paddingSize
=sectionHeaders64
[4].sh_offset
& 0xf;
1115 if(paddingSize
!=0) {
1116 paddingSize
=0x10-paddingSize
;
1117 sectionHeaders64
[4].sh_offset
+=paddingSize
;
1120 sectionHeaders64
[4].sh_size
=(Elf64_Xword
)size
;
1122 symbols64
[1].st_size
=(Elf64_Xword
)size
;
1124 /* write .o headers */
1125 T_FileStream_write(out
, &header64
, (int32_t)sizeof(header64
));
1126 T_FileStream_write(out
, sectionHeaders64
, (int32_t)sizeof(sectionHeaders64
));
1127 T_FileStream_write(out
, symbols64
, (int32_t)sizeof(symbols64
));
1131 T_FileStream_write(out
, sectionStrings
, (int32_t)sizeof(sectionStrings
));
1132 T_FileStream_write(out
, entry
, (int32_t)sizeof(entry
));
1133 if(paddingSize
!=0) {
1134 T_FileStream_write(out
, padding
, paddingSize
);
1136 #elif U_PLATFORM_HAS_WIN32_API
1137 /* populate the .obj headers */
1138 uprv_memset(&objHeader
, 0, sizeof(objHeader
));
1139 uprv_memset(&symbols
, 0, sizeof(symbols
));
1140 uprv_memset(&symbolNames
, 0, sizeof(symbolNames
));
1142 /* write the linker export directive */
1143 uprv_strcpy(objHeader
.linkerOptions
, "-export:");
1145 uprv_strcpy(objHeader
.linkerOptions
+length
, entry
);
1146 length
+=entryLength
;
1147 uprv_strcpy(objHeader
.linkerOptions
+length
, ",data ");
1150 /* set the file header */
1151 objHeader
.fileHeader
.Machine
=cpu
;
1152 objHeader
.fileHeader
.NumberOfSections
=2;
1153 objHeader
.fileHeader
.TimeDateStamp
=(DWORD
)time(NULL
);
1154 objHeader
.fileHeader
.PointerToSymbolTable
=IMAGE_SIZEOF_FILE_HEADER
+2*IMAGE_SIZEOF_SECTION_HEADER
+length
+size
; /* start of symbol table */
1155 objHeader
.fileHeader
.NumberOfSymbols
=1;
1157 /* set the section for the linker options */
1158 uprv_strncpy((char *)objHeader
.sections
[0].Name
, ".drectve", 8);
1159 objHeader
.sections
[0].SizeOfRawData
=length
;
1160 objHeader
.sections
[0].PointerToRawData
=IMAGE_SIZEOF_FILE_HEADER
+2*IMAGE_SIZEOF_SECTION_HEADER
;
1161 objHeader
.sections
[0].Characteristics
=IMAGE_SCN_LNK_INFO
|IMAGE_SCN_LNK_REMOVE
|IMAGE_SCN_ALIGN_1BYTES
;
1163 /* set the data section */
1164 uprv_strncpy((char *)objHeader
.sections
[1].Name
, ".rdata", 6);
1165 objHeader
.sections
[1].SizeOfRawData
=size
;
1166 objHeader
.sections
[1].PointerToRawData
=IMAGE_SIZEOF_FILE_HEADER
+2*IMAGE_SIZEOF_SECTION_HEADER
+length
;
1167 objHeader
.sections
[1].Characteristics
=IMAGE_SCN_CNT_INITIALIZED_DATA
|IMAGE_SCN_ALIGN_16BYTES
|IMAGE_SCN_MEM_READ
;
1169 /* set the symbol table */
1170 if(entryLength
<=8) {
1171 uprv_strncpy((char *)symbols
[0].N
.ShortName
, entry
, entryLength
);
1172 symbolNames
.sizeofLongNames
=4;
1174 symbols
[0].N
.Name
.Short
=0;
1175 symbols
[0].N
.Name
.Long
=4;
1176 symbolNames
.sizeofLongNames
=4+entryLength
+1;
1177 uprv_strcpy(symbolNames
.longNames
, entry
);
1179 symbols
[0].SectionNumber
=2;
1180 symbols
[0].StorageClass
=IMAGE_SYM_CLASS_EXTERNAL
;
1182 /* write the file header and the linker options section */
1183 T_FileStream_write(out
, &objHeader
, objHeader
.sections
[1].PointerToRawData
);
1185 # error "Unknown platform for CAN_GENERATE_OBJECTS."
1188 /* copy the data file into section 2 */
1190 length
=T_FileStream_read(in
, buffer
, sizeof(buffer
));
1194 T_FileStream_write(out
, buffer
, (int32_t)length
);
1197 #if U_PLATFORM_HAS_WIN32_API
1198 /* write the symbol table */
1199 T_FileStream_write(out
, symbols
, IMAGE_SIZEOF_SYMBOL
);
1200 T_FileStream_write(out
, &symbolNames
, symbolNames
.sizeofLongNames
);
1203 if(T_FileStream_error(in
)) {
1204 fprintf(stderr
, "genccode: file read error while generating from file %s\n", filename
);
1205 exit(U_FILE_ACCESS_ERROR
);
1208 if(T_FileStream_error(out
)) {
1209 fprintf(stderr
, "genccode: file write error while generating from file %s\n", filename
);
1210 exit(U_FILE_ACCESS_ERROR
);
1213 T_FileStream_close(out
);
1214 T_FileStream_close(in
);