| #!/usr/bin/env python3 | |
| # | |
| # Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | |
| # for details. All rights reserved. Use of this source code is governed by a | |
| # BSD-style license that can be found in the LICENSE file. | |
| # Generates an assembly source file the defines a symbol with the bytes from | |
| # a given file. | |
| import os | |
| import sys | |
| from optparse import OptionParser | |
| def Main(): | |
| parser = OptionParser() | |
| parser.add_option( | |
| "--output", | |
| action="store", | |
| type="string", | |
| help="output assembly file name") | |
| parser.add_option( | |
| "--input", action="store", type="string", help="input binary blob file") | |
| parser.add_option("--symbol_name", action="store", type="string") | |
| parser.add_option("--executable", action="store_true", default=False) | |
| parser.add_option("--target_os", action="store", type="string") | |
| parser.add_option("--size_symbol_name", action="store", type="string") | |
| parser.add_option("--target_arch", action="store", type="string") | |
| parser.add_option("--incbin", action="store_true", default=False) | |
| (options, args) = parser.parse_args() | |
| if not options.output: | |
| sys.stderr.write("--output not specified\n") | |
| parser.print_help() | |
| return -1 | |
| if not options.input: | |
| sys.stderr.write("--input not specified\n") | |
| parser.print_help() | |
| return -1 | |
| if not os.path.isfile(options.input): | |
| sys.stderr.write("input file does not exist: %s\n" % options.input) | |
| parser.print_help() | |
| return -1 | |
| if not options.symbol_name: | |
| sys.stderr.write("--symbol_name not specified\n") | |
| parser.print_help() | |
| return -1 | |
| if not options.target_os: | |
| sys.stderr.write("--target_os not specified\n") | |
| parser.print_help() | |
| return -1 | |
| with open(options.output, "w") as output_file: | |
| if options.target_os in ["mac", "ios", "watchos"]: | |
| if options.executable: | |
| output_file.write(".text\n") | |
| else: | |
| output_file.write(".const\n") | |
| output_file.write(".global _%s\n" % options.symbol_name) | |
| output_file.write(".balign 64\n") | |
| output_file.write("_%s:\n" % options.symbol_name) | |
| elif options.target_os in ["win"]: | |
| output_file.write("ifndef _ML64_X64\n") | |
| output_file.write(".model flat, C\n") | |
| output_file.write("endif\n") | |
| if options.executable: | |
| output_file.write(".code\n") | |
| else: | |
| output_file.write(".const\n") | |
| output_file.write("public %s\n" % options.symbol_name) | |
| output_file.write("%s label byte\n" % options.symbol_name) | |
| elif options.target_os in ["win_gnu"]: | |
| # Cross compilation from Linux to Windows. | |
| if options.executable: | |
| output_file.write(".text\n") | |
| else: | |
| output_file.write(".section .rodata\n") | |
| output_file.write(".global %s\n" % options.symbol_name) | |
| output_file.write(".balign 64\n") | |
| output_file.write("%s:\n" % options.symbol_name) | |
| else: | |
| if options.executable: | |
| output_file.write(".text\n") | |
| output_file.write(".type %s STT_FUNC\n" % options.symbol_name) | |
| else: | |
| output_file.write(".section .rodata\n") | |
| output_file.write(".type %s STT_OBJECT\n" % options.symbol_name) | |
| output_file.write(".global %s\n" % options.symbol_name) | |
| output_file.write(".balign 64\n") | |
| output_file.write("%s:\n" % options.symbol_name) | |
| size = os.path.getsize(options.input) | |
| if options.incbin: | |
| output_file.write(".incbin \"%s\"\n" % options.input) | |
| else: | |
| with open(options.input, "rb") as input_file: | |
| if options.target_os in ["win"]: | |
| for byte in input_file.read(): | |
| output_file.write("byte %d\n" % byte) | |
| else: | |
| for byte in input_file.read(): | |
| output_file.write(".byte %d\n" % byte) | |
| if options.target_os not in ["mac", "ios", "watchos", "win", "win_gnu"]: | |
| output_file.write(".size {0}, .-{0}\n".format(options.symbol_name)) | |
| is64bit = 0 | |
| if options.target_arch: | |
| if options.target_arch in ["arm64", "arm64e", "x64", "riscv64"]: | |
| is64bit = 1 | |
| if options.size_symbol_name: | |
| if not options.target_arch: | |
| sys.stderr.write("--target_arch not specified\n") | |
| parser.print_help() | |
| return -1 | |
| if options.target_os in ["win"]: | |
| output_file.write("public %s\n" % options.size_symbol_name) | |
| output_file.write("%s label byte\n" % options.size_symbol_name) | |
| if (is64bit == 1): | |
| output_file.write("qword %d\n" % size) | |
| else: | |
| output_file.write("dword %d\n" % size) | |
| else: | |
| if options.target_os in ["mac", "ios", "watchos"]: | |
| output_file.write( | |
| ".global _%s\n" % options.size_symbol_name) | |
| output_file.write("_%s:\n" % options.size_symbol_name) | |
| else: | |
| output_file.write(".global %s\n" % options.size_symbol_name) | |
| output_file.write("%s:\n" % options.size_symbol_name) | |
| if (is64bit == 1): | |
| output_file.write(".quad %d\n" % size) | |
| else: | |
| output_file.write(".long %d\n" % size) | |
| if options.target_os in ["win"]: | |
| output_file.write("end\n") | |
| # For text symbols, with -g the assembler will generate the | |
| # DW_TAG_subprogram/label (gcc/clang) for us. | |
| if not options.executable and options.target_arch != None and options.target_os not in [ | |
| "mac", "ios", "watchos", "win", "win_gnu" | |
| ]: | |
| output_file.write(".section .debug_abbrev,\"\"\n") | |
| output_file.write(".uleb128 1 // define abbreviation code\n") | |
| output_file.write(".uleb128 0x11 // DW_TAG_compile_unit\n") | |
| output_file.write(".byte 1 // DW_CHILDREN_yes\n") | |
| output_file.write(".uleb128 0x3 // DW_AT_name\n") | |
| output_file.write(".uleb128 0x8 // DW_FORM_string\n") | |
| output_file.write(".uleb128 0x1b // DW_AT_comp_dir\n") | |
| output_file.write(".uleb128 0x8 // DW_FORM_string\n") | |
| output_file.write(".uleb128 0 // End of attributes\n") | |
| output_file.write(".uleb128 0 // End of attributes\n") | |
| output_file.write(".uleb128 2 // define abbreviation code\n") | |
| output_file.write(".uleb128 0x34 // DW_TAG_variable\n") | |
| output_file.write(".byte 0 // DW_CHILDREN_no\n") | |
| output_file.write(".uleb128 0x3 // DW_AT_name\n") | |
| output_file.write(".uleb128 0x8 // DW_FORM_STRING\n") | |
| output_file.write(".uleb128 0x3f // DW_AT_external\n") | |
| output_file.write(".uleb128 0xc // DW_FORM_flag\n") | |
| output_file.write(".uleb128 0x2 // DW_AT_location\n") | |
| output_file.write(".uleb128 0x18 // DW_FORM_exprloc\n") | |
| output_file.write(".uleb128 0 // End of attributes\n") | |
| output_file.write(".uleb128 0 // End of attributes\n") | |
| output_file.write(".uleb128 0 // End abbreviations\n") | |
| output_file.write(".section .debug_info,\"\"\n") | |
| output_file.write(".4byte .Ldebug_info_end - .Ldebug_info_start\n") | |
| output_file.write(".Ldebug_info_start:\n") | |
| output_file.write(".2byte 5 // DWARF version 5\n") | |
| output_file.write(".byte 1 // DW_UT_compile\n") | |
| output_file.write(".byte %s // address size\n" % | |
| (8 if (is64bit == 1) else 4)) | |
| output_file.write(".4byte .debug_abbrev // debug_abbr_offset\n") | |
| output_file.write(".uleb128 1 // use abbreviation code\n") | |
| output_file.write(".string \"%s\" // DW_AT_name\n" % options.output) | |
| output_file.write(".string \"\" // DW_AT_comp_dir\n") | |
| output_file.write(".uleb128 2 // use abbreviation code\n") | |
| output_file.write(".string \"%s\" // DW_AT_name\n" % | |
| options.symbol_name) | |
| output_file.write(".byte 1 // DW_AT_external\n") | |
| if (is64bit == 1): | |
| output_file.write(".uleb128 9 // DW_AT_location\n") | |
| output_file.write(".uleb128 0x3 // DW_OP_addr \n") | |
| output_file.write(".8byte %s\n" % options.symbol_name) | |
| else: | |
| output_file.write(".uleb128 5 // DW_AT_location\n") | |
| output_file.write(".uleb128 0x3 // DW_OP_addr \n") | |
| output_file.write(".4byte %s\n" % options.symbol_name) | |
| output_file.write(".uleb128 0 // end children\n") | |
| output_file.write(".uleb128 0 // end entries\n") | |
| output_file.write(".Ldebug_info_end:\n") | |
| # Resource blobs are vacuously compatible with all the CFI extensions. | |
| if options.target_os in ["android", "linux", "fuchsia"]: | |
| if options.target_arch == "x64": | |
| output_file.write("// x86 feature: IBT, SHSTK, LAM_U48\n") | |
| output_file.write(".section .note.gnu.property,\"a\"\n") | |
| output_file.write(".align 8\n") | |
| output_file.write(".long 4\n") | |
| output_file.write(".long 16\n") | |
| output_file.write(".long 5 // NT_GNU_PROPERTY_TYPE_0\n") | |
| output_file.write(".string \"GNU\"\n") | |
| output_file.write(".align 8\n") | |
| output_file.write( | |
| ".long 0xC0000002 // GNU_PROPERTY_X86_FEATURE_1_AND\n") | |
| output_file.write(".long 4\n") | |
| output_file.write(".long 7 // IBT | SHSTK | LAM_U48\n") | |
| output_file.write(".align 8\n") | |
| elif options.target_arch == "arm64": | |
| output_file.write("// AArch64 feature: BTI, PAC, GCS\n") | |
| output_file.write(".section .note.gnu.property,\"a\"\n") | |
| output_file.write(".align 3\n") | |
| output_file.write(".word 4\n") | |
| output_file.write(".word 16\n") | |
| output_file.write(".word 5 // NT_GNU_PROPERTY_TYPE_0\n") | |
| output_file.write(".string \"GNU\"\n") | |
| output_file.write( | |
| ".word 0xC0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND\n") | |
| output_file.write(".word 4\n") | |
| output_file.write(".word 7 // BTI | PAC | GCS\n") | |
| output_file.write(".align 3\n") | |
| return 0 | |
| if __name__ == "__main__": | |
| sys.exit(Main()) |