diff --git a/build.zig b/build.zig index d0d9c8c..5a1d829 100644 --- a/build.zig +++ b/build.zig @@ -1,6 +1,6 @@ const std = @import("std"); -const version: std.SemanticVersion = .{ .major = 2, .minor = 44, .patch = 0 }; +const version: std.SemanticVersion = .{ .major = 2, .minor = 45, .patch = 0 }; pub fn build(b: *std.Build) void { const upstream = b.dependency("binutils", .{}); @@ -14,6 +14,21 @@ pub fn build(b: *std.Build) void { // Plugins have a dependency on the install prefix so they have been disabled by default in this port. const enable_plugins = b.option(bool, "plugins", "Enable plugins") orelse false; + const gnu_cpu = switch (target.result.cpu.arch) { + .x86 => "i386", + else => @tagName(target.result.cpu.arch), + }; + const gnu_vendor = switch (target.result.cpu.arch) { + .x86, .x86_64 => "pc", + else => "unknown", + }; + const gnu_triple = b.fmt("{s}-{s}-{s}-{s}", .{ + gnu_cpu, + gnu_vendor, + @tagName(target.result.os.tag), + @tagName(target.result.abi), + }); + const libsframe_config_header = b.addConfigHeader(.{}, .{ .HAVE_BYTESWAP_H = if (target.result.os.tag == .linux or target.result.os.tag == .wasi) true else null, .HAVE_DECL_BSWAP_16 = target.result.os.tag == .linux or target.result.os.tag == .wasi, @@ -619,7 +634,6 @@ pub fn build(b: *std.Build) void { // "pex-djgpp.c", // "pex-msdos.c", "pex-one.c", - // if (target.result.os.tag == .windows) "pex-win32.c" else "pex-unix.c", "physmem.c", // "putenv.c", // "random.c", @@ -668,7 +682,7 @@ pub fn build(b: *std.Build) void { "vfork.c", // "vfprintf.c", // "vprintf.c", - // "vprintf-support.c", + "vprintf-support.c", // "vsnprintf.c", // "vsprintf.c", // "waitpid.c", @@ -683,6 +697,12 @@ pub fn build(b: *std.Build) void { "xvasprintf.c", }, }); + iberty.root_module.addCSourceFile(.{ + .file = upstream.path(if (target.result.os.tag == .windows) + "libiberty/pex-win32.c" + else + "libiberty/pex-unix.c"), + }); const bfd_header = b.addConfigHeader(.{ .style = .{ .autoconf_at = upstream.path("bfd/bfd-in2.h") }, @@ -699,9 +719,9 @@ pub fn build(b: *std.Build) void { .style = .{ .autoconf_at = upstream.path("bfd/version.h") }, .include_path = "bfdver.h", }, .{ - .bfd_version = 244000000, + .bfd_version = @as(i64, version.major * 100 + version.minor) * 1000000 + version.patch * 10000, .bfd_version_package = "\"(GNU Binutils) \"", - .bfd_version_string = "\"2.44.0.20250215\"", + .bfd_version_string = b.fmt("\"{f}\"", .{version}), .report_bugs_to = "\"\"", }); @@ -889,27 +909,19 @@ pub fn build(b: *std.Build) void { else => std.debug.panic("TODO '{s}-{s}'", .{ @tagName(target.result.cpu.arch), @tagName(target.result.os.tag) }), }; - const find_replace_exe = b.addExecutable(.{ - .name = "find-replace", - .root_module = b.createModule(.{ - .root_source_file = b.path("find_replace.zig"), - .target = b.graph.host, - }), - }); - const generated_header_files: []const std.Build.LazyPath = &.{ - runFindReplace(b, find_replace_exe, upstream.path("bfd/elfxx-target.h"), "elf32-target.h", "NN", "32"), - runFindReplace(b, find_replace_exe, upstream.path("bfd/elfxx-target.h"), "elf64-target.h", "NN", "64"), - runFindReplace(b, find_replace_exe, upstream.path("bfd/elfxx-aarch64.h"), "elf32-aarch64.h", "NN", "32"), - runFindReplace(b, find_replace_exe, upstream.path("bfd/elfxx-aarch64.h"), "elf64-aarch64.h", "NN", "64"), - runFindReplace(b, find_replace_exe, upstream.path("bfd/elfxx-ia64.h"), "elf32-ia64.h", "NN", "32"), - runFindReplace(b, find_replace_exe, upstream.path("bfd/elfxx-ia64.h"), "elf64-ia64.h", "NN", "64"), - runFindReplace(b, find_replace_exe, upstream.path("bfd/elfxx-kvx.h"), "elf32-kvx.h", "NN", "32"), - runFindReplace(b, find_replace_exe, upstream.path("bfd/elfxx-kvx.h"), "elf64-kvx.h", "NN", "64"), - runFindReplace(b, find_replace_exe, upstream.path("bfd/elfxx-loongarch.h"), "elf32-loongarch.h", "NN", "32"), - runFindReplace(b, find_replace_exe, upstream.path("bfd/elfxx-loongarch.h"), "elf64-loongarch.h", "NN", "64"), - runFindReplace(b, find_replace_exe, upstream.path("bfd/elfxx-riscv.h"), "elf32-riscv.h", "NN", "32"), - runFindReplace(b, find_replace_exe, upstream.path("bfd/elfxx-riscv.h"), "elf64-riscv.h", "NN", "64"), + runFindReplace(b, upstream.path("bfd/elfxx-target.h"), "elf32-target.h", "NN", "32"), + runFindReplace(b, upstream.path("bfd/elfxx-target.h"), "elf64-target.h", "NN", "64"), + runFindReplace(b, upstream.path("bfd/elfxx-aarch64.h"), "elf32-aarch64.h", "NN", "32"), + runFindReplace(b, upstream.path("bfd/elfxx-aarch64.h"), "elf64-aarch64.h", "NN", "64"), + runFindReplace(b, upstream.path("bfd/elfxx-ia64.h"), "elf32-ia64.h", "NN", "32"), + runFindReplace(b, upstream.path("bfd/elfxx-ia64.h"), "elf64-ia64.h", "NN", "64"), + runFindReplace(b, upstream.path("bfd/elfxx-kvx.h"), "elf32-kvx.h", "NN", "32"), + runFindReplace(b, upstream.path("bfd/elfxx-kvx.h"), "elf64-kvx.h", "NN", "64"), + runFindReplace(b, upstream.path("bfd/elfxx-loongarch.h"), "elf32-loongarch.h", "NN", "32"), + runFindReplace(b, upstream.path("bfd/elfxx-loongarch.h"), "elf64-loongarch.h", "NN", "64"), + runFindReplace(b, upstream.path("bfd/elfxx-riscv.h"), "elf32-riscv.h", "NN", "32"), + runFindReplace(b, upstream.path("bfd/elfxx-riscv.h"), "elf64-riscv.h", "NN", "64"), }; for (generated_header_files) |header_file| { @@ -918,12 +930,12 @@ pub fn build(b: *std.Build) void { } const generated_sources = std.StaticStringMap(std.Build.LazyPath).init(&[_]struct { []const u8, std.Build.LazyPath }{ - .{ "peigen.c", runFindReplace(b, find_replace_exe, upstream.path("bfd/peXXigen.c"), "peigen.c", "XX", "pe") }, - .{ "pepigen.c", runFindReplace(b, find_replace_exe, upstream.path("bfd/peXXigen.c"), "pepigen.c", "XX", "pep") }, - .{ "pex64igen.c", runFindReplace(b, find_replace_exe, upstream.path("bfd/peXXigen.c"), "pex64igen.c", "XX", "pex64") }, - .{ "pe-aarch64igen.c", runFindReplace(b, find_replace_exe, upstream.path("bfd/peXXigen.c"), "pe-aarch64igen.c", "XX", "peAArch64") }, - .{ "pe-loongarch64igen.c", runFindReplace(b, find_replace_exe, upstream.path("bfd/peXXigen.c"), "pe-loongarch64igen.c", "XX", "peLoongArch64") }, - .{ "pe-riscv64igen.c", runFindReplace(b, find_replace_exe, upstream.path("bfd/peXXigen.c"), "pe-riscv64igen.c", "XX", "peRiscV64") }, + .{ "peigen.c", runFindReplace(b, upstream.path("bfd/peXXigen.c"), "peigen.c", "XX", "pe") }, + .{ "pepigen.c", runFindReplace(b, upstream.path("bfd/peXXigen.c"), "pepigen.c", "XX", "pep") }, + .{ "pex64igen.c", runFindReplace(b, upstream.path("bfd/peXXigen.c"), "pex64igen.c", "XX", "pex64") }, + .{ "pe-aarch64igen.c", runFindReplace(b, upstream.path("bfd/peXXigen.c"), "pe-aarch64igen.c", "XX", "peAArch64") }, + .{ "pe-loongarch64igen.c", runFindReplace(b, upstream.path("bfd/peXXigen.c"), "pe-loongarch64igen.c", "XX", "peLoongArch64") }, + .{ "pe-riscv64igen.c", runFindReplace(b, upstream.path("bfd/peXXigen.c"), "pe-riscv64igen.c", "XX", "peRiscV64") }, }, b.allocator) catch @panic("OOM"); for (std.mem.concat(b.allocator, []const u8, &.{ &.{default_vector}, select_vectors }) catch @panic("OOM")) |target_vector| { @@ -1050,7 +1062,7 @@ pub fn build(b: *std.Build) void { var arch_define = select_architecture; arch_define = std.mem.replaceOwned(u8, b.allocator, arch_define, "bfd_", "") catch @panic("OOM"); arch_define = std.mem.replaceOwned(u8, b.allocator, arch_define, "_arch", "") catch @panic("OOM"); - opcodes_arch_defines.append(b.allocator, b.fmt("-D{s}=1", .{arch_define})) catch @panic("OOM"); + opcodes_arch_defines.append(b.allocator, b.fmt("-DARCH_{s}", .{arch_define})) catch @panic("OOM"); libopcodes.root_module.addCSourceFiles(.{ .root = upstream.path("opcodes"), @@ -1062,18 +1074,567 @@ pub fn build(b: *std.Build) void { .file = upstream.path("opcodes/disassemble.c"), .flags = opcodes_arch_defines.items, }); -} -fn runFindReplace(b: *std.Build, find_replace_exe: *std.Build.Step.Compile, input: std.Build.LazyPath, output_filename: []const u8, needle: []const u8, replacement: []const u8) std.Build.LazyPath { - const run_find_replace = b.addRunArtifact(find_replace_exe); + const binutils_config_header = b.addConfigHeader(.{ + .style = .{ .autoconf_undef = upstream.path("binutils/config.in") }, + }, .{ + .AC_APPLE_UNIVERSAL_BUILD = null, + .DEFAULT_AR_DETERMINISTIC = 0, + .DEFAULT_FOR_COLORED_DISASSEMBLY = 0, + .DEFAULT_FOR_FOLLOW_LINKS = 1, + .DEFAULT_F_FOR_IFUNC_SYMBOLS = 0, + .DEFAULT_STRINGS_ALL = 1, + .ENABLE_CHECKING = null, + .ENABLE_LIBCTF = null, + .ENABLE_NLS = null, + .EXECUTABLE_SUFFIX = "", + .HAVE_CFLOCALECOPYPREFERREDLANGUAGES = null, + .HAVE_CFPREFERENCESCOPYAPPVALUE = null, + .HAVE_DCGETTEXT = null, + .HAVE_DECL_ENVIRON = target.result.os.tag != .windows, + .HAVE_DECL_GETC_UNLOCKED = true, + .HAVE_DECL_GETOPT = true, + .HAVE_DECL_STPCPY = true, + .HAVE_DECL_STRNLEN = true, + .HAVE_DLFCN_H = true, + .HAVE_EXECUTABLE_SUFFIX = null, + .HAVE_FCNTL_H = true, + .HAVE_FSEEKO = true, + .HAVE_FSEEKO64 = if (target.result.isGnuLibC()) true else null, + .HAVE_GETC_UNLOCKED = true, + .HAVE_GETPAGESIZE = true, + .HAVE_GETTEXT = null, + .HAVE_GOOD_UTIME_H = true, + .HAVE_ICONV = null, + .HAVE_INTTYPES_H = true, + .HAVE_LC_MESSAGES = true, + .HAVE_LIBDEBUGINFOD = null, + .HAVE_LIBDEBUGINFOD_FIND_SECTION = null, + .HAVE_MBSTATE_T = true, + .HAVE_MEMORY_H = true, + .HAVE_MKDTEMP = true, + .HAVE_MKSTEMP = true, + .HAVE_MMAP = if (target.result.os.tag == .linux) true else null, + .HAVE_MSGPACK = null, + .HAVE_STDINT_H = true, + .HAVE_STDLIB_H = true, + .HAVE_STRINGS_H = true, + .HAVE_STRING_H = true, + .HAVE_STRUCT_STAT_ST_ATIMENSEC = null, + .HAVE_STRUCT_STAT_ST_ATIMESPEC_TV_NSEC = null, + .HAVE_STRUCT_STAT_ST_ATIM_ST__TIM_TV_NSEC = null, + .HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC = if (target.result.os.tag == .linux) true else null, + .HAVE_SYS_FILE_H = true, + .HAVE_SYS_PARAM_H = true, + .HAVE_SYS_STAT_H = true, + .HAVE_SYS_TIME_H = true, + .HAVE_SYS_TYPES_H = true, + .HAVE_SYS_WAIT_H = true, + .HAVE_UNISTD_H = true, + .HAVE_UTIMENSAT = if (target.result.os.tag == .linux) true else null, + .HAVE_UTIMES = true, + .HAVE_WINDOWS_H = null, + .HAVE_ZSTD = null, + .ICONV_CONST = null, + .LT_OBJDIR = ".libs/", + .PACKAGE = "binutils", + .PACKAGE_BUGREPORT = "", + .PACKAGE_NAME = "binutils", + .PACKAGE_STRING = b.fmt("binutils {f}", .{version}), + .PACKAGE_TARNAME = "binutils", + .PACKAGE_URL = "", + .PACKAGE_VERSION = b.fmt("{f}", .{version}), + .STDC_HEADERS = true, + .TARGET = gnu_triple, + .TARGET_PREPENDS_UNDERSCORE = 0, + .TYPEOF_STRUCT_STAT_ST_ATIM_IS_STRUCT_TIMESPEC = if (target.result.os.tag == .linux) true else null, + .USE_BINARY_FOPEN = null, + .VERSION = b.fmt("{f}", .{version}), + .YYTEXT_POINTER = true, + ._FILE_OFFSET_BITS = 64, + ._LARGE_FILES = null, + ._MINIX = null, + ._POSIX_1_SOURCE = null, + ._POSIX_SOURCE = null, + ._ALL_SOURCE = true, + ._GNU_SOURCE = true, + ._POSIX_PTHREAD_SEMANTICS = true, + ._TANDEM_SOURCE = true, + .__EXTENSIONS__ = true, + .WORDS_BIGENDIAN = if (target.result.cpu.arch.endian() == .big) @as(i64, 1) else null, + }); + + for (binutils_programs) |program| { + const exe = b.addExecutable(.{ + .name = program[0], + .version = version, + .root_module = b.createModule(.{ + .target = target, + .optimize = optimize, + .strip = strip, + .pic = pic, + .link_libc = true, + }), + }); + b.installArtifact(exe); + exe.root_module.addCMacro("HAVE_CONFIG_H", "1"); + exe.root_module.addConfigHeader(binutils_config_header); + exe.root_module.addConfigHeader(bfd_header); + exe.root_module.addConfigHeader(bfdver_header); + exe.root_module.addIncludePath(upstream.path("binutils")); + exe.root_module.addIncludePath(upstream.path("bfd")); + exe.root_module.addIncludePath(upstream.path("include")); + exe.root_module.linkLibrary(bfd); + exe.root_module.linkLibrary(libopcodes); + exe.root_module.linkLibrary(iberty); + exe.root_module.linkLibrary(libsframe); + if (b.systemIntegrationOption("zlib", .{})) { + exe.root_module.linkSystemLibrary("z", .{}); + } else if (b.lazyDependency("zlib", .{ + .target = target, + .optimize = optimize, + })) |zlib_dependency| { + exe.root_module.linkLibrary(zlib_dependency.artifact("z")); + } + exe.root_module.addCSourceFiles(.{ + .root = upstream.path("binutils"), + .files = program[1], + .flags = &.{ + "-DOBJDUMP_PRIVATE_VECTORS=", + "-Dbin_dummy_emulation=bin_vanilla_emulation", + }, + }); + } + + const gas_cpu = switch (target.result.cpu.arch) { + .x86, .x86_64 => "i386", + else => std.debug.panic("TODO gas for '{s}'", .{@tagName(target.result.cpu.arch)}), + }; + const gas_env = switch (target.result.os.tag) { + .linux => "linux", + else => std.debug.panic("TODO gas for '{s}'", .{@tagName(target.result.os.tag)}), + }; + + const gas_headers = b.addWriteFiles(); + _ = gas_headers.add("targ-cpu.h", b.fmt("#include \"tc-{s}.h\"\n", .{gas_cpu})); + _ = gas_headers.add("targ-env.h", b.fmt("#include \"te-{s}.h\"\n", .{gas_env})); + _ = gas_headers.add("obj-format.h", "#include \"obj-elf.h\"\n"); + + const gas_config_header = b.addConfigHeader(.{ + .style = .{ .autoconf_undef = upstream.path("gas/config.in") }, + }, .{ + .AC_APPLE_UNIVERSAL_BUILD = null, + .AIX_WEAK_SUPPORT = null, + .BROKEN_ASSERT = null, + .CROSS_COMPILE = null, + .DEFAULT_ARCH = switch (target.result.cpu.arch) { + .x86_64 => "x86_64", + else => "i386", + }, + .DEFAULT_COMPRESSED_DEBUG_ALGORITHM = .COMPRESS_DEBUG_GABI_ZLIB, + .DEFAULT_CRIS_ARCH = null, + .DEFAULT_EMULATION = "", + .DEFAULT_FLAG_COMPRESS_DEBUG = 1, + .DEFAULT_GENERATE_BUILD_NOTES = 0, + .DEFAULT_GENERATE_ELF_STT_COMMON = 0, + .DEFAULT_GENERATE_X86_RELAX_RELOCATIONS = 1, + .DEFAULT_MIPS_FIX_LOONGSON3_LLSC = 0, + .DEFAULT_RISCV_ARCH_WITH_EXT = null, + .DEFAULT_RISCV_ATTR = 1, + .DEFAULT_RISCV_ISA_SPEC = null, + .DEFAULT_RISCV_PRIV_SPEC = null, + .DEFAULT_X86_TLS_CHECK = 1, + .DEFAULT_X86_USED_NOTE = 1, + .EMULATIONS = null, + .ENABLE_CHECKING = null, + .ENABLE_NLS = null, + .HAVE_CFLOCALECOPYPREFERREDLANGUAGES = null, + .HAVE_CFPREFERENCESCOPYAPPVALUE = null, + .HAVE_DCGETTEXT = null, + .HAVE_DECL_GETOPT = true, + .HAVE_DECL_MEMPCPY = target.result.isGnuLibC(), + .HAVE_DECL_STPCPY = true, + .HAVE_DLFCN_H = true, + .HAVE_GETTEXT = null, + .HAVE_ICONV = null, + .HAVE_INTTYPES_H = true, + .HAVE_LC_MESSAGES = true, + .HAVE_MEMORY_H = true, + .HAVE_STDINT_H = true, + .HAVE_STDLIB_H = true, + .HAVE_STRINGS_H = true, + .HAVE_STRING_H = true, + .HAVE_STRSIGNAL = true, + .HAVE_ST_MTIM_TV_NSEC = if (target.result.os.tag == .linux) true else null, + .HAVE_ST_MTIM_TV_SEC = if (target.result.os.tag == .linux) true else null, + .HAVE_SYS_STAT_H = true, + .HAVE_SYS_TYPES_H = true, + .HAVE_TM_GMTOFF = true, + .HAVE_UNISTD_H = true, + .HAVE_WINDOWS_H = null, + .HAVE_ZSTD = null, + .I386COFF = null, + .LT_OBJDIR = ".libs/", + .MIPS_CPU_STRING_DEFAULT = null, + .MIPS_DEFAULT_64BIT = null, + .MIPS_DEFAULT_ABI = null, + .NDS32_DEFAULT_ARCH_NAME = null, + .NDS32_DEFAULT_AUDIO_EXT = null, + .NDS32_DEFAULT_DSP_EXT = null, + .NDS32_DEFAULT_DX_REGS = null, + .NDS32_DEFAULT_PERF_EXT = null, + .NDS32_DEFAULT_PERF_EXT2 = null, + .NDS32_DEFAULT_STRING_EXT = null, + .NDS32_DEFAULT_ZOL_EXT = null, + .NDS32_LINUX_TOOLCHAIN = null, + .NEED_DECLARATION_ENVIRON = null, + .NEED_DECLARATION_FFS = null, + .OBJ_MAYBE_AOUT = null, + .OBJ_MAYBE_COFF = null, + .OBJ_MAYBE_ECOFF = null, + .OBJ_MAYBE_ELF = null, + .OBJ_MAYBE_GENERIC = null, + .OBJ_MAYBE_SOM = null, + .PACKAGE = "gas", + .PACKAGE_BUGREPORT = "", + .PACKAGE_NAME = "gas", + .PACKAGE_STRING = b.fmt("gas {f}", .{version}), + .PACKAGE_TARNAME = "gas", + .PACKAGE_URL = "", + .PACKAGE_VERSION = b.fmt("{f}", .{version}), + .STDC_HEADERS = true, + .STRICTCOFF = null, + .TARGET_ALIAS = gnu_triple, + .TARGET_BYTES_BIG_ENDIAN = if (target.result.cpu.arch.endian() == .big) @as(i64, 1) else @as(i64, 0), + .TARGET_CANONICAL = gnu_triple, + .TARGET_CPU = gnu_cpu, + .TARGET_OS = b.fmt("{s}-{s}", .{ @tagName(target.result.os.tag), @tagName(target.result.abi) }), + .TARGET_SOLARIS_COMMENT = null, + .TARGET_VENDOR = gnu_vendor, + .TARGET_WITH_CPU = null, + .USE_BINARY_FOPEN = null, + .USE_EF_MIPS_ABI_O32 = null, + .USE_EMULATIONS = null, + .USING_CGEN = null, + .VERSION = b.fmt("{f}", .{version}), + .YYTEXT_POINTER = true, + ._FILE_OFFSET_BITS = 64, + ._LARGE_FILES = null, + ._MINIX = null, + ._POSIX_1_SOURCE = null, + ._POSIX_SOURCE = null, + ._ALL_SOURCE = true, + ._GNU_SOURCE = true, + ._POSIX_PTHREAD_SEMANTICS = true, + ._TANDEM_SOURCE = true, + .__EXTENSIONS__ = true, + .WORDS_BIGENDIAN = if (target.result.cpu.arch.endian() == .big) @as(i64, 1) else null, + }); + + const as = b.addExecutable(.{ + .name = "as", + .version = version, + .root_module = b.createModule(.{ + .target = target, + .optimize = optimize, + .strip = strip, + .pic = pic, + .link_libc = true, + }), + }); + b.installArtifact(as); + as.root_module.addCMacro("HAVE_CONFIG_H", "1"); + as.root_module.addConfigHeader(gas_config_header); + as.root_module.addConfigHeader(bfd_header); + as.root_module.addConfigHeader(bfdver_header); + as.root_module.addIncludePath(gas_headers.getDirectory()); + as.root_module.addIncludePath(upstream.path("gas")); + as.root_module.addIncludePath(upstream.path("gas/config")); + as.root_module.addIncludePath(upstream.path("bfd")); + as.root_module.addIncludePath(upstream.path("include")); + as.root_module.addIncludePath(upstream.path(".")); + as.root_module.linkLibrary(bfd); + as.root_module.linkLibrary(libopcodes); + as.root_module.linkLibrary(iberty); + as.root_module.linkLibrary(libsframe); + if (b.systemIntegrationOption("zlib", .{})) { + as.root_module.linkSystemLibrary("z", .{}); + } else if (b.lazyDependency("zlib", .{ + .target = target, + .optimize = optimize, + })) |zlib_dependency| { + as.root_module.linkLibrary(zlib_dependency.artifact("z")); + } + as.root_module.addCSourceFiles(.{ .root = upstream.path("gas"), .files = gas_sources }); + as.root_module.addCSourceFiles(.{ + .root = upstream.path("gas/config"), + .files = &.{ b.fmt("tc-{s}.c", .{gas_cpu}), "obj-elf.c", "atof-ieee.c" }, + }); + + const ld_emulations = switch (target.result.cpu.arch) { + .x86_64 => "elf_x86_64 elf_i386", + .x86 => "elf_i386", + else => std.debug.panic("TODO ld for '{s}'", .{@tagName(target.result.cpu.arch)}), + }; + + const genscripts_exe = b.addExecutable(.{ + .name = "genscripts", + .root_module = b.createModule(.{ + .root_source_file = b.path("genscripts.zig"), + .target = b.graph.host, + .optimize = .ReleaseFast, + }), + }); + + const run_genscripts = b.addRunArtifact(genscripts_exe); + const emulations = run_genscripts.addOutputDirectoryArg("ld"); + run_genscripts.addDirectoryArg(upstream.path("ld")); + run_genscripts.addArgs(&.{ ld_emulations, gnu_triple }); + + var declarations: std.ArrayListUnmanaged(u8) = .empty; + var list: std.ArrayListUnmanaged(u8) = .empty; + var names = std.mem.tokenizeScalar(u8, ld_emulations, ' '); + while (names.next()) |name| { + declarations.appendSlice(b.allocator, b.fmt( + "extern ld_emulation_xfer_type ld_{s}_emulation;\n", + .{name}, + )) catch @panic("OOM"); + list.appendSlice(b.allocator, b.fmt(" &ld_{s}_emulation, \\\n", .{name})) catch @panic("OOM"); + } + + const ld_headers = b.addWriteFiles(); + _ = ld_headers.add("ldemul-list.h", b.fmt( + "/* This file is automatically generated. DO NOT EDIT! */\n{s}\n#define EMULATION_LIST \\\n{s} 0\n", + .{ declarations.items, list.items }, + )); + + const ld_config_header = b.addConfigHeader(.{ + .style = .{ .autoconf_undef = upstream.path("ld/config.in") }, + }, .{ + .DEFAULT_COMPRESSED_DEBUG_ALGORITHM = .COMPRESS_DEBUG_GABI_ZLIB, + .DEFAULT_EMIT_GNU_HASH = 1, + .DEFAULT_EMIT_SYSV_HASH = 1, + .DEFAULT_FLAG_COMPRESS_DEBUG = 0, + .DEFAULT_LD_ERROR_EXECSTACK = 0, + .DEFAULT_LD_ERROR_RWX_SEGMENTS = 0, + .DEFAULT_LD_EXECSTACK = 1, + .DEFAULT_LD_ROSEGMENT = 0, + .DEFAULT_LD_TEXTREL_CHECK = .textrel_check_warning, + .DEFAULT_LD_TEXTREL_CHECK_WARNING = 1, + .DEFAULT_LD_WARN_EXECSTACK = 2, + .DEFAULT_LD_WARN_RWX_SEGMENTS = 1, + .DEFAULT_LD_Z_MARK_PLT = 0, + .DEFAULT_LD_Z_MEMORY_SEAL = 0, + .DEFAULT_LD_Z_RELRO = 1, + .DEFAULT_LD_Z_SEPARATE_CODE = if (target.result.os.tag == .linux) @as(i64, 1) else @as(i64, 0), + .DEFAULT_NEW_DTAGS = 0, + .ENABLE_CHECKING = null, + .ENABLE_LIBCTF = null, + .ENABLE_NLS = null, + .EXTRA_SHLIB_EXTENSION = null, + .GOT_HANDLING_DEFAULT = .GOT_HANDLING_TARGET_DEFAULT, + .HAVE_CFLOCALECOPYPREFERREDLANGUAGES = null, + .HAVE_CFPREFERENCESCOPYAPPVALUE = null, + .HAVE_CLOSE = true, + .HAVE_DCGETTEXT = null, + .HAVE_DECL_ENVIRON = target.result.os.tag != .windows, + .HAVE_DECL_GETOPT = true, + .HAVE_DECL_STPCPY = true, + .HAVE_DLFCN_H = true, + .HAVE_ELF_HINTS_H = null, + .HAVE_FCNTL_H = true, + .HAVE_GETPAGESIZE = true, + .HAVE_GETRUSAGE = true, + .HAVE_GETTEXT = null, + .HAVE_GLOB = true, + .HAVE_ICONV = null, + .HAVE_INITFINI_ARRAY = true, + .HAVE_INTTYPES_H = true, + .HAVE_JANSSON = null, + .HAVE_LC_MESSAGES = true, + .HAVE_LIMITS_H = true, + .HAVE_LSEEK = true, + .HAVE_MEMORY_H = true, + .HAVE_MKSTEMP = true, + .HAVE_MMAP = if (target.result.os.tag == .linux) true else null, + .HAVE_OPEN = true, + .HAVE_REALPATH = true, + .HAVE_STDINT_H = true, + .HAVE_STDLIB_H = true, + .HAVE_STRINGS_H = true, + .HAVE_STRING_H = true, + .HAVE_SYS_FILE_H = true, + .HAVE_SYS_MMAN_H = true, + .HAVE_SYS_PARAM_H = true, + .HAVE_SYS_STAT_H = true, + .HAVE_SYS_TIME_H = true, + .HAVE_SYS_TYPES_H = true, + .HAVE_UNISTD_H = true, + .HAVE_WAITPID = true, + .HAVE_WINDOWS_H = null, + .HAVE_ZSTD = null, + .LT_OBJDIR = ".libs/", + .PACKAGE = "ld", + .PACKAGE_BUGREPORT = "", + .PACKAGE_NAME = "ld", + .PACKAGE_STRING = b.fmt("ld {f}", .{version}), + .PACKAGE_TARNAME = "ld", + .PACKAGE_URL = "", + .PACKAGE_VERSION = b.fmt("{f}", .{version}), + .STDC_HEADERS = true, + .SUPPORT_ERROR_HANDLING_SCRIPT = true, + .USE_BINARY_FOPEN = null, + .VERSION = b.fmt("{f}", .{version}), + .WITH_XXHASH = null, + .YYTEXT_POINTER = true, + ._FILE_OFFSET_BITS = 64, + ._LARGE_FILES = null, + ._MINIX = null, + ._POSIX_1_SOURCE = null, + ._POSIX_SOURCE = null, + ._ALL_SOURCE = true, + ._GNU_SOURCE = true, + ._POSIX_PTHREAD_SEMANTICS = true, + ._TANDEM_SOURCE = true, + .__EXTENSIONS__ = true, + }); + + const ld = b.addExecutable(.{ + .name = "ld", + .version = version, + .root_module = b.createModule(.{ + .target = target, + .optimize = optimize, + .strip = strip, + .pic = pic, + .link_libc = true, + }), + }); + b.installArtifact(ld); + ld.root_module.addCMacro("HAVE_CONFIG_H", "1"); + ld.root_module.addConfigHeader(ld_config_header); + ld.root_module.addConfigHeader(bfd_header); + ld.root_module.addConfigHeader(bfdver_header); + ld.root_module.addIncludePath(ld_headers.getDirectory()); + ld.root_module.addIncludePath(emulations); + ld.root_module.addIncludePath(upstream.path("ld")); + ld.root_module.addIncludePath(upstream.path("bfd")); + ld.root_module.addIncludePath(upstream.path("include")); + ld.root_module.addIncludePath(upstream.path(".")); + ld.root_module.linkLibrary(bfd); + ld.root_module.linkLibrary(iberty); + ld.root_module.linkLibrary(libsframe); + if (b.systemIntegrationOption("zlib", .{})) { + ld.root_module.linkSystemLibrary("z", .{}); + } else if (b.lazyDependency("zlib", .{ + .target = target, + .optimize = optimize, + })) |zlib_dependency| { + ld.root_module.linkLibrary(zlib_dependency.artifact("z")); + } + ld.root_module.addCSourceFiles(.{ + .root = upstream.path("ld"), + .files = ld_sources, + .flags = &.{ + b.fmt("-DDEFAULT_EMULATION=\"{s}\"", .{std.mem.sliceTo(ld_emulations, ' ')}), + b.fmt("-DTARGET=\"{s}\"", .{gnu_triple}), + "-DBINDIR=\"/usr/bin\"", + "-DTOOLBINDIR=\"/usr/bin\"", + "-DSCRIPTDIR=\"/usr/lib\"", + "-DELF_LIST_OPTIONS=true", + "-DELF_SHLIB_LIST_OPTIONS=true", + "-DELF_PLT_UNWIND_LIST_OPTIONS=true", + }, + }); + names.reset(); + while (names.next()) |name| { + ld.root_module.addCSourceFile(.{ + .file = emulations.path(b, b.fmt("e{s}.c", .{name})), + }); + } +} - run_find_replace.addFileArg(input); - const output = run_find_replace.addOutputFileArg(output_filename); - run_find_replace.addArg(needle); - run_find_replace.addArg(replacement); - return output; +// The substitution bfd's own Makefile makes: sed -e s/NN/32/g < elfxx-target.h +fn runFindReplace(b: *std.Build, input: std.Build.LazyPath, output_filename: []const u8, needle: []const u8, replacement: []const u8) std.Build.LazyPath { + const sed = b.addSystemCommand(&.{ "sed", "-e", b.fmt("s/{s}/{s}/g", .{ needle, replacement }) }); + sed.addFileArg(input); + return sed.captureStdOut(.{ .basename = output_filename }); } +const ld_sources: []const []const u8 = &.{ + "ldgram.c", + "ldlex-wrapper.c", + "lexsup.c", + "ldlang.c", + "mri.c", + "ldctor.c", + "ldmain.c", + "ldwrite.c", + "ldexp.c", + "ldemul.c", + "ldver.c", + "ldmisc.c", + "ldfile.c", + "ldcref.c", + "plugin.c", + "ldbuildid.c", + "ldelf.c", + "ldelfgen.c", +}; + +const gas_sources: []const []const u8 = &.{ + "app.c", + "as.c", + "atof-generic.c", + "codeview.c", + "compress-debug.c", + "cond.c", + "depend.c", + "dwarf2dbg.c", + "dw2gencfi.c", + "ecoff.c", + "ehopt.c", + "expr.c", + "flonum-copy.c", + "flonum-konst.c", + "flonum-mult.c", + "frags.c", + "gen-sframe.c", + "ginsn.c", + "hash.c", + "input-file.c", + "input-scrub.c", + "listing.c", + "literal.c", + "macro.c", + "messages.c", + "output-file.c", + "read.c", + "remap.c", + "sb.c", + "scfidw2gen.c", + "scfi.c", + "sframe-opt.c", + "stabs.c", + "subsegs.c", + "symbols.c", + "write.c", +}; + +const bulibs = [_][]const u8{ "bucomm.c", "version.c", "filemode.c" }; +const elflibs = [_][]const u8{"elfcomm.c"}; +const debug_sources = [_][]const u8{ "rddbg.c", "debug.c", "stabs.c", "rdcoff.c" }; +const write_debug_sources = debug_sources ++ [_][]const u8{"wrstabs.c"}; + +const binutils_programs: []const struct { []const u8, []const []const u8 } = &.{ + .{ "ar", &([_][]const u8{ "arparse.c", "arlex.c", "not-ranlib.c", "arsup.c", "rename.c", "binemul.c", "emul_vanilla.c" } ++ bulibs) }, + .{ "nm", &([_][]const u8{ "nm.c", "demanguse.c" } ++ bulibs) }, + .{ "objcopy", &([_][]const u8{ "not-strip.c", "rename.c" } ++ write_debug_sources ++ bulibs) }, + .{ "strip", &([_][]const u8{ "is-strip.c", "rename.c" } ++ write_debug_sources ++ bulibs) }, + .{ "objdump", &([_][]const u8{ "objdump.c", "dwarf.c", "prdbg.c", "demanguse.c" } ++ debug_sources ++ bulibs ++ elflibs) }, + .{ "readelf", &([_][]const u8{ "readelf.c", "version.c", "unwind-ia64.c", "dwarf.c", "demanguse.c" } ++ elflibs) }, +}; + const elf_sources: []const []const u8 = &.{ "elf.c", "elflink.c", diff --git a/build.zig.zon b/build.zig.zon index 7b46058..8ec5425 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -28,6 +28,7 @@ "README.md", "include/targmatch.h", "find_replace.zig", + "genscripts.zig", }, .fingerprint = 0x4911b3458854c64a, // Changing this has security and trust implications. } diff --git a/find_replace.zig b/find_replace.zig deleted file mode 100644 index 42c3fd7..0000000 --- a/find_replace.zig +++ /dev/null @@ -1,31 +0,0 @@ -//! This is used as a replacement for `sed` - -const std = @import("std"); - -pub fn main(init: std.process.Init) !void { - const gpa = init.gpa; - const io = init.io; - const cwd = std.Io.Dir.cwd(); - const args = try init.minimal.args.toSlice(init.arena.allocator()); - - if (args.len != 5) { - std.debug.print("usage: {s} \n", .{args[0]}); - std.process.exit(1); - } - - const input_filename = args[1]; - const output_filename = args[2]; - const before = args[3]; - const after = args[4]; - - const input = try cwd.readFileAlloc(io, input_filename, gpa, .limited(std.math.maxInt(u32))); - defer gpa.free(input); - - const output = try std.mem.replaceOwned(u8, gpa, input, before, after); - defer gpa.free(output); - - try cwd.writeFile(io, .{ - .sub_path = output_filename, - .data = output, - }); -} diff --git a/genscripts.zig b/genscripts.zig new file mode 100644 index 0000000..d3121af --- /dev/null +++ b/genscripts.zig @@ -0,0 +1,51 @@ +//! Runs upstream's genscripts.sh, which writes into the current directory + +const std = @import("std"); + +pub fn main(init: std.process.Init) !void { + const io = init.io; + const arena = init.arena.allocator(); + const args = try init.minimal.args.toSlice(arena); + + if (args.len != 5) { + std.debug.print("usage: {s} \n", .{args[0]}); + std.process.exit(1); + } + + const out = args[1]; + const source = try std.Io.Dir.cwd().realPathFileAlloc(io, args[2], arena); + const emulations = args[3]; + const triple = args[4]; + + try std.Io.Dir.cwd().createDirPath(io, try std.fmt.allocPrint(arena, "{s}/ldscripts", .{out})); + + var it = std.mem.tokenizeScalar(u8, emulations, ' '); + while (it.next()) |emulation| { + var child = try std.process.spawn(io, .{ + .cwd = .{ .path = out }, + .argv = &.{ + "sh", + try std.fmt.allocPrint(arena, "{s}/genscripts.sh", .{source}), + source, + "/usr/lib", + "/usr", + "/usr", + triple, + triple, + triple, + "", + "", + emulations, + "", + "no", + "yes", + emulation, + triple, + }, + }); + switch (try child.wait(io)) { + .exited => |code| if (code != 0) return error.GenscriptsFailed, + else => return error.GenscriptsFailed, + } + } +}