pkg_genc.cpp (44534B)
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 ******************************************************************************* 7 */ 8 #include "unicode/utypes.h" 9 10 #if U_PLATFORM_HAS_WIN32_API 11 # define VC_EXTRALEAN 12 # define WIN32_LEAN_AND_MEAN 13 # define NOUSER 14 # define NOSERVICE 15 # define NOIME 16 # define NOMCX 17 #include <windows.h> 18 #include <time.h> 19 # if defined(__clang__) 20 # include <exception> 21 # endif 22 # ifdef __GNUC__ 23 # define WINDOWS_WITH_GNUC 24 # endif 25 #endif 26 27 #if U_PLATFORM_IS_LINUX_BASED && U_HAVE_ELF_H 28 # define U_ELF 29 #endif 30 31 #ifdef U_ELF 32 # include <elf.h> 33 # if defined(ELFCLASS64) 34 # define U_ELF64 35 # endif 36 /* Old elf.h headers may not have EM_X86_64, or have EM_X8664 instead. */ 37 # ifndef EM_X86_64 38 # define EM_X86_64 62 39 # endif 40 # define ICU_ENTRY_OFFSET 0 41 #endif 42 43 #include <stdio.h> 44 #include <stdlib.h> 45 #include "unicode/putil.h" 46 #include "cmemory.h" 47 #include "cstring.h" 48 #include "filestrm.h" 49 #include "toolutil.h" 50 #include "unicode/uclean.h" 51 #include "uoptions.h" 52 #include "pkg_genc.h" 53 #include "filetools.h" 54 #include "charstr.h" 55 #include "unicode/errorcode.h" 56 57 #define MAX_COLUMN ((uint32_t)(0xFFFFFFFFU)) 58 59 #define HEX_0X 0 /* 0x1234 */ 60 #define HEX_0H 1 /* 01234h */ 61 62 /* prototypes --------------------------------------------------------------- */ 63 static void 64 getOutFilename( 65 const char *inFilename, 66 const char *destdir, 67 char *outFilename, 68 int32_t outFilenameCapacity, 69 char *entryName, 70 int32_t entryNameCapacity, 71 const char *newSuffix, 72 const char *optFilename); 73 74 static uint32_t 75 write8(FileStream *out, uint8_t byte, uint32_t column); 76 77 static uint32_t 78 write32(FileStream *out, uint32_t byte, uint32_t column); 79 80 #if U_PLATFORM == U_PF_OS400 81 static uint32_t 82 write8str(FileStream *out, uint8_t byte, uint32_t column); 83 #endif 84 /* -------------------------------------------------------------------------- */ 85 86 /* 87 Creating Template Files for New Platforms 88 89 Let the cc compiler help you get started. 90 Compile this program 91 const unsigned int x[5] = {1, 2, 0xdeadbeef, 0xffffffff, 16}; 92 with the -S option to produce assembly output. 93 94 For example, this will generate array.s: 95 gcc -S array.c 96 97 This will produce a .s file that may look like this: 98 99 .file "array.c" 100 .version "01.01" 101 gcc2_compiled.: 102 .globl x 103 .section .rodata 104 .align 4 105 .type x,@object 106 .size x,20 107 x: 108 .long 1 109 .long 2 110 .long -559038737 111 .long -1 112 .long 16 113 .ident "GCC: (GNU) 2.96 20000731 (Red Hat Linux 7.1 2.96-85)" 114 115 which gives a starting point that will compile, and can be transformed 116 to become the template, generally with some consulting of as docs and 117 some experimentation. 118 119 If you want ICU to automatically use this assembly, you should 120 specify "GENCCODE_ASSEMBLY=-a name" in the specific config/mh-* file, 121 where the name is the compiler or platform that you used in this 122 assemblyHeader data structure. 123 */ 124 static const struct AssemblyType { 125 const char *name; 126 const char *header; 127 const char *beginLine; 128 const char *footer; 129 int8_t hexType; /* HEX_0X or HEX_0h */ 130 } assemblyHeader[] = { 131 /* For gcc assemblers, the meaning of .align changes depending on the */ 132 /* hardware, so we use .balign 16 which always means 16 bytes. */ 133 /* https://sourceware.org/binutils/docs/as/Pseudo-Ops.html */ 134 {"gcc", 135 ".globl %s\n" 136 "\t.section .note.GNU-stack,\"\",%%progbits\n" 137 "#ifdef __CET__\n" 138 "# include <cet.h>\n" 139 "#endif\n" 140 "\t.section .rodata\n" 141 "\t.balign 16\n" 142 "#ifdef U_HIDE_DATA_SYMBOL\n" 143 "\t.hidden %s\n" 144 "#endif\n" 145 "\t.type %s,%%object\n" 146 "%s:\n\n", 147 148 ".long ",".size %s, .-%s\n",HEX_0X 149 }, 150 {"gcc-darwin", 151 /*"\t.section __TEXT,__text,regular,pure_instructions\n" 152 "\t.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32\n"*/ 153 ".globl _%s\n" 154 "#ifdef U_HIDE_DATA_SYMBOL\n" 155 "\t.private_extern _%s\n" 156 "#endif\n" 157 "\t.data\n" 158 "\t.const\n" 159 "\t.balign 16\n" 160 "_%s:\n\n", 161 162 ".long ","",HEX_0X 163 }, 164 /* macOS PPC should use `.p2align 4` instead `.balign 16` because is 165 * unknown pseudo ops for such legacy system*/ 166 {"gcc-darwin-ppc", 167 /*"\t.section __TEXT,__text,regular,pure_instructions\n" 168 "\t.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32\n"*/ 169 ".globl _%s\n" 170 "#ifdef U_HIDE_DATA_SYMBOL\n" 171 "\t.private_extern _%s\n" 172 "#endif\n" 173 "\t.data\n" 174 "\t.const\n" 175 "\t.p2align 4\n" 176 "_%s:\n\n", 177 178 ".long ","",HEX_0X 179 }, 180 {"gcc-cygwin", 181 ".globl _%s\n" 182 "\t.section .rodata\n" 183 "\t.balign 16\n" 184 "_%s:\n\n", 185 186 ".long ","",HEX_0X 187 }, 188 {"gcc-mingw64", 189 ".globl %s\n" 190 "\t.section .rodata\n" 191 "\t.balign 16\n" 192 "%s:\n\n", 193 194 ".long ","",HEX_0X 195 }, 196 /* 16 bytes alignment. */ 197 /* http://docs.oracle.com/cd/E19641-01/802-1947/802-1947.pdf */ 198 {"sun", 199 "\t.section \".rodata\"\n" 200 "\t.align 16\n" 201 ".globl %s\n" 202 "%s:\n", 203 204 ".word ","",HEX_0X 205 }, 206 /* 16 bytes alignment for sun-x86. */ 207 /* http://docs.oracle.com/cd/E19963-01/html/821-1608/eoiyg.html */ 208 {"sun-x86", 209 "Drodata.rodata:\n" 210 "\t.type Drodata.rodata,@object\n" 211 "\t.size Drodata.rodata,0\n" 212 "\t.globl %s\n" 213 "\t.align 16\n" 214 "%s:\n", 215 216 ".4byte ","",HEX_0X 217 }, 218 /* 1<<4 bit alignment for aix. */ 219 /* http://pic.dhe.ibm.com/infocenter/aix/v6r1/index.jsp?topic=%2Fcom.ibm.aix.aixassem%2Fdoc%2Falangref%2Fidalangref_csect_pseudoop.htm */ 220 {"xlc", 221 ".globl %s{RO}\n" 222 "\t.toc\n" 223 "%s:\n" 224 "\t.csect %s{RO}, 4\n", 225 226 ".long ","",HEX_0X 227 }, 228 {"aCC-ia64", 229 "\t.file \"%s.s\"\n" 230 "\t.type %s,@object\n" 231 "\t.global %s\n" 232 "\t.secalias .abe$0.rodata, \".rodata\"\n" 233 "\t.section .abe$0.rodata = \"a\", \"progbits\"\n" 234 "\t.align 16\n" 235 "%s::\t", 236 237 "data4 ","",HEX_0X 238 }, 239 {"aCC-parisc", 240 "\t.SPACE $TEXT$\n" 241 "\t.SUBSPA $LIT$\n" 242 "%s\n" 243 "\t.EXPORT %s\n" 244 "\t.ALIGN 16\n", 245 246 ".WORD ","",HEX_0X 247 }, 248 /* align 16 bytes */ 249 /* http://msdn.microsoft.com/en-us/library/dwa9fwef.aspx */ 250 {"nasm", 251 "global %s\n" 252 #if defined(_WIN32) 253 "section .rdata align=16\n" 254 #else 255 "section .rodata align=16\n" 256 #endif 257 "%s:\n", 258 " dd ","",HEX_0X 259 }, 260 { "masm", 261 "\tTITLE %s\n" 262 "; generated by genccode\n" 263 ".386\n" 264 ".model flat\n" 265 "\tPUBLIC _%s\n" 266 "ICUDATA_%s\tSEGMENT READONLY PARA PUBLIC FLAT 'DATA'\n" 267 "\tALIGN 16\n" 268 "_%s\tLABEL DWORD\n", 269 "\tDWORD ","\nICUDATA_%s\tENDS\n\tEND\n",HEX_0H 270 }, 271 { "masm64", 272 "\tTITLE %s\n" 273 "; generated by genccode\n" 274 "\tPUBLIC _%s\n" 275 "ICUDATA_%s\tSEGMENT READONLY 'DATA'\n" 276 "\tALIGN 16\n" 277 "_%s\tLABEL DWORD\n", 278 "\tDWORD ","\nICUDATA_%s\tENDS\n\tEND\n",HEX_0H 279 } 280 }; 281 282 static int32_t assemblyHeaderIndex = -1; 283 static int32_t hexType = HEX_0X; 284 285 U_CAPI UBool U_EXPORT2 286 checkAssemblyHeaderName(const char* optAssembly) { 287 int32_t idx; 288 assemblyHeaderIndex = -1; 289 for (idx = 0; idx < UPRV_LENGTHOF(assemblyHeader); idx++) { 290 if (uprv_strcmp(optAssembly, assemblyHeader[idx].name) == 0) { 291 assemblyHeaderIndex = idx; 292 hexType = assemblyHeader[idx].hexType; /* set the hex type */ 293 return true; 294 } 295 } 296 297 return false; 298 } 299 300 U_CAPI UBool U_EXPORT2 301 checkCpuArchitecture(const char* optCpuArch) { 302 return strcmp(optCpuArch, "x64") == 0 || strcmp(optCpuArch, "x86") == 0 || strcmp(optCpuArch, "arm64") == 0 || strcmp(optCpuArch, "arm") == 0 303 || strcmp(optCpuArch, "X64") == 0 || strcmp(optCpuArch, "X86") == 0 || strcmp(optCpuArch, "ARM64") == 0 || strcmp(optCpuArch, "ARM") == 0; 304 } 305 306 307 U_CAPI void U_EXPORT2 308 printAssemblyHeadersToStdErr() { 309 int32_t idx; 310 fprintf(stderr, "%s", assemblyHeader[0].name); 311 for (idx = 1; idx < UPRV_LENGTHOF(assemblyHeader); idx++) { 312 fprintf(stderr, ", %s", assemblyHeader[idx].name); 313 } 314 fprintf(stderr, 315 ")\n"); 316 } 317 318 U_CAPI void U_EXPORT2 319 writeAssemblyCode( 320 const char *filename, 321 const char *destdir, 322 const char *optEntryPoint, 323 const char *optFilename, 324 char *outFilePath, 325 size_t outFilePathCapacity) { 326 uint32_t column = MAX_COLUMN; 327 char entry[96]; 328 union { 329 uint32_t uint32s[1024]; 330 char chars[4096]; 331 } buffer; 332 FileStream *in, *out; 333 size_t i, length, count; 334 335 in=T_FileStream_open(filename, "rb"); 336 if(in==nullptr) { 337 fprintf(stderr, "genccode: unable to open input file %s\n", filename); 338 exit(U_FILE_ACCESS_ERROR); 339 } 340 341 const char* newSuffix = nullptr; 342 343 if (uprv_strcmp(assemblyHeader[assemblyHeaderIndex].name, "masm") == 0) { 344 newSuffix = ".masm"; 345 } 346 else if (uprv_strcmp(assemblyHeader[assemblyHeaderIndex].name, "nasm") == 0) { 347 newSuffix = ".asm"; 348 } else { 349 newSuffix = ".S"; 350 } 351 352 getOutFilename( 353 filename, 354 destdir, 355 buffer.chars, 356 sizeof(buffer.chars), 357 entry, 358 sizeof(entry), 359 newSuffix, 360 optFilename); 361 out=T_FileStream_open(buffer.chars, "w"); 362 if(out==nullptr) { 363 fprintf(stderr, "genccode: unable to open output file %s\n", buffer.chars); 364 exit(U_FILE_ACCESS_ERROR); 365 } 366 367 if (outFilePath != nullptr) { 368 if (uprv_strlen(buffer.chars) >= outFilePathCapacity) { 369 fprintf(stderr, "genccode: filename too long\n"); 370 exit(U_ILLEGAL_ARGUMENT_ERROR); 371 } 372 uprv_strcpy(outFilePath, buffer.chars); 373 #if defined (WINDOWS_WITH_GNUC) && U_PLATFORM != U_PF_CYGWIN 374 /* Need to fix the file separator character when using MinGW. */ 375 swapFileSepChar(outFilePath, U_FILE_SEP_CHAR, '/'); 376 #endif 377 } 378 379 if(optEntryPoint != nullptr) { 380 uprv_strcpy(entry, optEntryPoint); 381 uprv_strcat(entry, "_dat"); 382 } 383 384 /* turn dashes or dots in the entry name into underscores */ 385 length=uprv_strlen(entry); 386 for(i=0; i<length; ++i) { 387 if(entry[i]=='-' || entry[i]=='.') { 388 entry[i]='_'; 389 } 390 } 391 392 count = snprintf( 393 buffer.chars, sizeof(buffer.chars), 394 assemblyHeader[assemblyHeaderIndex].header, 395 entry, entry, entry, entry, 396 entry, entry, entry, entry); 397 if (count >= sizeof(buffer.chars)) { 398 fprintf(stderr, "genccode: entry name too long (long filename?)\n"); 399 exit(U_ILLEGAL_ARGUMENT_ERROR); 400 } 401 T_FileStream_writeLine(out, buffer.chars); 402 T_FileStream_writeLine(out, assemblyHeader[assemblyHeaderIndex].beginLine); 403 404 for(;;) { 405 memset(buffer.uint32s, 0, sizeof(buffer.uint32s)); 406 length=T_FileStream_read(in, buffer.uint32s, sizeof(buffer.uint32s)); 407 if(length==0) { 408 break; 409 } 410 for(i=0; i<(length/sizeof(buffer.uint32s[0])); i++) { 411 // TODO: What if the last read sees length not as a multiple of 4? 412 column = write32(out, buffer.uint32s[i], column); 413 } 414 } 415 416 T_FileStream_writeLine(out, "\n"); 417 418 count = snprintf( 419 buffer.chars, sizeof(buffer.chars), 420 assemblyHeader[assemblyHeaderIndex].footer, 421 entry, entry, entry, entry, 422 entry, entry, entry, entry); 423 if (count >= sizeof(buffer.chars)) { 424 fprintf(stderr, "genccode: entry name too long (long filename?)\n"); 425 exit(U_ILLEGAL_ARGUMENT_ERROR); 426 } 427 T_FileStream_writeLine(out, buffer.chars); 428 429 if(T_FileStream_error(in)) { 430 fprintf(stderr, "genccode: file read error while generating from file %s\n", filename); 431 exit(U_FILE_ACCESS_ERROR); 432 } 433 434 if(T_FileStream_error(out)) { 435 fprintf(stderr, "genccode: file write error while generating from file %s\n", filename); 436 exit(U_FILE_ACCESS_ERROR); 437 } 438 439 T_FileStream_close(out); 440 T_FileStream_close(in); 441 } 442 443 U_CAPI void U_EXPORT2 444 writeCCode( 445 const char *filename, 446 const char *destdir, 447 const char *optEntryPoint, 448 const char *optName, 449 const char *optFilename, 450 char *outFilePath, 451 size_t outFilePathCapacity) { 452 uint32_t column = MAX_COLUMN; 453 char buffer[4096], entry[96]; 454 FileStream *in, *out; 455 size_t i, length, count; 456 457 in=T_FileStream_open(filename, "rb"); 458 if(in==nullptr) { 459 fprintf(stderr, "genccode: unable to open input file %s\n", filename); 460 exit(U_FILE_ACCESS_ERROR); 461 } 462 463 if(optName != nullptr) { /* prepend 'icudt28_' */ 464 // +2 includes the _ and the NUL 465 if (uprv_strlen(optName) + 2 > sizeof(entry)) { 466 fprintf(stderr, "genccode: entry name too long (long filename?)\n"); 467 exit(U_ILLEGAL_ARGUMENT_ERROR); 468 } 469 strcpy(entry, optName); 470 strcat(entry, "_"); 471 } else { 472 entry[0] = 0; 473 } 474 475 getOutFilename( 476 filename, 477 destdir, 478 buffer, 479 static_cast<int32_t>(sizeof(buffer)), 480 entry + uprv_strlen(entry), 481 static_cast<int32_t>(sizeof(entry) - uprv_strlen(entry)), 482 ".c", 483 optFilename); 484 485 if (outFilePath != nullptr) { 486 if (uprv_strlen(buffer) >= outFilePathCapacity) { 487 fprintf(stderr, "genccode: filename too long\n"); 488 exit(U_ILLEGAL_ARGUMENT_ERROR); 489 } 490 uprv_strcpy(outFilePath, buffer); 491 #if defined (WINDOWS_WITH_GNUC) && U_PLATFORM != U_PF_CYGWIN 492 /* Need to fix the file separator character when using MinGW. */ 493 swapFileSepChar(outFilePath, U_FILE_SEP_CHAR, '/'); 494 #endif 495 } 496 497 out=T_FileStream_open(buffer, "w"); 498 if(out==nullptr) { 499 fprintf(stderr, "genccode: unable to open output file %s\n", buffer); 500 exit(U_FILE_ACCESS_ERROR); 501 } 502 503 if(optEntryPoint != nullptr) { 504 uprv_strcpy(entry, optEntryPoint); 505 uprv_strcat(entry, "_dat"); 506 } 507 508 /* turn dashes or dots in the entry name into underscores */ 509 length=uprv_strlen(entry); 510 for(i=0; i<length; ++i) { 511 if(entry[i]=='-' || entry[i]=='.') { 512 entry[i]='_'; 513 } 514 } 515 516 #if U_PLATFORM == U_PF_OS400 517 /* 518 TODO: Fix this once the compiler implements this feature. Keep in sync with udatamem.c 519 520 This is here because this platform can't currently put 521 const data into the read-only pages of an object or 522 shared library (service program). Only strings are allowed in read-only 523 pages, so we use char * strings to store the data. 524 525 In order to prevent the beginning of the data from ever matching the 526 magic numbers we must still use the initial double. 527 [grhoten 4/24/2003] 528 */ 529 count = snprintf(buffer, sizeof(buffer), 530 "#ifndef IN_GENERATED_CCODE\n" 531 "#define IN_GENERATED_CCODE\n" 532 "#define U_DISABLE_RENAMING 1\n" 533 "#include \"unicode/umachine.h\"\n" 534 "#endif\n" 535 "U_CDECL_BEGIN\n" 536 "const struct {\n" 537 " double bogus;\n" 538 " const char *bytes; \n" 539 "} %s={ 0.0, \n", 540 entry); 541 if (count >= sizeof(buffer)) { 542 fprintf(stderr, "genccode: entry name too long (long filename?)\n"); 543 exit(U_ILLEGAL_ARGUMENT_ERROR); 544 } 545 T_FileStream_writeLine(out, buffer); 546 547 for(;;) { 548 length=T_FileStream_read(in, buffer, sizeof(buffer)); 549 if(length==0) { 550 break; 551 } 552 for(i=0; i<length; ++i) { 553 column = write8str(out, (uint8_t)buffer[i], column); 554 } 555 } 556 557 T_FileStream_writeLine(out, "\"\n};\nU_CDECL_END\n"); 558 #else 559 /* Function renaming shouldn't be done in data */ 560 count = snprintf(buffer, sizeof(buffer), 561 "#ifndef IN_GENERATED_CCODE\n" 562 "#define IN_GENERATED_CCODE\n" 563 "#define U_DISABLE_RENAMING 1\n" 564 "#include \"unicode/umachine.h\"\n" 565 "#endif\n" 566 "U_CDECL_BEGIN\n" 567 "const struct {\n" 568 " double bogus;\n" 569 " uint8_t bytes[%ld]; \n" 570 "} %s={ 0.0, {\n", 571 (long)T_FileStream_size(in), entry); 572 if (count >= sizeof(buffer)) { 573 fprintf(stderr, "genccode: entry name too long (long filename?)\n"); 574 exit(U_ILLEGAL_ARGUMENT_ERROR); 575 } 576 T_FileStream_writeLine(out, buffer); 577 578 for(;;) { 579 length=T_FileStream_read(in, buffer, sizeof(buffer)); 580 if(length==0) { 581 break; 582 } 583 for(i=0; i<length; ++i) { 584 column = write8(out, (uint8_t)buffer[i], column); 585 } 586 } 587 588 T_FileStream_writeLine(out, "\n}\n};\nU_CDECL_END\n"); 589 #endif 590 591 if(T_FileStream_error(in)) { 592 fprintf(stderr, "genccode: file read error while generating from file %s\n", filename); 593 exit(U_FILE_ACCESS_ERROR); 594 } 595 596 if(T_FileStream_error(out)) { 597 fprintf(stderr, "genccode: file write error while generating from file %s\n", filename); 598 exit(U_FILE_ACCESS_ERROR); 599 } 600 601 T_FileStream_close(out); 602 T_FileStream_close(in); 603 } 604 605 static uint32_t 606 write32(FileStream *out, uint32_t bitField, uint32_t column) { 607 int32_t i; 608 char bitFieldStr[64]; /* This is more bits than needed for a 32-bit number */ 609 char *s = bitFieldStr; 610 uint8_t* ptrIdx = reinterpret_cast<uint8_t*>(&bitField); 611 static const char hexToStr[16] = { 612 '0','1','2','3', 613 '4','5','6','7', 614 '8','9','A','B', 615 'C','D','E','F' 616 }; 617 618 /* write the value, possibly with comma and newline */ 619 if(column==MAX_COLUMN) { 620 /* first byte */ 621 column=1; 622 } else if(column<32) { 623 *(s++)=','; 624 ++column; 625 } else { 626 *(s++)='\n'; 627 uprv_strcpy(s, assemblyHeader[assemblyHeaderIndex].beginLine); 628 s+=uprv_strlen(s); 629 column=1; 630 } 631 632 if (bitField < 10) { 633 /* It's a small number. Don't waste the space for 0x */ 634 *(s++)=hexToStr[bitField]; 635 } 636 else { 637 int seenNonZero = 0; /* This is used to remove leading zeros */ 638 639 if(hexType==HEX_0X) { 640 *(s++)='0'; 641 *(s++)='x'; 642 } else if(hexType==HEX_0H) { 643 *(s++)='0'; 644 } 645 646 /* This creates a 32-bit field */ 647 #if U_IS_BIG_ENDIAN 648 for (i = 0; i < sizeof(uint32_t); i++) 649 #else 650 for (i = sizeof(uint32_t)-1; i >= 0 ; i--) 651 #endif 652 { 653 uint8_t value = ptrIdx[i]; 654 if (value || seenNonZero) { 655 *(s++)=hexToStr[value>>4]; 656 *(s++)=hexToStr[value&0xF]; 657 seenNonZero = 1; 658 } 659 } 660 if(hexType==HEX_0H) { 661 *(s++)='h'; 662 } 663 } 664 665 *(s++)=0; 666 T_FileStream_writeLine(out, bitFieldStr); 667 return column; 668 } 669 670 static uint32_t 671 write8(FileStream *out, uint8_t byte, uint32_t column) { 672 char s[4]; 673 int i=0; 674 675 /* convert the byte value to a string */ 676 if(byte>=100) { 677 s[i++] = static_cast<char>('0' + byte / 100); 678 byte%=100; 679 } 680 if(i>0 || byte>=10) { 681 s[i++] = static_cast<char>('0' + byte / 10); 682 byte%=10; 683 } 684 s[i++] = static_cast<char>('0' + byte); 685 s[i]=0; 686 687 /* write the value, possibly with comma and newline */ 688 if(column==MAX_COLUMN) { 689 /* first byte */ 690 column=1; 691 } else if(column<16) { 692 T_FileStream_writeLine(out, ","); 693 ++column; 694 } else { 695 T_FileStream_writeLine(out, ",\n"); 696 column=1; 697 } 698 T_FileStream_writeLine(out, s); 699 return column; 700 } 701 702 #if U_PLATFORM == U_PF_OS400 703 static uint32_t 704 write8str(FileStream *out, uint8_t byte, uint32_t column) { 705 char s[8]; 706 707 if (byte > 7) 708 snprintf(s, sizeof(s), "\\x%X", byte); 709 else 710 snprintf(s, sizeof(s), "\\%X", byte); 711 712 /* write the value, possibly with comma and newline */ 713 if(column==MAX_COLUMN) { 714 /* first byte */ 715 column=1; 716 T_FileStream_writeLine(out, "\""); 717 } else if(column<24) { 718 ++column; 719 } else { 720 T_FileStream_writeLine(out, "\"\n\""); 721 column=1; 722 } 723 T_FileStream_writeLine(out, s); 724 return column; 725 } 726 #endif 727 728 static void 729 getOutFilename( 730 const char *inFilename, 731 const char *destdir, 732 char *outFilename, 733 int32_t outFilenameCapacity, 734 char *entryName, 735 int32_t entryNameCapacity, 736 const char *newSuffix, 737 const char *optFilename) { 738 const char *basename=findBasename(inFilename), *suffix=uprv_strrchr(basename, '.'); 739 740 icu::CharString outFilenameBuilder; 741 icu::CharString entryNameBuilder; 742 icu::ErrorCode status; 743 744 /* copy path */ 745 if(destdir!=nullptr && *destdir!=0) { 746 outFilenameBuilder.append(destdir, status); 747 outFilenameBuilder.ensureEndsWithFileSeparator(status); 748 } else { 749 outFilenameBuilder.append(inFilename, static_cast<int32_t>(basename - inFilename), status); 750 } 751 inFilename=basename; 752 753 if(suffix==nullptr) { 754 /* the filename does not have a suffix */ 755 entryNameBuilder.append(inFilename, status); 756 if(optFilename != nullptr) { 757 outFilenameBuilder.append(optFilename, status); 758 } else { 759 outFilenameBuilder.append(inFilename, status); 760 } 761 outFilenameBuilder.append(newSuffix, status); 762 } else { 763 int32_t saveOutFilenameLength = outFilenameBuilder.length(); 764 /* copy basename */ 765 while(inFilename<suffix) { 766 // iSeries cannot have '-' in the .o objects. 767 char c = (*inFilename=='-') ? '_' : *inFilename; 768 outFilenameBuilder.append(c, status); 769 entryNameBuilder.append(c, status); 770 inFilename++; 771 } 772 773 /* replace '.' by '_' */ 774 outFilenameBuilder.append('_', status); 775 entryNameBuilder.append('_', status); 776 ++inFilename; 777 778 /* copy suffix */ 779 outFilenameBuilder.append(inFilename, status); 780 entryNameBuilder.append(inFilename, status); 781 782 if(optFilename != nullptr) { 783 outFilenameBuilder.truncate(saveOutFilenameLength); 784 outFilenameBuilder.append(optFilename, status); 785 } 786 // add ".c" 787 outFilenameBuilder.append(newSuffix, status); 788 } 789 790 if (status.isFailure()) { 791 fprintf(stderr, "genccode: error building filename or entrypoint\n"); 792 exit(status.get()); 793 } 794 795 if (outFilenameBuilder.length() >= outFilenameCapacity) { 796 fprintf(stderr, "genccode: output filename too long\n"); 797 exit(U_ILLEGAL_ARGUMENT_ERROR); 798 } 799 800 if (entryNameBuilder.length() >= entryNameCapacity) { 801 fprintf(stderr, "genccode: entry name too long (long filename?)\n"); 802 exit(U_ILLEGAL_ARGUMENT_ERROR); 803 } 804 805 outFilenameBuilder.extract(outFilename, outFilenameCapacity, status); 806 entryNameBuilder.extract(entryName, entryNameCapacity, status); 807 } 808 809 #ifdef CAN_GENERATE_OBJECTS 810 static void 811 getArchitecture( 812 uint16_t *pCPU, 813 uint16_t *pBits, 814 UBool *pIsBigEndian, 815 const char *optMatchArch, 816 [[maybe_unused]] const char *optCpuArch) { 817 union { 818 char bytes[2048]; 819 #ifdef U_ELF 820 Elf32_Ehdr header32; 821 /* Elf32_Ehdr and ELF64_Ehdr are identical for the necessary fields. */ 822 #elif U_PLATFORM_HAS_WIN32_API 823 IMAGE_FILE_HEADER header; 824 #endif 825 } buffer; 826 827 const char *filename; 828 FileStream *in; 829 int32_t length; 830 831 #ifdef U_ELF 832 833 #elif U_PLATFORM_HAS_WIN32_API 834 const IMAGE_FILE_HEADER *pHeader; 835 #else 836 # error "Unknown platform for CAN_GENERATE_OBJECTS." 837 #endif 838 839 if(optMatchArch != nullptr) { 840 filename=optMatchArch; 841 } else { 842 /* set defaults */ 843 #ifdef U_ELF 844 /* set EM_386 because elf.h does not provide better defaults */ 845 *pCPU=EM_386; 846 *pBits=32; 847 *pIsBigEndian = static_cast<UBool>(U_IS_BIG_ENDIAN ? ELFDATA2MSB : ELFDATA2LSB); 848 #elif U_PLATFORM_HAS_WIN32_API 849 // Windows always runs in little-endian mode. 850 *pIsBigEndian = false; 851 852 // Note: The various _M_<arch> macros are predefined by the MSVC compiler based 853 // on the target compilation architecture. 854 // https://docs.microsoft.com/cpp/preprocessor/predefined-macros 855 856 // link.exe will link an IMAGE_FILE_MACHINE_UNKNOWN data-only .obj file 857 // no matter what architecture it is targeting (though other values are 858 // required to match). Unfortunately, the variable name decoration/mangling 859 // is slightly different on x86, which means we can't use the UNKNOWN type 860 // for all architectures though. 861 # if defined(_M_IX86) 862 *pCPU = IMAGE_FILE_MACHINE_I386; 863 # else 864 // Linker for ClangCL doesn't handle IMAGE_FILE_MACHINE_UNKNOWN the same as 865 // linker for MSVC. Because of this optCpuArch is used to define the CPU 866 // architecture in that case. While _M_AMD64 and _M_ARM64 could be used, 867 // this would potentially be problematic when cross-compiling as this code 868 // would most likely be ran on host machine to generate the .obj file for 869 // the target architecture. 870 # if defined(__clang__) 871 if (!optCpuArch) { 872 fprintf(stderr, "genccode: CPU architecture must be set for Clang-CL\n"); 873 exit(U_ILLEGAL_ARGUMENT_ERROR); 874 } if (strcmp(optCpuArch, "x64") == 0 || strcmp(optCpuArch, "X64") == 0) { 875 *pCPU = IMAGE_FILE_MACHINE_AMD64; 876 } else if (strcmp(optCpuArch, "x86") == 0 || strcmp(optCpuArch, "X86") == 0) { 877 *pCPU = IMAGE_FILE_MACHINE_I386; 878 } else if (strcmp(optCpuArch, "arm64") == 0 || strcmp(optCpuArch, "ARM64") == 0) { 879 *pCPU = IMAGE_FILE_MACHINE_ARM64; 880 } else if (strcmp(optCpuArch, "arm") == 0 || strcmp(optCpuArch, "ARM") == 0) { 881 *pCPU = IMAGE_FILE_MACHINE_ARM; 882 } else { 883 std::terminate(); // Unreachable. 884 } 885 # else 886 *pCPU = IMAGE_FILE_MACHINE_UNKNOWN; 887 # endif 888 # endif 889 # if defined(_M_IA64) || defined(_M_AMD64) || defined (_M_ARM64) 890 *pBits = 64; // Doesn't seem to be used for anything interesting though? 891 # elif defined(_M_IX86) || defined(_M_ARM) 892 *pBits = 32; 893 # else 894 # error "Unknown platform for CAN_GENERATE_OBJECTS." 895 # endif 896 #else 897 # error "Unknown platform for CAN_GENERATE_OBJECTS." 898 #endif 899 return; 900 } 901 902 in=T_FileStream_open(filename, "rb"); 903 if(in==nullptr) { 904 fprintf(stderr, "genccode: unable to open match-arch file %s\n", filename); 905 exit(U_FILE_ACCESS_ERROR); 906 } 907 length=T_FileStream_read(in, buffer.bytes, sizeof(buffer.bytes)); 908 909 #ifdef U_ELF 910 if (length < static_cast<int32_t>(sizeof(Elf32_Ehdr))) { 911 fprintf(stderr, "genccode: match-arch file %s is too short\n", filename); 912 exit(U_UNSUPPORTED_ERROR); 913 } 914 if( 915 buffer.header32.e_ident[0]!=ELFMAG0 || 916 buffer.header32.e_ident[1]!=ELFMAG1 || 917 buffer.header32.e_ident[2]!=ELFMAG2 || 918 buffer.header32.e_ident[3]!=ELFMAG3 || 919 buffer.header32.e_ident[EI_CLASS]<ELFCLASS32 || buffer.header32.e_ident[EI_CLASS]>ELFCLASS64 920 ) { 921 fprintf(stderr, "genccode: match-arch file %s is not an ELF object file, or not supported\n", filename); 922 exit(U_UNSUPPORTED_ERROR); 923 } 924 925 *pBits= buffer.header32.e_ident[EI_CLASS]==ELFCLASS32 ? 32 : 64; /* only 32 or 64: see check above */ 926 #ifdef U_ELF64 927 if(*pBits!=32 && *pBits!=64) { 928 fprintf(stderr, "genccode: currently only supports 32-bit and 64-bit ELF format\n"); 929 exit(U_UNSUPPORTED_ERROR); 930 } 931 #else 932 if(*pBits!=32) { 933 fprintf(stderr, "genccode: built with elf.h missing 64-bit definitions\n"); 934 exit(U_UNSUPPORTED_ERROR); 935 } 936 #endif 937 938 *pIsBigEndian = static_cast<UBool>(buffer.header32.e_ident[EI_DATA] == ELFDATA2MSB); 939 if(*pIsBigEndian!=U_IS_BIG_ENDIAN) { 940 fprintf(stderr, "genccode: currently only same-endianness ELF formats are supported\n"); 941 exit(U_UNSUPPORTED_ERROR); 942 } 943 /* TODO: Support byte swapping */ 944 945 *pCPU=buffer.header32.e_machine; 946 #elif U_PLATFORM_HAS_WIN32_API 947 if(length<sizeof(IMAGE_FILE_HEADER)) { 948 fprintf(stderr, "genccode: match-arch file %s is too short\n", filename); 949 exit(U_UNSUPPORTED_ERROR); 950 } 951 /* TODO: Use buffer.header. Keep aliasing legal. */ 952 pHeader=(const IMAGE_FILE_HEADER *)buffer.bytes; 953 *pCPU=pHeader->Machine; 954 /* 955 * The number of bits is implicit with the Machine value. 956 * *pBits is ignored in the calling code, so this need not be precise. 957 */ 958 *pBits= *pCPU==IMAGE_FILE_MACHINE_I386 ? 32 : 64; 959 /* Windows always runs on little-endian CPUs. */ 960 *pIsBigEndian=false; 961 #else 962 # error "Unknown platform for CAN_GENERATE_OBJECTS." 963 #endif 964 965 T_FileStream_close(in); 966 } 967 968 U_CAPI void U_EXPORT2 969 writeObjectCode( 970 const char *filename, 971 const char *destdir, 972 const char *optEntryPoint, 973 const char *optMatchArch, 974 const char *optCpuArch, 975 const char *optFilename, 976 char *outFilePath, 977 size_t outFilePathCapacity, 978 UBool optWinDllExport) { 979 /* common variables */ 980 char buffer[4096], entry[96]={ 0 }; 981 FileStream *in, *out; 982 const char *newSuffix; 983 int32_t i, entryLength, length, size, entryOffset=0, entryLengthOffset=0; 984 985 uint16_t cpu, bits; 986 UBool makeBigEndian; 987 988 (void)optWinDllExport; /* unused except Windows */ 989 990 /* platform-specific variables and initialization code */ 991 #ifdef U_ELF 992 /* 32-bit Elf file header */ 993 static Elf32_Ehdr header32={ 994 { 995 /* e_ident[] */ 996 ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3, 997 ELFCLASS32, 998 U_IS_BIG_ENDIAN ? ELFDATA2MSB : ELFDATA2LSB, 999 EV_CURRENT /* EI_VERSION */ 1000 }, 1001 ET_REL, 1002 EM_386, 1003 EV_CURRENT, /* e_version */ 1004 0, /* e_entry */ 1005 0, /* e_phoff */ 1006 (Elf32_Off)sizeof(Elf32_Ehdr), /* e_shoff */ 1007 0, /* e_flags */ 1008 (Elf32_Half)sizeof(Elf32_Ehdr), /* eh_size */ 1009 0, /* e_phentsize */ 1010 0, /* e_phnum */ 1011 (Elf32_Half)sizeof(Elf32_Shdr), /* e_shentsize */ 1012 5, /* e_shnum */ 1013 2 /* e_shstrndx */ 1014 }; 1015 1016 /* 32-bit Elf section header table */ 1017 static Elf32_Shdr sectionHeaders32[5]={ 1018 { /* SHN_UNDEF */ 1019 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 1020 }, 1021 { /* .symtab */ 1022 1, /* sh_name */ 1023 SHT_SYMTAB, 1024 0, /* sh_flags */ 1025 0, /* sh_addr */ 1026 (Elf32_Off)(sizeof(header32)+sizeof(sectionHeaders32)), /* sh_offset */ 1027 (Elf32_Word)(2*sizeof(Elf32_Sym)), /* sh_size */ 1028 3, /* sh_link=sect hdr index of .strtab */ 1029 1, /* sh_info=One greater than the symbol table index of the last 1030 * local symbol (with STB_LOCAL). */ 1031 4, /* sh_addralign */ 1032 (Elf32_Word)(sizeof(Elf32_Sym)) /* sh_entsize */ 1033 }, 1034 { /* .shstrtab */ 1035 9, /* sh_name */ 1036 SHT_STRTAB, 1037 0, /* sh_flags */ 1038 0, /* sh_addr */ 1039 (Elf32_Off)(sizeof(header32)+sizeof(sectionHeaders32)+2*sizeof(Elf32_Sym)), /* sh_offset */ 1040 40, /* sh_size */ 1041 0, /* sh_link */ 1042 0, /* sh_info */ 1043 1, /* sh_addralign */ 1044 0 /* sh_entsize */ 1045 }, 1046 { /* .strtab */ 1047 19, /* sh_name */ 1048 SHT_STRTAB, 1049 0, /* sh_flags */ 1050 0, /* sh_addr */ 1051 (Elf32_Off)(sizeof(header32)+sizeof(sectionHeaders32)+2*sizeof(Elf32_Sym)+40), /* sh_offset */ 1052 (Elf32_Word)sizeof(entry), /* sh_size */ 1053 0, /* sh_link */ 1054 0, /* sh_info */ 1055 1, /* sh_addralign */ 1056 0 /* sh_entsize */ 1057 }, 1058 { /* .rodata */ 1059 27, /* sh_name */ 1060 SHT_PROGBITS, 1061 SHF_ALLOC, /* sh_flags */ 1062 0, /* sh_addr */ 1063 (Elf32_Off)(sizeof(header32)+sizeof(sectionHeaders32)+2*sizeof(Elf32_Sym)+40+sizeof(entry)), /* sh_offset */ 1064 0, /* sh_size */ 1065 0, /* sh_link */ 1066 0, /* sh_info */ 1067 16, /* sh_addralign */ 1068 0 /* sh_entsize */ 1069 } 1070 }; 1071 1072 /* symbol table */ 1073 static Elf32_Sym symbols32[2]={ 1074 { /* STN_UNDEF */ 1075 0, 0, 0, 0, 0, 0 1076 }, 1077 { /* data entry point */ 1078 1, /* st_name */ 1079 0, /* st_value */ 1080 0, /* st_size */ 1081 ELF64_ST_INFO(STB_GLOBAL, STT_OBJECT), 1082 0, /* st_other */ 1083 4 /* st_shndx=index of related section table entry */ 1084 } 1085 }; 1086 1087 /* section header string table, with decimal string offsets */ 1088 static const char sectionStrings[40]= 1089 /* 0 */ "\0" 1090 /* 1 */ ".symtab\0" 1091 /* 9 */ ".shstrtab\0" 1092 /* 19 */ ".strtab\0" 1093 /* 27 */ ".rodata\0" 1094 /* 35 */ "\0\0\0\0"; /* contains terminating NUL */ 1095 /* 40: padded to multiple of 8 bytes */ 1096 1097 /* 1098 * Use entry[] for the string table which will contain only the 1099 * entry point name. 1100 * entry[0] must be 0 (NUL) 1101 * The entry point name can be up to 38 characters long (sizeof(entry)-2). 1102 */ 1103 1104 /* 16-align .rodata in the .o file, just in case */ 1105 static const char padding[16]={ 0 }; 1106 int32_t paddingSize; 1107 1108 #ifdef U_ELF64 1109 /* 64-bit Elf file header */ 1110 static Elf64_Ehdr header64={ 1111 { 1112 /* e_ident[] */ 1113 ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3, 1114 ELFCLASS64, 1115 U_IS_BIG_ENDIAN ? ELFDATA2MSB : ELFDATA2LSB, 1116 EV_CURRENT /* EI_VERSION */ 1117 }, 1118 ET_REL, 1119 EM_X86_64, 1120 EV_CURRENT, /* e_version */ 1121 0, /* e_entry */ 1122 0, /* e_phoff */ 1123 (Elf64_Off)sizeof(Elf64_Ehdr), /* e_shoff */ 1124 0, /* e_flags */ 1125 (Elf64_Half)sizeof(Elf64_Ehdr), /* eh_size */ 1126 0, /* e_phentsize */ 1127 0, /* e_phnum */ 1128 (Elf64_Half)sizeof(Elf64_Shdr), /* e_shentsize */ 1129 5, /* e_shnum */ 1130 2 /* e_shstrndx */ 1131 }; 1132 1133 /* 64-bit Elf section header table */ 1134 static Elf64_Shdr sectionHeaders64[5]={ 1135 { /* SHN_UNDEF */ 1136 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 1137 }, 1138 { /* .symtab */ 1139 1, /* sh_name */ 1140 SHT_SYMTAB, 1141 0, /* sh_flags */ 1142 0, /* sh_addr */ 1143 (Elf64_Off)(sizeof(header64)+sizeof(sectionHeaders64)), /* sh_offset */ 1144 (Elf64_Xword)(2*sizeof(Elf64_Sym)), /* sh_size */ 1145 3, /* sh_link=sect hdr index of .strtab */ 1146 1, /* sh_info=One greater than the symbol table index of the last 1147 * local symbol (with STB_LOCAL). */ 1148 4, /* sh_addralign */ 1149 (Elf64_Xword)(sizeof(Elf64_Sym)) /* sh_entsize */ 1150 }, 1151 { /* .shstrtab */ 1152 9, /* sh_name */ 1153 SHT_STRTAB, 1154 0, /* sh_flags */ 1155 0, /* sh_addr */ 1156 (Elf64_Off)(sizeof(header64)+sizeof(sectionHeaders64)+2*sizeof(Elf64_Sym)), /* sh_offset */ 1157 40, /* sh_size */ 1158 0, /* sh_link */ 1159 0, /* sh_info */ 1160 1, /* sh_addralign */ 1161 0 /* sh_entsize */ 1162 }, 1163 { /* .strtab */ 1164 19, /* sh_name */ 1165 SHT_STRTAB, 1166 0, /* sh_flags */ 1167 0, /* sh_addr */ 1168 (Elf64_Off)(sizeof(header64)+sizeof(sectionHeaders64)+2*sizeof(Elf64_Sym)+40), /* sh_offset */ 1169 (Elf64_Xword)sizeof(entry), /* sh_size */ 1170 0, /* sh_link */ 1171 0, /* sh_info */ 1172 1, /* sh_addralign */ 1173 0 /* sh_entsize */ 1174 }, 1175 { /* .rodata */ 1176 27, /* sh_name */ 1177 SHT_PROGBITS, 1178 SHF_ALLOC, /* sh_flags */ 1179 0, /* sh_addr */ 1180 (Elf64_Off)(sizeof(header64)+sizeof(sectionHeaders64)+2*sizeof(Elf64_Sym)+40+sizeof(entry)), /* sh_offset */ 1181 0, /* sh_size */ 1182 0, /* sh_link */ 1183 0, /* sh_info */ 1184 16, /* sh_addralign */ 1185 0 /* sh_entsize */ 1186 } 1187 }; 1188 1189 /* 1190 * 64-bit symbol table 1191 * careful: different order of items compared with Elf32_sym! 1192 */ 1193 static Elf64_Sym symbols64[2]={ 1194 { /* STN_UNDEF */ 1195 0, 0, 0, 0, 0, 0 1196 }, 1197 { /* data entry point */ 1198 1, /* st_name */ 1199 ELF64_ST_INFO(STB_GLOBAL, STT_OBJECT), 1200 0, /* st_other */ 1201 4, /* st_shndx=index of related section table entry */ 1202 0, /* st_value */ 1203 0 /* st_size */ 1204 } 1205 }; 1206 1207 #endif /* U_ELF64 */ 1208 1209 /* entry[] have a leading NUL */ 1210 entryOffset=1; 1211 1212 /* in the common code, count entryLength from after the NUL */ 1213 entryLengthOffset=1; 1214 1215 newSuffix=".o"; 1216 1217 #elif U_PLATFORM_HAS_WIN32_API 1218 struct { 1219 IMAGE_FILE_HEADER fileHeader; 1220 IMAGE_SECTION_HEADER sections[2]; 1221 char linkerOptions[100]; 1222 } objHeader; 1223 IMAGE_SYMBOL symbols[1]; 1224 struct { 1225 DWORD sizeofLongNames; 1226 char longNames[100]; 1227 } symbolNames; 1228 1229 /* 1230 * entry sometimes have a leading '_' 1231 * overwritten if entryOffset==0 depending on the target platform 1232 * see check for cpu below 1233 */ 1234 entry[0]='_'; 1235 1236 newSuffix=".obj"; 1237 #else 1238 # error "Unknown platform for CAN_GENERATE_OBJECTS." 1239 #endif 1240 1241 /* deal with options, files and the entry point name */ 1242 getArchitecture(&cpu, &bits, &makeBigEndian, optMatchArch, optCpuArch); 1243 if (optMatchArch) 1244 { 1245 printf("genccode: --match-arch cpu=%hu bits=%hu big-endian=%d\n", cpu, bits, makeBigEndian); 1246 } 1247 else 1248 { 1249 printf("genccode: using architecture cpu=%hu bits=%hu big-endian=%d\n", cpu, bits, makeBigEndian); 1250 } 1251 #if U_PLATFORM_HAS_WIN32_API 1252 if(cpu==IMAGE_FILE_MACHINE_I386) { 1253 entryOffset=1; 1254 } 1255 #endif 1256 1257 in=T_FileStream_open(filename, "rb"); 1258 if(in==nullptr) { 1259 fprintf(stderr, "genccode: unable to open input file %s\n", filename); 1260 exit(U_FILE_ACCESS_ERROR); 1261 } 1262 size=T_FileStream_size(in); 1263 1264 getOutFilename( 1265 filename, 1266 destdir, 1267 buffer, 1268 sizeof(buffer), 1269 entry + entryOffset, 1270 sizeof(entry) - entryOffset, 1271 newSuffix, 1272 optFilename); 1273 1274 if (outFilePath != nullptr) { 1275 if (uprv_strlen(buffer) >= outFilePathCapacity) { 1276 fprintf(stderr, "genccode: filename too long\n"); 1277 exit(U_ILLEGAL_ARGUMENT_ERROR); 1278 } 1279 uprv_strcpy(outFilePath, buffer); 1280 } 1281 1282 if(optEntryPoint != nullptr) { 1283 uprv_strcpy(entry+entryOffset, optEntryPoint); 1284 uprv_strcat(entry+entryOffset, "_dat"); 1285 } 1286 /* turn dashes in the entry name into underscores */ 1287 entryLength=(int32_t)uprv_strlen(entry+entryLengthOffset); 1288 for(i=0; i<entryLength; ++i) { 1289 if(entry[entryLengthOffset+i]=='-') { 1290 entry[entryLengthOffset+i]='_'; 1291 } 1292 } 1293 1294 /* open the output file */ 1295 out=T_FileStream_open(buffer, "wb"); 1296 if(out==nullptr) { 1297 fprintf(stderr, "genccode: unable to open output file %s\n", buffer); 1298 exit(U_FILE_ACCESS_ERROR); 1299 } 1300 1301 #ifdef U_ELF 1302 if(bits==32) { 1303 header32.e_ident[EI_DATA]= makeBigEndian ? ELFDATA2MSB : ELFDATA2LSB; 1304 header32.e_machine=cpu; 1305 1306 /* 16-align .rodata in the .o file, just in case */ 1307 paddingSize=sectionHeaders32[4].sh_offset & 0xf; 1308 if(paddingSize!=0) { 1309 paddingSize=0x10-paddingSize; 1310 sectionHeaders32[4].sh_offset+=paddingSize; 1311 } 1312 1313 sectionHeaders32[4].sh_size=(Elf32_Word)size; 1314 1315 symbols32[1].st_size=(Elf32_Word)size; 1316 1317 /* write .o headers */ 1318 T_FileStream_write(out, &header32, (int32_t)sizeof(header32)); 1319 T_FileStream_write(out, sectionHeaders32, (int32_t)sizeof(sectionHeaders32)); 1320 T_FileStream_write(out, symbols32, (int32_t)sizeof(symbols32)); 1321 } else /* bits==64 */ { 1322 #ifdef U_ELF64 1323 header64.e_ident[EI_DATA]= makeBigEndian ? ELFDATA2MSB : ELFDATA2LSB; 1324 header64.e_machine=cpu; 1325 1326 /* 16-align .rodata in the .o file, just in case */ 1327 paddingSize=sectionHeaders64[4].sh_offset & 0xf; 1328 if(paddingSize!=0) { 1329 paddingSize=0x10-paddingSize; 1330 sectionHeaders64[4].sh_offset+=paddingSize; 1331 } 1332 1333 sectionHeaders64[4].sh_size=(Elf64_Xword)size; 1334 1335 symbols64[1].st_size=(Elf64_Xword)size; 1336 1337 /* write .o headers */ 1338 T_FileStream_write(out, &header64, (int32_t)sizeof(header64)); 1339 T_FileStream_write(out, sectionHeaders64, (int32_t)sizeof(sectionHeaders64)); 1340 T_FileStream_write(out, symbols64, (int32_t)sizeof(symbols64)); 1341 #endif 1342 } 1343 1344 T_FileStream_write(out, sectionStrings, (int32_t)sizeof(sectionStrings)); 1345 T_FileStream_write(out, entry, (int32_t)sizeof(entry)); 1346 if(paddingSize!=0) { 1347 T_FileStream_write(out, padding, paddingSize); 1348 } 1349 #elif U_PLATFORM_HAS_WIN32_API 1350 /* populate the .obj headers */ 1351 uprv_memset(&objHeader, 0, sizeof(objHeader)); 1352 uprv_memset(&symbols, 0, sizeof(symbols)); 1353 uprv_memset(&symbolNames, 0, sizeof(symbolNames)); 1354 1355 /* write the linker export directive */ 1356 if (optWinDllExport) { 1357 uprv_strcpy(objHeader.linkerOptions, "-export:"); 1358 length=8; 1359 uprv_strcpy(objHeader.linkerOptions+length, entry); 1360 length+=entryLength; 1361 uprv_strcpy(objHeader.linkerOptions+length, ",data "); 1362 length+=6; 1363 } 1364 else { 1365 length=0; 1366 } 1367 1368 /* set the file header */ 1369 objHeader.fileHeader.Machine=cpu; 1370 objHeader.fileHeader.NumberOfSections=2; 1371 objHeader.fileHeader.TimeDateStamp=(DWORD)time(nullptr); 1372 objHeader.fileHeader.PointerToSymbolTable=IMAGE_SIZEOF_FILE_HEADER+2*IMAGE_SIZEOF_SECTION_HEADER+length+size; /* start of symbol table */ 1373 objHeader.fileHeader.NumberOfSymbols=1; 1374 1375 /* set the section for the linker options */ 1376 uprv_strncpy((char *)objHeader.sections[0].Name, ".drectve", 8); 1377 objHeader.sections[0].SizeOfRawData=length; 1378 objHeader.sections[0].PointerToRawData=IMAGE_SIZEOF_FILE_HEADER+2*IMAGE_SIZEOF_SECTION_HEADER; 1379 objHeader.sections[0].Characteristics=IMAGE_SCN_LNK_INFO|IMAGE_SCN_LNK_REMOVE|IMAGE_SCN_ALIGN_1BYTES; 1380 1381 /* set the data section */ 1382 uprv_strncpy((char *)objHeader.sections[1].Name, ".rdata", 6); 1383 objHeader.sections[1].SizeOfRawData=size; 1384 objHeader.sections[1].PointerToRawData=IMAGE_SIZEOF_FILE_HEADER+2*IMAGE_SIZEOF_SECTION_HEADER+length; 1385 objHeader.sections[1].Characteristics=IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_ALIGN_16BYTES|IMAGE_SCN_MEM_READ; 1386 1387 /* set the symbol table */ 1388 if(entryLength<=8) { 1389 uprv_strncpy((char *)symbols[0].N.ShortName, entry, entryLength); 1390 symbolNames.sizeofLongNames=4; 1391 } else { 1392 symbols[0].N.Name.Short=0; 1393 symbols[0].N.Name.Long=4; 1394 symbolNames.sizeofLongNames=4+entryLength+1; 1395 uprv_strcpy(symbolNames.longNames, entry); 1396 } 1397 symbols[0].SectionNumber=2; 1398 symbols[0].StorageClass=IMAGE_SYM_CLASS_EXTERNAL; 1399 1400 /* write the file header and the linker options section */ 1401 T_FileStream_write(out, &objHeader, objHeader.sections[1].PointerToRawData); 1402 #else 1403 # error "Unknown platform for CAN_GENERATE_OBJECTS." 1404 #endif 1405 1406 /* copy the data file into section 2 */ 1407 for(;;) { 1408 length=T_FileStream_read(in, buffer, sizeof(buffer)); 1409 if(length==0) { 1410 break; 1411 } 1412 T_FileStream_write(out, buffer, length); 1413 } 1414 1415 #if U_PLATFORM_HAS_WIN32_API 1416 /* write the symbol table */ 1417 T_FileStream_write(out, symbols, IMAGE_SIZEOF_SYMBOL); 1418 T_FileStream_write(out, &symbolNames, symbolNames.sizeofLongNames); 1419 #endif 1420 1421 if(T_FileStream_error(in)) { 1422 fprintf(stderr, "genccode: file read error while generating from file %s\n", filename); 1423 exit(U_FILE_ACCESS_ERROR); 1424 } 1425 1426 if(T_FileStream_error(out)) { 1427 fprintf(stderr, "genccode: file write error while generating from file %s\n", filename); 1428 exit(U_FILE_ACCESS_ERROR); 1429 } 1430 1431 T_FileStream_close(out); 1432 T_FileStream_close(in); 1433 } 1434 #endif