1 /******************************************************************************
2 * Copyright (C) 2009-2013, 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 "\t.type %s,%%object\n"
129 /*"\t.section __TEXT,__text,regular,pure_instructions\n"
130 "\t.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32\n"*/
141 "\t.section .rodata\n"
149 "\t.section .rodata\n"
155 // 16 bytes alignment.
156 // http://docs.oracle.com/cd/E19641-01/802-1947/802-1947.pdf
158 "\t.section \".rodata\"\n"
165 // 16 bytes alignment for sun-x86.
166 // http://docs.oracle.com/cd/E19963-01/html/821-1608/eoiyg.html
169 "\t.type Drodata.rodata,@object\n"
170 "\t.size Drodata.rodata,0\n"
177 // 1<<4 bit alignment for aix.
178 // http://pic.dhe.ibm.com/infocenter/aix/v6r1/index.jsp?topic=%2Fcom.ibm.aix.aixassem%2Fdoc%2Falangref%2Fidalangref_csect_pseudoop.htm
183 "\t.csect %s{RO}, 4\n",
189 "\t.type %s,@object\n"
191 "\t.secalias .abe$0.rodata, \".rodata\"\n"
192 "\t.section .abe$0.rodata = \"a\", \"progbits\"\n"
208 // http://msdn.microsoft.com/en-us/library/dwa9fwef.aspx
211 "; generated by genccode\n"
215 "ICUDATA_%s\tSEGMENT READONLY PARA PUBLIC FLAT 'DATA'\n"
217 "_%s\tLABEL DWORD\n",
218 "\tDWORD ","\nICUDATA_%s\tENDS\n\tEND\n",HEX_0H
222 static int32_t assemblyHeaderIndex
= -1;
223 static int32_t hexType
= HEX_0X
;
225 U_CAPI UBool U_EXPORT2
226 checkAssemblyHeaderName(const char* optAssembly
) {
228 assemblyHeaderIndex
= -1;
229 for (idx
= 0; idx
< (int32_t)(sizeof(assemblyHeader
)/sizeof(assemblyHeader
[0])); idx
++) {
230 if (uprv_strcmp(optAssembly
, assemblyHeader
[idx
].name
) == 0) {
231 assemblyHeaderIndex
= idx
;
232 hexType
= assemblyHeader
[idx
].hexType
; /* set the hex type */
241 U_CAPI
void U_EXPORT2
242 printAssemblyHeadersToStdErr(void) {
244 fprintf(stderr
, "%s", assemblyHeader
[0].name
);
245 for (idx
= 1; idx
< (int32_t)(sizeof(assemblyHeader
)/sizeof(assemblyHeader
[0])); idx
++) {
246 fprintf(stderr
, ", %s", assemblyHeader
[idx
].name
);
252 U_CAPI
void U_EXPORT2
253 writeAssemblyCode(const char *filename
, const char *destdir
, const char *optEntryPoint
, const char *optFilename
, char *outFilePath
) {
254 uint32_t column
= MAX_COLUMN
;
256 uint32_t buffer
[1024];
257 char *bufferStr
= (char *)buffer
;
258 FileStream
*in
, *out
;
261 in
=T_FileStream_open(filename
, "rb");
263 fprintf(stderr
, "genccode: unable to open input file %s\n", filename
);
264 exit(U_FILE_ACCESS_ERROR
);
267 getOutFilename(filename
, destdir
, bufferStr
, entry
, ".s", optFilename
);
268 out
=T_FileStream_open(bufferStr
, "w");
270 fprintf(stderr
, "genccode: unable to open output file %s\n", bufferStr
);
271 exit(U_FILE_ACCESS_ERROR
);
274 if (outFilePath
!= NULL
) {
275 uprv_strcpy(outFilePath
, bufferStr
);
278 #ifdef WINDOWS_WITH_GNUC
279 /* Need to fix the file seperator character when using MinGW. */
280 swapFileSepChar(outFilePath
, U_FILE_SEP_CHAR
, '/');
283 if(optEntryPoint
!= NULL
) {
284 uprv_strcpy(entry
, optEntryPoint
);
285 uprv_strcat(entry
, "_dat");
288 /* turn dashes or dots in the entry name into underscores */
289 length
=uprv_strlen(entry
);
290 for(i
=0; i
<length
; ++i
) {
291 if(entry
[i
]=='-' || entry
[i
]=='.') {
296 sprintf(bufferStr
, assemblyHeader
[assemblyHeaderIndex
].header
,
297 entry
, entry
, entry
, entry
,
298 entry
, entry
, entry
, entry
);
299 T_FileStream_writeLine(out
, bufferStr
);
300 T_FileStream_writeLine(out
, assemblyHeader
[assemblyHeaderIndex
].beginLine
);
303 length
=T_FileStream_read(in
, buffer
, sizeof(buffer
));
307 if (length
!= sizeof(buffer
)) {
308 /* pad with extra 0's when at the end of the file */
309 for(i
=0; i
< (length
% sizeof(uint32_t)); ++i
) {
310 buffer
[length
+i
] = 0;
313 for(i
=0; i
<(length
/sizeof(buffer
[0])); i
++) {
314 column
= write32(out
, buffer
[i
], column
);
318 T_FileStream_writeLine(out
, "\n");
320 sprintf(bufferStr
, assemblyHeader
[assemblyHeaderIndex
].footer
,
321 entry
, entry
, entry
, entry
,
322 entry
, entry
, entry
, entry
);
323 T_FileStream_writeLine(out
, bufferStr
);
325 if(T_FileStream_error(in
)) {
326 fprintf(stderr
, "genccode: file read error while generating from file %s\n", filename
);
327 exit(U_FILE_ACCESS_ERROR
);
330 if(T_FileStream_error(out
)) {
331 fprintf(stderr
, "genccode: file write error while generating from file %s\n", filename
);
332 exit(U_FILE_ACCESS_ERROR
);
335 T_FileStream_close(out
);
336 T_FileStream_close(in
);
339 U_CAPI
void U_EXPORT2
340 writeCCode(const char *filename
, const char *destdir
, const char *optName
, const char *optFilename
, char *outFilePath
) {
341 uint32_t column
= MAX_COLUMN
;
342 char buffer
[4096], entry
[64];
343 FileStream
*in
, *out
;
346 in
=T_FileStream_open(filename
, "rb");
348 fprintf(stderr
, "genccode: unable to open input file %s\n", filename
);
349 exit(U_FILE_ACCESS_ERROR
);
352 if(optName
!= NULL
) { /* prepend 'icudt28_' */
353 strcpy(entry
, optName
);
359 getOutFilename(filename
, destdir
, buffer
, entry
+uprv_strlen(entry
), ".c", optFilename
);
360 if (outFilePath
!= NULL
) {
361 uprv_strcpy(outFilePath
, buffer
);
363 out
=T_FileStream_open(buffer
, "w");
365 fprintf(stderr
, "genccode: unable to open output file %s\n", buffer
);
366 exit(U_FILE_ACCESS_ERROR
);
369 /* turn dashes or dots in the entry name into underscores */
370 length
=uprv_strlen(entry
);
371 for(i
=0; i
<length
; ++i
) {
372 if(entry
[i
]=='-' || entry
[i
]=='.') {
377 #if U_PLATFORM == U_PF_OS400
379 TODO: Fix this once the compiler implements this feature. Keep in sync with udatamem.c
381 This is here because this platform can't currently put
382 const data into the read-only pages of an object or
383 shared library (service program). Only strings are allowed in read-only
384 pages, so we use char * strings to store the data.
386 In order to prevent the beginning of the data from ever matching the
387 magic numbers we must still use the initial double.
391 "#ifndef IN_GENERATED_CCODE\n"
392 "#define IN_GENERATED_CCODE\n"
393 "#define U_DISABLE_RENAMING 1\n"
394 "#include \"unicode/umachine.h\"\n"
399 " const char *bytes; \n"
402 T_FileStream_writeLine(out
, buffer
);
405 length
=T_FileStream_read(in
, buffer
, sizeof(buffer
));
409 for(i
=0; i
<length
; ++i
) {
410 column
= write8str(out
, (uint8_t)buffer
[i
], column
);
414 T_FileStream_writeLine(out
, "\"\n};\nU_CDECL_END\n");
416 /* Function renaming shouldn't be done in data */
418 "#ifndef IN_GENERATED_CCODE\n"
419 "#define IN_GENERATED_CCODE\n"
420 "#define U_DISABLE_RENAMING 1\n"
421 "#include \"unicode/umachine.h\"\n"
426 " uint8_t bytes[%ld]; \n"
428 (long)T_FileStream_size(in
), entry
);
429 T_FileStream_writeLine(out
, buffer
);
432 length
=T_FileStream_read(in
, buffer
, sizeof(buffer
));
436 for(i
=0; i
<length
; ++i
) {
437 column
= write8(out
, (uint8_t)buffer
[i
], column
);
441 T_FileStream_writeLine(out
, "\n}\n};\nU_CDECL_END\n");
444 if(T_FileStream_error(in
)) {
445 fprintf(stderr
, "genccode: file read error while generating from file %s\n", filename
);
446 exit(U_FILE_ACCESS_ERROR
);
449 if(T_FileStream_error(out
)) {
450 fprintf(stderr
, "genccode: file write error while generating from file %s\n", filename
);
451 exit(U_FILE_ACCESS_ERROR
);
454 T_FileStream_close(out
);
455 T_FileStream_close(in
);
459 write32(FileStream
*out
, uint32_t bitField
, uint32_t column
) {
461 char bitFieldStr
[64]; /* This is more bits than needed for a 32-bit number */
462 char *s
= bitFieldStr
;
463 uint8_t *ptrIdx
= (uint8_t *)&bitField
;
464 static const char hexToStr
[16] = {
471 /* write the value, possibly with comma and newline */
472 if(column
==MAX_COLUMN
) {
475 } else if(column
<32) {
480 uprv_strcpy(s
, assemblyHeader
[assemblyHeaderIndex
].beginLine
);
486 /* It's a small number. Don't waste the space for 0x */
487 *(s
++)=hexToStr
[bitField
];
490 int seenNonZero
= 0; /* This is used to remove leading zeros */
492 if(hexType
==HEX_0X
) {
495 } else if(hexType
==HEX_0H
) {
499 /* This creates a 32-bit field */
501 for (i
= 0; i
< sizeof(uint32_t); i
++)
503 for (i
= sizeof(uint32_t)-1; i
>= 0 ; i
--)
506 uint8_t value
= ptrIdx
[i
];
507 if (value
|| seenNonZero
) {
508 *(s
++)=hexToStr
[value
>>4];
509 *(s
++)=hexToStr
[value
&0xF];
513 if(hexType
==HEX_0H
) {
519 T_FileStream_writeLine(out
, bitFieldStr
);
524 write8(FileStream
*out
, uint8_t byte
, uint32_t column
) {
528 /* convert the byte value to a string */
530 s
[i
++]=(char)('0'+byte
/100);
533 if(i
>0 || byte
>=10) {
534 s
[i
++]=(char)('0'+byte
/10);
537 s
[i
++]=(char)('0'+byte
);
540 /* write the value, possibly with comma and newline */
541 if(column
==MAX_COLUMN
) {
544 } else if(column
<16) {
545 T_FileStream_writeLine(out
, ",");
548 T_FileStream_writeLine(out
, ",\n");
551 T_FileStream_writeLine(out
, s
);
555 #if U_PLATFORM == U_PF_OS400
557 write8str(FileStream
*out
, uint8_t byte
, uint32_t column
) {
561 sprintf(s
, "\\x%X", byte
);
563 sprintf(s
, "\\%X", byte
);
565 /* write the value, possibly with comma and newline */
566 if(column
==MAX_COLUMN
) {
569 T_FileStream_writeLine(out
, "\"");
570 } else if(column
<24) {
573 T_FileStream_writeLine(out
, "\"\n\"");
576 T_FileStream_writeLine(out
, s
);
582 getOutFilename(const char *inFilename
, const char *destdir
, char *outFilename
, char *entryName
, const char *newSuffix
, const char *optFilename
) {
583 const char *basename
=findBasename(inFilename
), *suffix
=uprv_strrchr(basename
, '.');
586 if(destdir
!=NULL
&& *destdir
!=0) {
588 *outFilename
++=*destdir
++;
589 } while(*destdir
!=0);
590 if(*(outFilename
-1)!=U_FILE_SEP_CHAR
) {
591 *outFilename
++=U_FILE_SEP_CHAR
;
595 while(inFilename
<basename
) {
596 *outFilename
++=*inFilename
++;
601 /* the filename does not have a suffix */
602 uprv_strcpy(entryName
, inFilename
);
603 if(optFilename
!= NULL
) {
604 uprv_strcpy(outFilename
, optFilename
);
606 uprv_strcpy(outFilename
, inFilename
);
608 uprv_strcat(outFilename
, newSuffix
);
610 char *saveOutFilename
= outFilename
;
612 while(inFilename
<suffix
) {
613 if(*inFilename
=='-') {
614 /* iSeries cannot have '-' in the .o objects. */
615 *outFilename
++=*entryName
++='_';
619 *outFilename
++=*entryName
++=*inFilename
++;
623 /* replace '.' by '_' */
624 *outFilename
++=*entryName
++='_';
628 while(*inFilename
!=0) {
629 *outFilename
++=*entryName
++=*inFilename
++;
634 if(optFilename
!= NULL
) {
635 uprv_strcpy(saveOutFilename
, optFilename
);
636 uprv_strcat(saveOutFilename
, newSuffix
);
639 uprv_strcpy(outFilename
, newSuffix
);
644 #ifdef CAN_GENERATE_OBJECTS
646 getArchitecture(uint16_t *pCPU
, uint16_t *pBits
, UBool
*pIsBigEndian
, const char *optMatchArch
) {
651 /* Elf32_Ehdr and ELF64_Ehdr are identical for the necessary fields. */
652 #elif U_PLATFORM_HAS_WIN32_API
653 IMAGE_FILE_HEADER header
;
657 const char *filename
;
663 #elif U_PLATFORM_HAS_WIN32_API
664 const IMAGE_FILE_HEADER
*pHeader
;
666 # error "Unknown platform for CAN_GENERATE_OBJECTS."
669 if(optMatchArch
!= NULL
) {
670 filename
=optMatchArch
;
674 /* set EM_386 because elf.h does not provide better defaults */
677 *pIsBigEndian
=(UBool
)(U_IS_BIG_ENDIAN
? ELFDATA2MSB
: ELFDATA2LSB
);
678 #elif U_PLATFORM_HAS_WIN32_API
679 /* _M_IA64 should be defined in windows.h */
680 # if defined(_M_IA64)
681 *pCPU
=IMAGE_FILE_MACHINE_IA64
;
682 # elif defined(_M_AMD64)
683 *pCPU
=IMAGE_FILE_MACHINE_AMD64
;
685 *pCPU
=IMAGE_FILE_MACHINE_I386
;
687 *pBits
= *pCPU
==IMAGE_FILE_MACHINE_I386
? 32 : 64;
690 # error "Unknown platform for CAN_GENERATE_OBJECTS."
695 in
=T_FileStream_open(filename
, "rb");
697 fprintf(stderr
, "genccode: unable to open match-arch file %s\n", filename
);
698 exit(U_FILE_ACCESS_ERROR
);
700 length
=T_FileStream_read(in
, buffer
.bytes
, sizeof(buffer
.bytes
));
703 if(length
<sizeof(Elf32_Ehdr
)) {
704 fprintf(stderr
, "genccode: match-arch file %s is too short\n", filename
);
705 exit(U_UNSUPPORTED_ERROR
);
708 buffer
.header32
.e_ident
[0]!=ELFMAG0
||
709 buffer
.header32
.e_ident
[1]!=ELFMAG1
||
710 buffer
.header32
.e_ident
[2]!=ELFMAG2
||
711 buffer
.header32
.e_ident
[3]!=ELFMAG3
||
712 buffer
.header32
.e_ident
[EI_CLASS
]<ELFCLASS32
|| buffer
.header32
.e_ident
[EI_CLASS
]>ELFCLASS64
714 fprintf(stderr
, "genccode: match-arch file %s is not an ELF object file, or not supported\n", filename
);
715 exit(U_UNSUPPORTED_ERROR
);
718 *pBits
= buffer
.header32
.e_ident
[EI_CLASS
]==ELFCLASS32
? 32 : 64; /* only 32 or 64: see check above */
720 if(*pBits
!=32 && *pBits
!=64) {
721 fprintf(stderr
, "genccode: currently only supports 32-bit and 64-bit ELF format\n");
722 exit(U_UNSUPPORTED_ERROR
);
726 fprintf(stderr
, "genccode: built with elf.h missing 64-bit definitions\n");
727 exit(U_UNSUPPORTED_ERROR
);
731 *pIsBigEndian
=(UBool
)(buffer
.header32
.e_ident
[EI_DATA
]==ELFDATA2MSB
);
732 if(*pIsBigEndian
!=U_IS_BIG_ENDIAN
) {
733 fprintf(stderr
, "genccode: currently only same-endianness ELF formats are supported\n");
734 exit(U_UNSUPPORTED_ERROR
);
736 /* TODO: Support byte swapping */
738 *pCPU
=buffer
.header32
.e_machine
;
739 #elif U_PLATFORM_HAS_WIN32_API
740 if(length
<sizeof(IMAGE_FILE_HEADER
)) {
741 fprintf(stderr
, "genccode: match-arch file %s is too short\n", filename
);
742 exit(U_UNSUPPORTED_ERROR
);
744 /* TODO: Use buffer.header. Keep aliasing legal. */
745 pHeader
=(const IMAGE_FILE_HEADER
*)buffer
.bytes
;
746 *pCPU
=pHeader
->Machine
;
748 * The number of bits is implicit with the Machine value.
749 * *pBits is ignored in the calling code, so this need not be precise.
751 *pBits
= *pCPU
==IMAGE_FILE_MACHINE_I386
? 32 : 64;
752 /* Windows always runs on little-endian CPUs. */
755 # error "Unknown platform for CAN_GENERATE_OBJECTS."
758 T_FileStream_close(in
);
761 U_CAPI
void U_EXPORT2
762 writeObjectCode(const char *filename
, const char *destdir
, const char *optEntryPoint
, const char *optMatchArch
, const char *optFilename
, char *outFilePath
) {
763 /* common variables */
764 char buffer
[4096], entry
[40]={ 0 };
765 FileStream
*in
, *out
;
766 const char *newSuffix
;
767 int32_t i
, entryLength
, length
, size
, entryOffset
=0, entryLengthOffset
=0;
772 /* platform-specific variables and initialization code */
774 /* 32-bit Elf file header */
775 static Elf32_Ehdr header32
={
778 ELFMAG0
, ELFMAG1
, ELFMAG2
, ELFMAG3
,
780 U_IS_BIG_ENDIAN
? ELFDATA2MSB
: ELFDATA2LSB
,
781 EV_CURRENT
/* EI_VERSION */
785 EV_CURRENT
, /* e_version */
788 (Elf32_Off
)sizeof(Elf32_Ehdr
), /* e_shoff */
790 (Elf32_Half
)sizeof(Elf32_Ehdr
), /* eh_size */
793 (Elf32_Half
)sizeof(Elf32_Shdr
), /* e_shentsize */
798 /* 32-bit Elf section header table */
799 static Elf32_Shdr sectionHeaders32
[5]={
808 (Elf32_Off
)(sizeof(header32
)+sizeof(sectionHeaders32
)), /* sh_offset */
809 (Elf32_Word
)(2*sizeof(Elf32_Sym
)), /* sh_size */
810 3, /* sh_link=sect hdr index of .strtab */
811 1, /* sh_info=One greater than the symbol table index of the last
812 * local symbol (with STB_LOCAL). */
813 4, /* sh_addralign */
814 (Elf32_Word
)(sizeof(Elf32_Sym
)) /* sh_entsize */
821 (Elf32_Off
)(sizeof(header32
)+sizeof(sectionHeaders32
)+2*sizeof(Elf32_Sym
)), /* sh_offset */
825 1, /* sh_addralign */
833 (Elf32_Off
)(sizeof(header32
)+sizeof(sectionHeaders32
)+2*sizeof(Elf32_Sym
)+40), /* sh_offset */
834 (Elf32_Word
)sizeof(entry
), /* sh_size */
837 1, /* sh_addralign */
843 SHF_ALLOC
, /* sh_flags */
845 (Elf32_Off
)(sizeof(header32
)+sizeof(sectionHeaders32
)+2*sizeof(Elf32_Sym
)+40+sizeof(entry
)), /* sh_offset */
849 16, /* sh_addralign */
855 static Elf32_Sym symbols32
[2]={
859 { /* data entry point */
863 ELF64_ST_INFO(STB_GLOBAL
, STT_OBJECT
),
865 4 /* st_shndx=index of related section table entry */
869 /* section header string table, with decimal string offsets */
870 static const char sectionStrings
[40]=
873 /* 9 */ ".shstrtab\0"
876 /* 35 */ "\0\0\0\0"; /* contains terminating NUL */
877 /* 40: padded to multiple of 8 bytes */
880 * Use entry[] for the string table which will contain only the
882 * entry[0] must be 0 (NUL)
883 * The entry point name can be up to 38 characters long (sizeof(entry)-2).
886 /* 16-align .rodata in the .o file, just in case */
887 static const char padding
[16]={ 0 };
891 /* 64-bit Elf file header */
892 static Elf64_Ehdr header64
={
895 ELFMAG0
, ELFMAG1
, ELFMAG2
, ELFMAG3
,
897 U_IS_BIG_ENDIAN
? ELFDATA2MSB
: ELFDATA2LSB
,
898 EV_CURRENT
/* EI_VERSION */
902 EV_CURRENT
, /* e_version */
905 (Elf64_Off
)sizeof(Elf64_Ehdr
), /* e_shoff */
907 (Elf64_Half
)sizeof(Elf64_Ehdr
), /* eh_size */
910 (Elf64_Half
)sizeof(Elf64_Shdr
), /* e_shentsize */
915 /* 64-bit Elf section header table */
916 static Elf64_Shdr sectionHeaders64
[5]={
925 (Elf64_Off
)(sizeof(header64
)+sizeof(sectionHeaders64
)), /* sh_offset */
926 (Elf64_Xword
)(2*sizeof(Elf64_Sym
)), /* sh_size */
927 3, /* sh_link=sect hdr index of .strtab */
928 1, /* sh_info=One greater than the symbol table index of the last
929 * local symbol (with STB_LOCAL). */
930 4, /* sh_addralign */
931 (Elf64_Xword
)(sizeof(Elf64_Sym
)) /* sh_entsize */
938 (Elf64_Off
)(sizeof(header64
)+sizeof(sectionHeaders64
)+2*sizeof(Elf64_Sym
)), /* sh_offset */
942 1, /* sh_addralign */
950 (Elf64_Off
)(sizeof(header64
)+sizeof(sectionHeaders64
)+2*sizeof(Elf64_Sym
)+40), /* sh_offset */
951 (Elf64_Xword
)sizeof(entry
), /* sh_size */
954 1, /* sh_addralign */
960 SHF_ALLOC
, /* sh_flags */
962 (Elf64_Off
)(sizeof(header64
)+sizeof(sectionHeaders64
)+2*sizeof(Elf64_Sym
)+40+sizeof(entry
)), /* sh_offset */
966 16, /* sh_addralign */
972 * 64-bit symbol table
973 * careful: different order of items compared with Elf32_sym!
975 static Elf64_Sym symbols64
[2]={
979 { /* data entry point */
981 ELF64_ST_INFO(STB_GLOBAL
, STT_OBJECT
),
983 4, /* st_shndx=index of related section table entry */
991 /* entry[] have a leading NUL */
994 /* in the common code, count entryLength from after the NUL */
999 #elif U_PLATFORM_HAS_WIN32_API
1001 IMAGE_FILE_HEADER fileHeader
;
1002 IMAGE_SECTION_HEADER sections
[2];
1003 char linkerOptions
[100];
1005 IMAGE_SYMBOL symbols
[1];
1007 DWORD sizeofLongNames
;
1008 char longNames
[100];
1012 * entry sometimes have a leading '_'
1013 * overwritten if entryOffset==0 depending on the target platform
1014 * see check for cpu below
1020 # error "Unknown platform for CAN_GENERATE_OBJECTS."
1023 /* deal with options, files and the entry point name */
1024 getArchitecture(&cpu
, &bits
, &makeBigEndian
, optMatchArch
);
1025 printf("genccode: --match-arch cpu=%hu bits=%hu big-endian=%d\n", cpu
, bits
, makeBigEndian
);
1026 #if U_PLATFORM_HAS_WIN32_API
1027 if(cpu
==IMAGE_FILE_MACHINE_I386
) {
1032 in
=T_FileStream_open(filename
, "rb");
1034 fprintf(stderr
, "genccode: unable to open input file %s\n", filename
);
1035 exit(U_FILE_ACCESS_ERROR
);
1037 size
=T_FileStream_size(in
);
1039 getOutFilename(filename
, destdir
, buffer
, entry
+entryOffset
, newSuffix
, optFilename
);
1040 if (outFilePath
!= NULL
) {
1041 uprv_strcpy(outFilePath
, buffer
);
1044 if(optEntryPoint
!= NULL
) {
1045 uprv_strcpy(entry
+entryOffset
, optEntryPoint
);
1046 uprv_strcat(entry
+entryOffset
, "_dat");
1048 /* turn dashes in the entry name into underscores */
1049 entryLength
=(int32_t)uprv_strlen(entry
+entryLengthOffset
);
1050 for(i
=0; i
<entryLength
; ++i
) {
1051 if(entry
[entryLengthOffset
+i
]=='-') {
1052 entry
[entryLengthOffset
+i
]='_';
1056 /* open the output file */
1057 out
=T_FileStream_open(buffer
, "wb");
1059 fprintf(stderr
, "genccode: unable to open output file %s\n", buffer
);
1060 exit(U_FILE_ACCESS_ERROR
);
1065 header32
.e_ident
[EI_DATA
]= makeBigEndian
? ELFDATA2MSB
: ELFDATA2LSB
;
1066 header32
.e_machine
=cpu
;
1068 /* 16-align .rodata in the .o file, just in case */
1069 paddingSize
=sectionHeaders32
[4].sh_offset
& 0xf;
1070 if(paddingSize
!=0) {
1071 paddingSize
=0x10-paddingSize
;
1072 sectionHeaders32
[4].sh_offset
+=paddingSize
;
1075 sectionHeaders32
[4].sh_size
=(Elf32_Word
)size
;
1077 symbols32
[1].st_size
=(Elf32_Word
)size
;
1079 /* write .o headers */
1080 T_FileStream_write(out
, &header32
, (int32_t)sizeof(header32
));
1081 T_FileStream_write(out
, sectionHeaders32
, (int32_t)sizeof(sectionHeaders32
));
1082 T_FileStream_write(out
, symbols32
, (int32_t)sizeof(symbols32
));
1083 } else /* bits==64 */ {
1085 header64
.e_ident
[EI_DATA
]= makeBigEndian
? ELFDATA2MSB
: ELFDATA2LSB
;
1086 header64
.e_machine
=cpu
;
1088 /* 16-align .rodata in the .o file, just in case */
1089 paddingSize
=sectionHeaders64
[4].sh_offset
& 0xf;
1090 if(paddingSize
!=0) {
1091 paddingSize
=0x10-paddingSize
;
1092 sectionHeaders64
[4].sh_offset
+=paddingSize
;
1095 sectionHeaders64
[4].sh_size
=(Elf64_Xword
)size
;
1097 symbols64
[1].st_size
=(Elf64_Xword
)size
;
1099 /* write .o headers */
1100 T_FileStream_write(out
, &header64
, (int32_t)sizeof(header64
));
1101 T_FileStream_write(out
, sectionHeaders64
, (int32_t)sizeof(sectionHeaders64
));
1102 T_FileStream_write(out
, symbols64
, (int32_t)sizeof(symbols64
));
1106 T_FileStream_write(out
, sectionStrings
, (int32_t)sizeof(sectionStrings
));
1107 T_FileStream_write(out
, entry
, (int32_t)sizeof(entry
));
1108 if(paddingSize
!=0) {
1109 T_FileStream_write(out
, padding
, paddingSize
);
1111 #elif U_PLATFORM_HAS_WIN32_API
1112 /* populate the .obj headers */
1113 uprv_memset(&objHeader
, 0, sizeof(objHeader
));
1114 uprv_memset(&symbols
, 0, sizeof(symbols
));
1115 uprv_memset(&symbolNames
, 0, sizeof(symbolNames
));
1117 /* write the linker export directive */
1118 uprv_strcpy(objHeader
.linkerOptions
, "-export:");
1120 uprv_strcpy(objHeader
.linkerOptions
+length
, entry
);
1121 length
+=entryLength
;
1122 uprv_strcpy(objHeader
.linkerOptions
+length
, ",data ");
1125 /* set the file header */
1126 objHeader
.fileHeader
.Machine
=cpu
;
1127 objHeader
.fileHeader
.NumberOfSections
=2;
1128 objHeader
.fileHeader
.TimeDateStamp
=(DWORD
)time(NULL
);
1129 objHeader
.fileHeader
.PointerToSymbolTable
=IMAGE_SIZEOF_FILE_HEADER
+2*IMAGE_SIZEOF_SECTION_HEADER
+length
+size
; /* start of symbol table */
1130 objHeader
.fileHeader
.NumberOfSymbols
=1;
1132 /* set the section for the linker options */
1133 uprv_strncpy((char *)objHeader
.sections
[0].Name
, ".drectve", 8);
1134 objHeader
.sections
[0].SizeOfRawData
=length
;
1135 objHeader
.sections
[0].PointerToRawData
=IMAGE_SIZEOF_FILE_HEADER
+2*IMAGE_SIZEOF_SECTION_HEADER
;
1136 objHeader
.sections
[0].Characteristics
=IMAGE_SCN_LNK_INFO
|IMAGE_SCN_LNK_REMOVE
|IMAGE_SCN_ALIGN_1BYTES
;
1138 /* set the data section */
1139 uprv_strncpy((char *)objHeader
.sections
[1].Name
, ".rdata", 6);
1140 objHeader
.sections
[1].SizeOfRawData
=size
;
1141 objHeader
.sections
[1].PointerToRawData
=IMAGE_SIZEOF_FILE_HEADER
+2*IMAGE_SIZEOF_SECTION_HEADER
+length
;
1142 objHeader
.sections
[1].Characteristics
=IMAGE_SCN_CNT_INITIALIZED_DATA
|IMAGE_SCN_ALIGN_16BYTES
|IMAGE_SCN_MEM_READ
;
1144 /* set the symbol table */
1145 if(entryLength
<=8) {
1146 uprv_strncpy((char *)symbols
[0].N
.ShortName
, entry
, entryLength
);
1147 symbolNames
.sizeofLongNames
=4;
1149 symbols
[0].N
.Name
.Short
=0;
1150 symbols
[0].N
.Name
.Long
=4;
1151 symbolNames
.sizeofLongNames
=4+entryLength
+1;
1152 uprv_strcpy(symbolNames
.longNames
, entry
);
1154 symbols
[0].SectionNumber
=2;
1155 symbols
[0].StorageClass
=IMAGE_SYM_CLASS_EXTERNAL
;
1157 /* write the file header and the linker options section */
1158 T_FileStream_write(out
, &objHeader
, objHeader
.sections
[1].PointerToRawData
);
1160 # error "Unknown platform for CAN_GENERATE_OBJECTS."
1163 /* copy the data file into section 2 */
1165 length
=T_FileStream_read(in
, buffer
, sizeof(buffer
));
1169 T_FileStream_write(out
, buffer
, (int32_t)length
);
1172 #if U_PLATFORM_HAS_WIN32_API
1173 /* write the symbol table */
1174 T_FileStream_write(out
, symbols
, IMAGE_SIZEOF_SYMBOL
);
1175 T_FileStream_write(out
, &symbolNames
, symbolNames
.sizeofLongNames
);
1178 if(T_FileStream_error(in
)) {
1179 fprintf(stderr
, "genccode: file read error while generating from file %s\n", filename
);
1180 exit(U_FILE_ACCESS_ERROR
);
1183 if(T_FileStream_error(out
)) {
1184 fprintf(stderr
, "genccode: file write error while generating from file %s\n", filename
);
1185 exit(U_FILE_ACCESS_ERROR
);
1188 T_FileStream_close(out
);
1189 T_FileStream_close(in
);