tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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