blob: 1f81bf94a42dde774b7444b7c7974fcca903e044 [file] [log] [blame]
Jungshik Shin87232d82017-05-13 21:10:13 -07001// © 2016 and later: Unicode, Inc. and others.
Jungshik Shin5feb9ad2016-10-21 12:52:48 -07002// License & terms of use: http://www.unicode.org/copyright.html
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00003/******************************************************************************
Jungshik Shin5feb9ad2016-10-21 12:52:48 -07004 * Copyright (C) 2009-2016, International Business Machines
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00005 * 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# ifdef __GNUC__
20# define WINDOWS_WITH_GNUC
21# endif
22#endif
23
24#if U_PLATFORM_IS_LINUX_BASED && U_HAVE_ELF_H
25# define U_ELF
26#endif
27
28#ifdef U_ELF
29# include <elf.h>
30# if defined(ELFCLASS64)
31# define U_ELF64
32# endif
33 /* Old elf.h headers may not have EM_X86_64, or have EM_X8664 instead. */
34# ifndef EM_X86_64
35# define EM_X86_64 62
36# endif
37# define ICU_ENTRY_OFFSET 0
38#endif
39
40#include <stdio.h>
41#include <stdlib.h>
42#include "unicode/putil.h"
43#include "cmemory.h"
44#include "cstring.h"
45#include "filestrm.h"
46#include "toolutil.h"
47#include "unicode/uclean.h"
48#include "uoptions.h"
49#include "pkg_genc.h"
Jungshik Shinb3189662017-11-07 11:18:34 -080050#include "filetools.h"
Frank Tangb8696612019-10-25 14:58:21 -070051#include "charstr.h"
52#include "unicode/errorcode.h"
jshin@chromium.org6f31ac32014-03-26 22:15:14 +000053
54#define MAX_COLUMN ((uint32_t)(0xFFFFFFFFU))
55
56#define HEX_0X 0 /* 0x1234 */
57#define HEX_0H 1 /* 01234h */
58
59/* prototypes --------------------------------------------------------------- */
60static void
Frank Tangb8696612019-10-25 14:58:21 -070061getOutFilename(
62 const char *inFilename,
63 const char *destdir,
64 char *outFilename,
65 int32_t outFilenameCapacity,
66 char *entryName,
67 int32_t entryNameCapacity,
68 const char *newSuffix,
69 const char *optFilename);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +000070
71static uint32_t
72write8(FileStream *out, uint8_t byte, uint32_t column);
73
74static uint32_t
75write32(FileStream *out, uint32_t byte, uint32_t column);
76
77#if U_PLATFORM == U_PF_OS400
78static uint32_t
79write8str(FileStream *out, uint8_t byte, uint32_t column);
80#endif
81/* -------------------------------------------------------------------------- */
82
83/*
84Creating Template Files for New Platforms
85
86Let the cc compiler help you get started.
87Compile this program
88 const unsigned int x[5] = {1, 2, 0xdeadbeef, 0xffffffff, 16};
89with the -S option to produce assembly output.
90
91For example, this will generate array.s:
92gcc -S array.c
93
94This will produce a .s file that may look like this:
95
96 .file "array.c"
97 .version "01.01"
98gcc2_compiled.:
99 .globl x
100 .section .rodata
101 .align 4
102 .type x,@object
103 .size x,20
104x:
105 .long 1
106 .long 2
107 .long -559038737
108 .long -1
109 .long 16
110 .ident "GCC: (GNU) 2.96 20000731 (Red Hat Linux 7.1 2.96-85)"
111
112which gives a starting point that will compile, and can be transformed
113to become the template, generally with some consulting of as docs and
114some experimentation.
115
116If you want ICU to automatically use this assembly, you should
117specify "GENCCODE_ASSEMBLY=-a name" in the specific config/mh-* file,
118where the name is the compiler or platform that you used in this
119assemblyHeader data structure.
120*/
121static const struct AssemblyType {
122 const char *name;
123 const char *header;
124 const char *beginLine;
125 const char *footer;
126 int8_t hexType; /* HEX_0X or HEX_0h */
127} assemblyHeader[] = {
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800128 /* For gcc assemblers, the meaning of .align changes depending on the */
129 /* hardware, so we use .balign 16 which always means 16 bytes. */
130 /* https://sourceware.org/binutils/docs/as/Pseudo-Ops.html */
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000131 {"gcc",
132 ".globl %s\n"
133 "\t.section .note.GNU-stack,\"\",%%progbits\n"
Frank Tangf2223962020-04-27 18:25:29 -0700134 "#ifdef __CET__\n"
135 "# include <cet.h>\n"
136 "#endif\n"
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000137 "\t.section .rodata\n"
Jungshik Shin (jungshik at google)5580ad62015-01-12 13:00:44 -0800138 "\t.balign 16\n"
Jungshik Shin (jungshik at google)5580ad62015-01-12 13:00:44 -0800139 "#ifdef U_HIDE_DATA_SYMBOL\n"
140 "\t.hidden %s\n"
141 "#endif\n"
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000142 "\t.type %s,%%object\n"
143 "%s:\n\n",
144
Jungshik Shin5feb9ad2016-10-21 12:52:48 -0700145 ".long ",".size %s, .-%s\n",HEX_0X
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000146 },
147 {"gcc-darwin",
148 /*"\t.section __TEXT,__text,regular,pure_instructions\n"
149 "\t.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32\n"*/
150 ".globl _%s\n"
Jungshik Shin (jungshik at google)5580ad62015-01-12 13:00:44 -0800151 "#ifdef U_HIDE_DATA_SYMBOL\n"
152 "\t.private_extern _%s\n"
153 "#endif\n"
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000154 "\t.data\n"
155 "\t.const\n"
156 "\t.balign 16\n"
157 "_%s:\n\n",
158
159 ".long ","",HEX_0X
160 },
161 {"gcc-cygwin",
162 ".globl _%s\n"
163 "\t.section .rodata\n"
164 "\t.balign 16\n"
165 "_%s:\n\n",
166
167 ".long ","",HEX_0X
168 },
169 {"gcc-mingw64",
170 ".globl %s\n"
171 "\t.section .rodata\n"
172 "\t.balign 16\n"
173 "%s:\n\n",
174
175 ".long ","",HEX_0X
176 },
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800177/* 16 bytes alignment. */
178/* http://docs.oracle.com/cd/E19641-01/802-1947/802-1947.pdf */
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000179 {"sun",
180 "\t.section \".rodata\"\n"
181 "\t.align 16\n"
182 ".globl %s\n"
183 "%s:\n",
184
185 ".word ","",HEX_0X
186 },
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800187/* 16 bytes alignment for sun-x86. */
188/* http://docs.oracle.com/cd/E19963-01/html/821-1608/eoiyg.html */
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000189 {"sun-x86",
190 "Drodata.rodata:\n"
191 "\t.type Drodata.rodata,@object\n"
192 "\t.size Drodata.rodata,0\n"
193 "\t.globl %s\n"
194 "\t.align 16\n"
195 "%s:\n",
196
197 ".4byte ","",HEX_0X
198 },
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800199/* 1<<4 bit alignment for aix. */
200/* http://pic.dhe.ibm.com/infocenter/aix/v6r1/index.jsp?topic=%2Fcom.ibm.aix.aixassem%2Fdoc%2Falangref%2Fidalangref_csect_pseudoop.htm */
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000201 {"xlc",
202 ".globl %s{RO}\n"
203 "\t.toc\n"
204 "%s:\n"
205 "\t.csect %s{RO}, 4\n",
206
207 ".long ","",HEX_0X
208 },
209 {"aCC-ia64",
210 "\t.file \"%s.s\"\n"
211 "\t.type %s,@object\n"
212 "\t.global %s\n"
213 "\t.secalias .abe$0.rodata, \".rodata\"\n"
214 "\t.section .abe$0.rodata = \"a\", \"progbits\"\n"
215 "\t.align 16\n"
216 "%s::\t",
217
218 "data4 ","",HEX_0X
219 },
220 {"aCC-parisc",
221 "\t.SPACE $TEXT$\n"
222 "\t.SUBSPA $LIT$\n"
223 "%s\n"
224 "\t.EXPORT %s\n"
225 "\t.ALIGN 16\n",
226
227 ".WORD ","",HEX_0X
228 },
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800229/* align 16 bytes */
230/* http://msdn.microsoft.com/en-us/library/dwa9fwef.aspx */
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000231 { "masm",
232 "\tTITLE %s\n"
233 "; generated by genccode\n"
234 ".386\n"
235 ".model flat\n"
236 "\tPUBLIC _%s\n"
237 "ICUDATA_%s\tSEGMENT READONLY PARA PUBLIC FLAT 'DATA'\n"
238 "\tALIGN 16\n"
239 "_%s\tLABEL DWORD\n",
240 "\tDWORD ","\nICUDATA_%s\tENDS\n\tEND\n",HEX_0H
241 }
242};
243
244static int32_t assemblyHeaderIndex = -1;
245static int32_t hexType = HEX_0X;
246
247U_CAPI UBool U_EXPORT2
248checkAssemblyHeaderName(const char* optAssembly) {
249 int32_t idx;
250 assemblyHeaderIndex = -1;
Jungshik Shin5feb9ad2016-10-21 12:52:48 -0700251 for (idx = 0; idx < UPRV_LENGTHOF(assemblyHeader); idx++) {
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000252 if (uprv_strcmp(optAssembly, assemblyHeader[idx].name) == 0) {
253 assemblyHeaderIndex = idx;
254 hexType = assemblyHeader[idx].hexType; /* set the hex type */
Frank Tang1f164ee2022-11-08 12:31:27 -0800255 return true;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000256 }
257 }
258
Frank Tang1f164ee2022-11-08 12:31:27 -0800259 return false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000260}
261
262
263U_CAPI void U_EXPORT2
264printAssemblyHeadersToStdErr(void) {
265 int32_t idx;
266 fprintf(stderr, "%s", assemblyHeader[0].name);
Jungshik Shin5feb9ad2016-10-21 12:52:48 -0700267 for (idx = 1; idx < UPRV_LENGTHOF(assemblyHeader); idx++) {
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000268 fprintf(stderr, ", %s", assemblyHeader[idx].name);
269 }
270 fprintf(stderr,
271 ")\n");
272}
273
274U_CAPI void U_EXPORT2
Frank Tangb8696612019-10-25 14:58:21 -0700275writeAssemblyCode(
276 const char *filename,
277 const char *destdir,
278 const char *optEntryPoint,
279 const char *optFilename,
280 char *outFilePath,
281 size_t outFilePathCapacity) {
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000282 uint32_t column = MAX_COLUMN;
Frank Tangb8696612019-10-25 14:58:21 -0700283 char entry[96];
284 union {
285 uint32_t uint32s[1024];
286 char chars[4096];
287 } buffer;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000288 FileStream *in, *out;
Frank Tangb8696612019-10-25 14:58:21 -0700289 size_t i, length, count;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000290
291 in=T_FileStream_open(filename, "rb");
292 if(in==NULL) {
293 fprintf(stderr, "genccode: unable to open input file %s\n", filename);
294 exit(U_FILE_ACCESS_ERROR);
295 }
296
Frank Tangb8696612019-10-25 14:58:21 -0700297 getOutFilename(
298 filename,
299 destdir,
300 buffer.chars,
301 sizeof(buffer.chars),
302 entry,
303 sizeof(entry),
304 ".S",
305 optFilename);
306 out=T_FileStream_open(buffer.chars, "w");
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000307 if(out==NULL) {
Frank Tangb8696612019-10-25 14:58:21 -0700308 fprintf(stderr, "genccode: unable to open output file %s\n", buffer.chars);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000309 exit(U_FILE_ACCESS_ERROR);
310 }
311
312 if (outFilePath != NULL) {
Frank Tangb8696612019-10-25 14:58:21 -0700313 if (uprv_strlen(buffer.chars) >= outFilePathCapacity) {
314 fprintf(stderr, "genccode: filename too long\n");
315 exit(U_ILLEGAL_ARGUMENT_ERROR);
316 }
317 uprv_strcpy(outFilePath, buffer.chars);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000318 }
319
Jungshik Shin87232d82017-05-13 21:10:13 -0700320#if defined (WINDOWS_WITH_GNUC) && U_PLATFORM != U_PF_CYGWIN
Jungshik Shinb3189662017-11-07 11:18:34 -0800321 /* Need to fix the file separator character when using MinGW. */
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000322 swapFileSepChar(outFilePath, U_FILE_SEP_CHAR, '/');
323#endif
324
325 if(optEntryPoint != NULL) {
326 uprv_strcpy(entry, optEntryPoint);
327 uprv_strcat(entry, "_dat");
328 }
329
330 /* turn dashes or dots in the entry name into underscores */
331 length=uprv_strlen(entry);
332 for(i=0; i<length; ++i) {
333 if(entry[i]=='-' || entry[i]=='.') {
334 entry[i]='_';
335 }
336 }
337
Frank Tangb8696612019-10-25 14:58:21 -0700338 count = snprintf(
339 buffer.chars, sizeof(buffer.chars),
340 assemblyHeader[assemblyHeaderIndex].header,
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000341 entry, entry, entry, entry,
342 entry, entry, entry, entry);
Frank Tangb8696612019-10-25 14:58:21 -0700343 if (count >= sizeof(buffer.chars)) {
344 fprintf(stderr, "genccode: entry name too long (long filename?)\n");
345 exit(U_ILLEGAL_ARGUMENT_ERROR);
346 }
347 T_FileStream_writeLine(out, buffer.chars);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000348 T_FileStream_writeLine(out, assemblyHeader[assemblyHeaderIndex].beginLine);
349
350 for(;;) {
Frank Tangb8696612019-10-25 14:58:21 -0700351 memset(buffer.uint32s, 0, sizeof(buffer.uint32s));
352 length=T_FileStream_read(in, buffer.uint32s, sizeof(buffer.uint32s));
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000353 if(length==0) {
354 break;
355 }
Frank Tangb8696612019-10-25 14:58:21 -0700356 for(i=0; i<(length/sizeof(buffer.uint32s[0])); i++) {
357 // TODO: What if the last read sees length not as a multiple of 4?
358 column = write32(out, buffer.uint32s[i], column);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000359 }
360 }
361
362 T_FileStream_writeLine(out, "\n");
363
Frank Tangb8696612019-10-25 14:58:21 -0700364 count = snprintf(
365 buffer.chars, sizeof(buffer.chars),
366 assemblyHeader[assemblyHeaderIndex].footer,
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000367 entry, entry, entry, entry,
368 entry, entry, entry, entry);
Frank Tangb8696612019-10-25 14:58:21 -0700369 if (count >= sizeof(buffer.chars)) {
370 fprintf(stderr, "genccode: entry name too long (long filename?)\n");
371 exit(U_ILLEGAL_ARGUMENT_ERROR);
372 }
373 T_FileStream_writeLine(out, buffer.chars);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000374
375 if(T_FileStream_error(in)) {
376 fprintf(stderr, "genccode: file read error while generating from file %s\n", filename);
377 exit(U_FILE_ACCESS_ERROR);
378 }
379
380 if(T_FileStream_error(out)) {
381 fprintf(stderr, "genccode: file write error while generating from file %s\n", filename);
382 exit(U_FILE_ACCESS_ERROR);
383 }
384
385 T_FileStream_close(out);
386 T_FileStream_close(in);
387}
388
389U_CAPI void U_EXPORT2
Frank Tangb8696612019-10-25 14:58:21 -0700390writeCCode(
391 const char *filename,
392 const char *destdir,
393 const char *optName,
394 const char *optFilename,
395 char *outFilePath,
396 size_t outFilePathCapacity) {
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000397 uint32_t column = MAX_COLUMN;
Frank Tangb8696612019-10-25 14:58:21 -0700398 char buffer[4096], entry[96];
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000399 FileStream *in, *out;
Frank Tangb8696612019-10-25 14:58:21 -0700400 size_t i, length, count;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000401
402 in=T_FileStream_open(filename, "rb");
403 if(in==NULL) {
404 fprintf(stderr, "genccode: unable to open input file %s\n", filename);
405 exit(U_FILE_ACCESS_ERROR);
406 }
407
408 if(optName != NULL) { /* prepend 'icudt28_' */
Frank Tangb8696612019-10-25 14:58:21 -0700409 // +2 includes the _ and the NUL
410 if (uprv_strlen(optName) + 2 > sizeof(entry)) {
411 fprintf(stderr, "genccode: entry name too long (long filename?)\n");
412 exit(U_ILLEGAL_ARGUMENT_ERROR);
413 }
414 strcpy(entry, optName);
415 strcat(entry, "_");
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000416 } else {
Frank Tangb8696612019-10-25 14:58:21 -0700417 entry[0] = 0;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000418 }
419
Frank Tangb8696612019-10-25 14:58:21 -0700420 getOutFilename(
421 filename,
422 destdir,
423 buffer,
Frank Tangf2223962020-04-27 18:25:29 -0700424 static_cast<int32_t>(sizeof(buffer)),
Frank Tangb8696612019-10-25 14:58:21 -0700425 entry + uprv_strlen(entry),
Frank Tangf2223962020-04-27 18:25:29 -0700426 static_cast<int32_t>(sizeof(entry) - uprv_strlen(entry)),
Frank Tangb8696612019-10-25 14:58:21 -0700427 ".c",
428 optFilename);
429
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000430 if (outFilePath != NULL) {
Frank Tangb8696612019-10-25 14:58:21 -0700431 if (uprv_strlen(buffer) >= outFilePathCapacity) {
432 fprintf(stderr, "genccode: filename too long\n");
433 exit(U_ILLEGAL_ARGUMENT_ERROR);
434 }
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000435 uprv_strcpy(outFilePath, buffer);
436 }
Frank Tangb8696612019-10-25 14:58:21 -0700437
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000438 out=T_FileStream_open(buffer, "w");
439 if(out==NULL) {
440 fprintf(stderr, "genccode: unable to open output file %s\n", buffer);
441 exit(U_FILE_ACCESS_ERROR);
442 }
443
444 /* turn dashes or dots in the entry name into underscores */
445 length=uprv_strlen(entry);
446 for(i=0; i<length; ++i) {
447 if(entry[i]=='-' || entry[i]=='.') {
448 entry[i]='_';
449 }
450 }
451
452#if U_PLATFORM == U_PF_OS400
453 /*
454 TODO: Fix this once the compiler implements this feature. Keep in sync with udatamem.c
455
456 This is here because this platform can't currently put
457 const data into the read-only pages of an object or
458 shared library (service program). Only strings are allowed in read-only
459 pages, so we use char * strings to store the data.
460
461 In order to prevent the beginning of the data from ever matching the
462 magic numbers we must still use the initial double.
463 [grhoten 4/24/2003]
464 */
Frank Tangb8696612019-10-25 14:58:21 -0700465 count = snprintf(buffer, sizeof(buffer),
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000466 "#ifndef IN_GENERATED_CCODE\n"
467 "#define IN_GENERATED_CCODE\n"
468 "#define U_DISABLE_RENAMING 1\n"
469 "#include \"unicode/umachine.h\"\n"
470 "#endif\n"
471 "U_CDECL_BEGIN\n"
472 "const struct {\n"
473 " double bogus;\n"
474 " const char *bytes; \n"
475 "} %s={ 0.0, \n",
476 entry);
Frank Tangb8696612019-10-25 14:58:21 -0700477 if (count >= sizeof(buffer)) {
478 fprintf(stderr, "genccode: entry name too long (long filename?)\n");
479 exit(U_ILLEGAL_ARGUMENT_ERROR);
480 }
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000481 T_FileStream_writeLine(out, buffer);
482
483 for(;;) {
484 length=T_FileStream_read(in, buffer, sizeof(buffer));
485 if(length==0) {
486 break;
487 }
488 for(i=0; i<length; ++i) {
489 column = write8str(out, (uint8_t)buffer[i], column);
490 }
491 }
492
493 T_FileStream_writeLine(out, "\"\n};\nU_CDECL_END\n");
494#else
495 /* Function renaming shouldn't be done in data */
Frank Tangb8696612019-10-25 14:58:21 -0700496 count = snprintf(buffer, sizeof(buffer),
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000497 "#ifndef IN_GENERATED_CCODE\n"
498 "#define IN_GENERATED_CCODE\n"
499 "#define U_DISABLE_RENAMING 1\n"
500 "#include \"unicode/umachine.h\"\n"
501 "#endif\n"
502 "U_CDECL_BEGIN\n"
503 "const struct {\n"
504 " double bogus;\n"
505 " uint8_t bytes[%ld]; \n"
506 "} %s={ 0.0, {\n",
507 (long)T_FileStream_size(in), entry);
Frank Tangb8696612019-10-25 14:58:21 -0700508 if (count >= sizeof(buffer)) {
509 fprintf(stderr, "genccode: entry name too long (long filename?)\n");
510 exit(U_ILLEGAL_ARGUMENT_ERROR);
511 }
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000512 T_FileStream_writeLine(out, buffer);
513
514 for(;;) {
515 length=T_FileStream_read(in, buffer, sizeof(buffer));
516 if(length==0) {
517 break;
518 }
519 for(i=0; i<length; ++i) {
520 column = write8(out, (uint8_t)buffer[i], column);
521 }
522 }
523
524 T_FileStream_writeLine(out, "\n}\n};\nU_CDECL_END\n");
525#endif
526
527 if(T_FileStream_error(in)) {
528 fprintf(stderr, "genccode: file read error while generating from file %s\n", filename);
529 exit(U_FILE_ACCESS_ERROR);
530 }
531
532 if(T_FileStream_error(out)) {
533 fprintf(stderr, "genccode: file write error while generating from file %s\n", filename);
534 exit(U_FILE_ACCESS_ERROR);
535 }
536
537 T_FileStream_close(out);
538 T_FileStream_close(in);
539}
540
541static uint32_t
542write32(FileStream *out, uint32_t bitField, uint32_t column) {
543 int32_t i;
544 char bitFieldStr[64]; /* This is more bits than needed for a 32-bit number */
545 char *s = bitFieldStr;
546 uint8_t *ptrIdx = (uint8_t *)&bitField;
547 static const char hexToStr[16] = {
548 '0','1','2','3',
549 '4','5','6','7',
550 '8','9','A','B',
551 'C','D','E','F'
552 };
553
554 /* write the value, possibly with comma and newline */
555 if(column==MAX_COLUMN) {
556 /* first byte */
557 column=1;
558 } else if(column<32) {
559 *(s++)=',';
560 ++column;
561 } else {
562 *(s++)='\n';
563 uprv_strcpy(s, assemblyHeader[assemblyHeaderIndex].beginLine);
564 s+=uprv_strlen(s);
565 column=1;
566 }
567
568 if (bitField < 10) {
569 /* It's a small number. Don't waste the space for 0x */
570 *(s++)=hexToStr[bitField];
571 }
572 else {
573 int seenNonZero = 0; /* This is used to remove leading zeros */
574
575 if(hexType==HEX_0X) {
576 *(s++)='0';
577 *(s++)='x';
578 } else if(hexType==HEX_0H) {
579 *(s++)='0';
580 }
581
582 /* This creates a 32-bit field */
583#if U_IS_BIG_ENDIAN
584 for (i = 0; i < sizeof(uint32_t); i++)
585#else
586 for (i = sizeof(uint32_t)-1; i >= 0 ; i--)
587#endif
588 {
589 uint8_t value = ptrIdx[i];
590 if (value || seenNonZero) {
591 *(s++)=hexToStr[value>>4];
592 *(s++)=hexToStr[value&0xF];
593 seenNonZero = 1;
594 }
595 }
596 if(hexType==HEX_0H) {
597 *(s++)='h';
598 }
599 }
600
601 *(s++)=0;
602 T_FileStream_writeLine(out, bitFieldStr);
603 return column;
604}
605
606static uint32_t
607write8(FileStream *out, uint8_t byte, uint32_t column) {
608 char s[4];
609 int i=0;
610
611 /* convert the byte value to a string */
612 if(byte>=100) {
613 s[i++]=(char)('0'+byte/100);
614 byte%=100;
615 }
616 if(i>0 || byte>=10) {
617 s[i++]=(char)('0'+byte/10);
618 byte%=10;
619 }
620 s[i++]=(char)('0'+byte);
621 s[i]=0;
622
623 /* write the value, possibly with comma and newline */
624 if(column==MAX_COLUMN) {
625 /* first byte */
626 column=1;
627 } else if(column<16) {
628 T_FileStream_writeLine(out, ",");
629 ++column;
630 } else {
631 T_FileStream_writeLine(out, ",\n");
632 column=1;
633 }
634 T_FileStream_writeLine(out, s);
635 return column;
636}
637
638#if U_PLATFORM == U_PF_OS400
639static uint32_t
640write8str(FileStream *out, uint8_t byte, uint32_t column) {
641 char s[8];
642
643 if (byte > 7)
644 sprintf(s, "\\x%X", byte);
645 else
646 sprintf(s, "\\%X", byte);
647
648 /* write the value, possibly with comma and newline */
649 if(column==MAX_COLUMN) {
650 /* first byte */
651 column=1;
652 T_FileStream_writeLine(out, "\"");
653 } else if(column<24) {
654 ++column;
655 } else {
656 T_FileStream_writeLine(out, "\"\n\"");
657 column=1;
658 }
659 T_FileStream_writeLine(out, s);
660 return column;
661}
662#endif
663
664static void
Frank Tangb8696612019-10-25 14:58:21 -0700665getOutFilename(
666 const char *inFilename,
667 const char *destdir,
668 char *outFilename,
669 int32_t outFilenameCapacity,
670 char *entryName,
671 int32_t entryNameCapacity,
672 const char *newSuffix,
673 const char *optFilename) {
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000674 const char *basename=findBasename(inFilename), *suffix=uprv_strrchr(basename, '.');
675
Frank Tangb8696612019-10-25 14:58:21 -0700676 icu::CharString outFilenameBuilder;
677 icu::CharString entryNameBuilder;
678 icu::ErrorCode status;
679
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000680 /* copy path */
681 if(destdir!=NULL && *destdir!=0) {
Frank Tangb8696612019-10-25 14:58:21 -0700682 outFilenameBuilder.append(destdir, status);
683 outFilenameBuilder.ensureEndsWithFileSeparator(status);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000684 } else {
Frank Tangf2223962020-04-27 18:25:29 -0700685 outFilenameBuilder.append(inFilename, static_cast<int32_t>(basename - inFilename), status);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000686 }
Frank Tangb8696612019-10-25 14:58:21 -0700687 inFilename=basename;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000688
689 if(suffix==NULL) {
690 /* the filename does not have a suffix */
Frank Tangb8696612019-10-25 14:58:21 -0700691 entryNameBuilder.append(inFilename, status);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000692 if(optFilename != NULL) {
Frank Tangb8696612019-10-25 14:58:21 -0700693 outFilenameBuilder.append(optFilename, status);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000694 } else {
Frank Tangb8696612019-10-25 14:58:21 -0700695 outFilenameBuilder.append(inFilename, status);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000696 }
Frank Tangb8696612019-10-25 14:58:21 -0700697 outFilenameBuilder.append(newSuffix, status);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000698 } else {
Frank Tangb8696612019-10-25 14:58:21 -0700699 int32_t saveOutFilenameLength = outFilenameBuilder.length();
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000700 /* copy basename */
701 while(inFilename<suffix) {
Frank Tangb8696612019-10-25 14:58:21 -0700702 // iSeries cannot have '-' in the .o objects.
703 char c = (*inFilename=='-') ? '_' : *inFilename;
704 outFilenameBuilder.append(c, status);
705 entryNameBuilder.append(c, status);
706 inFilename++;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000707 }
708
709 /* replace '.' by '_' */
Frank Tangb8696612019-10-25 14:58:21 -0700710 outFilenameBuilder.append('_', status);
711 entryNameBuilder.append('_', status);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000712 ++inFilename;
713
714 /* copy suffix */
Frank Tangb8696612019-10-25 14:58:21 -0700715 outFilenameBuilder.append(inFilename, status);
716 entryNameBuilder.append(inFilename, status);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000717
718 if(optFilename != NULL) {
Frank Tangb8696612019-10-25 14:58:21 -0700719 outFilenameBuilder.truncate(saveOutFilenameLength);
720 outFilenameBuilder.append(optFilename, status);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000721 }
Frank Tangb8696612019-10-25 14:58:21 -0700722 // add ".c"
723 outFilenameBuilder.append(newSuffix, status);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000724 }
Frank Tangb8696612019-10-25 14:58:21 -0700725
726 if (status.isFailure()) {
727 fprintf(stderr, "genccode: error building filename or entrypoint\n");
728 exit(status.get());
729 }
730
731 if (outFilenameBuilder.length() >= outFilenameCapacity) {
732 fprintf(stderr, "genccode: output filename too long\n");
733 exit(U_ILLEGAL_ARGUMENT_ERROR);
734 }
735
736 if (entryNameBuilder.length() >= entryNameCapacity) {
737 fprintf(stderr, "genccode: entry name too long (long filename?)\n");
738 exit(U_ILLEGAL_ARGUMENT_ERROR);
739 }
740
Frank Tangf90543d2020-10-30 19:02:04 -0700741 outFilenameBuilder.extract(outFilename, outFilenameCapacity, status);
742 entryNameBuilder.extract(entryName, entryNameCapacity, status);
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000743}
744
745#ifdef CAN_GENERATE_OBJECTS
746static void
747getArchitecture(uint16_t *pCPU, uint16_t *pBits, UBool *pIsBigEndian, const char *optMatchArch) {
748 union {
749 char bytes[2048];
750#ifdef U_ELF
751 Elf32_Ehdr header32;
752 /* Elf32_Ehdr and ELF64_Ehdr are identical for the necessary fields. */
753#elif U_PLATFORM_HAS_WIN32_API
754 IMAGE_FILE_HEADER header;
755#endif
756 } buffer;
757
758 const char *filename;
759 FileStream *in;
760 int32_t length;
761
762#ifdef U_ELF
763
764#elif U_PLATFORM_HAS_WIN32_API
765 const IMAGE_FILE_HEADER *pHeader;
766#else
767# error "Unknown platform for CAN_GENERATE_OBJECTS."
768#endif
769
770 if(optMatchArch != NULL) {
771 filename=optMatchArch;
772 } else {
773 /* set defaults */
774#ifdef U_ELF
775 /* set EM_386 because elf.h does not provide better defaults */
776 *pCPU=EM_386;
777 *pBits=32;
778 *pIsBigEndian=(UBool)(U_IS_BIG_ENDIAN ? ELFDATA2MSB : ELFDATA2LSB);
779#elif U_PLATFORM_HAS_WIN32_API
Frank Tang69c72a62019-04-03 21:41:21 -0700780 // Windows always runs in little-endian mode.
Frank Tang1f164ee2022-11-08 12:31:27 -0800781 *pIsBigEndian = false;
Frank Tang69c72a62019-04-03 21:41:21 -0700782
783 // Note: The various _M_<arch> macros are predefined by the MSVC compiler based
784 // on the target compilation architecture.
785 // https://docs.microsoft.com/cpp/preprocessor/predefined-macros
786
787 // link.exe will link an IMAGE_FILE_MACHINE_UNKNOWN data-only .obj file
788 // no matter what architecture it is targeting (though other values are
789 // required to match). Unfortunately, the variable name decoration/mangling
790 // is slightly different on x86, which means we can't use the UNKNOWN type
791 // for all architectures though.
792# if defined(_M_IX86)
793 *pCPU = IMAGE_FILE_MACHINE_I386;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000794# else
Frank Tang69c72a62019-04-03 21:41:21 -0700795 *pCPU = IMAGE_FILE_MACHINE_UNKNOWN;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000796# endif
Frank Tang69c72a62019-04-03 21:41:21 -0700797# if defined(_M_IA64) || defined(_M_AMD64) || defined (_M_ARM64)
798 *pBits = 64; // Doesn't seem to be used for anything interesting though?
799# elif defined(_M_IX86) || defined(_M_ARM)
800 *pBits = 32;
801# else
802# error "Unknown platform for CAN_GENERATE_OBJECTS."
803# endif
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000804#else
805# error "Unknown platform for CAN_GENERATE_OBJECTS."
806#endif
807 return;
808 }
809
810 in=T_FileStream_open(filename, "rb");
811 if(in==NULL) {
812 fprintf(stderr, "genccode: unable to open match-arch file %s\n", filename);
813 exit(U_FILE_ACCESS_ERROR);
814 }
815 length=T_FileStream_read(in, buffer.bytes, sizeof(buffer.bytes));
816
817#ifdef U_ELF
Jungshik Shin87232d82017-05-13 21:10:13 -0700818 if(length<(int32_t)sizeof(Elf32_Ehdr)) {
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000819 fprintf(stderr, "genccode: match-arch file %s is too short\n", filename);
820 exit(U_UNSUPPORTED_ERROR);
821 }
822 if(
823 buffer.header32.e_ident[0]!=ELFMAG0 ||
824 buffer.header32.e_ident[1]!=ELFMAG1 ||
825 buffer.header32.e_ident[2]!=ELFMAG2 ||
826 buffer.header32.e_ident[3]!=ELFMAG3 ||
827 buffer.header32.e_ident[EI_CLASS]<ELFCLASS32 || buffer.header32.e_ident[EI_CLASS]>ELFCLASS64
828 ) {
829 fprintf(stderr, "genccode: match-arch file %s is not an ELF object file, or not supported\n", filename);
830 exit(U_UNSUPPORTED_ERROR);
831 }
832
833 *pBits= buffer.header32.e_ident[EI_CLASS]==ELFCLASS32 ? 32 : 64; /* only 32 or 64: see check above */
834#ifdef U_ELF64
835 if(*pBits!=32 && *pBits!=64) {
836 fprintf(stderr, "genccode: currently only supports 32-bit and 64-bit ELF format\n");
837 exit(U_UNSUPPORTED_ERROR);
838 }
839#else
840 if(*pBits!=32) {
841 fprintf(stderr, "genccode: built with elf.h missing 64-bit definitions\n");
842 exit(U_UNSUPPORTED_ERROR);
843 }
844#endif
845
846 *pIsBigEndian=(UBool)(buffer.header32.e_ident[EI_DATA]==ELFDATA2MSB);
847 if(*pIsBigEndian!=U_IS_BIG_ENDIAN) {
848 fprintf(stderr, "genccode: currently only same-endianness ELF formats are supported\n");
849 exit(U_UNSUPPORTED_ERROR);
850 }
851 /* TODO: Support byte swapping */
852
853 *pCPU=buffer.header32.e_machine;
854#elif U_PLATFORM_HAS_WIN32_API
855 if(length<sizeof(IMAGE_FILE_HEADER)) {
856 fprintf(stderr, "genccode: match-arch file %s is too short\n", filename);
857 exit(U_UNSUPPORTED_ERROR);
858 }
859 /* TODO: Use buffer.header. Keep aliasing legal. */
860 pHeader=(const IMAGE_FILE_HEADER *)buffer.bytes;
861 *pCPU=pHeader->Machine;
862 /*
863 * The number of bits is implicit with the Machine value.
864 * *pBits is ignored in the calling code, so this need not be precise.
865 */
866 *pBits= *pCPU==IMAGE_FILE_MACHINE_I386 ? 32 : 64;
867 /* Windows always runs on little-endian CPUs. */
Frank Tang1f164ee2022-11-08 12:31:27 -0800868 *pIsBigEndian=false;
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000869#else
870# error "Unknown platform for CAN_GENERATE_OBJECTS."
871#endif
872
873 T_FileStream_close(in);
874}
875
876U_CAPI void U_EXPORT2
Frank Tangb8696612019-10-25 14:58:21 -0700877writeObjectCode(
878 const char *filename,
879 const char *destdir,
880 const char *optEntryPoint,
881 const char *optMatchArch,
882 const char *optFilename,
883 char *outFilePath,
Frank Tangf2223962020-04-27 18:25:29 -0700884 size_t outFilePathCapacity,
885 UBool optWinDllExport) {
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000886 /* common variables */
Jungshik Shin (jungshik at google)0f8746a2015-01-08 15:46:45 -0800887 char buffer[4096], entry[96]={ 0 };
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000888 FileStream *in, *out;
889 const char *newSuffix;
890 int32_t i, entryLength, length, size, entryOffset=0, entryLengthOffset=0;
891
892 uint16_t cpu, bits;
893 UBool makeBigEndian;
894
Frank Tangf2223962020-04-27 18:25:29 -0700895 (void)optWinDllExport; /* unused except Windows */
896
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000897 /* platform-specific variables and initialization code */
898#ifdef U_ELF
899 /* 32-bit Elf file header */
900 static Elf32_Ehdr header32={
901 {
902 /* e_ident[] */
903 ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3,
904 ELFCLASS32,
905 U_IS_BIG_ENDIAN ? ELFDATA2MSB : ELFDATA2LSB,
906 EV_CURRENT /* EI_VERSION */
907 },
908 ET_REL,
909 EM_386,
910 EV_CURRENT, /* e_version */
911 0, /* e_entry */
912 0, /* e_phoff */
913 (Elf32_Off)sizeof(Elf32_Ehdr), /* e_shoff */
914 0, /* e_flags */
915 (Elf32_Half)sizeof(Elf32_Ehdr), /* eh_size */
916 0, /* e_phentsize */
917 0, /* e_phnum */
918 (Elf32_Half)sizeof(Elf32_Shdr), /* e_shentsize */
919 5, /* e_shnum */
920 2 /* e_shstrndx */
921 };
922
923 /* 32-bit Elf section header table */
924 static Elf32_Shdr sectionHeaders32[5]={
925 { /* SHN_UNDEF */
Jungshik Shin87232d82017-05-13 21:10:13 -0700926 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000927 },
928 { /* .symtab */
929 1, /* sh_name */
930 SHT_SYMTAB,
931 0, /* sh_flags */
932 0, /* sh_addr */
933 (Elf32_Off)(sizeof(header32)+sizeof(sectionHeaders32)), /* sh_offset */
934 (Elf32_Word)(2*sizeof(Elf32_Sym)), /* sh_size */
935 3, /* sh_link=sect hdr index of .strtab */
936 1, /* sh_info=One greater than the symbol table index of the last
937 * local symbol (with STB_LOCAL). */
938 4, /* sh_addralign */
939 (Elf32_Word)(sizeof(Elf32_Sym)) /* sh_entsize */
940 },
941 { /* .shstrtab */
942 9, /* sh_name */
943 SHT_STRTAB,
944 0, /* sh_flags */
945 0, /* sh_addr */
946 (Elf32_Off)(sizeof(header32)+sizeof(sectionHeaders32)+2*sizeof(Elf32_Sym)), /* sh_offset */
947 40, /* sh_size */
948 0, /* sh_link */
949 0, /* sh_info */
950 1, /* sh_addralign */
951 0 /* sh_entsize */
952 },
953 { /* .strtab */
954 19, /* sh_name */
955 SHT_STRTAB,
956 0, /* sh_flags */
957 0, /* sh_addr */
958 (Elf32_Off)(sizeof(header32)+sizeof(sectionHeaders32)+2*sizeof(Elf32_Sym)+40), /* sh_offset */
959 (Elf32_Word)sizeof(entry), /* sh_size */
960 0, /* sh_link */
961 0, /* sh_info */
962 1, /* sh_addralign */
963 0 /* sh_entsize */
964 },
965 { /* .rodata */
966 27, /* sh_name */
967 SHT_PROGBITS,
968 SHF_ALLOC, /* sh_flags */
969 0, /* sh_addr */
970 (Elf32_Off)(sizeof(header32)+sizeof(sectionHeaders32)+2*sizeof(Elf32_Sym)+40+sizeof(entry)), /* sh_offset */
971 0, /* sh_size */
972 0, /* sh_link */
973 0, /* sh_info */
974 16, /* sh_addralign */
975 0 /* sh_entsize */
976 }
977 };
978
979 /* symbol table */
980 static Elf32_Sym symbols32[2]={
981 { /* STN_UNDEF */
Jungshik Shin87232d82017-05-13 21:10:13 -0700982 0, 0, 0, 0, 0, 0
jshin@chromium.org6f31ac32014-03-26 22:15:14 +0000983 },
984 { /* data entry point */
985 1, /* st_name */
986 0, /* st_value */
987 0, /* st_size */
988 ELF64_ST_INFO(STB_GLOBAL, STT_OBJECT),
989 0, /* st_other */
990 4 /* st_shndx=index of related section table entry */
991 }
992 };
993
994 /* section header string table, with decimal string offsets */
995 static const char sectionStrings[40]=
996 /* 0 */ "\0"
997 /* 1 */ ".symtab\0"
998 /* 9 */ ".shstrtab\0"
999 /* 19 */ ".strtab\0"
1000 /* 27 */ ".rodata\0"
1001 /* 35 */ "\0\0\0\0"; /* contains terminating NUL */
1002 /* 40: padded to multiple of 8 bytes */
1003
1004 /*
1005 * Use entry[] for the string table which will contain only the
1006 * entry point name.
1007 * entry[0] must be 0 (NUL)
1008 * The entry point name can be up to 38 characters long (sizeof(entry)-2).
1009 */
1010
1011 /* 16-align .rodata in the .o file, just in case */
1012 static const char padding[16]={ 0 };
1013 int32_t paddingSize;
1014
1015#ifdef U_ELF64
1016 /* 64-bit Elf file header */
1017 static Elf64_Ehdr header64={
1018 {
1019 /* e_ident[] */
1020 ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3,
1021 ELFCLASS64,
1022 U_IS_BIG_ENDIAN ? ELFDATA2MSB : ELFDATA2LSB,
1023 EV_CURRENT /* EI_VERSION */
1024 },
1025 ET_REL,
1026 EM_X86_64,
1027 EV_CURRENT, /* e_version */
1028 0, /* e_entry */
1029 0, /* e_phoff */
1030 (Elf64_Off)sizeof(Elf64_Ehdr), /* e_shoff */
1031 0, /* e_flags */
1032 (Elf64_Half)sizeof(Elf64_Ehdr), /* eh_size */
1033 0, /* e_phentsize */
1034 0, /* e_phnum */
1035 (Elf64_Half)sizeof(Elf64_Shdr), /* e_shentsize */
1036 5, /* e_shnum */
1037 2 /* e_shstrndx */
1038 };
1039
1040 /* 64-bit Elf section header table */
1041 static Elf64_Shdr sectionHeaders64[5]={
1042 { /* SHN_UNDEF */
Jungshik Shin87232d82017-05-13 21:10:13 -07001043 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001044 },
1045 { /* .symtab */
1046 1, /* sh_name */
1047 SHT_SYMTAB,
1048 0, /* sh_flags */
1049 0, /* sh_addr */
1050 (Elf64_Off)(sizeof(header64)+sizeof(sectionHeaders64)), /* sh_offset */
1051 (Elf64_Xword)(2*sizeof(Elf64_Sym)), /* sh_size */
1052 3, /* sh_link=sect hdr index of .strtab */
1053 1, /* sh_info=One greater than the symbol table index of the last
1054 * local symbol (with STB_LOCAL). */
1055 4, /* sh_addralign */
1056 (Elf64_Xword)(sizeof(Elf64_Sym)) /* sh_entsize */
1057 },
1058 { /* .shstrtab */
1059 9, /* sh_name */
1060 SHT_STRTAB,
1061 0, /* sh_flags */
1062 0, /* sh_addr */
1063 (Elf64_Off)(sizeof(header64)+sizeof(sectionHeaders64)+2*sizeof(Elf64_Sym)), /* sh_offset */
1064 40, /* sh_size */
1065 0, /* sh_link */
1066 0, /* sh_info */
1067 1, /* sh_addralign */
1068 0 /* sh_entsize */
1069 },
1070 { /* .strtab */
1071 19, /* sh_name */
1072 SHT_STRTAB,
1073 0, /* sh_flags */
1074 0, /* sh_addr */
1075 (Elf64_Off)(sizeof(header64)+sizeof(sectionHeaders64)+2*sizeof(Elf64_Sym)+40), /* sh_offset */
1076 (Elf64_Xword)sizeof(entry), /* sh_size */
1077 0, /* sh_link */
1078 0, /* sh_info */
1079 1, /* sh_addralign */
1080 0 /* sh_entsize */
1081 },
1082 { /* .rodata */
1083 27, /* sh_name */
1084 SHT_PROGBITS,
1085 SHF_ALLOC, /* sh_flags */
1086 0, /* sh_addr */
1087 (Elf64_Off)(sizeof(header64)+sizeof(sectionHeaders64)+2*sizeof(Elf64_Sym)+40+sizeof(entry)), /* sh_offset */
1088 0, /* sh_size */
1089 0, /* sh_link */
1090 0, /* sh_info */
1091 16, /* sh_addralign */
1092 0 /* sh_entsize */
1093 }
1094 };
1095
1096 /*
1097 * 64-bit symbol table
1098 * careful: different order of items compared with Elf32_sym!
1099 */
1100 static Elf64_Sym symbols64[2]={
1101 { /* STN_UNDEF */
Jungshik Shin87232d82017-05-13 21:10:13 -07001102 0, 0, 0, 0, 0, 0
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001103 },
1104 { /* data entry point */
1105 1, /* st_name */
1106 ELF64_ST_INFO(STB_GLOBAL, STT_OBJECT),
1107 0, /* st_other */
1108 4, /* st_shndx=index of related section table entry */
1109 0, /* st_value */
1110 0 /* st_size */
1111 }
1112 };
1113
1114#endif /* U_ELF64 */
1115
1116 /* entry[] have a leading NUL */
1117 entryOffset=1;
1118
1119 /* in the common code, count entryLength from after the NUL */
1120 entryLengthOffset=1;
1121
1122 newSuffix=".o";
1123
1124#elif U_PLATFORM_HAS_WIN32_API
1125 struct {
1126 IMAGE_FILE_HEADER fileHeader;
1127 IMAGE_SECTION_HEADER sections[2];
1128 char linkerOptions[100];
1129 } objHeader;
1130 IMAGE_SYMBOL symbols[1];
1131 struct {
1132 DWORD sizeofLongNames;
1133 char longNames[100];
1134 } symbolNames;
1135
1136 /*
1137 * entry sometimes have a leading '_'
1138 * overwritten if entryOffset==0 depending on the target platform
1139 * see check for cpu below
1140 */
1141 entry[0]='_';
1142
1143 newSuffix=".obj";
1144#else
1145# error "Unknown platform for CAN_GENERATE_OBJECTS."
1146#endif
1147
1148 /* deal with options, files and the entry point name */
1149 getArchitecture(&cpu, &bits, &makeBigEndian, optMatchArch);
Jungshik Shin87232d82017-05-13 21:10:13 -07001150 if (optMatchArch)
1151 {
1152 printf("genccode: --match-arch cpu=%hu bits=%hu big-endian=%d\n", cpu, bits, makeBigEndian);
1153 }
1154 else
1155 {
1156 printf("genccode: using architecture cpu=%hu bits=%hu big-endian=%d\n", cpu, bits, makeBigEndian);
1157 }
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001158#if U_PLATFORM_HAS_WIN32_API
1159 if(cpu==IMAGE_FILE_MACHINE_I386) {
1160 entryOffset=1;
1161 }
1162#endif
1163
1164 in=T_FileStream_open(filename, "rb");
1165 if(in==NULL) {
1166 fprintf(stderr, "genccode: unable to open input file %s\n", filename);
1167 exit(U_FILE_ACCESS_ERROR);
1168 }
1169 size=T_FileStream_size(in);
1170
Frank Tangb8696612019-10-25 14:58:21 -07001171 getOutFilename(
1172 filename,
1173 destdir,
1174 buffer,
1175 sizeof(buffer),
1176 entry + entryOffset,
1177 sizeof(entry) - entryOffset,
1178 newSuffix,
1179 optFilename);
1180
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001181 if (outFilePath != NULL) {
Frank Tangb8696612019-10-25 14:58:21 -07001182 if (uprv_strlen(buffer) >= outFilePathCapacity) {
1183 fprintf(stderr, "genccode: filename too long\n");
1184 exit(U_ILLEGAL_ARGUMENT_ERROR);
1185 }
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001186 uprv_strcpy(outFilePath, buffer);
1187 }
1188
1189 if(optEntryPoint != NULL) {
1190 uprv_strcpy(entry+entryOffset, optEntryPoint);
1191 uprv_strcat(entry+entryOffset, "_dat");
1192 }
1193 /* turn dashes in the entry name into underscores */
1194 entryLength=(int32_t)uprv_strlen(entry+entryLengthOffset);
1195 for(i=0; i<entryLength; ++i) {
1196 if(entry[entryLengthOffset+i]=='-') {
1197 entry[entryLengthOffset+i]='_';
1198 }
1199 }
1200
1201 /* open the output file */
1202 out=T_FileStream_open(buffer, "wb");
1203 if(out==NULL) {
1204 fprintf(stderr, "genccode: unable to open output file %s\n", buffer);
1205 exit(U_FILE_ACCESS_ERROR);
1206 }
1207
1208#ifdef U_ELF
1209 if(bits==32) {
1210 header32.e_ident[EI_DATA]= makeBigEndian ? ELFDATA2MSB : ELFDATA2LSB;
1211 header32.e_machine=cpu;
1212
1213 /* 16-align .rodata in the .o file, just in case */
1214 paddingSize=sectionHeaders32[4].sh_offset & 0xf;
1215 if(paddingSize!=0) {
1216 paddingSize=0x10-paddingSize;
1217 sectionHeaders32[4].sh_offset+=paddingSize;
1218 }
1219
1220 sectionHeaders32[4].sh_size=(Elf32_Word)size;
1221
1222 symbols32[1].st_size=(Elf32_Word)size;
1223
1224 /* write .o headers */
1225 T_FileStream_write(out, &header32, (int32_t)sizeof(header32));
1226 T_FileStream_write(out, sectionHeaders32, (int32_t)sizeof(sectionHeaders32));
1227 T_FileStream_write(out, symbols32, (int32_t)sizeof(symbols32));
1228 } else /* bits==64 */ {
1229#ifdef U_ELF64
1230 header64.e_ident[EI_DATA]= makeBigEndian ? ELFDATA2MSB : ELFDATA2LSB;
1231 header64.e_machine=cpu;
1232
1233 /* 16-align .rodata in the .o file, just in case */
1234 paddingSize=sectionHeaders64[4].sh_offset & 0xf;
1235 if(paddingSize!=0) {
1236 paddingSize=0x10-paddingSize;
1237 sectionHeaders64[4].sh_offset+=paddingSize;
1238 }
1239
1240 sectionHeaders64[4].sh_size=(Elf64_Xword)size;
1241
1242 symbols64[1].st_size=(Elf64_Xword)size;
1243
1244 /* write .o headers */
1245 T_FileStream_write(out, &header64, (int32_t)sizeof(header64));
1246 T_FileStream_write(out, sectionHeaders64, (int32_t)sizeof(sectionHeaders64));
1247 T_FileStream_write(out, symbols64, (int32_t)sizeof(symbols64));
1248#endif
1249 }
1250
1251 T_FileStream_write(out, sectionStrings, (int32_t)sizeof(sectionStrings));
1252 T_FileStream_write(out, entry, (int32_t)sizeof(entry));
1253 if(paddingSize!=0) {
1254 T_FileStream_write(out, padding, paddingSize);
1255 }
1256#elif U_PLATFORM_HAS_WIN32_API
1257 /* populate the .obj headers */
1258 uprv_memset(&objHeader, 0, sizeof(objHeader));
1259 uprv_memset(&symbols, 0, sizeof(symbols));
1260 uprv_memset(&symbolNames, 0, sizeof(symbolNames));
1261
1262 /* write the linker export directive */
Frank Tangf2223962020-04-27 18:25:29 -07001263 if (optWinDllExport) {
1264 uprv_strcpy(objHeader.linkerOptions, "-export:");
1265 length=8;
1266 uprv_strcpy(objHeader.linkerOptions+length, entry);
1267 length+=entryLength;
1268 uprv_strcpy(objHeader.linkerOptions+length, ",data ");
1269 length+=6;
1270 }
1271 else {
1272 length=0;
1273 }
jshin@chromium.org6f31ac32014-03-26 22:15:14 +00001274
1275 /* set the file header */
1276 objHeader.fileHeader.Machine=cpu;
1277 objHeader.fileHeader.NumberOfSections=2;
1278 objHeader.fileHeader.TimeDateStamp=(DWORD)time(NULL);
1279 objHeader.fileHeader.PointerToSymbolTable=IMAGE_SIZEOF_FILE_HEADER+2*IMAGE_SIZEOF_SECTION_HEADER+length+size; /* start of symbol table */
1280 objHeader.fileHeader.NumberOfSymbols=1;
1281
1282 /* set the section for the linker options */
1283 uprv_strncpy((char *)objHeader.sections[0].Name, ".drectve", 8);
1284 objHeader.sections[0].SizeOfRawData=length;
1285 objHeader.sections[0].PointerToRawData=IMAGE_SIZEOF_FILE_HEADER+2*IMAGE_SIZEOF_SECTION_HEADER;
1286 objHeader.sections[0].Characteristics=IMAGE_SCN_LNK_INFO|IMAGE_SCN_LNK_REMOVE|IMAGE_SCN_ALIGN_1BYTES;
1287
1288 /* set the data section */
1289 uprv_strncpy((char *)objHeader.sections[1].Name, ".rdata", 6);
1290 objHeader.sections[1].SizeOfRawData=size;
1291 objHeader.sections[1].PointerToRawData=IMAGE_SIZEOF_FILE_HEADER+2*IMAGE_SIZEOF_SECTION_HEADER+length;
1292 objHeader.sections[1].Characteristics=IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_ALIGN_16BYTES|IMAGE_SCN_MEM_READ;
1293
1294 /* set the symbol table */
1295 if(entryLength<=8) {
1296 uprv_strncpy((char *)symbols[0].N.ShortName, entry, entryLength);
1297 symbolNames.sizeofLongNames=4;
1298 } else {
1299 symbols[0].N.Name.Short=0;
1300 symbols[0].N.Name.Long=4;
1301 symbolNames.sizeofLongNames=4+entryLength+1;
1302 uprv_strcpy(symbolNames.longNames, entry);
1303 }
1304 symbols[0].SectionNumber=2;
1305 symbols[0].StorageClass=IMAGE_SYM_CLASS_EXTERNAL;
1306
1307 /* write the file header and the linker options section */
1308 T_FileStream_write(out, &objHeader, objHeader.sections[1].PointerToRawData);
1309#else
1310# error "Unknown platform for CAN_GENERATE_OBJECTS."
1311#endif
1312
1313 /* copy the data file into section 2 */
1314 for(;;) {
1315 length=T_FileStream_read(in, buffer, sizeof(buffer));
1316 if(length==0) {
1317 break;
1318 }
1319 T_FileStream_write(out, buffer, (int32_t)length);
1320 }
1321
1322#if U_PLATFORM_HAS_WIN32_API
1323 /* write the symbol table */
1324 T_FileStream_write(out, symbols, IMAGE_SIZEOF_SYMBOL);
1325 T_FileStream_write(out, &symbolNames, symbolNames.sizeofLongNames);
1326#endif
1327
1328 if(T_FileStream_error(in)) {
1329 fprintf(stderr, "genccode: file read error while generating from file %s\n", filename);
1330 exit(U_FILE_ACCESS_ERROR);
1331 }
1332
1333 if(T_FileStream_error(out)) {
1334 fprintf(stderr, "genccode: file write error while generating from file %s\n", filename);
1335 exit(U_FILE_ACCESS_ERROR);
1336 }
1337
1338 T_FileStream_close(out);
1339 T_FileStream_close(in);
1340}
1341#endif