1 /******************************************************************************
2 * Copyright (C) 2009-2016, International Business Machines
3 * Corporation and others. All Rights Reserved.
4 *******************************************************************************
6 #include "unicode/utypes.h"
8 #if U_PLATFORM_HAS_WIN32_API
10 # define WIN32_LEAN_AND_MEAN
18 # define WINDOWS_WITH_GNUC
22 #if U_PLATFORM_IS_LINUX_BASED && U_HAVE_ELF_H
28 # if defined(ELFCLASS64)
31 /* Old elf.h headers may not have EM_X86_64, or have EM_X8664 instead. */
35 # define ICU_ENTRY_OFFSET 0
40 #include "unicode/putil.h"
45 #include "unicode/uclean.h"
49 #define MAX_COLUMN ((uint32_t)(0xFFFFFFFFU))
51 #define HEX_0X 0 /* 0x1234 */
52 #define HEX_0H 1 /* 01234h */
54 /* prototypes --------------------------------------------------------------- */
56 getOutFilename(const char *inFilename
, const char *destdir
, char *outFilename
, char *entryName
, const char *newSuffix
, const char *optFilename
);
59 write8(FileStream
*out
, uint8_t byte
, uint32_t column
);
62 write32(FileStream
*out
, uint32_t byte
, uint32_t column
);
64 #if U_PLATFORM == U_PF_OS400
66 write8str(FileStream
*out
, uint8_t byte
, uint32_t column
);
68 /* -------------------------------------------------------------------------- */
71 Creating Template Files for New Platforms
73 Let the cc compiler help you get started.
75 const unsigned int x[5] = {1, 2, 0xdeadbeef, 0xffffffff, 16};
76 with the -S option to produce assembly output.
78 For example, this will generate array.s:
81 This will produce a .s file that may look like this:
97 .ident "GCC: (GNU) 2.96 20000731 (Red Hat Linux 7.1 2.96-85)"
99 which gives a starting point that will compile, and can be transformed
100 to become the template, generally with some consulting of as docs and
101 some experimentation.
103 If you want ICU to automatically use this assembly, you should
104 specify "GENCCODE_ASSEMBLY=-a name" in the specific config/mh-* file,
105 where the name is the compiler or platform that you used in this
106 assemblyHeader data structure.
108 static const struct AssemblyType
{
111 const char *beginLine
;
113 int8_t hexType
; /* HEX_0X or HEX_0h */
114 } assemblyHeader
[] = {
115 /* For gcc assemblers, the meaning of .align changes depending on the */
116 /* hardware, so we use .balign 16 which always means 16 bytes. */
117 /* https://sourceware.org/binutils/docs/as/Pseudo-Ops.html */
120 "\t.section .note.GNU-stack,\"\",%%progbits\n"
121 "\t.section .rodata\n"
123 "#ifdef U_HIDE_DATA_SYMBOL\n"
126 "\t.type %s,%%object\n"
129 ".long ",".size %s, .-%s\n",HEX_0X
132 /*"\t.section __TEXT,__text,regular,pure_instructions\n"
133 "\t.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32\n"*/
135 "#ifdef U_HIDE_DATA_SYMBOL\n"
136 "\t.private_extern _%s\n"
147 "\t.section .rodata\n"
155 "\t.section .rodata\n"
161 /* 16 bytes alignment. */
162 /* http://docs.oracle.com/cd/E19641-01/802-1947/802-1947.pdf */
164 "\t.section \".rodata\"\n"
171 /* 16 bytes alignment for sun-x86. */
172 /* http://docs.oracle.com/cd/E19963-01/html/821-1608/eoiyg.html */
175 "\t.type Drodata.rodata,@object\n"
176 "\t.size Drodata.rodata,0\n"
183 /* 1<<4 bit alignment for aix. */
184 /* http://pic.dhe.ibm.com/infocenter/aix/v6r1/index.jsp?topic=%2Fcom.ibm.aix.aixassem%2Fdoc%2Falangref%2Fidalangref_csect_pseudoop.htm */
189 "\t.csect %s{RO}, 4\n",
195 "\t.type %s,@object\n"
197 "\t.secalias .abe$0.rodata, \".rodata\"\n"
198 "\t.section .abe$0.rodata = \"a\", \"progbits\"\n"
214 /* http://msdn.microsoft.com/en-us/library/dwa9fwef.aspx */
217 "; generated by genccode\n"
221 "ICUDATA_%s\tSEGMENT READONLY PARA PUBLIC FLAT 'DATA'\n"
223 "_%s\tLABEL DWORD\n",
224 "\tDWORD ","\nICUDATA_%s\tENDS\n\tEND\n",HEX_0H
228 static int32_t assemblyHeaderIndex
= -1;
229 static int32_t hexType
= HEX_0X
;
231 U_CAPI UBool U_EXPORT2
232 checkAssemblyHeaderName(const char* optAssembly
) {
234 assemblyHeaderIndex
= -1;
235 for (idx
= 0; idx
< UPRV_LENGTHOF(assemblyHeader
); idx
++) {
236 if (uprv_strcmp(optAssembly
, assemblyHeader
[idx
].name
) == 0) {
237 assemblyHeaderIndex
= idx
;
238 hexType
= assemblyHeader
[idx
].hexType
; /* set the hex type */
247 U_CAPI
void U_EXPORT2
248 printAssemblyHeadersToStdErr(void) {
250 fprintf(stderr
, "%s", assemblyHeader
[0].name
);
251 for (idx
= 1; idx
< UPRV_LENGTHOF(assemblyHeader
); idx
++) {
252 fprintf(stderr
, ", %s", assemblyHeader
[idx
].name
);
258 U_CAPI
void U_EXPORT2
259 writeAssemblyCode(const char *filename
, const char *destdir
, const char *optEntryPoint
, const char *optFilename
, char *outFilePath
) {
260 uint32_t column
= MAX_COLUMN
;
262 uint32_t buffer
[1024];
263 char *bufferStr
= (char *)buffer
;
264 FileStream
*in
, *out
;
267 in
=T_FileStream_open(filename
, "rb");
269 fprintf(stderr
, "genccode: unable to open input file %s\n", filename
);
270 exit(U_FILE_ACCESS_ERROR
);
273 getOutFilename(filename
, destdir
, bufferStr
, entry
, ".S", optFilename
);
274 out
=T_FileStream_open(bufferStr
, "w");
276 fprintf(stderr
, "genccode: unable to open output file %s\n", bufferStr
);
277 exit(U_FILE_ACCESS_ERROR
);
280 if (outFilePath
!= NULL
) {
281 uprv_strcpy(outFilePath
, bufferStr
);
284 #ifdef WINDOWS_WITH_GNUC
285 /* Need to fix the file seperator character when using MinGW. */
286 swapFileSepChar(outFilePath
, U_FILE_SEP_CHAR
, '/');
289 if(optEntryPoint
!= NULL
) {
290 uprv_strcpy(entry
, optEntryPoint
);
291 uprv_strcat(entry
, "_dat");
294 /* turn dashes or dots in the entry name into underscores */
295 length
=uprv_strlen(entry
);
296 for(i
=0; i
<length
; ++i
) {
297 if(entry
[i
]=='-' || entry
[i
]=='.') {
302 sprintf(bufferStr
, assemblyHeader
[assemblyHeaderIndex
].header
,
303 entry
, entry
, entry
, entry
,
304 entry
, entry
, entry
, entry
);
305 T_FileStream_writeLine(out
, bufferStr
);
306 T_FileStream_writeLine(out
, assemblyHeader
[assemblyHeaderIndex
].beginLine
);
309 length
=T_FileStream_read(in
, buffer
, sizeof(buffer
));
313 if (length
!= sizeof(buffer
)) {
314 /* pad with extra 0's when at the end of the file */
315 for(i
=0; i
< (length
% sizeof(uint32_t)); ++i
) {
316 buffer
[length
+i
] = 0;
319 for(i
=0; i
<(length
/sizeof(buffer
[0])); i
++) {
320 column
= write32(out
, buffer
[i
], column
);
324 T_FileStream_writeLine(out
, "\n");
326 sprintf(bufferStr
, assemblyHeader
[assemblyHeaderIndex
].footer
,
327 entry
, entry
, entry
, entry
,
328 entry
, entry
, entry
, entry
);
329 T_FileStream_writeLine(out
, bufferStr
);
331 if(T_FileStream_error(in
)) {
332 fprintf(stderr
, "genccode: file read error while generating from file %s\n", filename
);
333 exit(U_FILE_ACCESS_ERROR
);
336 if(T_FileStream_error(out
)) {
337 fprintf(stderr
, "genccode: file write error while generating from file %s\n", filename
);
338 exit(U_FILE_ACCESS_ERROR
);
341 T_FileStream_close(out
);
342 T_FileStream_close(in
);
345 U_CAPI
void U_EXPORT2
346 writeCCode(const char *filename
, const char *destdir
, const char *optName
, const char *optFilename
, char *outFilePath
) {
347 uint32_t column
= MAX_COLUMN
;
348 char buffer
[4096], entry
[64];
349 FileStream
*in
, *out
;
352 in
=T_FileStream_open(filename
, "rb");
354 fprintf(stderr
, "genccode: unable to open input file %s\n", filename
);
355 exit(U_FILE_ACCESS_ERROR
);
358 if(optName
!= NULL
) { /* prepend 'icudt28_' */
359 strcpy(entry
, optName
);
365 getOutFilename(filename
, destdir
, buffer
, entry
+uprv_strlen(entry
), ".c", optFilename
);
366 if (outFilePath
!= NULL
) {
367 uprv_strcpy(outFilePath
, buffer
);
369 out
=T_FileStream_open(buffer
, "w");
371 fprintf(stderr
, "genccode: unable to open output file %s\n", buffer
);
372 exit(U_FILE_ACCESS_ERROR
);
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
]=='.') {
383 #if U_PLATFORM == U_PF_OS400
385 TODO: Fix this once the compiler implements this feature. Keep in sync with udatamem.c
387 This is here because this platform can't currently put
388 const data into the read-only pages of an object or
389 shared library (service program). Only strings are allowed in read-only
390 pages, so we use char * strings to store the data.
392 In order to prevent the beginning of the data from ever matching the
393 magic numbers we must still use the initial double.
397 "#ifndef IN_GENERATED_CCODE\n"
398 "#define IN_GENERATED_CCODE\n"
399 "#define U_DISABLE_RENAMING 1\n"
400 "#include \"unicode/umachine.h\"\n"
405 " const char *bytes; \n"
408 T_FileStream_writeLine(out
, buffer
);
411 length
=T_FileStream_read(in
, buffer
, sizeof(buffer
));
415 for(i
=0; i
<length
; ++i
) {
416 column
= write8str(out
, (uint8_t)buffer
[i
], column
);
420 T_FileStream_writeLine(out
, "\"\n};\nU_CDECL_END\n");
422 /* Function renaming shouldn't be done in data */
424 "#ifndef IN_GENERATED_CCODE\n"
425 "#define IN_GENERATED_CCODE\n"
426 "#define U_DISABLE_RENAMING 1\n"
427 "#include \"unicode/umachine.h\"\n"
432 " uint8_t bytes[%ld]; \n"
434 (long)T_FileStream_size(in
), entry
);
435 T_FileStream_writeLine(out
, buffer
);
438 length
=T_FileStream_read(in
, buffer
, sizeof(buffer
));
442 for(i
=0; i
<length
; ++i
) {
443 column
= write8(out
, (uint8_t)buffer
[i
], column
);
447 T_FileStream_writeLine(out
, "\n}\n};\nU_CDECL_END\n");
450 if(T_FileStream_error(in
)) {
451 fprintf(stderr
, "genccode: file read error while generating from file %s\n", filename
);
452 exit(U_FILE_ACCESS_ERROR
);
455 if(T_FileStream_error(out
)) {
456 fprintf(stderr
, "genccode: file write error while generating from file %s\n", filename
);
457 exit(U_FILE_ACCESS_ERROR
);
460 T_FileStream_close(out
);
461 T_FileStream_close(in
);
465 write32(FileStream
*out
, uint32_t bitField
, uint32_t column
) {
467 char bitFieldStr
[64]; /* This is more bits than needed for a 32-bit number */
468 char *s
= bitFieldStr
;
469 uint8_t *ptrIdx
= (uint8_t *)&bitField
;
470 static const char hexToStr
[16] = {
477 /* write the value, possibly with comma and newline */
478 if(column
==MAX_COLUMN
) {
481 } else if(column
<32) {
486 uprv_strcpy(s
, assemblyHeader
[assemblyHeaderIndex
].beginLine
);
492 /* It's a small number. Don't waste the space for 0x */
493 *(s
++)=hexToStr
[bitField
];
496 int seenNonZero
= 0; /* This is used to remove leading zeros */
498 if(hexType
==HEX_0X
) {
501 } else if(hexType
==HEX_0H
) {
505 /* This creates a 32-bit field */
507 for (i
= 0; i
< sizeof(uint32_t); i
++)
509 for (i
= sizeof(uint32_t)-1; i
>= 0 ; i
--)
512 uint8_t value
= ptrIdx
[i
];
513 if (value
|| seenNonZero
) {
514 *(s
++)=hexToStr
[value
>>4];
515 *(s
++)=hexToStr
[value
&0xF];
519 if(hexType
==HEX_0H
) {
525 T_FileStream_writeLine(out
, bitFieldStr
);
530 write8(FileStream
*out
, uint8_t byte
, uint32_t column
) {
534 /* convert the byte value to a string */
536 s
[i
++]=(char)('0'+byte
/100);
539 if(i
>0 || byte
>=10) {
540 s
[i
++]=(char)('0'+byte
/10);
543 s
[i
++]=(char)('0'+byte
);
546 /* write the value, possibly with comma and newline */
547 if(column
==MAX_COLUMN
) {
550 } else if(column
<16) {
551 T_FileStream_writeLine(out
, ",");
554 T_FileStream_writeLine(out
, ",\n");
557 T_FileStream_writeLine(out
, s
);
561 #if U_PLATFORM == U_PF_OS400
563 write8str(FileStream
*out
, uint8_t byte
, uint32_t column
) {
567 sprintf(s
, "\\x%X", byte
);
569 sprintf(s
, "\\%X", byte
);
571 /* write the value, possibly with comma and newline */
572 if(column
==MAX_COLUMN
) {
575 T_FileStream_writeLine(out
, "\"");
576 } else if(column
<24) {
579 T_FileStream_writeLine(out
, "\"\n\"");
582 T_FileStream_writeLine(out
, s
);
588 getOutFilename(const char *inFilename
, const char *destdir
, char *outFilename
, char *entryName
, const char *newSuffix
, const char *optFilename
) {
589 const char *basename
=findBasename(inFilename
), *suffix
=uprv_strrchr(basename
, '.');
592 if(destdir
!=NULL
&& *destdir
!=0) {
594 *outFilename
++=*destdir
++;
595 } while(*destdir
!=0);
596 if(*(outFilename
-1)!=U_FILE_SEP_CHAR
) {
597 *outFilename
++=U_FILE_SEP_CHAR
;
601 while(inFilename
<basename
) {
602 *outFilename
++=*inFilename
++;
607 /* the filename does not have a suffix */
608 uprv_strcpy(entryName
, inFilename
);
609 if(optFilename
!= NULL
) {
610 uprv_strcpy(outFilename
, optFilename
);
612 uprv_strcpy(outFilename
, inFilename
);
614 uprv_strcat(outFilename
, newSuffix
);
616 char *saveOutFilename
= outFilename
;
618 while(inFilename
<suffix
) {
619 if(*inFilename
=='-') {
620 /* iSeries cannot have '-' in the .o objects. */
621 *outFilename
++=*entryName
++='_';
625 *outFilename
++=*entryName
++=*inFilename
++;
629 /* replace '.' by '_' */
630 *outFilename
++=*entryName
++='_';
634 while(*inFilename
!=0) {
635 *outFilename
++=*entryName
++=*inFilename
++;
640 if(optFilename
!= NULL
) {
641 uprv_strcpy(saveOutFilename
, optFilename
);
642 uprv_strcat(saveOutFilename
, newSuffix
);
645 uprv_strcpy(outFilename
, newSuffix
);
650 #ifdef CAN_GENERATE_OBJECTS
652 getArchitecture(uint16_t *pCPU
, uint16_t *pBits
, UBool
*pIsBigEndian
, const char *optMatchArch
) {
657 /* Elf32_Ehdr and ELF64_Ehdr are identical for the necessary fields. */
658 #elif U_PLATFORM_HAS_WIN32_API
659 IMAGE_FILE_HEADER header
;
663 const char *filename
;
669 #elif U_PLATFORM_HAS_WIN32_API
670 const IMAGE_FILE_HEADER
*pHeader
;
672 # error "Unknown platform for CAN_GENERATE_OBJECTS."
675 if(optMatchArch
!= NULL
) {
676 filename
=optMatchArch
;
680 /* set EM_386 because elf.h does not provide better defaults */
683 *pIsBigEndian
=(UBool
)(U_IS_BIG_ENDIAN
? ELFDATA2MSB
: ELFDATA2LSB
);
684 #elif U_PLATFORM_HAS_WIN32_API
685 /* _M_IA64 should be defined in windows.h */
686 # if defined(_M_IA64)
687 *pCPU
=IMAGE_FILE_MACHINE_IA64
;
688 # elif defined(_M_AMD64)
689 *pCPU
=IMAGE_FILE_MACHINE_AMD64
;
691 *pCPU
=IMAGE_FILE_MACHINE_I386
;
693 *pBits
= *pCPU
==IMAGE_FILE_MACHINE_I386
? 32 : 64;
696 # error "Unknown platform for CAN_GENERATE_OBJECTS."
701 in
=T_FileStream_open(filename
, "rb");
703 fprintf(stderr
, "genccode: unable to open match-arch file %s\n", filename
);
704 exit(U_FILE_ACCESS_ERROR
);
706 length
=T_FileStream_read(in
, buffer
.bytes
, sizeof(buffer
.bytes
));
709 if(length
<sizeof(Elf32_Ehdr
)) {
710 fprintf(stderr
, "genccode: match-arch file %s is too short\n", filename
);
711 exit(U_UNSUPPORTED_ERROR
);
714 buffer
.header32
.e_ident
[0]!=ELFMAG0
||
715 buffer
.header32
.e_ident
[1]!=ELFMAG1
||
716 buffer
.header32
.e_ident
[2]!=ELFMAG2
||
717 buffer
.header32
.e_ident
[3]!=ELFMAG3
||
718 buffer
.header32
.e_ident
[EI_CLASS
]<ELFCLASS32
|| buffer
.header32
.e_ident
[EI_CLASS
]>ELFCLASS64
720 fprintf(stderr
, "genccode: match-arch file %s is not an ELF object file, or not supported\n", filename
);
721 exit(U_UNSUPPORTED_ERROR
);
724 *pBits
= buffer
.header32
.e_ident
[EI_CLASS
]==ELFCLASS32
? 32 : 64; /* only 32 or 64: see check above */
726 if(*pBits
!=32 && *pBits
!=64) {
727 fprintf(stderr
, "genccode: currently only supports 32-bit and 64-bit ELF format\n");
728 exit(U_UNSUPPORTED_ERROR
);
732 fprintf(stderr
, "genccode: built with elf.h missing 64-bit definitions\n");
733 exit(U_UNSUPPORTED_ERROR
);
737 *pIsBigEndian
=(UBool
)(buffer
.header32
.e_ident
[EI_DATA
]==ELFDATA2MSB
);
738 if(*pIsBigEndian
!=U_IS_BIG_ENDIAN
) {
739 fprintf(stderr
, "genccode: currently only same-endianness ELF formats are supported\n");
740 exit(U_UNSUPPORTED_ERROR
);
742 /* TODO: Support byte swapping */
744 *pCPU
=buffer
.header32
.e_machine
;
745 #elif U_PLATFORM_HAS_WIN32_API
746 if(length
<sizeof(IMAGE_FILE_HEADER
)) {
747 fprintf(stderr
, "genccode: match-arch file %s is too short\n", filename
);
748 exit(U_UNSUPPORTED_ERROR
);
750 /* TODO: Use buffer.header. Keep aliasing legal. */
751 pHeader
=(const IMAGE_FILE_HEADER
*)buffer
.bytes
;
752 *pCPU
=pHeader
->Machine
;
754 * The number of bits is implicit with the Machine value.
755 * *pBits is ignored in the calling code, so this need not be precise.
757 *pBits
= *pCPU
==IMAGE_FILE_MACHINE_I386
? 32 : 64;
758 /* Windows always runs on little-endian CPUs. */
761 # error "Unknown platform for CAN_GENERATE_OBJECTS."
764 T_FileStream_close(in
);
767 U_CAPI
void U_EXPORT2
768 writeObjectCode(const char *filename
, const char *destdir
, const char *optEntryPoint
, const char *optMatchArch
, const char *optFilename
, char *outFilePath
) {
769 /* common variables */
770 char buffer
[4096], entry
[96]={ 0 };
771 FileStream
*in
, *out
;
772 const char *newSuffix
;
773 int32_t i
, entryLength
, length
, size
, entryOffset
=0, entryLengthOffset
=0;
778 /* platform-specific variables and initialization code */
780 /* 32-bit Elf file header */
781 static Elf32_Ehdr header32
={
784 ELFMAG0
, ELFMAG1
, ELFMAG2
, ELFMAG3
,
786 U_IS_BIG_ENDIAN
? ELFDATA2MSB
: ELFDATA2LSB
,
787 EV_CURRENT
/* EI_VERSION */
791 EV_CURRENT
, /* e_version */
794 (Elf32_Off
)sizeof(Elf32_Ehdr
), /* e_shoff */
796 (Elf32_Half
)sizeof(Elf32_Ehdr
), /* eh_size */
799 (Elf32_Half
)sizeof(Elf32_Shdr
), /* e_shentsize */
804 /* 32-bit Elf section header table */
805 static Elf32_Shdr sectionHeaders32
[5]={
814 (Elf32_Off
)(sizeof(header32
)+sizeof(sectionHeaders32
)), /* sh_offset */
815 (Elf32_Word
)(2*sizeof(Elf32_Sym
)), /* sh_size */
816 3, /* sh_link=sect hdr index of .strtab */
817 1, /* sh_info=One greater than the symbol table index of the last
818 * local symbol (with STB_LOCAL). */
819 4, /* sh_addralign */
820 (Elf32_Word
)(sizeof(Elf32_Sym
)) /* sh_entsize */
827 (Elf32_Off
)(sizeof(header32
)+sizeof(sectionHeaders32
)+2*sizeof(Elf32_Sym
)), /* sh_offset */
831 1, /* sh_addralign */
839 (Elf32_Off
)(sizeof(header32
)+sizeof(sectionHeaders32
)+2*sizeof(Elf32_Sym
)+40), /* sh_offset */
840 (Elf32_Word
)sizeof(entry
), /* sh_size */
843 1, /* sh_addralign */
849 SHF_ALLOC
, /* sh_flags */
851 (Elf32_Off
)(sizeof(header32
)+sizeof(sectionHeaders32
)+2*sizeof(Elf32_Sym
)+40+sizeof(entry
)), /* sh_offset */
855 16, /* sh_addralign */
861 static Elf32_Sym symbols32
[2]={
865 { /* data entry point */
869 ELF64_ST_INFO(STB_GLOBAL
, STT_OBJECT
),
871 4 /* st_shndx=index of related section table entry */
875 /* section header string table, with decimal string offsets */
876 static const char sectionStrings
[40]=
879 /* 9 */ ".shstrtab\0"
882 /* 35 */ "\0\0\0\0"; /* contains terminating NUL */
883 /* 40: padded to multiple of 8 bytes */
886 * Use entry[] for the string table which will contain only the
888 * entry[0] must be 0 (NUL)
889 * The entry point name can be up to 38 characters long (sizeof(entry)-2).
892 /* 16-align .rodata in the .o file, just in case */
893 static const char padding
[16]={ 0 };
897 /* 64-bit Elf file header */
898 static Elf64_Ehdr header64
={
901 ELFMAG0
, ELFMAG1
, ELFMAG2
, ELFMAG3
,
903 U_IS_BIG_ENDIAN
? ELFDATA2MSB
: ELFDATA2LSB
,
904 EV_CURRENT
/* EI_VERSION */
908 EV_CURRENT
, /* e_version */
911 (Elf64_Off
)sizeof(Elf64_Ehdr
), /* e_shoff */
913 (Elf64_Half
)sizeof(Elf64_Ehdr
), /* eh_size */
916 (Elf64_Half
)sizeof(Elf64_Shdr
), /* e_shentsize */
921 /* 64-bit Elf section header table */
922 static Elf64_Shdr sectionHeaders64
[5]={
931 (Elf64_Off
)(sizeof(header64
)+sizeof(sectionHeaders64
)), /* sh_offset */
932 (Elf64_Xword
)(2*sizeof(Elf64_Sym
)), /* sh_size */
933 3, /* sh_link=sect hdr index of .strtab */
934 1, /* sh_info=One greater than the symbol table index of the last
935 * local symbol (with STB_LOCAL). */
936 4, /* sh_addralign */
937 (Elf64_Xword
)(sizeof(Elf64_Sym
)) /* sh_entsize */
944 (Elf64_Off
)(sizeof(header64
)+sizeof(sectionHeaders64
)+2*sizeof(Elf64_Sym
)), /* sh_offset */
948 1, /* sh_addralign */
956 (Elf64_Off
)(sizeof(header64
)+sizeof(sectionHeaders64
)+2*sizeof(Elf64_Sym
)+40), /* sh_offset */
957 (Elf64_Xword
)sizeof(entry
), /* sh_size */
960 1, /* sh_addralign */
966 SHF_ALLOC
, /* sh_flags */
968 (Elf64_Off
)(sizeof(header64
)+sizeof(sectionHeaders64
)+2*sizeof(Elf64_Sym
)+40+sizeof(entry
)), /* sh_offset */
972 16, /* sh_addralign */
978 * 64-bit symbol table
979 * careful: different order of items compared with Elf32_sym!
981 static Elf64_Sym symbols64
[2]={
985 { /* data entry point */
987 ELF64_ST_INFO(STB_GLOBAL
, STT_OBJECT
),
989 4, /* st_shndx=index of related section table entry */
997 /* entry[] have a leading NUL */
1000 /* in the common code, count entryLength from after the NUL */
1001 entryLengthOffset
=1;
1005 #elif U_PLATFORM_HAS_WIN32_API
1007 IMAGE_FILE_HEADER fileHeader
;
1008 IMAGE_SECTION_HEADER sections
[2];
1009 char linkerOptions
[100];
1011 IMAGE_SYMBOL symbols
[1];
1013 DWORD sizeofLongNames
;
1014 char longNames
[100];
1018 * entry sometimes have a leading '_'
1019 * overwritten if entryOffset==0 depending on the target platform
1020 * see check for cpu below
1026 # error "Unknown platform for CAN_GENERATE_OBJECTS."
1029 /* deal with options, files and the entry point name */
1030 getArchitecture(&cpu
, &bits
, &makeBigEndian
, optMatchArch
);
1031 printf("genccode: --match-arch cpu=%hu bits=%hu big-endian=%d\n", cpu
, bits
, makeBigEndian
);
1032 #if U_PLATFORM_HAS_WIN32_API
1033 if(cpu
==IMAGE_FILE_MACHINE_I386
) {
1038 in
=T_FileStream_open(filename
, "rb");
1040 fprintf(stderr
, "genccode: unable to open input file %s\n", filename
);
1041 exit(U_FILE_ACCESS_ERROR
);
1043 size
=T_FileStream_size(in
);
1045 getOutFilename(filename
, destdir
, buffer
, entry
+entryOffset
, newSuffix
, optFilename
);
1046 if (outFilePath
!= NULL
) {
1047 uprv_strcpy(outFilePath
, buffer
);
1050 if(optEntryPoint
!= NULL
) {
1051 uprv_strcpy(entry
+entryOffset
, optEntryPoint
);
1052 uprv_strcat(entry
+entryOffset
, "_dat");
1054 /* turn dashes in the entry name into underscores */
1055 entryLength
=(int32_t)uprv_strlen(entry
+entryLengthOffset
);
1056 for(i
=0; i
<entryLength
; ++i
) {
1057 if(entry
[entryLengthOffset
+i
]=='-') {
1058 entry
[entryLengthOffset
+i
]='_';
1062 /* open the output file */
1063 out
=T_FileStream_open(buffer
, "wb");
1065 fprintf(stderr
, "genccode: unable to open output file %s\n", buffer
);
1066 exit(U_FILE_ACCESS_ERROR
);
1071 header32
.e_ident
[EI_DATA
]= makeBigEndian
? ELFDATA2MSB
: ELFDATA2LSB
;
1072 header32
.e_machine
=cpu
;
1074 /* 16-align .rodata in the .o file, just in case */
1075 paddingSize
=sectionHeaders32
[4].sh_offset
& 0xf;
1076 if(paddingSize
!=0) {
1077 paddingSize
=0x10-paddingSize
;
1078 sectionHeaders32
[4].sh_offset
+=paddingSize
;
1081 sectionHeaders32
[4].sh_size
=(Elf32_Word
)size
;
1083 symbols32
[1].st_size
=(Elf32_Word
)size
;
1085 /* write .o headers */
1086 T_FileStream_write(out
, &header32
, (int32_t)sizeof(header32
));
1087 T_FileStream_write(out
, sectionHeaders32
, (int32_t)sizeof(sectionHeaders32
));
1088 T_FileStream_write(out
, symbols32
, (int32_t)sizeof(symbols32
));
1089 } else /* bits==64 */ {
1091 header64
.e_ident
[EI_DATA
]= makeBigEndian
? ELFDATA2MSB
: ELFDATA2LSB
;
1092 header64
.e_machine
=cpu
;
1094 /* 16-align .rodata in the .o file, just in case */
1095 paddingSize
=sectionHeaders64
[4].sh_offset
& 0xf;
1096 if(paddingSize
!=0) {
1097 paddingSize
=0x10-paddingSize
;
1098 sectionHeaders64
[4].sh_offset
+=paddingSize
;
1101 sectionHeaders64
[4].sh_size
=(Elf64_Xword
)size
;
1103 symbols64
[1].st_size
=(Elf64_Xword
)size
;
1105 /* write .o headers */
1106 T_FileStream_write(out
, &header64
, (int32_t)sizeof(header64
));
1107 T_FileStream_write(out
, sectionHeaders64
, (int32_t)sizeof(sectionHeaders64
));
1108 T_FileStream_write(out
, symbols64
, (int32_t)sizeof(symbols64
));
1112 T_FileStream_write(out
, sectionStrings
, (int32_t)sizeof(sectionStrings
));
1113 T_FileStream_write(out
, entry
, (int32_t)sizeof(entry
));
1114 if(paddingSize
!=0) {
1115 T_FileStream_write(out
, padding
, paddingSize
);
1117 #elif U_PLATFORM_HAS_WIN32_API
1118 /* populate the .obj headers */
1119 uprv_memset(&objHeader
, 0, sizeof(objHeader
));
1120 uprv_memset(&symbols
, 0, sizeof(symbols
));
1121 uprv_memset(&symbolNames
, 0, sizeof(symbolNames
));
1123 /* write the linker export directive */
1124 uprv_strcpy(objHeader
.linkerOptions
, "-export:");
1126 uprv_strcpy(objHeader
.linkerOptions
+length
, entry
);
1127 length
+=entryLength
;
1128 uprv_strcpy(objHeader
.linkerOptions
+length
, ",data ");
1131 /* set the file header */
1132 objHeader
.fileHeader
.Machine
=cpu
;
1133 objHeader
.fileHeader
.NumberOfSections
=2;
1134 objHeader
.fileHeader
.TimeDateStamp
=(DWORD
)time(NULL
);
1135 objHeader
.fileHeader
.PointerToSymbolTable
=IMAGE_SIZEOF_FILE_HEADER
+2*IMAGE_SIZEOF_SECTION_HEADER
+length
+size
; /* start of symbol table */
1136 objHeader
.fileHeader
.NumberOfSymbols
=1;
1138 /* set the section for the linker options */
1139 uprv_strncpy((char *)objHeader
.sections
[0].Name
, ".drectve", 8);
1140 objHeader
.sections
[0].SizeOfRawData
=length
;
1141 objHeader
.sections
[0].PointerToRawData
=IMAGE_SIZEOF_FILE_HEADER
+2*IMAGE_SIZEOF_SECTION_HEADER
;
1142 objHeader
.sections
[0].Characteristics
=IMAGE_SCN_LNK_INFO
|IMAGE_SCN_LNK_REMOVE
|IMAGE_SCN_ALIGN_1BYTES
;
1144 /* set the data section */
1145 uprv_strncpy((char *)objHeader
.sections
[1].Name
, ".rdata", 6);
1146 objHeader
.sections
[1].SizeOfRawData
=size
;
1147 objHeader
.sections
[1].PointerToRawData
=IMAGE_SIZEOF_FILE_HEADER
+2*IMAGE_SIZEOF_SECTION_HEADER
+length
;
1148 objHeader
.sections
[1].Characteristics
=IMAGE_SCN_CNT_INITIALIZED_DATA
|IMAGE_SCN_ALIGN_16BYTES
|IMAGE_SCN_MEM_READ
;
1150 /* set the symbol table */
1151 if(entryLength
<=8) {
1152 uprv_strncpy((char *)symbols
[0].N
.ShortName
, entry
, entryLength
);
1153 symbolNames
.sizeofLongNames
=4;
1155 symbols
[0].N
.Name
.Short
=0;
1156 symbols
[0].N
.Name
.Long
=4;
1157 symbolNames
.sizeofLongNames
=4+entryLength
+1;
1158 uprv_strcpy(symbolNames
.longNames
, entry
);
1160 symbols
[0].SectionNumber
=2;
1161 symbols
[0].StorageClass
=IMAGE_SYM_CLASS_EXTERNAL
;
1163 /* write the file header and the linker options section */
1164 T_FileStream_write(out
, &objHeader
, objHeader
.sections
[1].PointerToRawData
);
1166 # error "Unknown platform for CAN_GENERATE_OBJECTS."
1169 /* copy the data file into section 2 */
1171 length
=T_FileStream_read(in
, buffer
, sizeof(buffer
));
1175 T_FileStream_write(out
, buffer
, (int32_t)length
);
1178 #if U_PLATFORM_HAS_WIN32_API
1179 /* write the symbol table */
1180 T_FileStream_write(out
, symbols
, IMAGE_SIZEOF_SYMBOL
);
1181 T_FileStream_write(out
, &symbolNames
, symbolNames
.sizeofLongNames
);
1184 if(T_FileStream_error(in
)) {
1185 fprintf(stderr
, "genccode: file read error while generating from file %s\n", filename
);
1186 exit(U_FILE_ACCESS_ERROR
);
1189 if(T_FileStream_error(out
)) {
1190 fprintf(stderr
, "genccode: file write error while generating from file %s\n", filename
);
1191 exit(U_FILE_ACCESS_ERROR
);
1194 T_FileStream_close(out
);
1195 T_FileStream_close(in
);