╭ Lld.zig ──────────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭ find file ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╮ ╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │ │ │http│ ssh │ │ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
1 base: link.File, 2 ofmt: union(enum) { 3 elf: Elf, 4 coff: Coff, 5 wasm: Wasm, 6 }, 7 8 const Coff = struct { 9 image_base: u64, 10 entry: link.File.OpenOptions.Entry, 11 pdb_out_path: ?[]const u8, 12 repro: bool, 13 tsaware: bool, 14 nxcompat: bool, 15 dynamicbase: bool, 16 /// TODO this and minor_subsystem_version should be combined into one property and left as 17 /// default or populated together. They should not be separate fields. 18 major_subsystem_version: u16, 19 minor_subsystem_version: u16, 20 lib_directories: []const Cache.Directory, 21 module_definition_file: ?[]const u8, 22 subsystem: ?std.zig.Subsystem, 23 /// These flags are populated by `codegen.llvm.updateExports` to allow us to guess the subsystem. 24 lld_export_flags: struct { 25 c_main: bool, 26 winmain: bool, 27 wwinmain: bool, 28 winmain_crt_startup: bool, 29 wwinmain_crt_startup: bool, 30 dllmain_crt_startup: bool, 31 }, 32 fn init(comp: *Compilation, options: link.File.OpenOptions) !Coff { 33 const target = &comp.root_mod.resolved_target.result; 34 const output_mode = comp.config.output_mode; 35 return .{ 36 .image_base = options.image_base orelse switch (output_mode) { 37 .Exe => switch (target.cpu.arch) { 38 .aarch64, .x86_64 => 0x140000000, 39 .thumb, .x86 => 0x400000, 40 else => return error.UnsupportedCoffArchitecture, 41 }, 42 .Lib => switch (target.cpu.arch) { 43 .aarch64, .x86_64 => 0x180000000, 44 .thumb, .x86 => 0x10000000, 45 else => return error.UnsupportedCoffArchitecture, 46 }, 47 .Obj => 0, 48 }, 49 .entry = options.entry, 50 .pdb_out_path = options.pdb_out_path, 51 .repro = options.repro, 52 .tsaware = options.tsaware, 53 .nxcompat = options.nxcompat, 54 .dynamicbase = options.dynamicbase, 55 .major_subsystem_version = options.major_subsystem_version orelse 6, 56 .minor_subsystem_version = options.minor_subsystem_version orelse 0, 57 .lib_directories = options.lib_directories, 58 .module_definition_file = options.module_definition_file, 59 // Subsystem depends on the set of public symbol names from linked objects. 60 // See LinkerDriver::inferSubsystem from the LLD project for the flow chart. 61 .subsystem = options.subsystem, 62 // These flags are initially all `false`; the LLVM backend populates them when it learns about exports. 63 .lld_export_flags = .{ 64 .c_main = false, 65 .winmain = false, 66 .wwinmain = false, 67 .winmain_crt_startup = false, 68 .wwinmain_crt_startup = false, 69 .dllmain_crt_startup = false, 70 }, 71 }; 72 } 73 }; 74 pub const Elf = struct { 75 entry_name: ?[]const u8, 76 hash_style: HashStyle, 77 image_base: u64, 78 linker_script: ?Cache.Path, 79 version_script: ?Cache.Path, 80 sort_section: ?SortSection, 81 print_icf_sections: bool, 82 print_map: bool, 83 nmagic: bool, 84 fatal_warnings: bool, 85 emit_relocs: bool, 86 z_nodelete: bool, 87 z_notext: bool, 88 z_defs: bool, 89 z_origin: bool, 90 z_nocopyreloc: bool, 91 z_now: bool, 92 z_relro: bool, 93 z_common_page_size: ?u64, 94 z_max_page_size: ?u64, 95 rpath_list: []const []const u8, 96 symbol_wrap_set: []const []const u8, 97 soname: ?[]const u8, 98 allow_undefined_version: bool, 99 enable_new_dtags: ?bool, 100 compress_debug_sections: std.zig.CompressDebugSections, 101 bind_global_refs_locally: bool, 102 pub const HashStyle = enum { sysv, gnu, both }; 103 pub const SortSection = enum { name, alignment }; 104 105 fn init(comp: *Compilation, options: link.File.OpenOptions) !Elf { 106 const PtrWidth = enum { p32, p64 }; 107 const target = &comp.root_mod.resolved_target.result; 108 const output_mode = comp.config.output_mode; 109 const is_dyn_lib = output_mode == .Lib and comp.config.link_mode == .dynamic; 110 const ptr_width: PtrWidth = switch (target.ptrBitWidth()) { 111 0...32 => .p32, 112 33...64 => .p64, 113 else => return error.UnsupportedElfArchitecture, 114 }; 115 const default_entry_name: []const u8 = switch (target.cpu.arch) { 116 .mips, .mipsel, .mips64, .mips64el => "__start", 117 else => "_start", 118 }; 119 return .{ 120 .entry_name = switch (options.entry) { 121 .disabled => null, 122 .default => if (output_mode != .Exe) null else default_entry_name, 123 .enabled => default_entry_name, 124 .named => |name| name, 125 }, 126 .hash_style = options.hash_style, 127 .image_base = b: { 128 if (is_dyn_lib) break :b 0; 129 if (output_mode == .Exe and (comp.config.pie or target.os.tag == .haiku)) break :b 0; 130 break :b options.image_base orelse switch (ptr_width) { 131 .p32 => 0x10000, 132 .p64 => 0x1000000, 133 }; 134 }, 135 .linker_script = options.linker_script, 136 .version_script = options.version_script, 137 .sort_section = options.sort_section, 138 .print_icf_sections = options.print_icf_sections, 139 .print_map = options.print_map, 140 .nmagic = options.nmagic, 141 .fatal_warnings = options.fatal_warnings, 142 .emit_relocs = options.emit_relocs, 143 .z_nodelete = options.z_nodelete, 144 .z_notext = options.z_notext, 145 .z_defs = options.z_defs, 146 .z_origin = options.z_origin, 147 .z_nocopyreloc = options.z_nocopyreloc, 148 .z_now = options.z_now, 149 .z_relro = options.z_relro, 150 .z_common_page_size = options.z_common_page_size, 151 .z_max_page_size = options.z_max_page_size, 152 .rpath_list = options.rpath_list, 153 .symbol_wrap_set = options.symbol_wrap_set.keys(), 154 .soname = options.soname, 155 .allow_undefined_version = options.allow_undefined_version, 156 .enable_new_dtags = options.enable_new_dtags, 157 .compress_debug_sections = options.compress_debug_sections, 158 .bind_global_refs_locally = options.bind_global_refs_locally, 159 }; 160 } 161 }; 162 const Wasm = struct { 163 /// Symbol name of the entry function to export 164 entry_name: ?[]const u8, 165 /// When true, will import the function table from the host environment. 166 import_table: bool, 167 /// When true, will export the function table to the host environment. 168 export_table: bool, 169 /// When true, remove maximum size from function table, allowing table to grow. 170 growable_table: bool, 171 /// When defined, sets the initial memory size of the memory. 172 initial_memory: ?u64, 173 /// When defined, sets the maximum memory size of the memory. 174 max_memory: ?u64, 175 /// When defined, sets the start of the data section. 176 global_base: ?u64, 177 /// Set of *global* symbol names to export to the host environment. 178 export_symbol_names: []const []const u8, 179 /// When true, will allow undefined symbols 180 import_symbols: bool, 181 fn init(comp: *Compilation, options: link.File.OpenOptions) !Wasm { 182 const default_entry_name: []const u8 = switch (comp.config.wasi_exec_model) { 183 .reactor => "_initialize", 184 .command => "_start", 185 }; 186 return .{ 187 .entry_name = switch (options.entry) { 188 .disabled => null, 189 .default => if (comp.config.output_mode != .Exe) null else default_entry_name, 190 .enabled => default_entry_name, 191 .named => |name| name, 192 }, 193 .import_table = options.import_table, 194 .export_table = options.export_table, 195 .growable_table = options.growable_table, 196 .initial_memory = options.initial_memory, 197 .max_memory = options.max_memory, 198 .global_base = options.global_base, 199 .export_symbol_names = options.export_symbol_names, 200 .import_symbols = options.import_symbols, 201 }; 202 } 203 }; 204 205 pub fn createEmpty( 206 arena: Allocator, 207 comp: *Compilation, 208 emit: Cache.Path, 209 options: link.File.OpenOptions, 210 ) !*Lld { 211 const target = &comp.root_mod.resolved_target.result; 212 const output_mode = comp.config.output_mode; 213 const optimize_mode = comp.root_mod.optimize_mode; 214 215 const gc_sections: bool = options.gc_sections orelse switch (target.ofmt) { 216 .coff => optimize_mode != .debug, 217 .elf => optimize_mode != .debug and output_mode != .Obj, 218 .wasm => output_mode != .Obj, 219 else => unreachable, 220 }; 221 const stack_size: u64 = options.stack_size orelse default: { 222 if (target.ofmt == .wasm and target.os.tag == .freestanding) 223 break :default 1 * 1024 * 1024; // 1 MiB 224 break :default 16 * 1024 * 1024; // 16 MiB 225 }; 226 227 const lld = try arena.create(Lld); 228 lld.* = .{ 229 .base = .{ 230 .tag = .lld, 231 .comp = comp, 232 .emit = emit, 233 .gc_sections = gc_sections, 234 .print_gc_sections = options.print_gc_sections, 235 .stack_size = stack_size, 236 .allow_shlib_undefined = options.allow_shlib_undefined orelse false, 237 .file = null, 238 .build_id = options.build_id, 239 }, 240 .ofmt = switch (target.ofmt) { 241 .coff => .{ .coff = try .init(comp, options) }, 242 .elf => .{ .elf = try .init(comp, options) }, 243 .wasm => .{ .wasm = try .init(comp, options) }, 244 else => unreachable, 245 }, 246 }; 247 return lld; 248 } 249 pub fn deinit(lld: *Lld) void { 250 _ = lld; 251 } 252 pub fn flush( 253 lld: *Lld, 254 arena: Allocator, 255 tid: Zcu.PerThread.Id, 256 prog_node: std.Progress.Node, 257 ) link.Error!void { 258 dev.check(.lld_linker); 259 _ = tid; 260 261 const tracy = trace(@src()); 262 defer tracy.end(); 263 264 const sub_prog_node = prog_node.start("LLD Link", 0); 265 defer sub_prog_node.end(); 266 267 const comp = lld.base.comp; 268 const result = if (comp.config.output_mode == .Lib and comp.config.link_mode == .static) r: { 269 if (!@import("build_options").have_llvm or !comp.config.use_lib_llvm) { 270 return lld.base.comp.link_diags.fail("using lld without libllvm not implemented", .{}); 271 } 272 break :r linkAsArchive(lld, arena); 273 } else switch (lld.ofmt) { 274 .coff => coffLink(lld, arena), 275 .elf => elfLink(lld, arena), 276 .wasm => wasmLink(lld, arena), 277 }; 278 result catch |err| switch (err) { 279 error.OutOfMemory, error.AlreadyReported, error.Canceled => |e| return e, 280 else => |e| return lld.base.comp.link_diags.fail("failed to link with LLD: {t}", .{e}), 281 }; 282 } 283 284 fn linkAsArchive(lld: *Lld, arena: Allocator) link.Error!void { 285 const base = &lld.base; 286 const comp = base.comp; 287 const directory = base.emit.root_dir; // Just an alias to make it shorter to type. 288 const full_out_path = try directory.join(arena, &[_][]const u8{base.emit.sub_path}); 289 const full_out_path_z = try arena.dupeSentinel(u8, full_out_path, 0); 290 const opt_zcu = comp.zcu; 291 292 const zcu_obj_path: ?Cache.Path = if (opt_zcu) |zcu| p: { 293 break :p try comp.resolveEmitPathFlush(arena, .temp, zcu.llvm_object.?.out_bin_basename); 294 } else null; 295 296 log.debug("zcu_obj_path={?f}", .{zcu_obj_path}); 297 298 const compiler_rt_path: ?Cache.Path = if (comp.compiler_rt_strat == .obj) 299 comp.compiler_rt_obj.?.full_object_path 300 else 301 null; 302 303 const ubsan_rt_path: ?Cache.Path = if (comp.ubsan_rt_strat == .obj) 304 comp.ubsan_rt_obj.?.full_object_path 305 else 306 null; 307 308 var object_files: std.ArrayList([*:0]const u8) = .empty; 309 310 try object_files.ensureUnusedCapacity(arena, comp.link_inputs.len); 311 for (comp.link_inputs) |input| switch (input) { 312 .dso, .dso_exact, .archive => {}, // static archives should not contain shared libraries or other static archives 313 .res, .object => { 314 const path = try input.path().?.toStringZ(arena); 315 object_files.appendAssumeCapacity(path); 316 }, 317 }; 318 319 try object_files.ensureUnusedCapacity(arena, comp.c_objects.items.len + 320 comp.win32_resources.items.len + 2); 321 322 for (comp.c_objects.items) |c_object| { 323 object_files.appendAssumeCapacity(try c_object.status.success.object_path.toStringZ(arena)); 324 } 325 for (comp.win32_resources.items) |win32_resource| { 326 object_files.appendAssumeCapacity(try arena.dupeSentinel(u8, win32_resource.status.success.res_path, 0)); 327 } 328 if (zcu_obj_path) |p| object_files.appendAssumeCapacity(try p.toStringZ(arena)); 329 if (compiler_rt_path) |p| object_files.appendAssumeCapacity(try p.toStringZ(arena)); 330 if (ubsan_rt_path) |p| object_files.appendAssumeCapacity(try p.toStringZ(arena)); 331 332 if (comp.verbose_link) { 333 std.debug.print("ar rcs {s}", .{full_out_path_z}); 334 for (object_files.items) |arg| { 335 std.debug.print(" {s}", .{arg}); 336 } 337 std.debug.print("\n", .{}); 338 } 339 340 const llvm_bindings = @import("../codegen/llvm/bindings.zig"); 341 const llvm = @import("../codegen/llvm.zig"); 342 const target = &comp.root_mod.resolved_target.result; 343 llvm.initializeLLVMTarget(comp.io, target.cpu.arch); 344 var err_file_index: usize = undefined; 345 var err_msg: [*:0]u8 = undefined; 346 if (llvm_bindings.WriteArchive( 347 full_out_path_z, 348 object_files.items.ptr, 349 object_files.items.len, 350 switch (target.os.tag) { 351 .windows => .COFF, 352 else => if (target.os.tag.isDarwin()) .DARWIN else .GNU, 353 }, 354 &err_file_index, 355 &err_msg, 356 )) { 357 defer std.c.free(err_msg); 358 if (err_file_index < object_files.items.len) { 359 return comp.link_diags.fail("LLD failed to open input file '{s}': {s}", .{ 360 object_files.items[err_file_index], 361 err_msg, 362 }); 363 } else { 364 return comp.link_diags.fail("LLD failed to write archive: {s}", .{err_msg}); 365 } 366 } 367 } 368 369 fn addCommonArgs(argv: *std.array_list.Managed([]const u8), coff: bool) !void { 370 if (builtin.os.tag == .netbsd) { 371 // NetBSD 10.1's `malloc` appears to have some nasty bugs that occur 372 // when doing parallel linking in LLD, manifesting as input and/or 373 // output section memory randomly being unmapped. So just don't do 374 // parallel linking for now. 375 try argv.append(if (coff) "-threads:1" else "--threads=1"); 376 } 377 } 378 379 fn coffLink(lld: *Lld, arena: Allocator) !void { 380 const comp = lld.base.comp; 381 const gpa = comp.gpa; 382 const io = comp.io; 383 const base = &lld.base; 384 const coff = &lld.ofmt.coff; 385 386 const directory = base.emit.root_dir; // Just an alias to make it shorter to type. 387 const full_out_path = try directory.join(arena, &[_][]const u8{base.emit.sub_path}); 388 389 const zcu_obj_path: ?Cache.Path = if (comp.zcu) |zcu| p: { 390 break :p try comp.resolveEmitPathFlush(arena, .temp, zcu.llvm_object.?.out_bin_basename); 391 } else null; 392 393 const is_lib = comp.config.output_mode == .Lib; 394 const is_dyn_lib = comp.config.link_mode == .dynamic and is_lib; 395 const is_exe_or_dyn_lib = is_dyn_lib or comp.config.output_mode == .Exe; 396 const link_in_crt = comp.config.link_libc and is_exe_or_dyn_lib; 397 const target = &comp.root_mod.resolved_target.result; 398 const optimize_mode = comp.root_mod.optimize_mode; 399 const entry_name: ?[]const u8 = switch (coff.entry) { 400 // This logic isn't quite right for default or enabled. No point in fixing it 401 // when the goal is to eliminate dependency on LLD anyway. 402 // https://github.com/ziglang/zig/issues/17751 403 .disabled, .default, .enabled => null, 404 .named => |name| name, 405 }; 406 407 if (comp.config.output_mode == .Obj) { 408 // LLD's COFF driver does not support the equivalent of `-r` so we do a simple file copy 409 // here. TODO: think carefully about how we can avoid this redundant operation when doing 410 // build-obj. See also the corresponding TODO in linkAsArchive. 411 const the_object_path = blk: { 412 if (link.firstObjectInput(comp.link_inputs)) |obj| break :blk obj.path; 413 414 if (comp.c_objects.items.len != 0) 415 break :blk comp.c_objects.items[0].status.success.object_path; 416 417 if (zcu_obj_path) |p| 418 break :blk p; 419 420 // TODO I think this is unreachable. Audit this situation when solving the above TODO 421 // regarding eliding redundant object -> object transformations. 422 return error.NoObjectsToLink; 423 }; 424 try Io.Dir.copyFile( 425 the_object_path.root_dir.handle, 426 the_object_path.sub_path, 427 directory.handle, 428 base.emit.sub_path, 429 io, 430 .{}, 431 ); 432 } else { 433 // Create an LLD command line and invoke it. 434 var argv = std.array_list.Managed([]const u8).init(gpa); 435 defer argv.deinit(); 436 // We will invoke ourselves as a child process to gain access to LLD. 437 // This is necessary because LLD does not behave properly as a library - 438 // it calls exit() and does not reset all global data between invocations. 439 const linker_command = "lld-link"; 440 try argv.appendSlice(&[_][]const u8{ comp.self_exe_path.?, linker_command }); 441 try addCommonArgs(&argv, true); 442 443 if (target.isMinGW()) { 444 try argv.append("-lldmingw"); 445 } 446 447 try argv.append("-ERRORLIMIT:0"); 448 try argv.append("-NOLOGO"); 449 if (comp.config.debug_format != .strip) { 450 try argv.append("-DEBUG"); 451 452 const out_ext = std.fs.path.extension(full_out_path); 453 const out_pdb = coff.pdb_out_path orelse try arena.print("{s}.pdb", .{ 454 full_out_path[0 .. full_out_path.len - out_ext.len], 455 }); 456 const out_pdb_basename = std.fs.path.basename(out_pdb); 457 458 try argv.append(try arena.print("-PDB:{s}", .{out_pdb})); 459 try argv.append(try arena.print("-PDBALTPATH:{s}", .{out_pdb_basename})); 460 } 461 if (comp.version) |version| { 462 try argv.append(try arena.print("-VERSION:{d}.{d}", .{ version.major, version.minor })); 463 } 464 465 if (target_util.llvmMachineAbi(target)) |mabi| { 466 try argv.append(try arena.print("-MLLVM:-target-abi={s}", .{mabi})); 467 } 468 469 try argv.append(try arena.print("-MLLVM:-float-abi={s}", .{if (target.abi.float() == .hard) "hard" else "soft"})); 470 471 if (comp.config.lto != .none) { 472 switch (optimize_mode) { 473 .debug => {}, 474 .small => try argv.append("-OPT:lldlto=2"), 475 .fast, .safe => try argv.append("-OPT:lldlto=3"), 476 } 477 } 478 if (comp.config.output_mode == .Exe) { 479 try argv.append(try arena.print("-STACK:{d}", .{base.stack_size})); 480 } 481 try argv.append(try arena.print("-BASE:{d}", .{coff.image_base})); 482 483 switch (base.build_id) { 484 .none => try argv.append("-BUILD-ID:NO"), 485 .fast => try argv.append("-BUILD-ID"), 486 .uuid, .sha1, .md5, .hexstring => {}, 487 } 488 489 if (target.cpu.arch == .x86) { 490 try argv.append("-MACHINE:X86"); 491 } else if (target.cpu.arch == .x86_64) { 492 try argv.append("-MACHINE:X64"); 493 } else if (target.cpu.arch == .thumb) { 494 try argv.append("-MACHINE:ARM"); 495 } else if (target.cpu.arch == .aarch64) { 496 try argv.append("-MACHINE:ARM64"); 497 } 498 499 for (comp.force_undefined_symbols.keys()) |symbol| { 500 try argv.append(try arena.print("-INCLUDE:{s}", .{symbol})); 501 } 502 503 if (is_dyn_lib) { 504 try argv.append("-DLL"); 505 } 506 507 if (entry_name) |name| { 508 try argv.append(try arena.print("-ENTRY:{s}", .{name})); 509 } else if (coff.entry == .disabled) { 510 try argv.append("-NOENTRY"); 511 } 512 513 if (coff.repro) { 514 try argv.append("-BREPRO"); 515 } 516 517 if (coff.tsaware) { 518 try argv.append("-tsaware"); 519 } 520 if (coff.nxcompat) { 521 try argv.append("-nxcompat"); 522 } 523 if (!coff.dynamicbase) { 524 try argv.append("-dynamicbase:NO"); 525 } 526 if (base.allow_shlib_undefined) { 527 try argv.append("-FORCE:UNRESOLVED"); 528 } 529 530 try argv.append(try arena.print("-OUT:{s}", .{full_out_path})); 531 532 if (comp.emit_implib) |raw_emit_path| { 533 const path = try comp.resolveEmitPathFlush(arena, .artifact, raw_emit_path); 534 try argv.append(try arena.print("-IMPLIB:{f}", .{path})); 535 } 536 537 if (comp.config.link_libc) { 538 if (comp.libc_installation) |libc_installation| { 539 try argv.append(try arena.print("-LIBPATH:{s}", .{libc_installation.crt_dir.?})); 540 541 if (target.abi == .msvc or target.abi == .itanium) { 542 try argv.append(try arena.print("-LIBPATH:{s}", .{libc_installation.msvc_lib_dir.?})); 543 try argv.append(try arena.print("-LIBPATH:{s}", .{libc_installation.kernel32_lib_dir.?})); 544 } 545 } 546 } 547 548 for (coff.lib_directories) |lib_directory| { 549 try argv.append(try arena.print("-LIBPATH:{s}", .{lib_directory.path orelse "."})); 550 } 551 552 try argv.ensureUnusedCapacity(comp.link_inputs.len); 553 for (comp.link_inputs) |link_input| switch (link_input) { 554 .dso_exact => unreachable, // not applicable to PE/COFF 555 inline .dso, .res => |x| { 556 argv.appendAssumeCapacity(try x.path.toString(arena)); 557 }, 558 .object, .archive => |obj| { 559 if (obj.must_link) { 560 argv.appendAssumeCapacity(try arena.print("-WHOLEARCHIVE:{f}", .{@as(Cache.Path, obj.path)})); 561 } else { 562 argv.appendAssumeCapacity(try obj.path.toString(arena)); 563 } 564 }, 565 }; 566 567 for (comp.c_objects.items) |c_object| { 568 try argv.append(try c_object.status.success.object_path.toString(arena)); 569 } 570 571 for (comp.win32_resources.items) |win32_resource| { 572 try argv.append(win32_resource.status.success.res_path); 573 } 574 575 if (zcu_obj_path) |p| { 576 try argv.append(try p.toString(arena)); 577 } 578 579 if (coff.module_definition_file) |def| { 580 try argv.append(try arena.print("-DEF:{s}", .{def})); 581 } 582 583 const resolved_subsystem: ?std.zig.Subsystem = blk: { 584 if (coff.subsystem) |explicit| break :blk explicit; 585 switch (target.os.tag) { 586 .windows => { 587 if (comp.zcu != null) { 588 if (coff.lld_export_flags.dllmain_crt_startup or is_dyn_lib) 589 break :blk null; 590 if (coff.lld_export_flags.c_main or comp.config.is_test or 591 coff.lld_export_flags.winmain_crt_startup or 592 coff.lld_export_flags.wwinmain_crt_startup) 593 { 594 break :blk .console; 595 } 596 if (coff.lld_export_flags.winmain or coff.lld_export_flags.wwinmain) 597 break :blk .windows; 598 } 599 }, 600 .uefi => break :blk .efi_application, 601 else => {}, 602 } 603 break :blk null; 604 }; 605 606 const Mode = enum { uefi, win32 }; 607 const mode: Mode = mode: { 608 if (resolved_subsystem) |subsystem| { 609 try argv.append(try arena.print("-SUBSYSTEM:{s},{d}.{d}", .{ 610 @tagName(subsystem), 611 coff.major_subsystem_version, 612 coff.minor_subsystem_version, 613 })); 614 break :mode switch (subsystem) { 615 .console, 616 .windows, 617 .posix, 618 .native, 619 => .win32, 620 .efi_application, 621 .efi_boot_service_driver, 622 .efi_rom, 623 .efi_runtime_driver, 624 => .uefi, 625 }; 626 } else if (target.os.tag == .uefi) { 627 break :mode .uefi; 628 } else { 629 break :mode .win32; 630 } 631 }; 632 633 switch (mode) { 634 .uefi => try argv.appendSlice(&[_][]const u8{ 635 "-BASE:0", 636 "-ENTRY:EfiMain", 637 "-OPT:REF", 638 "-SAFESEH:NO", 639 "-MERGE:.rdata=.data", 640 "-NODEFAULTLIB", 641 "-SECTION:.xdata,D", 642 }), 643 .win32 => { 644 if (link_in_crt) { 645 if (target.abi.isGnu()) { 646 if (target.cpu.arch == .x86) { 647 try argv.append("-ALTERNATENAME:__image_base__=___ImageBase"); 648 } else { 649 try argv.append("-ALTERNATENAME:__image_base__=__ImageBase"); 650 } 651 652 try argv.append(try comp.crtFileAsString(arena, if (is_dyn_lib) "dllcrt2.obj" else "crt2.obj")); 653 try argv.append(try comp.crtFileAsString(arena, "libmingw32.lib")); 654 } else { 655 try argv.append(switch (comp.config.link_mode) { 656 .static => "libcmt.lib", 657 .dynamic => "msvcrt.lib", 658 }); 659 660 const lib_str = switch (comp.config.link_mode) { 661 .static => "lib", 662 .dynamic => "", 663 }; 664 try argv.append(try arena.print("{s}vcruntime.lib", .{lib_str})); 665 try argv.append(try arena.print("{s}ucrt.lib", .{lib_str})); 666 667 //Visual C++ 2015 Conformance Changes 668 //https://msdn.microsoft.com/en-us/library/bb531344.aspx 669 try argv.append("legacy_stdio_definitions.lib"); 670 671 // msvcrt depends on kernel32 and ntdll 672 try argv.append("kernel32.lib"); 673 try argv.append("ntdll.lib"); 674 } 675 } else { 676 try argv.append("-NODEFAULTLIB"); 677 if (!is_lib and entry_name == null) { 678 if (comp.zcu != null) { 679 if (coff.lld_export_flags.winmain_crt_startup) { 680 try argv.append("-ENTRY:WinMainCRTStartup"); 681 } else { 682 try argv.append("-ENTRY:wWinMainCRTStartup"); 683 } 684 } else { 685 try argv.append("-ENTRY:wWinMainCRTStartup"); 686 } 687 } 688 } 689 }, 690 } 691 692 if (comp.config.link_libc and link_in_crt) { 693 if (comp.zigc_static_lib) |zigc| { 694 try argv.append(try zigc.full_object_path.toString(arena)); 695 } 696 } 697 698 // libc++ dep 699 if (comp.config.link_libcpp) { 700 try argv.append(try comp.libcxxabi_static_lib.?.full_object_path.toString(arena)); 701 try argv.append(try comp.libcxx_static_lib.?.full_object_path.toString(arena)); 702 } 703 704 // libunwind dep 705 if (comp.config.link_libunwind) { 706 try argv.append(try comp.libunwind_static_lib.?.full_object_path.toString(arena)); 707 } 708 709 if (comp.config.any_fuzz) { 710 try argv.append(try comp.fuzzer_lib.?.full_object_path.toString(arena)); 711 } 712 713 const ubsan_rt_path: ?Cache.Path = blk: { 714 if (comp.ubsan_rt_lib) |x| break :blk x.full_object_path; 715 if (comp.ubsan_rt_obj) |x| break :blk x.full_object_path; 716 break :blk null; 717 }; 718 if (ubsan_rt_path) |path| { 719 try argv.append(try path.toString(arena)); 720 } 721 722 if (is_exe_or_dyn_lib and !comp.skip_linker_dependencies) { 723 // MSVC compiler_rt is missing some stuff, so we build it unconditionally but 724 // and rely on weak linkage to allow MSVC compiler_rt functions to override ours. 725 if (comp.compiler_rt_obj) |obj| try argv.append(try obj.full_object_path.toString(arena)); 726 if (comp.compiler_rt_lib) |lib| try argv.append(try lib.full_object_path.toString(arena)); 727 } 728 729 try argv.ensureUnusedCapacity(comp.windows_libs.count()); 730 for (comp.windows_libs.keys()) |key| { 731 const lib_basename = try arena.print("{s}.lib", .{key}); 732 if (comp.crt_files.get(lib_basename)) |crt_file| { 733 argv.appendAssumeCapacity(try crt_file.full_object_path.toString(arena)); 734 continue; 735 } 736 if (try findLib(arena, io, lib_basename, coff.lib_directories)) |full_path| { 737 argv.appendAssumeCapacity(full_path); 738 continue; 739 } 740 if (target.abi.isGnu()) { 741 const fallback_name = try arena.print("lib{s}.dll.a", .{key}); 742 if (try findLib(arena, io, fallback_name, coff.lib_directories)) |full_path| { 743 argv.appendAssumeCapacity(full_path); 744 continue; 745 } 746 } 747 if (target.abi == .msvc or target.abi == .itanium) { 748 argv.appendAssumeCapacity(lib_basename); 749 continue; 750 } 751 752 log.err("DLL import library for -l{s} not found", .{key}); 753 return error.DllImportLibraryNotFound; 754 } 755 756 try spawnLld(comp, arena, argv.items); 757 } 758 } 759 fn findLib(arena: Allocator, io: Io, name: []const u8, lib_directories: []const Cache.Directory) !?[]const u8 { 760 for (lib_directories) |lib_directory| { 761 lib_directory.handle.access(io, name, .{}) catch |err| switch (err) { 762 error.FileNotFound => continue, 763 else => |e| return e, 764 }; 765 return try lib_directory.join(arena, &.{name}); 766 } 767 return null; 768 } 769 770 fn elfLink(lld: *Lld, arena: Allocator) !void { 771 const comp = lld.base.comp; 772 const gpa = comp.gpa; 773 const io = comp.io; 774 const diags = &comp.link_diags; 775 const base = &lld.base; 776 const elf = &lld.ofmt.elf; 777 778 const directory = base.emit.root_dir; // Just an alias to make it shorter to type. 779 const full_out_path = try directory.join(arena, &[_][]const u8{base.emit.sub_path}); 780 781 const zcu_obj_path: ?Cache.Path = if (comp.zcu) |zcu| p: { 782 break :p try comp.resolveEmitPathFlush(arena, .temp, zcu.llvm_object.?.out_bin_basename); 783 } else null; 784 785 const output_mode = comp.config.output_mode; 786 const is_obj = output_mode == .Obj; 787 const is_lib = output_mode == .Lib; 788 const link_mode = comp.config.link_mode; 789 const is_dyn_lib = link_mode == .dynamic and is_lib; 790 const is_exe_or_dyn_lib = is_dyn_lib or output_mode == .Exe; 791 const target = &comp.root_mod.resolved_target.result; 792 const compiler_rt_path: ?Cache.Path = blk: { 793 if (comp.compiler_rt_lib) |x| break :blk x.full_object_path; 794 if (comp.compiler_rt_obj) |x| break :blk x.full_object_path; 795 break :blk null; 796 }; 797 const ubsan_rt_path: ?Cache.Path = blk: { 798 if (comp.ubsan_rt_lib) |x| break :blk x.full_object_path; 799 if (comp.ubsan_rt_obj) |x| break :blk x.full_object_path; 800 break :blk null; 801 }; 802 803 // Due to a deficiency in LLD, we need to special-case BPF to a simple file 804 // copy when generating relocatables. Normally, we would expect `lld -r` to work. 805 // However, because LLD wants to resolve BPF relocations which it shouldn't, it fails 806 // before even generating the relocatable. 807 // 808 // For m68k, we go through this path because LLD doesn't support it yet, but LLVM can 809 // produce usable object files. 810 if (output_mode == .Obj and 811 (comp.config.lto != .none or 812 target.cpu.arch.isBpf() or 813 target.cpu.arch == .lanai or 814 target.cpu.arch == .m68k or 815 target.cpu.arch.isSPARC() or 816 target.cpu.arch == .ve or 817 target.cpu.arch == .xcore or 818 target.cpu.arch == .xtensa)) 819 { 820 // In this case we must do a simple file copy 821 // here. TODO: think carefully about how we can avoid this redundant operation when doing 822 // build-obj. See also the corresponding TODO in linkAsArchive. 823 const the_object_path = blk: { 824 if (link.firstObjectInput(comp.link_inputs)) |obj| break :blk obj.path; 825 826 if (comp.c_objects.items.len != 0) 827 break :blk comp.c_objects.items[0].status.success.object_path; 828 829 if (zcu_obj_path) |p| 830 break :blk p; 831 832 // TODO I think this is unreachable. Audit this situation when solving the above TODO 833 // regarding eliding redundant object -> object transformations. 834 return error.NoObjectsToLink; 835 }; 836 try Io.Dir.copyFile( 837 the_object_path.root_dir.handle, 838 the_object_path.sub_path, 839 directory.handle, 840 base.emit.sub_path, 841 io, 842 .{}, 843 ); 844 } else { 845 // Create an LLD command line and invoke it. 846 var argv = std.array_list.Managed([]const u8).init(gpa); 847 defer argv.deinit(); 848 // We will invoke ourselves as a child process to gain access to LLD. 849 // This is necessary because LLD does not behave properly as a library - 850 // it calls exit() and does not reset all global data between invocations. 851 const linker_command = "ld.lld"; 852 try argv.appendSlice(&[_][]const u8{ comp.self_exe_path.?, linker_command }); 853 try addCommonArgs(&argv, false); 854 855 if (is_obj) { 856 try argv.append("-r"); 857 } 858 859 try argv.append("--error-limit=0"); 860 861 if (comp.sysroot) |sysroot| { 862 try argv.append(try arena.print("--sysroot={s}", .{sysroot})); 863 } 864 865 if (target_util.llvmMachineAbi(target)) |mabi| { 866 try argv.appendSlice(&.{ 867 "-mllvm", 868 try arena.print("-target-abi={s}", .{mabi}), 869 }); 870 } 871 872 try argv.appendSlice(&.{ 873 "-mllvm", 874 try arena.print("-float-abi={s}", .{if (target.abi.float() == .hard) "hard" else "soft"}), 875 }); 876 877 switch (target.cpu.arch) { 878 .armeb, .thumbeb => if (is_exe_or_dyn_lib and target.cpu.has(.arm, .has_v6)) try argv.append("--be8"), 879 else => {}, 880 } 881 882 if (comp.config.lto != .none) { 883 switch (comp.root_mod.optimize_mode) { 884 .debug => {}, 885 .small => try argv.append("--lto-O2"), 886 .fast, .safe => try argv.append("--lto-O3"), 887 } 888 } 889 switch (comp.root_mod.optimize_mode) { 890 .debug => {}, 891 .small => try argv.append("-O2"), 892 .fast, .safe => try argv.append("-O3"), 893 } 894 895 if (elf.entry_name) |name| { 896 try argv.appendSlice(&.{ "--entry", name }); 897 } 898 899 for (comp.force_undefined_symbols.keys()) |sym| { 900 try argv.append("-u"); 901 try argv.append(sym); 902 } 903 904 switch (elf.hash_style) { 905 .gnu => try argv.append("--hash-style=gnu"), 906 .sysv => try argv.append("--hash-style=sysv"), 907 .both => {}, // this is the default 908 } 909 910 if (output_mode == .Exe) { 911 try argv.appendSlice(&.{ 912 "-z", 913 try arena.print("stack-size={d}", .{base.stack_size}), 914 }); 915 } 916 917 switch (base.build_id) { 918 .none => try argv.append("--build-id=none"), 919 .fast, .uuid, .sha1, .md5 => try argv.append(try arena.print("--build-id={s}", .{ 920 @tagName(base.build_id), 921 })), 922 .hexstring => |hs| try argv.append(try arena.print("--build-id=0x{x}", .{hs.toSlice()})), 923 } 924 925 try argv.append(try arena.print("--image-base={d}", .{elf.image_base})); 926 927 if (elf.linker_script) |linker_script| { 928 try argv.append("-T"); 929 try argv.append(try linker_script.toString(arena)); 930 } 931 932 if (elf.sort_section) |how| { 933 const arg = try arena.print("--sort-section={s}", .{@tagName(how)}); 934 try argv.append(arg); 935 } 936 937 if (base.gc_sections) { 938 try argv.append("--gc-sections"); 939 } 940 941 if (base.print_gc_sections) { 942 try argv.append("--print-gc-sections"); 943 } 944 945 if (elf.print_icf_sections) { 946 try argv.append("--print-icf-sections"); 947 } 948 949 if (elf.print_map) { 950 try argv.append("--print-map"); 951 } 952 953 if (elf.nmagic) { 954 try argv.append("--nmagic"); 955 } 956 957 if (elf.fatal_warnings) { 958 try argv.append("--fatal-warnings"); 959 } 960 961 if (comp.link_eh_frame_hdr) { 962 try argv.append("--eh-frame-hdr"); 963 } 964 965 if (elf.emit_relocs) { 966 try argv.append("--emit-relocs"); 967 } 968 969 if (comp.config.rdynamic) { 970 try argv.append("--export-dynamic"); 971 } 972 973 if (comp.config.debug_format == .strip) { 974 try argv.append("-s"); 975 } 976 977 if (elf.z_nodelete) { 978 try argv.append("-z"); 979 try argv.append("nodelete"); 980 } 981 if (elf.z_notext) { 982 try argv.append("-z"); 983 try argv.append("notext"); 984 } 985 if (elf.z_defs) { 986 try argv.append("-z"); 987 try argv.append("defs"); 988 } 989 if (elf.z_origin) { 990 try argv.append("-z"); 991 try argv.append("origin"); 992 } 993 if (elf.z_nocopyreloc) { 994 try argv.append("-z"); 995 try argv.append("nocopyreloc"); 996 } 997 if (elf.z_now) { 998 // LLD defaults to -zlazy 999 try argv.append("-znow"); 1000 } 1001 if (!elf.z_relro) { 1002 // LLD defaults to -zrelro 1003 try argv.append("-znorelro"); 1004 } 1005 if (elf.z_common_page_size) |size| { 1006 try argv.append("-z"); 1007 try argv.append(try arena.print("common-page-size={d}", .{size})); 1008 } 1009 if (elf.z_max_page_size) |size| { 1010 try argv.append("-z"); 1011 try argv.append(try arena.print("max-page-size={d}", .{size})); 1012 } 1013 1014 if (getLDMOption(target)) |ldm| { 1015 try argv.append("-m"); 1016 try argv.append(ldm); 1017 } 1018 1019 if (link_mode == .static) { 1020 if (target.cpu.arch.isArm()) { 1021 try argv.append("-Bstatic"); 1022 } else { 1023 try argv.append("-static"); 1024 } 1025 } else if (switch (target.os.tag) { 1026 else => is_dyn_lib, 1027 .haiku => is_exe_or_dyn_lib, 1028 }) { 1029 try argv.append("-shared"); 1030 } 1031 1032 if (comp.config.pie and output_mode == .Exe) { 1033 try argv.append("-pie"); 1034 } 1035 1036 if (is_exe_or_dyn_lib and target.os.tag == .netbsd) { 1037 // Add options to produce shared objects with only 2 PT.LOAD segments. 1038 // NetBSD expects 2 PT.LOAD segments in a shared object, otherwise 1039 // ld.elf_so fails loading dynamic libraries with "not found" error. 1040 // See https://github.com/ziglang/zig/issues/9109 . 1041 try argv.append("--no-rosegment"); 1042 try argv.append("-znorelro"); 1043 } 1044 1045 try argv.append("-o"); 1046 try argv.append(full_out_path); 1047 1048 // csu prelude 1049 const csu = try comp.getCrtPaths(arena); 1050 if (csu.crt0) |p| try argv.append(try p.toString(arena)); 1051 if (csu.crti) |p| try argv.append(try p.toString(arena)); 1052 if (csu.crtbegin) |p| try argv.append(try p.toString(arena)); 1053 1054 for (elf.rpath_list) |rpath| { 1055 try argv.appendSlice(&.{ "-rpath", rpath }); 1056 } 1057 1058 for (elf.symbol_wrap_set) |symbol_name| { 1059 try argv.appendSlice(&.{ "-wrap", symbol_name }); 1060 } 1061 1062 if (comp.config.link_libc) { 1063 if (comp.libc_installation) |libc_installation| { 1064 try argv.append("-L"); 1065 try argv.append(libc_installation.crt_dir.?); 1066 } 1067 } 1068 1069 if (output_mode == .Exe and link_mode == .dynamic) { 1070 if (target.dynamic_linker.get()) |dynamic_linker| { 1071 try argv.append("--dynamic-linker"); 1072 try argv.append(dynamic_linker); 1073 } else { 1074 try argv.append("--no-dynamic-linker"); 1075 } 1076 } 1077 1078 if (is_dyn_lib) { 1079 if (elf.soname) |soname| { 1080 try argv.append("-soname"); 1081 try argv.append(soname); 1082 } 1083 if (elf.version_script) |version_script| { 1084 try argv.append("-version-script"); 1085 try argv.append(try version_script.toString(arena)); 1086 } 1087 if (elf.allow_undefined_version) { 1088 try argv.append("--undefined-version"); 1089 } else { 1090 try argv.append("--no-undefined-version"); 1091 } 1092 if (elf.enable_new_dtags) |enable_new_dtags| { 1093 if (enable_new_dtags) { 1094 try argv.append("--enable-new-dtags"); 1095 } else { 1096 try argv.append("--disable-new-dtags"); 1097 } 1098 } 1099 } 1100 1101 // Positional arguments to the linker such as object files. 1102 var whole_archive = false; 1103 1104 for (base.comp.link_inputs) |link_input| switch (link_input) { 1105 .res => unreachable, // Windows-only 1106 .dso => continue, 1107 .object, .archive => |obj| { 1108 if (obj.must_link and !whole_archive) { 1109 try argv.append("--whole-archive"); 1110 whole_archive = true; 1111 } else if (!obj.must_link and whole_archive) { 1112 try argv.append("--no-whole-archive"); 1113 whole_archive = false; 1114 } 1115 try argv.append(try obj.path.toString(arena)); 1116 }, 1117 .dso_exact => |dso_exact| { 1118 assert(dso_exact.name[0] == ':'); 1119 try argv.appendSlice(&.{ "-l", dso_exact.name }); 1120 }, 1121 }; 1122 1123 if (whole_archive) { 1124 try argv.append("--no-whole-archive"); 1125 whole_archive = false; 1126 } 1127 1128 for (comp.c_objects.items) |c_object| { 1129 try argv.append(try c_object.status.success.object_path.toString(arena)); 1130 } 1131 1132 if (zcu_obj_path) |p| { 1133 try argv.append(try p.toString(arena)); 1134 } 1135 1136 if (comp.tsan_lib) |lib| { 1137 assert(comp.config.any_sanitize_thread); 1138 try argv.appendSlice(&.{ 1139 "--whole-archive", 1140 try lib.full_object_path.toString(arena), 1141 "--no-whole-archive", 1142 }); 1143 } 1144 1145 if (comp.fuzzer_lib) |lib| { 1146 assert(comp.config.any_fuzz); 1147 try argv.append(try lib.full_object_path.toString(arena)); 1148 } 1149 1150 if (ubsan_rt_path) |p| { 1151 try argv.append(try p.toString(arena)); 1152 } 1153 1154 // Shared libraries. 1155 if (is_exe_or_dyn_lib) { 1156 // Worst-case, we need an --as-needed argument for every lib, as well 1157 // as one before and one after. 1158 try argv.ensureUnusedCapacity(2 * base.comp.link_inputs.len + 2); 1159 argv.appendAssumeCapacity("--as-needed"); 1160 var as_needed = true; 1161 1162 for (base.comp.link_inputs) |link_input| switch (link_input) { 1163 .res => unreachable, // Windows-only 1164 .object, .archive, .dso_exact => continue, 1165 .dso => |dso| { 1166 const lib_as_needed = !dso.needed; 1167 switch ((@as(u2, @intFromBool(lib_as_needed)) << 1) | @intFromBool(as_needed)) { 1168 0b00, 0b11 => {}, 1169 0b01 => { 1170 argv.appendAssumeCapacity("--no-as-needed"); 1171 as_needed = false; 1172 }, 1173 0b10 => { 1174 argv.appendAssumeCapacity("--as-needed"); 1175 as_needed = true; 1176 }, 1177 } 1178 1179 // By this time, we depend on these libs being dynamically linked 1180 // libraries and not static libraries (the check for that needs to be earlier), 1181 // but they could be full paths to .so files, in which case we 1182 // want to avoid prepending "-l". 1183 argv.appendAssumeCapacity(try dso.path.toString(arena)); 1184 }, 1185 }; 1186 1187 if (!as_needed) { 1188 argv.appendAssumeCapacity("--as-needed"); 1189 as_needed = true; 1190 } 1191 1192 // libc++ dep 1193 if (comp.config.link_libcpp) { 1194 try argv.append(try comp.libcxxabi_static_lib.?.full_object_path.toString(arena)); 1195 try argv.append(try comp.libcxx_static_lib.?.full_object_path.toString(arena)); 1196 } 1197 1198 // libunwind dep 1199 if (comp.config.link_libunwind) { 1200 try argv.append(try comp.libunwind_static_lib.?.full_object_path.toString(arena)); 1201 } 1202 1203 // libc dep 1204 diags.flags.missing_libc = false; 1205 if (comp.config.link_libc) { 1206 if (comp.libc_installation != null) { 1207 const needs_grouping = link_mode == .static; 1208 if (needs_grouping) try argv.append("--start-group"); 1209 try argv.appendSlice(target_util.libcFullLinkFlags(target)); 1210 if (needs_grouping) try argv.append("--end-group"); 1211 } else if (target.isGnuLibC()) { 1212 for (glibc.libs) |lib| { 1213 if (lib.removed_in) |rem_in| { 1214 if (target.os.versionRange().gnuLibCVersion().?.order(rem_in) != .lt) continue; 1215 } 1216 1217 const lib_path = try arena.print("{f}{c}lib{s}.so.{d}", .{ 1218 comp.glibc_so_files.?.dir_path, fs.path.sep, lib.name, lib.sover, 1219 }); 1220 try argv.append(lib_path); 1221 } 1222 try argv.append(try comp.crtFileAsString(arena, "libc_nonshared.a")); 1223 } else if (target.isMuslLibC()) { 1224 try argv.append(try comp.crtFileAsString(arena, switch (link_mode) { 1225 .static => "libc.a", 1226 .dynamic => "libc.so", 1227 })); 1228 } else if (target.isFreeBSDLibC()) { 1229 for (freebsd.libs) |lib| { 1230 if (lib.added_in) |add_in| { 1231 if (target.os.version_range.semver.min.order(add_in) == .lt) continue; 1232 } 1233 1234 const lib_path = try arena.print("{f}{c}lib{s}.so.{d}", .{ 1235 comp.freebsd_so_files.?.dir_path, fs.path.sep, lib.name, lib.getSoVersion(&target.os), 1236 }); 1237 try argv.append(lib_path); 1238 } 1239 } else if (target.isNetBSDLibC()) { 1240 for (netbsd.libs) |lib| { 1241 const lib_path = try arena.print("{f}{c}lib{s}.so.{d}", .{ 1242 comp.netbsd_so_files.?.dir_path, fs.path.sep, lib.name, lib.sover, 1243 }); 1244 try argv.append(lib_path); 1245 } 1246 } else if (target.isOpenBSDLibC()) { 1247 for (openbsd.libs) |lib| { 1248 const lib_path = try arena.print("{f}{c}lib{s}.so", .{ 1249 comp.openbsd_so_files.?.dir_path, fs.path.sep, lib.name, 1250 }); 1251 try argv.append(lib_path); 1252 } 1253 } else { 1254 diags.flags.missing_libc = true; 1255 } 1256 1257 if (comp.zigc_static_lib) |zigc| { 1258 try argv.append(try zigc.full_object_path.toString(arena)); 1259 } 1260 } 1261 } 1262 1263 // compiler-rt. Since compiler_rt exports symbols like `memset`, it needs 1264 // to be after the shared libraries, so they are picked up from the shared 1265 // libraries, not libcompiler_rt. 1266 if (compiler_rt_path) |p| { 1267 try argv.append(try p.toString(arena)); 1268 } 1269 1270 // crt postlude 1271 if (csu.crtend) |p| try argv.append(try p.toString(arena)); 1272 if (csu.crtn) |p| try argv.append(try p.toString(arena)); 1273 1274 if (base.allow_shlib_undefined) { 1275 try argv.append("--allow-shlib-undefined"); 1276 } 1277 1278 switch (elf.compress_debug_sections) { 1279 .none => {}, 1280 .zlib => try argv.append("--compress-debug-sections=zlib"), 1281 .zstd => try argv.append("--compress-debug-sections=zstd"), 1282 } 1283 1284 if (elf.bind_global_refs_locally) { 1285 try argv.append("-Bsymbolic"); 1286 } 1287 1288 try spawnLld(comp, arena, argv.items); 1289 } 1290 } 1291 fn getLDMOption(target: *const std.Target) ?[]const u8 { 1292 // This should only return emulations understood by LLD's parseEmulation(). 1293 return switch (target.cpu.arch) { 1294 .aarch64 => switch (target.os.tag) { 1295 .linux => "aarch64linux", 1296 else => "aarch64elf", 1297 }, 1298 .aarch64_be => switch (target.os.tag) { 1299 .linux => "aarch64linuxb", 1300 else => "aarch64elfb", 1301 }, 1302 .amdgcn => "elf64_amdgpu", 1303 .arm, .thumb => switch (target.os.tag) { 1304 .linux => "armelf_linux_eabi", 1305 else => "armelf", 1306 }, 1307 .armeb, .thumbeb => switch (target.os.tag) { 1308 .linux => "armelfb_linux_eabi", 1309 else => "armelfb", 1310 }, 1311 .hexagon => "hexagonelf", 1312 .loongarch32 => "elf32loongarch", 1313 .loongarch64 => "elf64loongarch", 1314 .mips => switch (target.os.tag) { 1315 .freebsd => "elf32btsmip_fbsd", 1316 else => "elf32btsmip", 1317 }, 1318 .mipsel => switch (target.os.tag) { 1319 .freebsd => "elf32ltsmip_fbsd", 1320 else => "elf32ltsmip", 1321 }, 1322 .mips64 => switch (target.os.tag) { 1323 .freebsd => switch (target.abi) { 1324 .gnuabin32, .muslabin32, .abin32 => "elf32btsmipn32_fbsd", 1325 else => "elf64btsmip_fbsd", 1326 }, 1327 else => switch (target.abi) { 1328 .gnuabin32, .muslabin32, .abin32 => "elf32btsmipn32", 1329 else => "elf64btsmip", 1330 }, 1331 }, 1332 .mips64el => switch (target.os.tag) { 1333 .freebsd => switch (target.abi) { 1334 .gnuabin32, .muslabin32, .abin32 => "elf32ltsmipn32_fbsd", 1335 else => "elf64ltsmip_fbsd", 1336 }, 1337 else => switch (target.abi) { 1338 .gnuabin32, .muslabin32, .abin32 => "elf32ltsmipn32", 1339 else => "elf64ltsmip", 1340 }, 1341 }, 1342 .msp430 => "msp430elf", 1343 .powerpc => switch (target.os.tag) { 1344 .freebsd => "elf32ppc_fbsd", 1345 .linux => "elf32ppclinux", 1346 else => "elf32ppc", 1347 }, 1348 .powerpcle => switch (target.os.tag) { 1349 .linux => "elf32lppclinux", 1350 else => "elf32lppc", 1351 }, 1352 .powerpc64 => "elf64ppc", 1353 .powerpc64le => "elf64lppc", 1354 .riscv32 => "elf32lriscv", 1355 .riscv32be => "elf32briscv", 1356 .riscv64 => "elf64lriscv", 1357 .riscv64be => "elf64briscv", 1358 .s390x => "elf64_s390", 1359 .sparc64 => "elf64_sparc", 1360 .x86 => switch (target.os.tag) { 1361 .freebsd => "elf_i386_fbsd", 1362 else => "elf_i386", 1363 }, 1364 .x86_64 => switch (target.abi) { 1365 .gnux32, .muslx32, .x32 => "elf32_x86_64", 1366 else => "elf_x86_64", 1367 }, 1368 else => null, 1369 }; 1370 } 1371 fn wasmLink(lld: *Lld, arena: Allocator) !void { 1372 const comp = lld.base.comp; 1373 const diags = &comp.link_diags; 1374 const shared_memory = comp.config.shared_memory; 1375 const export_memory = comp.config.export_memory; 1376 const import_memory = comp.config.import_memory; 1377 const target = &comp.root_mod.resolved_target.result; 1378 const base = &lld.base; 1379 const wasm = &lld.ofmt.wasm; 1380 1381 const gpa = comp.gpa; 1382 const io = comp.io; 1383 1384 const directory = base.emit.root_dir; // Just an alias to make it shorter to type. 1385 const full_out_path = try directory.join(arena, &[_][]const u8{base.emit.sub_path}); 1386 1387 const zcu_obj_path: ?Cache.Path = if (comp.zcu) |zcu| p: { 1388 break :p try comp.resolveEmitPathFlush(arena, .temp, zcu.llvm_object.?.out_bin_basename); 1389 } else null; 1390 1391 const is_obj = comp.config.output_mode == .Obj; 1392 const compiler_rt_path: ?Cache.Path = blk: { 1393 if (comp.compiler_rt_lib) |lib| break :blk lib.full_object_path; 1394 if (comp.compiler_rt_obj) |obj| break :blk obj.full_object_path; 1395 break :blk null; 1396 }; 1397 const ubsan_rt_path: ?Cache.Path = blk: { 1398 if (comp.ubsan_rt_lib) |lib| break :blk lib.full_object_path; 1399 if (comp.ubsan_rt_obj) |obj| break :blk obj.full_object_path; 1400 break :blk null; 1401 }; 1402 1403 if (is_obj) { 1404 // LLD's WASM driver does not support the equivalent of `-r` so we do a simple file copy 1405 // here. TODO: think carefully about how we can avoid this redundant operation when doing 1406 // build-obj. See also the corresponding TODO in linkAsArchive. 1407 const the_object_path = blk: { 1408 if (link.firstObjectInput(comp.link_inputs)) |obj| break :blk obj.path; 1409 1410 if (comp.c_objects.items.len != 0) 1411 break :blk comp.c_objects.items[0].status.success.object_path; 1412 1413 if (zcu_obj_path) |p| 1414 break :blk p; 1415 1416 // TODO I think this is unreachable. Audit this situation when solving the above TODO 1417 // regarding eliding redundant object -> object transformations. 1418 return error.NoObjectsToLink; 1419 }; 1420 try Io.Dir.copyFile( 1421 the_object_path.root_dir.handle, 1422 the_object_path.sub_path, 1423 directory.handle, 1424 base.emit.sub_path, 1425 io, 1426 .{}, 1427 ); 1428 } else { 1429 // Create an LLD command line and invoke it. 1430 var argv = std.array_list.Managed([]const u8).init(gpa); 1431 defer argv.deinit(); 1432 // We will invoke ourselves as a child process to gain access to LLD. 1433 // This is necessary because LLD does not behave properly as a library - 1434 // it calls exit() and does not reset all global data between invocations. 1435 const linker_command = "wasm-ld"; 1436 try argv.appendSlice(&[_][]const u8{ comp.self_exe_path.?, linker_command }); 1437 try addCommonArgs(&argv, false); 1438 1439 try argv.append("--error-limit=0"); 1440 1441 if (comp.config.lto != .none) { 1442 switch (comp.root_mod.optimize_mode) { 1443 .debug => {}, 1444 .small => try argv.append("-O2"), 1445 .fast, .safe => try argv.append("-O3"), 1446 } 1447 } 1448 1449 if (import_memory) { 1450 try argv.append("--import-memory"); 1451 } 1452 1453 if (export_memory) { 1454 try argv.append("--export-memory"); 1455 } 1456 1457 if (wasm.import_table) { 1458 assert(!wasm.export_table); 1459 try argv.append("--import-table"); 1460 } 1461 1462 if (wasm.export_table) { 1463 assert(!wasm.import_table); 1464 try argv.append("--export-table"); 1465 } 1466 1467 if (wasm.growable_table) { 1468 try argv.append("--growable-table"); 1469 } 1470 1471 // For wasm-ld we only need to specify '--no-gc-sections' when the user explicitly 1472 // specified it as garbage collection is enabled by default. 1473 if (!base.gc_sections) { 1474 try argv.append("--no-gc-sections"); 1475 } 1476 1477 if (comp.config.debug_format == .strip) { 1478 try argv.append("-s"); 1479 } 1480 1481 if (wasm.initial_memory) |initial_memory| { 1482 const arg = try arena.print("--initial-memory={d}", .{initial_memory}); 1483 try argv.append(arg); 1484 } 1485 1486 if (wasm.max_memory) |max_memory| { 1487 const arg = try arena.print("--max-memory={d}", .{max_memory}); 1488 try argv.append(arg); 1489 } 1490 1491 if (shared_memory) { 1492 try argv.append("--shared-memory"); 1493 } 1494 1495 if (wasm.global_base) |global_base| { 1496 const arg = try arena.print("--global-base={d}", .{global_base}); 1497 try argv.append(arg); 1498 } else { 1499 // We prepend it by default, so when a stack overflow happens the runtime will trap correctly, 1500 // rather than silently overwrite all global declarations. See https://github.com/ziglang/zig/issues/4496 1501 // 1502 // The user can overwrite this behavior by setting the global-base 1503 try argv.append("--stack-first"); 1504 } 1505 1506 // Users are allowed to specify which symbols they want to export to the wasm host. 1507 for (wasm.export_symbol_names) |symbol_name| { 1508 const arg = try arena.print("--export={s}", .{symbol_name}); 1509 try argv.append(arg); 1510 } 1511 1512 if (comp.config.rdynamic) { 1513 try argv.append("--export-dynamic"); 1514 } 1515 1516 if (wasm.entry_name) |entry_name| { 1517 try argv.appendSlice(&.{ "--entry", entry_name }); 1518 } else { 1519 try argv.append("--no-entry"); 1520 } 1521 1522 try argv.appendSlice(&.{ 1523 "-z", 1524 try arena.print("stack-size={d}", .{base.stack_size}), 1525 }); 1526 1527 switch (base.build_id) { 1528 .none => try argv.append("--build-id=none"), 1529 .fast, .uuid, .sha1 => try argv.append(try arena.print("--build-id={s}", .{ 1530 @tagName(base.build_id), 1531 })), 1532 .hexstring => |hs| try argv.append(try arena.print("--build-id=0x{x}", .{hs.toSlice()})), 1533 .md5 => {}, 1534 } 1535 1536 if (wasm.import_symbols) { 1537 try argv.append("--allow-undefined"); 1538 } 1539 1540 if (comp.config.output_mode == .Lib and comp.config.link_mode == .dynamic) { 1541 try argv.append("--shared"); 1542 } 1543 if (comp.config.pie) { 1544 try argv.append("--pie"); 1545 } 1546 1547 try argv.appendSlice(&.{ "-o", full_out_path }); 1548 1549 if (target.cpu.arch == .wasm64) { 1550 try argv.append("-mwasm64"); 1551 } 1552 1553 const is_exe_or_dyn_lib = comp.config.output_mode == .Exe or 1554 (comp.config.output_mode == .Lib and comp.config.link_mode == .dynamic); 1555 1556 if (comp.config.link_libc and is_exe_or_dyn_lib) { 1557 if (target.os.tag == .wasi) { 1558 try argv.append(try comp.crtFileAsString( 1559 arena, 1560 wasi_libc.execModelCrtFileFullName(comp.config.wasi_exec_model), 1561 )); 1562 try argv.append(try comp.crtFileAsString(arena, "libc.a")); 1563 } 1564 1565 if (comp.zigc_static_lib) |zigc| { 1566 try argv.append(try zigc.full_object_path.toString(arena)); 1567 } 1568 1569 if (comp.config.link_libcpp) { 1570 try argv.append(try comp.libcxx_static_lib.?.full_object_path.toString(arena)); 1571 try argv.append(try comp.libcxxabi_static_lib.?.full_object_path.toString(arena)); 1572 } 1573 } 1574 1575 // Positional arguments to the linker such as object files. 1576 var whole_archive = false; 1577 for (comp.link_inputs) |link_input| switch (link_input) { 1578 .object, .archive => |obj| { 1579 if (obj.must_link and !whole_archive) { 1580 try argv.append("--whole-archive"); 1581 whole_archive = true; 1582 } else if (!obj.must_link and whole_archive) { 1583 try argv.append("--no-whole-archive"); 1584 whole_archive = false; 1585 } 1586 try argv.append(try obj.path.toString(arena)); 1587 }, 1588 .dso => |dso| { 1589 try argv.append(try dso.path.toString(arena)); 1590 }, 1591 .dso_exact => unreachable, 1592 .res => unreachable, 1593 }; 1594 if (whole_archive) { 1595 try argv.append("--no-whole-archive"); 1596 whole_archive = false; 1597 } 1598 1599 for (comp.c_objects.items) |c_object| { 1600 try argv.append(try c_object.status.success.object_path.toString(arena)); 1601 } 1602 if (zcu_obj_path) |p| { 1603 try argv.append(try p.toString(arena)); 1604 } 1605 1606 if (compiler_rt_path) |p| { 1607 try argv.append(try p.toString(arena)); 1608 } 1609 1610 if (ubsan_rt_path) |p| { 1611 try argv.append(try p.toStringZ(arena)); 1612 } 1613 1614 try spawnLld(comp, arena, argv.items); 1615 1616 // Give +x to the .wasm file if it is an executable and the OS is WASI. 1617 // Some systems may be configured to execute such binaries directly. Even if that 1618 // is not the case, it means we will get "exec format error" when trying to run 1619 // it, and then can react to that in the same way as trying to run an ELF file 1620 // from a foreign CPU architecture. 1621 if (Io.File.Permissions.has_executable_bit and target.os.tag == .wasi and 1622 comp.config.output_mode == .Exe) 1623 { 1624 // chmod does not interact with umask, so we use a conservative -rwxr--r-- here. 1625 Io.Dir.cwd().setFilePermissions(io, full_out_path, .fromMode(0o744), .{}) catch |err| 1626 return diags.fail("{s}: failed to enable executable permissions: {t}", .{ full_out_path, err }); 1627 } 1628 } 1629 } 1630 1631 fn spawnLld(comp: *Compilation, arena: Allocator, argv: []const []const u8) !void { 1632 const io = comp.io; 1633 const gpa = comp.gpa; 1634 1635 if (comp.verbose_link) { 1636 // Skip over our own name so that the LLD linker name is the first argv item. 1637 try Compilation.dumpArgv(io, argv[1..]); 1638 } 1639 1640 // If possible, we run LLD as a child process because it does not always 1641 // behave properly as a library, unfortunately. 1642 // https://github.com/ziglang/zig/issues/3825 1643 if (!std.process.can_spawn) { 1644 const exit_code = try lldMain(arena, argv, false); 1645 if (exit_code == 0) return; 1646 if (comp.clang_passthrough_mode) std.process.exit(exit_code); 1647 return error.AlreadyReported; 1648 } 1649 1650 var stderr: []u8 = &.{}; 1651 defer gpa.free(stderr); 1652 1653 // TODO rework this awkward logic to call child.kill() in the failure case 1654 const term = (if (comp.clang_passthrough_mode) term: { 1655 var child = std.process.spawn(io, .{ 1656 .argv = argv, 1657 .stdin = .inherit, 1658 .stdout = .inherit, 1659 .stderr = .inherit, 1660 }) catch |err| break :term err; 1661 1662 break :term child.wait(io); 1663 } else term: { 1664 var child = std.process.spawn(io, .{ 1665 .argv = argv, 1666 .stdin = .ignore, 1667 .stdout = .ignore, 1668 .stderr = .pipe, 1669 }) catch |err| break :term err; 1670 1671 var stderr_reader = child.stderr.?.readerStreaming(io, &.{}); 1672 stderr = stderr_reader.interface.allocRemaining(gpa, .unlimited) catch |err| switch (err) { 1673 error.StreamTooLong => unreachable, // unlimited 1674 error.OutOfMemory => |e| return e, 1675 error.ReadFailed => return stderr_reader.err.?, 1676 }; 1677 break :term child.wait(io); 1678 }) catch |first_err| term: { 1679 const err = switch (first_err) { 1680 error.NameTooLong => err: { 1681 const s = fs.path.sep_str; 1682 const rand_int = r: { 1683 var x: u64 = undefined; 1684 io.random(@ptrCast(&x)); 1685 break :r x; 1686 }; 1687 const rsp_path = "tmp" ++ s ++ std.fmt.hex(rand_int) ++ ".rsp"; 1688 1689 const rsp_file = try comp.dirs.local_cache.handle.createFile(io, rsp_path, .{}); 1690 defer comp.dirs.local_cache.handle.deleteFile(io, rsp_path) catch |err| 1691 log.warn("failed to delete response file {s}: {t}", .{ rsp_path, err }); 1692 { 1693 defer rsp_file.close(io); 1694 var rsp_file_buffer: [1024]u8 = undefined; 1695 var rsp_file_writer = rsp_file.writer(io, &rsp_file_buffer); 1696 const rsp_writer = &rsp_file_writer.interface; 1697 for (argv[2..]) |arg| { 1698 try rsp_writer.writeByte('"'); 1699 for (arg) |c| { 1700 switch (c) { 1701 '\"', '\\' => try rsp_writer.writeByte('\\'), 1702 else => {}, 1703 } 1704 try rsp_writer.writeByte(c); 1705 } 1706 try rsp_writer.writeByte('"'); 1707 try rsp_writer.writeByte('\n'); 1708 } 1709 try rsp_writer.flush(); 1710 } 1711 1712 var rsp_child = std.process.spawn(io, .{ 1713 .argv = &.{ 1714 argv[0], 1715 argv[1], 1716 try arena.print("@{s}", .{ 1717 try comp.dirs.local_cache.join(arena, &.{rsp_path}), 1718 }), 1719 }, 1720 .stdin = if (comp.clang_passthrough_mode) .inherit else .ignore, 1721 .stdout = if (comp.clang_passthrough_mode) .inherit else .ignore, 1722 .stderr = if (comp.clang_passthrough_mode) .inherit else .pipe, 1723 }) catch |err| break :err err; 1724 if (comp.clang_passthrough_mode) { 1725 break :term rsp_child.wait(io) catch |err| break :err err; 1726 } else { 1727 var stderr_reader = rsp_child.stderr.?.readerStreaming(io, &.{}); 1728 stderr = stderr_reader.interface.allocRemaining(gpa, .unlimited) catch |err| switch (err) { 1729 error.StreamTooLong => unreachable, // unlimited 1730 error.OutOfMemory => |e| return e, 1731 error.ReadFailed => return stderr_reader.err.?, 1732 }; 1733 break :term rsp_child.wait(io) catch |err| break :err err; 1734 } 1735 }, 1736 else => first_err, 1737 }; 1738 log.err("unable to spawn LLD {s}: {t}", .{ argv[0], err }); 1739 return error.UnableToSpawnSelf; 1740 }; 1741 1742 const diags = &comp.link_diags; 1743 switch (term) { 1744 .exited => |code| if (code != 0) { 1745 if (comp.clang_passthrough_mode) std.process.exit(code); 1746 diags.lockAndParseLldStderr(argv[1], stderr); 1747 return error.AlreadyReported; 1748 }, 1749 .signal => |sig| { 1750 if (comp.clang_passthrough_mode) std.process.abort(); 1751 return diags.fail("{s} terminated with signal {t} and stderr:\n{s}", .{ argv[0], sig, stderr }); 1752 }, 1753 .stopped => |sig| { 1754 if (comp.clang_passthrough_mode) std.process.abort(); 1755 return diags.fail("{s} stopped with signal {t} and stderr:\n{s}", .{ argv[0], sig, stderr }); 1756 }, 1757 .unknown => |code| { 1758 if (comp.clang_passthrough_mode) std.process.abort(); 1759 return diags.fail("{s} terminated for unknown reason with code {d} and stderr:\n{s}", .{ argv[0], code, stderr }); 1760 }, 1761 } 1762 1763 if (stderr.len > 0) log.warn("unexpected LLD stderr:\n{s}", .{stderr}); 1764 } 1765 1766 const builtin = @import("builtin"); 1767 const std = @import("std"); 1768 const Io = std.Io; 1769 const Allocator = std.mem.Allocator; 1770 const Cache = std.Build.Cache; 1771 const assert = std.debug.assert; 1772 const fs = std.fs; 1773 const log = std.log.scoped(.link); 1774 const mem = std.mem; 1775 1776 const Compilation = @import("../Compilation.zig"); 1777 const Zcu = @import("../Zcu.zig"); 1778 const dev = @import("../dev.zig"); 1779 const freebsd = @import("../libs/freebsd.zig"); 1780 const glibc = @import("../libs/glibc.zig"); 1781 const netbsd = @import("../libs/netbsd.zig"); 1782 const openbsd = @import("../libs/openbsd.zig"); 1783 const wasi_libc = @import("../libs/wasi_libc.zig"); 1784 const link = @import("../link.zig"); 1785 const lldMain = @import("../main.zig").lldMain; 1786 const target_util = @import("../target.zig"); 1787 const trace = @import("../tracy.zig").trace; 1788 const Lld = @This(); 1789