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 length
=T_FileStream_read(in
, buffer
, sizeof(buffer
));
316 if (length
!= sizeof(buffer
)) {
317 /* pad with extra 0's when at the end of the file */
318 for(i
=0; i
< (length
% sizeof(uint32_t)); ++i
) {
319 buffer
[length
+i
] = 0;
322 for(i
=0; i
<(length
/sizeof(buffer
[0])); i
++) {
323 column
= write32(out
, buffer
[i
], column
);
327 T_FileStream_writeLine(out
, "\n");
329 sprintf(bufferStr
, assemblyHeader
[assemblyHeaderIndex
].footer
,
330 entry
, entry
, entry
, entry
,
331 entry
, entry
, entry
, entry
);
332 T_FileStream_writeLine(out
, bufferStr
);
334 if(T_FileStream_error(in
)) {
335 fprintf(stderr
, "genccode: file read error while generating from file %s\n", filename
);
336 exit(U_FILE_ACCESS_ERROR
);
339 if(T_FileStream_error(out
)) {
340 fprintf(stderr
, "genccode: file write error while generating from file %s\n", filename
);
341 exit(U_FILE_ACCESS_ERROR
);
344 T_FileStream_close(out
);
345 T_FileStream_close(in
);
348 U_CAPI
void U_EXPORT2
349 writeCCode(const char *filename
, const char *destdir
, const char *optName
, const char *optFilename
, char *outFilePath
) {
350 uint32_t column
= MAX_COLUMN
;
351 char buffer
[4096], entry
[64];
352 FileStream
*in
, *out
;
355 in
=T_FileStream_open(filename
, "rb");
357 fprintf(stderr
, "genccode: unable to open input file %s\n", filename
);
358 exit(U_FILE_ACCESS_ERROR
);
361 if(optName
!= NULL
) { /* prepend 'icudt28_' */
362 strcpy(entry
, optName
);
368 getOutFilename(filename
, destdir
, buffer
, entry
+uprv_strlen(entry
), ".c", optFilename
);
369 if (outFilePath
!= NULL
) {
370 uprv_strcpy(outFilePath
, buffer
);
372 out
=T_FileStream_open(buffer
, "w");
374 fprintf(stderr
, "genccode: unable to open output file %s\n", buffer
);
375 exit(U_FILE_ACCESS_ERROR
);
378 /* turn dashes or dots in the entry name into underscores */
379 length
=uprv_strlen(entry
);
380 for(i
=0; i
<length
; ++i
) {
381 if(entry
[i
]=='-' || entry
[i
]=='.') {
386 #if U_PLATFORM == U_PF_OS400
388 TODO: Fix this once the compiler implements this feature. Keep in sync with udatamem.c
390 This is here because this platform can't currently put
391 const data into the read-only pages of an object or
392 shared library (service program). Only strings are allowed in read-only
393 pages, so we use char * strings to store the data.
395 In order to prevent the beginning of the data from ever matching the
396 magic numbers we must still use the initial double.
400 "#ifndef IN_GENERATED_CCODE\n"
401 "#define IN_GENERATED_CCODE\n"
402 "#define U_DISABLE_RENAMING 1\n"
403 "#include \"unicode/umachine.h\"\n"
408 " const char *bytes; \n"
411 T_FileStream_writeLine(out
, buffer
);
414 length
=T_FileStream_read(in
, buffer
, sizeof(buffer
));
418 for(i
=0; i
<length
; ++i
) {
419 column
= write8str(out
, (uint8_t)buffer
[i
], column
);
423 T_FileStream_writeLine(out
, "\"\n};\nU_CDECL_END\n");
425 /* Function renaming shouldn't be done in data */
427 "#ifndef IN_GENERATED_CCODE\n"
428 "#define IN_GENERATED_CCODE\n"
429 "#define U_DISABLE_RENAMING 1\n"
430 "#include \"unicode/umachine.h\"\n"
435 " uint8_t bytes[%ld]; \n"
437 (long)T_FileStream_size(in
), entry
);
438 T_FileStream_writeLine(out
, buffer
);
441 length
=T_FileStream_read(in
, buffer
, sizeof(buffer
));
445 for(i
=0; i
<length
; ++i
) {
446 column
= write8(out
, (uint8_t)buffer
[i
], column
);
450 T_FileStream_writeLine(out
, "\n}\n};\nU_CDECL_END\n");
453 if(T_FileStream_error(in
)) {
454 fprintf(stderr
, "genccode: file read error while generating from file %s\n", filename
);
455 exit(U_FILE_ACCESS_ERROR
);
458 if(T_FileStream_error(out
)) {
459 fprintf(stderr
, "genccode: file write error while generating from file %s\n", filename
);
460 exit(U_FILE_ACCESS_ERROR
);
463 T_FileStream_close(out
);
464 T_FileStream_close(in
);
468 write32(FileStream
*out
, uint32_t bitField
, uint32_t column
) {
470 char bitFieldStr
[64]; /* This is more bits than needed for a 32-bit number */
471 char *s
= bitFieldStr
;
472 uint8_t *ptrIdx
= (uint8_t *)&bitField
;
473 static const char hexToStr
[16] = {
480 /* write the value, possibly with comma and newline */
481 if(column
==MAX_COLUMN
) {
484 } else if(column
<32) {
489 uprv_strcpy(s
, assemblyHeader
[assemblyHeaderIndex
].beginLine
);
495 /* It's a small number. Don't waste the space for 0x */
496 *(s
++)=hexToStr
[bitField
];
499 int seenNonZero
= 0; /* This is used to remove leading zeros */
501 if(hexType
==HEX_0X
) {
504 } else if(hexType
==HEX_0H
) {
508 /* This creates a 32-bit field */
510 for (i
= 0; i
< sizeof(uint32_t); i
++)
512 for (i
= sizeof(uint32_t)-1; i
>= 0 ; i
--)
515 uint8_t value
= ptrIdx
[i
];
516 if (value
|| seenNonZero
) {
517 *(s
++)=hexToStr
[value
>>4];
518 *(s
++)=hexToStr
[value
&0xF];
522 if(hexType
==HEX_0H
) {
528 T_FileStream_writeLine(out
, bitFieldStr
);
533 write8(FileStream
*out
, uint8_t byte
, uint32_t column
) {
537 /* convert the byte value to a string */
539 s
[i
++]=(char)('0'+byte
/100);
542 if(i
>0 || byte
>=10) {
543 s
[i
++]=(char)('0'+byte
/10);
546 s
[i
++]=(char)('0'+byte
);
549 /* write the value, possibly with comma and newline */
550 if(column
==MAX_COLUMN
) {
553 } else if(column
<16) {
554 T_FileStream_writeLine(out
, ",");
557 T_FileStream_writeLine(out
, ",\n");
560 T_FileStream_writeLine(out
, s
);
564 #if U_PLATFORM == U_PF_OS400
566 write8str(FileStream
*out
, uint8_t byte
, uint32_t column
) {
570 sprintf(s
, "\\x%X", byte
);
572 sprintf(s
, "\\%X", byte
);
574 /* write the value, possibly with comma and newline */
575 if(column
==MAX_COLUMN
) {
578 T_FileStream_writeLine(out
, "\"");
579 } else if(column
<24) {
582 T_FileStream_writeLine(out
, "\"\n\"");
585 T_FileStream_writeLine(out
, s
);
591 getOutFilename(const char *inFilename
, const char *destdir
, char *outFilename
, char *entryName
, const char *newSuffix
, const char *optFilename
) {
592 const char *basename
=findBasename(inFilename
), *suffix
=uprv_strrchr(basename
, '.');
595 if(destdir
!=NULL
&& *destdir
!=0) {
597 *outFilename
++=*destdir
++;
598 } while(*destdir
!=0);
599 if(*(outFilename
-1)!=U_FILE_SEP_CHAR
) {
600 *outFilename
++=U_FILE_SEP_CHAR
;
604 while(inFilename
<basename
) {
605 *outFilename
++=*inFilename
++;
610 /* the filename does not have a suffix */
611 uprv_strcpy(entryName
, inFilename
);
612 if(optFilename
!= NULL
) {
613 uprv_strcpy(outFilename
, optFilename
);
615 uprv_strcpy(outFilename
, inFilename
);
617 uprv_strcat(outFilename
, newSuffix
);
619 char *saveOutFilename
= outFilename
;
621 while(inFilename
<suffix
) {
622 if(*inFilename
=='-') {
623 /* iSeries cannot have '-' in the .o objects. */
624 *outFilename
++=*entryName
++='_';
628 *outFilename
++=*entryName
++=*inFilename
++;
632 /* replace '.' by '_' */
633 *outFilename
++=*entryName
++='_';
637 while(*inFilename
!=0) {
638 *outFilename
++=*entryName
++=*inFilename
++;
643 if(optFilename
!= NULL
) {
644 uprv_strcpy(saveOutFilename
, optFilename
);
645 uprv_strcat(saveOutFilename
, newSuffix
);
648 uprv_strcpy(outFilename
, newSuffix
);
653 #ifdef CAN_GENERATE_OBJECTS
655 getArchitecture(uint16_t *pCPU
, uint16_t *pBits
, UBool
*pIsBigEndian
, const char *optMatchArch
) {
660 /* Elf32_Ehdr and ELF64_Ehdr are identical for the necessary fields. */
661 #elif U_PLATFORM_HAS_WIN32_API
662 IMAGE_FILE_HEADER header
;
666 const char *filename
;
672 #elif U_PLATFORM_HAS_WIN32_API
673 const IMAGE_FILE_HEADER
*pHeader
;
675 # error "Unknown platform for CAN_GENERATE_OBJECTS."
678 if(optMatchArch
!= NULL
) {
679 filename
=optMatchArch
;
683 /* set EM_386 because elf.h does not provide better defaults */
686 *pIsBigEndian
=(UBool
)(U_IS_BIG_ENDIAN
? ELFDATA2MSB
: ELFDATA2LSB
);
687 #elif U_PLATFORM_HAS_WIN32_API
688 /* _M_IA64 should be defined in windows.h */
689 # if defined(_M_IA64)
690 *pCPU
=IMAGE_FILE_MACHINE_IA64
;
692 # elif defined(_M_AMD64)
693 // link.exe does not really care about the .obj machine type and this will
694 // allow us to build a dll for both ARM & x64 with an amd64 built tool
695 // ARM is same as x64 except for first 2 bytes of object file
696 *pCPU
= IMAGE_FILE_MACHINE_UNKNOWN
;
697 // *pCPU = IMAGE_FILE_MACHINE_ARMNT; // If we wanted to be explicit
698 // *pCPU = IMAGE_FILE_MACHINE_AMD64; // We would use one of these names
699 *pBits
= 64; // Doesn't seem to be used for anything interesting?
701 *pCPU
=IMAGE_FILE_MACHINE_I386
; // We would use one of these names
706 # error "Unknown platform for CAN_GENERATE_OBJECTS."
711 in
=T_FileStream_open(filename
, "rb");
713 fprintf(stderr
, "genccode: unable to open match-arch file %s\n", filename
);
714 exit(U_FILE_ACCESS_ERROR
);
716 length
=T_FileStream_read(in
, buffer
.bytes
, sizeof(buffer
.bytes
));
719 if(length
<(int32_t)sizeof(Elf32_Ehdr
)) {
720 fprintf(stderr
, "genccode: match-arch file %s is too short\n", filename
);
721 exit(U_UNSUPPORTED_ERROR
);
724 buffer
.header32
.e_ident
[0]!=ELFMAG0
||
725 buffer
.header32
.e_ident
[1]!=ELFMAG1
||
726 buffer
.header32
.e_ident
[2]!=ELFMAG2
||
727 buffer
.header32
.e_ident
[3]!=ELFMAG3
||
728 buffer
.header32
.e_ident
[EI_CLASS
]<ELFCLASS32
|| buffer
.header32
.e_ident
[EI_CLASS
]>ELFCLASS64
730 fprintf(stderr
, "genccode: match-arch file %s is not an ELF object file, or not supported\n", filename
);
731 exit(U_UNSUPPORTED_ERROR
);
734 *pBits
= buffer
.header32
.e_ident
[EI_CLASS
]==ELFCLASS32
? 32 : 64; /* only 32 or 64: see check above */
736 if(*pBits
!=32 && *pBits
!=64) {
737 fprintf(stderr
, "genccode: currently only supports 32-bit and 64-bit ELF format\n");
738 exit(U_UNSUPPORTED_ERROR
);
742 fprintf(stderr
, "genccode: built with elf.h missing 64-bit definitions\n");
743 exit(U_UNSUPPORTED_ERROR
);
747 *pIsBigEndian
=(UBool
)(buffer
.header32
.e_ident
[EI_DATA
]==ELFDATA2MSB
);
748 if(*pIsBigEndian
!=U_IS_BIG_ENDIAN
) {
749 fprintf(stderr
, "genccode: currently only same-endianness ELF formats are supported\n");
750 exit(U_UNSUPPORTED_ERROR
);
752 /* TODO: Support byte swapping */
754 *pCPU
=buffer
.header32
.e_machine
;
755 #elif U_PLATFORM_HAS_WIN32_API
756 if(length
<sizeof(IMAGE_FILE_HEADER
)) {
757 fprintf(stderr
, "genccode: match-arch file %s is too short\n", filename
);
758 exit(U_UNSUPPORTED_ERROR
);
760 /* TODO: Use buffer.header. Keep aliasing legal. */
761 pHeader
=(const IMAGE_FILE_HEADER
*)buffer
.bytes
;
762 *pCPU
=pHeader
->Machine
;
764 * The number of bits is implicit with the Machine value.
765 * *pBits is ignored in the calling code, so this need not be precise.
767 *pBits
= *pCPU
==IMAGE_FILE_MACHINE_I386
? 32 : 64;
768 /* Windows always runs on little-endian CPUs. */
771 # error "Unknown platform for CAN_GENERATE_OBJECTS."
774 T_FileStream_close(in
);
777 U_CAPI
void U_EXPORT2
778 writeObjectCode(const char *filename
, const char *destdir
, const char *optEntryPoint
, const char *optMatchArch
, const char *optFilename
, char *outFilePath
) {
779 /* common variables */
780 char buffer
[4096], entry
[96]={ 0 };
781 FileStream
*in
, *out
;
782 const char *newSuffix
;
783 int32_t i
, entryLength
, length
, size
, entryOffset
=0, entryLengthOffset
=0;
788 /* platform-specific variables and initialization code */
790 /* 32-bit Elf file header */
791 static Elf32_Ehdr header32
={
794 ELFMAG0
, ELFMAG1
, ELFMAG2
, ELFMAG3
,
796 U_IS_BIG_ENDIAN
? ELFDATA2MSB
: ELFDATA2LSB
,
797 EV_CURRENT
/* EI_VERSION */
801 EV_CURRENT
, /* e_version */
804 (Elf32_Off
)sizeof(Elf32_Ehdr
), /* e_shoff */
806 (Elf32_Half
)sizeof(Elf32_Ehdr
), /* eh_size */
809 (Elf32_Half
)sizeof(Elf32_Shdr
), /* e_shentsize */
814 /* 32-bit Elf section header table */
815 static Elf32_Shdr sectionHeaders32
[5]={
817 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
824 (Elf32_Off
)(sizeof(header32
)+sizeof(sectionHeaders32
)), /* sh_offset */
825 (Elf32_Word
)(2*sizeof(Elf32_Sym
)), /* sh_size */
826 3, /* sh_link=sect hdr index of .strtab */
827 1, /* sh_info=One greater than the symbol table index of the last
828 * local symbol (with STB_LOCAL). */
829 4, /* sh_addralign */
830 (Elf32_Word
)(sizeof(Elf32_Sym
)) /* sh_entsize */
837 (Elf32_Off
)(sizeof(header32
)+sizeof(sectionHeaders32
)+2*sizeof(Elf32_Sym
)), /* sh_offset */
841 1, /* sh_addralign */
849 (Elf32_Off
)(sizeof(header32
)+sizeof(sectionHeaders32
)+2*sizeof(Elf32_Sym
)+40), /* sh_offset */
850 (Elf32_Word
)sizeof(entry
), /* sh_size */
853 1, /* sh_addralign */
859 SHF_ALLOC
, /* sh_flags */
861 (Elf32_Off
)(sizeof(header32
)+sizeof(sectionHeaders32
)+2*sizeof(Elf32_Sym
)+40+sizeof(entry
)), /* sh_offset */
865 16, /* sh_addralign */
871 static Elf32_Sym symbols32
[2]={
875 { /* data entry point */
879 ELF64_ST_INFO(STB_GLOBAL
, STT_OBJECT
),
881 4 /* st_shndx=index of related section table entry */
885 /* section header string table, with decimal string offsets */
886 static const char sectionStrings
[40]=
889 /* 9 */ ".shstrtab\0"
892 /* 35 */ "\0\0\0\0"; /* contains terminating NUL */
893 /* 40: padded to multiple of 8 bytes */
896 * Use entry[] for the string table which will contain only the
898 * entry[0] must be 0 (NUL)
899 * The entry point name can be up to 38 characters long (sizeof(entry)-2).
902 /* 16-align .rodata in the .o file, just in case */
903 static const char padding
[16]={ 0 };
907 /* 64-bit Elf file header */
908 static Elf64_Ehdr header64
={
911 ELFMAG0
, ELFMAG1
, ELFMAG2
, ELFMAG3
,
913 U_IS_BIG_ENDIAN
? ELFDATA2MSB
: ELFDATA2LSB
,
914 EV_CURRENT
/* EI_VERSION */
918 EV_CURRENT
, /* e_version */
921 (Elf64_Off
)sizeof(Elf64_Ehdr
), /* e_shoff */
923 (Elf64_Half
)sizeof(Elf64_Ehdr
), /* eh_size */
926 (Elf64_Half
)sizeof(Elf64_Shdr
), /* e_shentsize */
931 /* 64-bit Elf section header table */
932 static Elf64_Shdr sectionHeaders64
[5]={
934 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
941 (Elf64_Off
)(sizeof(header64
)+sizeof(sectionHeaders64
)), /* sh_offset */
942 (Elf64_Xword
)(2*sizeof(Elf64_Sym
)), /* sh_size */
943 3, /* sh_link=sect hdr index of .strtab */
944 1, /* sh_info=One greater than the symbol table index of the last
945 * local symbol (with STB_LOCAL). */
946 4, /* sh_addralign */
947 (Elf64_Xword
)(sizeof(Elf64_Sym
)) /* sh_entsize */
954 (Elf64_Off
)(sizeof(header64
)+sizeof(sectionHeaders64
)+2*sizeof(Elf64_Sym
)), /* sh_offset */
958 1, /* sh_addralign */
966 (Elf64_Off
)(sizeof(header64
)+sizeof(sectionHeaders64
)+2*sizeof(Elf64_Sym
)+40), /* sh_offset */
967 (Elf64_Xword
)sizeof(entry
), /* sh_size */
970 1, /* sh_addralign */
976 SHF_ALLOC
, /* sh_flags */
978 (Elf64_Off
)(sizeof(header64
)+sizeof(sectionHeaders64
)+2*sizeof(Elf64_Sym
)+40+sizeof(entry
)), /* sh_offset */
982 16, /* sh_addralign */
988 * 64-bit symbol table
989 * careful: different order of items compared with Elf32_sym!
991 static Elf64_Sym symbols64
[2]={
995 { /* data entry point */
997 ELF64_ST_INFO(STB_GLOBAL
, STT_OBJECT
),
999 4, /* st_shndx=index of related section table entry */
1005 #endif /* U_ELF64 */
1007 /* entry[] have a leading NUL */
1010 /* in the common code, count entryLength from after the NUL */
1011 entryLengthOffset
=1;
1015 #elif U_PLATFORM_HAS_WIN32_API
1017 IMAGE_FILE_HEADER fileHeader
;
1018 IMAGE_SECTION_HEADER sections
[2];
1019 char linkerOptions
[100];
1021 IMAGE_SYMBOL symbols
[1];
1023 DWORD sizeofLongNames
;
1024 char longNames
[100];
1028 * entry sometimes have a leading '_'
1029 * overwritten if entryOffset==0 depending on the target platform
1030 * see check for cpu below
1036 # error "Unknown platform for CAN_GENERATE_OBJECTS."
1039 /* deal with options, files and the entry point name */
1040 getArchitecture(&cpu
, &bits
, &makeBigEndian
, optMatchArch
);
1043 printf("genccode: --match-arch cpu=%hu bits=%hu big-endian=%d\n", cpu
, bits
, makeBigEndian
);
1047 printf("genccode: using architecture cpu=%hu bits=%hu big-endian=%d\n", cpu
, bits
, makeBigEndian
);
1049 #if U_PLATFORM_HAS_WIN32_API
1050 if(cpu
==IMAGE_FILE_MACHINE_I386
) {
1055 in
=T_FileStream_open(filename
, "rb");
1057 fprintf(stderr
, "genccode: unable to open input file %s\n", filename
);
1058 exit(U_FILE_ACCESS_ERROR
);
1060 size
=T_FileStream_size(in
);
1062 getOutFilename(filename
, destdir
, buffer
, entry
+entryOffset
, newSuffix
, optFilename
);
1063 if (outFilePath
!= NULL
) {
1064 uprv_strcpy(outFilePath
, buffer
);
1067 if(optEntryPoint
!= NULL
) {
1068 uprv_strcpy(entry
+entryOffset
, optEntryPoint
);
1069 uprv_strcat(entry
+entryOffset
, "_dat");
1071 /* turn dashes in the entry name into underscores */
1072 entryLength
=(int32_t)uprv_strlen(entry
+entryLengthOffset
);
1073 for(i
=0; i
<entryLength
; ++i
) {
1074 if(entry
[entryLengthOffset
+i
]=='-') {
1075 entry
[entryLengthOffset
+i
]='_';
1079 /* open the output file */
1080 out
=T_FileStream_open(buffer
, "wb");
1082 fprintf(stderr
, "genccode: unable to open output file %s\n", buffer
);
1083 exit(U_FILE_ACCESS_ERROR
);
1088 header32
.e_ident
[EI_DATA
]= makeBigEndian
? ELFDATA2MSB
: ELFDATA2LSB
;
1089 header32
.e_machine
=cpu
;
1091 /* 16-align .rodata in the .o file, just in case */
1092 paddingSize
=sectionHeaders32
[4].sh_offset
& 0xf;
1093 if(paddingSize
!=0) {
1094 paddingSize
=0x10-paddingSize
;
1095 sectionHeaders32
[4].sh_offset
+=paddingSize
;
1098 sectionHeaders32
[4].sh_size
=(Elf32_Word
)size
;
1100 symbols32
[1].st_size
=(Elf32_Word
)size
;
1102 /* write .o headers */
1103 T_FileStream_write(out
, &header32
, (int32_t)sizeof(header32
));
1104 T_FileStream_write(out
, sectionHeaders32
, (int32_t)sizeof(sectionHeaders32
));
1105 T_FileStream_write(out
, symbols32
, (int32_t)sizeof(symbols32
));
1106 } else /* bits==64 */ {
1108 header64
.e_ident
[EI_DATA
]= makeBigEndian
? ELFDATA2MSB
: ELFDATA2LSB
;
1109 header64
.e_machine
=cpu
;
1111 /* 16-align .rodata in the .o file, just in case */
1112 paddingSize
=sectionHeaders64
[4].sh_offset
& 0xf;
1113 if(paddingSize
!=0) {
1114 paddingSize
=0x10-paddingSize
;
1115 sectionHeaders64
[4].sh_offset
+=paddingSize
;
1118 sectionHeaders64
[4].sh_size
=(Elf64_Xword
)size
;
1120 symbols64
[1].st_size
=(Elf64_Xword
)size
;
1122 /* write .o headers */
1123 T_FileStream_write(out
, &header64
, (int32_t)sizeof(header64
));
1124 T_FileStream_write(out
, sectionHeaders64
, (int32_t)sizeof(sectionHeaders64
));
1125 T_FileStream_write(out
, symbols64
, (int32_t)sizeof(symbols64
));
1129 T_FileStream_write(out
, sectionStrings
, (int32_t)sizeof(sectionStrings
));
1130 T_FileStream_write(out
, entry
, (int32_t)sizeof(entry
));
1131 if(paddingSize
!=0) {
1132 T_FileStream_write(out
, padding
, paddingSize
);
1134 #elif U_PLATFORM_HAS_WIN32_API
1135 /* populate the .obj headers */
1136 uprv_memset(&objHeader
, 0, sizeof(objHeader
));
1137 uprv_memset(&symbols
, 0, sizeof(symbols
));
1138 uprv_memset(&symbolNames
, 0, sizeof(symbolNames
));
1140 /* write the linker export directive */
1141 uprv_strcpy(objHeader
.linkerOptions
, "-export:");
1143 uprv_strcpy(objHeader
.linkerOptions
+length
, entry
);
1144 length
+=entryLength
;
1145 uprv_strcpy(objHeader
.linkerOptions
+length
, ",data ");
1148 /* set the file header */
1149 objHeader
.fileHeader
.Machine
=cpu
;
1150 objHeader
.fileHeader
.NumberOfSections
=2;
1151 objHeader
.fileHeader
.TimeDateStamp
=(DWORD
)time(NULL
);
1152 objHeader
.fileHeader
.PointerToSymbolTable
=IMAGE_SIZEOF_FILE_HEADER
+2*IMAGE_SIZEOF_SECTION_HEADER
+length
+size
; /* start of symbol table */
1153 objHeader
.fileHeader
.NumberOfSymbols
=1;
1155 /* set the section for the linker options */
1156 uprv_strncpy((char *)objHeader
.sections
[0].Name
, ".drectve", 8);
1157 objHeader
.sections
[0].SizeOfRawData
=length
;
1158 objHeader
.sections
[0].PointerToRawData
=IMAGE_SIZEOF_FILE_HEADER
+2*IMAGE_SIZEOF_SECTION_HEADER
;
1159 objHeader
.sections
[0].Characteristics
=IMAGE_SCN_LNK_INFO
|IMAGE_SCN_LNK_REMOVE
|IMAGE_SCN_ALIGN_1BYTES
;
1161 /* set the data section */
1162 uprv_strncpy((char *)objHeader
.sections
[1].Name
, ".rdata", 6);
1163 objHeader
.sections
[1].SizeOfRawData
=size
;
1164 objHeader
.sections
[1].PointerToRawData
=IMAGE_SIZEOF_FILE_HEADER
+2*IMAGE_SIZEOF_SECTION_HEADER
+length
;
1165 objHeader
.sections
[1].Characteristics
=IMAGE_SCN_CNT_INITIALIZED_DATA
|IMAGE_SCN_ALIGN_16BYTES
|IMAGE_SCN_MEM_READ
;
1167 /* set the symbol table */
1168 if(entryLength
<=8) {
1169 uprv_strncpy((char *)symbols
[0].N
.ShortName
, entry
, entryLength
);
1170 symbolNames
.sizeofLongNames
=4;
1172 symbols
[0].N
.Name
.Short
=0;
1173 symbols
[0].N
.Name
.Long
=4;
1174 symbolNames
.sizeofLongNames
=4+entryLength
+1;
1175 uprv_strcpy(symbolNames
.longNames
, entry
);
1177 symbols
[0].SectionNumber
=2;
1178 symbols
[0].StorageClass
=IMAGE_SYM_CLASS_EXTERNAL
;
1180 /* write the file header and the linker options section */
1181 T_FileStream_write(out
, &objHeader
, objHeader
.sections
[1].PointerToRawData
);
1183 # error "Unknown platform for CAN_GENERATE_OBJECTS."
1186 /* copy the data file into section 2 */
1188 length
=T_FileStream_read(in
, buffer
, sizeof(buffer
));
1192 T_FileStream_write(out
, buffer
, (int32_t)length
);
1195 #if U_PLATFORM_HAS_WIN32_API
1196 /* write the symbol table */
1197 T_FileStream_write(out
, symbols
, IMAGE_SIZEOF_SYMBOL
);
1198 T_FileStream_write(out
, &symbolNames
, symbolNames
.sizeofLongNames
);
1201 if(T_FileStream_error(in
)) {
1202 fprintf(stderr
, "genccode: file read error while generating from file %s\n", filename
);
1203 exit(U_FILE_ACCESS_ERROR
);
1206 if(T_FileStream_error(out
)) {
1207 fprintf(stderr
, "genccode: file write error while generating from file %s\n", filename
);
1208 exit(U_FILE_ACCESS_ERROR
);
1211 T_FileStream_close(out
);
1212 T_FileStream_close(in
);