| author | |
| committer | |
| log | 22a22ceaeb3f693207fc4821b55959ba0732d7ed |
| tree | feb6df740e4d0a2fbe767b48d92518484bb57619 |
| parent | 2be291c98773e25d4a47e5c35744084627d11f15 |
- Add MappedFile.realign
- Fix the case of MappedFile.addNode adding a node in between nodes that have lower alignment than it (by realigning the following node)
- Fixup the capacity reservation in addNode to occur after the resize (which may have consumed that capacity)
- Remove incorrect path in `.load_host_libc` that was loading mingw libs, they were already being loaded via their build tasks
- Generate mingw implibs as a prelink task, so they can be supplied to the linker before prelink()
- Any other libraries discovered during Sema are have their implibs generated after, but the self-hosted linker is not passed these. Lld can still use this path.
- mingw implib generation now interacts with the progress system
- Supply `__ImageBase` for mingw6 files changed, 161 insertions(+), 61 deletions(-)
src/Compilation.zig+40-11| ... | @@ -4475,18 +4475,10 @@ fn performAllTheWork( | ... | @@ -4475,18 +4475,10 @@ fn performAllTheWork( |
| 4475 | 4475 | ||
| 4476 | comp.link_queue.finishZcuQueue(comp); | 4476 | comp.link_queue.finishZcuQueue(comp); |
| 4477 | 4477 | ||
| 4478 | // This has to happen after the main semantic analysis loop because it is possible for Sema to | 4478 | // This has to happen again after the main semantic analysis loop because it is possible for Sema to |
| 4479 | // call `addLinkLib` and hence add more items to `comp.windows_libs`. | 4479 | // call `addLinkLib` and hence add more items to `comp.windows_libs`. |
| 4480 | for (comp.windows_libs.keys()[comp.windows_libs_num_done..]) |link_lib| { | 4480 | for (comp.windows_libs.keys()[comp.windows_libs_num_done..]) |lib_name| |
| 4481 | mingw.buildImportLib(comp, link_lib) catch |err| { | 4481 | comp.buildMingwImportLib(lib_name, false, main_progress_node); |
| 4482 | // TODO Surface more error details. | ||
| 4483 | comp.lockAndSetMiscFailure( | ||
| 4484 | .windows_import_lib, | ||
| 4485 | "unable to generate DLL import .lib file for {s}: {t}", | ||
| 4486 | .{ link_lib, err }, | ||
| 4487 | ); | ||
| 4488 | }; | ||
| 4489 | } | ||
| 4490 | comp.windows_libs_num_done = @intCast(comp.windows_libs.count()); | 4482 | comp.windows_libs_num_done = @intCast(comp.windows_libs.count()); |
| 4491 | 4483 | ||
| 4492 | // Main thread work is all done, now just wait for all async work. | 4484 | // Main thread work is all done, now just wait for all async work. |
| ... | @@ -4692,6 +4684,15 @@ fn dispatchPrelinkWork(comp: *Compilation, main_progress_node: std.Progress.Node | ... | @@ -4692,6 +4684,15 @@ fn dispatchPrelinkWork(comp: *Compilation, main_progress_node: std.Progress.Node |
| 4692 | }); | 4684 | }); |
| 4693 | } | 4685 | } |
| 4694 | 4686 | ||
| 4687 | while (comp.windows_libs_num_done < comp.windows_libs.count()) { | ||
| 4688 | prelink_group.async( | ||
| 4689 | io, | ||
| 4690 | buildMingwImportLib, | ||
| 4691 | .{ comp, comp.windows_libs.keys()[comp.windows_libs_num_done], true, main_progress_node }, | ||
| 4692 | ); | ||
| 4693 | comp.windows_libs_num_done += 1; | ||
| 4694 | } | ||
| 4695 | |||
| 4695 | prelink_group.await(io) catch |err| switch (err) { | 4696 | prelink_group.await(io) catch |err| switch (err) { |
| 4696 | error.Canceled => unreachable, // see swapCancelProtection above | 4697 | error.Canceled => unreachable, // see swapCancelProtection above |
| 4697 | }; | 4698 | }; |
| ... | @@ -5377,6 +5378,34 @@ fn buildMingwCrtFile(comp: *Compilation, crt_file: mingw.CrtFile, prog_node: std | ... | @@ -5377,6 +5378,34 @@ fn buildMingwCrtFile(comp: *Compilation, crt_file: mingw.CrtFile, prog_node: std |
| 5377 | } | 5378 | } |
| 5378 | } | 5379 | } |
| 5379 | 5380 | ||
| 5381 | fn buildMingwImportLib(comp: *Compilation, lib_name: []const u8, is_prelink: bool, prog_node: std.Progress.Node) void { | ||
| 5382 | const crt_file_path = mingw.buildImportLib(comp, lib_name, prog_node) catch |err| switch (err) { | ||
| 5383 | // TODO: This isn't actually true for self-hosted | ||
| 5384 | // In the non-prelink case we will end up putting foo.lib onto the linker line and letting the linker | ||
| 5385 | // use its library paths to look for libraries and report any problems. | ||
| 5386 | error.DefNotFound => return if (is_prelink) { | ||
| 5387 | comp.lockAndSetMiscFailure( | ||
| 5388 | .windows_import_lib, | ||
| 5389 | "definition not found for required mingw DLL import .lib {s}", | ||
| 5390 | .{lib_name}, | ||
| 5391 | ); | ||
| 5392 | }, | ||
| 5393 | // TODO Surface more error details. | ||
| 5394 | else => |e| return comp.lockAndSetMiscFailure( | ||
| 5395 | .windows_import_lib, | ||
| 5396 | "unable to generate mingw DLL import .lib file for {s}: {t}", | ||
| 5397 | .{ lib_name, e }, | ||
| 5398 | ), | ||
| 5399 | }; | ||
| 5400 | |||
| 5401 | if (is_prelink) | ||
| 5402 | comp.queuePrelinkTasks(&.{.{ .load_archive = crt_file_path }}) catch |err| comp.lockAndSetMiscFailure( | ||
| 5403 | .windows_import_lib, | ||
| 5404 | "unable to queue prelink task for mingw import lib {f}: {t}", | ||
| 5405 | .{ crt_file_path, err }, | ||
| 5406 | ); | ||
| 5407 | } | ||
| 5408 | |||
| 5380 | fn buildWasiLibcCrtFile(comp: *Compilation, crt_file: wasi_libc.CrtFile, prog_node: std.Progress.Node) void { | 5409 | fn buildWasiLibcCrtFile(comp: *Compilation, crt_file: wasi_libc.CrtFile, prog_node: std.Progress.Node) void { |
| 5381 | if (wasi_libc.buildCrtFile(comp, crt_file, prog_node)) |_| { | 5410 | if (wasi_libc.buildCrtFile(comp, crt_file, prog_node)) |_| { |
| 5382 | comp.queued_jobs.wasi_libc_crt_file[@intFromEnum(crt_file)] = false; | 5411 | comp.queued_jobs.wasi_libc_crt_file[@intFromEnum(crt_file)] = false; |
src/libs/mingw.zig+21-16| ... | @@ -207,9 +207,12 @@ fn addCrtCcArgs( | ... | @@ -207,9 +207,12 @@ fn addCrtCcArgs( |
| 207 | }); | 207 | }); |
| 208 | } | 208 | } |
| 209 | 209 | ||
| 210 | pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void { | 210 | pub fn buildImportLib(comp: *Compilation, lib_name: []const u8, prog_node: std.Progress.Node) !Cache.Path { |
| 211 | dev.check(.build_import_lib); | 211 | dev.check(.build_import_lib); |
| 212 | 212 | ||
| 213 | const sub_node = prog_node.start(lib_name, 0); | ||
| 214 | defer sub_node.end(); | ||
| 215 | |||
| 213 | const gpa = comp.gpa; | 216 | const gpa = comp.gpa; |
| 214 | const io = comp.io; | 217 | const io = comp.io; |
| 215 | 218 | ||
| ... | @@ -218,12 +221,7 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void { | ... | @@ -218,12 +221,7 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void { |
| 218 | const arena = arena_allocator.allocator(); | 221 | const arena = arena_allocator.allocator(); |
| 219 | 222 | ||
| 220 | const def_file_path = findDef(arena, io, comp.getTarget(), comp.dirs.zig_lib, lib_name) catch |err| switch (err) { | 223 | const def_file_path = findDef(arena, io, comp.getTarget(), comp.dirs.zig_lib, lib_name) catch |err| switch (err) { |
| 221 | error.FileNotFound => { | 224 | error.FileNotFound => return error.DefNotFound, |
| 222 | log.debug("no {s}.def file available to make a DLL import {s}.lib", .{ lib_name, lib_name }); | ||
| 223 | // In this case we will end up putting foo.lib onto the linker line and letting the linker | ||
| 224 | // use its library paths to look for libraries and report any problems. | ||
| 225 | return; | ||
| 226 | }, | ||
| 227 | else => |e| return e, | 225 | else => |e| return e, |
| 228 | }; | 226 | }; |
| 229 | // Only .def.in files need preprocessing | 227 | // Only .def.in files need preprocessing |
| ... | @@ -263,14 +261,16 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void { | ... | @@ -263,14 +261,16 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void { |
| 263 | comp.mutex.lockUncancelable(io); | 261 | comp.mutex.lockUncancelable(io); |
| 264 | defer comp.mutex.unlock(io); | 262 | defer comp.mutex.unlock(io); |
| 265 | try comp.crt_files.ensureUnusedCapacity(gpa, 1); | 263 | try comp.crt_files.ensureUnusedCapacity(gpa, 1); |
| 264 | |||
| 265 | const crt_file_path: Cache.Path = .{ | ||
| 266 | .root_dir = comp.dirs.global_cache, | ||
| 267 | .sub_path = sub_path, | ||
| 268 | }; | ||
| 266 | comp.crt_files.putAssumeCapacityNoClobber(final_lib_basename, .{ | 269 | comp.crt_files.putAssumeCapacityNoClobber(final_lib_basename, .{ |
| 267 | .full_object_path = .{ | 270 | .full_object_path = crt_file_path, |
| 268 | .root_dir = comp.dirs.global_cache, | ||
| 269 | .sub_path = sub_path, | ||
| 270 | }, | ||
| 271 | .lock = man.toOwnedLock(), | 271 | .lock = man.toOwnedLock(), |
| 272 | }); | 272 | }); |
| 273 | return; | 273 | return crt_file_path; |
| 274 | } | 274 | } |
| 275 | 275 | ||
| 276 | const digest = man.final(); | 276 | const digest = man.final(); |
| ... | @@ -294,6 +294,9 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void { | ... | @@ -294,6 +294,9 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void { |
| 294 | } | 294 | } |
| 295 | 295 | ||
| 296 | const members = members: { | 296 | const members = members: { |
| 297 | const members_node = sub_node.start("Members", 0); | ||
| 298 | defer members_node.end(); | ||
| 299 | |||
| 297 | const input = switch (def_needs_preprocessing) { | 300 | const input = switch (def_needs_preprocessing) { |
| 298 | true => pp: { | 301 | true => pp: { |
| 299 | var aw: Io.Writer.Allocating = .init(gpa); | 302 | var aw: Io.Writer.Allocating = .init(gpa); |
| ... | @@ -357,13 +360,15 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void { | ... | @@ -357,13 +360,15 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void { |
| 357 | 360 | ||
| 358 | comp.mutex.lockUncancelable(io); | 361 | comp.mutex.lockUncancelable(io); |
| 359 | defer comp.mutex.unlock(io); | 362 | defer comp.mutex.unlock(io); |
| 363 | const crt_file_path: Cache.Path = .{ | ||
| 364 | .root_dir = comp.dirs.global_cache, | ||
| 365 | .sub_path = lib_final_path, | ||
| 366 | }; | ||
| 360 | try comp.crt_files.putNoClobber(gpa, final_lib_basename, .{ | 367 | try comp.crt_files.putNoClobber(gpa, final_lib_basename, .{ |
| 361 | .full_object_path = .{ | 368 | .full_object_path = crt_file_path, |
| 362 | .root_dir = comp.dirs.global_cache, | ||
| 363 | .sub_path = lib_final_path, | ||
| 364 | }, | ||
| 365 | .lock = man.toOwnedLock(), | 369 | .lock = man.toOwnedLock(), |
| 366 | }); | 370 | }); |
| 371 | return crt_file_path; | ||
| 367 | } | 372 | } |
| 368 | 373 | ||
| 369 | pub fn libExists( | 374 | pub fn libExists( |
src/link.zig+3-12| ... | @@ -482,7 +482,7 @@ pub const File = struct { | ... | @@ -482,7 +482,7 @@ pub const File = struct { |
| 482 | rpath_list: []const []const u8, | 482 | rpath_list: []const []const u8, |
| 483 | 483 | ||
| 484 | /// Zig compiler development linker flags. | 484 | /// Zig compiler development linker flags. |
| 485 | /// Enable dumping of linker's state as JSON. | 485 | /// Enable dumping of linker's state. |
| 486 | enable_link_snapshots: bool, | 486 | enable_link_snapshots: bool, |
| 487 | 487 | ||
| 488 | /// Darwin-specific linker flags: | 488 | /// Darwin-specific linker flags: |
| ... | @@ -1527,20 +1527,11 @@ pub fn doPrelinkTask(comp: *Compilation, task: PrelinkTask) void { | ... | @@ -1527,20 +1527,11 @@ pub fn doPrelinkTask(comp: *Compilation, task: PrelinkTask) void { |
| 1527 | } | 1527 | } |
| 1528 | } | 1528 | } |
| 1529 | 1529 | ||
| 1530 | if (target.os.tag == .windows) { | 1530 | if (target.os.tag == .windows and target.abi == .msvc) { |
| 1531 | const inputs: []const struct { | 1531 | const inputs: []const struct { |
| 1532 | dir: enum { crt, msvc_lib, kernel32_lib }, | 1532 | dir: enum { crt, msvc_lib, kernel32_lib }, |
| 1533 | name: []const u8, | 1533 | name: []const u8, |
| 1534 | } = if (target.abi.isGnu()) switch (comp.config.link_mode) { | 1534 | } = switch (comp.config.link_mode) { |
| 1535 | .dynamic => &.{ | ||
| 1536 | .{ .dir = .crt, .name = "dllcrt2.obj" }, | ||
| 1537 | .{ .dir = .crt, .name = "libmingw32.lib" }, | ||
| 1538 | }, | ||
| 1539 | .static => &.{ | ||
| 1540 | .{ .dir = .crt, .name = "crt2.obj" }, | ||
| 1541 | .{ .dir = .crt, .name = "libmingw32.lib" }, | ||
| 1542 | }, | ||
| 1543 | } else switch (comp.config.link_mode) { | ||
| 1544 | .dynamic => &.{ | 1535 | .dynamic => &.{ |
| 1545 | .{ .dir = .msvc_lib, .name = "msvcrt.lib" }, | 1536 | .{ .dir = .msvc_lib, .name = "msvcrt.lib" }, |
| 1546 | .{ .dir = .msvc_lib, .name = "vcruntime.lib" }, | 1537 | .{ .dir = .msvc_lib, .name = "vcruntime.lib" }, |
src/link/Coff.zig+29-8| ... | @@ -2017,6 +2017,16 @@ fn initHeaders( | ... | @@ -2017,6 +2017,16 @@ fn initHeaders( |
| 2017 | .{ .read = true, .write = !is_image }, | 2017 | .{ .read = true, .write = !is_image }, |
| 2018 | ); | 2018 | ); |
| 2019 | } | 2019 | } |
| 2020 | |||
| 2021 | // Linker-supplied symbols | ||
| 2022 | { | ||
| 2023 | const target = &comp.root_mod.resolved_target.result; | ||
| 2024 | if (is_image and target.isMinGW()) { | ||
| 2025 | const si = try coff.globalSymbol(.{ .name = "__ImageBase", .type = .data }); | ||
| 2026 | const sym = si.get(coff); | ||
| 2027 | sym.ni = Node.known.header; | ||
| 2028 | } | ||
| 2029 | } | ||
| 2020 | } | 2030 | } |
| 2021 | 2031 | ||
| 2022 | pub fn startProgress(coff: *Coff, prog_node: std.Progress.Node) void { | 2032 | pub fn startProgress(coff: *Coff, prog_node: std.Progress.Node) void { |
| ... | @@ -2044,7 +2054,7 @@ pub fn endProgress(coff: *Coff) void { | ... | @@ -2044,7 +2054,7 @@ pub fn endProgress(coff: *Coff) void { |
| 2044 | coff.mf.update_prog_node = .none; | 2054 | coff.mf.update_prog_node = .none; |
| 2045 | coff.input_prog_node.end(); | 2055 | coff.input_prog_node.end(); |
| 2046 | coff.input_prog_node = .none; | 2056 | coff.input_prog_node = .none; |
| 2047 | if (!isImage(coff)) { | 2057 | if (!coff.isImage()) { |
| 2048 | coff.member_prog_node.end(); | 2058 | coff.member_prog_node.end(); |
| 2049 | coff.member_prog_node = .none; | 2059 | coff.member_prog_node = .none; |
| 2050 | coff.symbol_prog_node.end(); | 2060 | coff.symbol_prog_node.end(); |
| ... | @@ -3103,7 +3113,7 @@ fn objectSectionMapIndex( | ... | @@ -3103,7 +3113,7 @@ fn objectSectionMapIndex( |
| 3103 | 3113 | ||
| 3104 | const object_section_gop = try coff.object_section_table.getOrPut(gpa, name); | 3114 | const object_section_gop = try coff.object_section_table.getOrPut(gpa, name); |
| 3105 | const osmi: Node.ObjectSectionMapIndex = @enumFromInt(object_section_gop.index); | 3115 | const osmi: Node.ObjectSectionMapIndex = @enumFromInt(object_section_gop.index); |
| 3106 | const sn = if (!object_section_gop.found_existing) sn: { | 3116 | const sym = if (!object_section_gop.found_existing) sn: { |
| 3107 | try coff.ensureUnusedStringCapacity(name_slice.len); | 3117 | try coff.ensureUnusedStringCapacity(name_slice.len); |
| 3108 | const parent_name = coff.getOrPutStringAssumeCapacity(coff.objectSectionParentName(name_slice)); | 3118 | const parent_name = coff.getOrPutStringAssumeCapacity(coff.objectSectionParentName(name_slice)); |
| 3109 | const parent = (try coff.pseudoSectionMapIndex(parent_name, alignment, effective_attributes)).symbol(coff); | 3119 | const parent = (try coff.pseudoSectionMapIndex(parent_name, alignment, effective_attributes)).symbol(coff); |
| ... | @@ -3140,14 +3150,24 @@ fn objectSectionMapIndex( | ... | @@ -3140,14 +3150,24 @@ fn objectSectionMapIndex( |
| 3140 | assert(sym.loc_relocs == .none); | 3150 | assert(sym.loc_relocs == .none); |
| 3141 | sym.loc_relocs = @enumFromInt(coff.relocs.items.len); | 3151 | sym.loc_relocs = @enumFromInt(coff.relocs.items.len); |
| 3142 | coff.nodes.appendAssumeCapacity(.{ .object_section = osmi }); | 3152 | coff.nodes.appendAssumeCapacity(.{ .object_section = osmi }); |
| 3143 | break :sn sym.section_number; | 3153 | break :sn sym; |
| 3144 | } else object_section_gop.value_ptr.get(coff).section_number; | 3154 | } else object_section_gop.value_ptr.get(coff); |
| 3155 | |||
| 3156 | const parent_ni = sym.ni.parent(&coff.mf); | ||
| 3157 | const parent_alignment = parent_ni.alignment(&coff.mf); | ||
| 3158 | if (alignment.compare(.gt, parent_alignment)) { | ||
| 3159 | log.debug("realignParent({s}, {d}) {d}->{d}", .{ name.toSlice(coff), parent_ni, parent_alignment, alignment }); | ||
| 3160 | parent_ni.realign(&coff.mf, gpa, alignment, true) catch |err| switch (err) { | ||
| 3161 | error.Unimplemented => unreachable, | ||
| 3162 | else => |e| return e, | ||
| 3163 | }; | ||
| 3164 | } | ||
| 3145 | 3165 | ||
| 3146 | try coff.verifyParentSectionAttributes( | 3166 | try coff.verifyParentSectionAttributes( |
| 3147 | .object, | 3167 | .object, |
| 3148 | sn.name(coff), | 3168 | sym.section_number.name(coff), |
| 3149 | name, | 3169 | name, |
| 3150 | .fromFlags(sn.header(coff).flags), | 3170 | .fromFlags(sym.section_number.header(coff).flags), |
| 3151 | effective_attributes, | 3171 | effective_attributes, |
| 3152 | ); | 3172 | ); |
| 3153 | 3173 | ||
| ... | @@ -4135,7 +4155,7 @@ fn loadObject( | ... | @@ -4135,7 +4155,7 @@ fn loadObject( |
| 4135 | }, | 4155 | }, |
| 4136 | .weak_external => unreachable, | 4156 | .weak_external => unreachable, |
| 4137 | }); | 4157 | }); |
| 4138 | sym.section_number = symbol.section_number; | 4158 | sym.section_number = section.si.get(coff).section_number; |
| 4139 | } | 4159 | } |
| 4140 | 4160 | ||
| 4141 | log.debug("addInputSymbol({s}, 0x{x}, {t}=0x{x}) = {d}@{d}", .{ | 4161 | log.debug("addInputSymbol({s}, 0x{x}, {t}=0x{x}) = {d}@{d}", .{ |
| ... | @@ -4988,7 +5008,7 @@ fn reportUndefs(coff: *Coff, tid: Zcu.PerThread.Id) !void { | ... | @@ -4988,7 +5008,7 @@ fn reportUndefs(coff: *Coff, tid: Zcu.PerThread.Id) !void { |
| 4988 | const other_ioi = isi.input(coff); | 5008 | const other_ioi = isi.input(coff); |
| 4989 | if (loc_sym.gmi == .none) { | 5009 | if (loc_sym.gmi == .none) { |
| 4990 | // TODO: We could report the name here if we interned it in loadObject | 5010 | // TODO: We could report the name here if we interned it in loadObject |
| 4991 | err.addNote("referenced internally by input '{f}{f}'", .{ | 5011 | err.addNote("referenced by input '{f}{f}'", .{ |
| 4992 | other_ioi.path(coff).fmtEscapeString(), | 5012 | other_ioi.path(coff).fmtEscapeString(), |
| 4993 | fmtMemberNameString(other_ioi.memberName(coff)), | 5013 | fmtMemberNameString(other_ioi.memberName(coff)), |
| 4994 | }); | 5014 | }); |
| ... | @@ -5430,6 +5450,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { | ... | @@ -5430,6 +5450,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { |
| 5430 | return true; | 5450 | return true; |
| 5431 | } | 5451 | } |
| 5432 | 5452 | ||
| 5453 | // TODO: Only do this if actually referenced? Might have to do on-demand? | ||
| 5433 | { | 5454 | { |
| 5434 | // Resolve unresolved .WEAK_EXTERNAL symbols to their aliases | 5455 | // Resolve unresolved .WEAK_EXTERNAL symbols to their aliases |
| 5435 | const alias_si = sym.weakAlias(); | 5456 | const alias_si = sym.weakAlias(); |
src/link/MappedFile.zig+68-12| ... | @@ -351,15 +351,17 @@ pub const Node = extern struct { | ... | @@ -351,15 +351,17 @@ pub const Node = extern struct { |
| 351 | } | 351 | } |
| 352 | 352 | ||
| 353 | /// Moves and expands a node such that its offset and size are aligned to `new_alignment`. | 353 | /// Moves and expands a node such that its offset and size are aligned to `new_alignment`. |
| 354 | /// | 354 | /// If it is possible to move the node backwards, this will be done instead of moving it forward. |
| 355 | /// If `set_alignment` is set, persists `new_alignment` as the node's alignment for future operations. | ||
| 355 | /// Asserts that `ni` is not `Node.Index.root`. | 356 | /// Asserts that `ni` is not `Node.Index.root`. |
| 356 | pub fn realign( | 357 | pub fn realign( |
| 357 | ni: Node.Index, | 358 | ni: Node.Index, |
| 358 | mf: *MappedFile, | 359 | mf: *MappedFile, |
| 359 | gpa: std.mem.Allocator, | 360 | gpa: std.mem.Allocator, |
| 360 | new_alignment: std.mem.Alignment, | 361 | new_alignment: std.mem.Alignment, |
| 362 | set_alignment: bool, | ||
| 361 | ) Error!void { | 363 | ) Error!void { |
| 362 | mf.realignNode(gpa, ni, new_alignment) catch |err| switch (err) { | 364 | mf.realignNode(gpa, ni, new_alignment, true, set_alignment) catch |err| switch (err) { |
| 363 | error.OutOfMemory, | 365 | error.OutOfMemory, |
| 364 | error.Canceled, | 366 | error.Canceled, |
| 365 | => |e| return e, | 367 | => |e| return e, |
| ... | @@ -554,6 +556,24 @@ fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct { | ... | @@ -554,6 +556,24 @@ fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct { |
| 554 | }) Error!Node.Index { | 556 | }) Error!Node.Index { |
| 555 | if (opts.add_node.moved or opts.add_node.resized) try mf.updates.ensureUnusedCapacity(gpa, 1); | 557 | if (opts.add_node.moved or opts.add_node.resized) try mf.updates.ensureUnusedCapacity(gpa, 1); |
| 556 | const offset = opts.add_node.alignment.forward(@intCast(opts.offset)); | 558 | const offset = opts.add_node.alignment.forward(@intCast(opts.offset)); |
| 559 | if (opts.parent != .none) { | ||
| 560 | const new_end = offset + opts.add_node.size; | ||
| 561 | switch (opts.next) { | ||
| 562 | .none => { | ||
| 563 | _, const parent_size = opts.parent.location(mf).resolve(mf); | ||
| 564 | if (new_end > parent_size) | ||
| 565 | try opts.parent.resize(mf, gpa, new_end); | ||
| 566 | }, | ||
| 567 | else => |next_ni| { | ||
| 568 | const next_offset, _ = next_ni.location(mf).resolve(mf); | ||
| 569 | if (new_end > next_offset) | ||
| 570 | mf.realignNode(gpa, next_ni, opts.add_node.alignment, false, false) catch |err| switch (err) { | ||
| 571 | error.Unimplemented => unreachable, | ||
| 572 | else => |e| return e, | ||
| 573 | }; | ||
| 574 | }, | ||
| 575 | } | ||
| 576 | } | ||
| 557 | const location_tag: Node.Location.Tag, const location_payload: Node.Location.Payload = location: { | 577 | const location_tag: Node.Location.Tag, const location_payload: Node.Location.Payload = location: { |
| 558 | if (std.math.cast(u32, offset)) |small_offset| break :location .{ .small, .{ | 578 | if (std.math.cast(u32, offset)) |small_offset| break :location .{ .small, .{ |
| 559 | .small = .{ .offset = small_offset, .size = 0 }, | 579 | .small = .{ .offset = small_offset, .size = 0 }, |
| ... | @@ -595,16 +615,12 @@ fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct { | ... | @@ -595,16 +615,12 @@ fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct { |
| 595 | }, | 615 | }, |
| 596 | .location_payload = location_payload, | 616 | .location_payload = location_payload, |
| 597 | }; | 617 | }; |
| 618 | |||
| 598 | { | 619 | { |
| 599 | defer { | ||
| 600 | free_node.flags.moved = false; | ||
| 601 | free_node.flags.resized = false; | ||
| 602 | } | ||
| 603 | _, const parent_size = opts.parent.location(mf).resolve(mf); | ||
| 604 | const required_parent_size = offset + opts.add_node.size; | ||
| 605 | if (required_parent_size > parent_size) | ||
| 606 | try opts.parent.resize(mf, gpa, required_parent_size); | ||
| 607 | try free_ni.resize(mf, gpa, opts.add_node.size); | 620 | try free_ni.resize(mf, gpa, opts.add_node.size); |
| 621 | if (opts.add_node.moved or opts.add_node.resized) try mf.updates.ensureUnusedCapacity(gpa, 1); | ||
| 622 | free_node.flags.moved = false; | ||
| 623 | free_node.flags.resized = false; | ||
| 608 | } | 624 | } |
| 609 | if (opts.add_node.moved) free_ni.movedAssumeCapacity(mf); | 625 | if (opts.add_node.moved) free_ni.movedAssumeCapacity(mf); |
| 610 | if (opts.add_node.resized) free_ni.resizedAssumeCapacity(mf); | 626 | if (opts.add_node.resized) free_ni.resizedAssumeCapacity(mf); |
| ... | @@ -703,6 +719,7 @@ fn shrinkNode( | ... | @@ -703,6 +719,7 @@ fn shrinkNode( |
| 703 | 719 | ||
| 704 | // This would require unmapping first | 720 | // This would require unmapping first |
| 705 | if (ni == Node.Index.root) return error.Unimplemented; | 721 | if (ni == Node.Index.root) return error.Unimplemented; |
| 722 | defer if (std.debug.runtime_safety) mf.verify(); | ||
| 706 | 723 | ||
| 707 | if (node.last != .none) { | 724 | if (node.last != .none) { |
| 708 | const last = node.last.get(mf); | 725 | const last = node.last.get(mf); |
| ... | @@ -725,9 +742,10 @@ fn shrinkNode( | ... | @@ -725,9 +742,10 @@ fn shrinkNode( |
| 725 | const old_file_offset = node.next.fileLocation(mf, false).offset; | 742 | const old_file_offset = node.next.fileLocation(mf, false).offset; |
| 726 | const new_file_offset = (old_file_offset - old_next_offset) + new_next_offset; | 743 | const new_file_offset = (old_file_offset - old_next_offset) + new_next_offset; |
| 727 | @memmove( | 744 | @memmove( |
| 728 | mf.memory_map.memory[new_file_offset..][0..next_size], | 745 | mf.memory_map.memory[@intCast(new_file_offset)..][0..@intCast(next_size)], |
| 729 | mf.memory_map.memory[old_file_offset..][0..next_size], | 746 | mf.memory_map.memory[@intCast(old_file_offset)..][0..@intCast(next_size)], |
| 730 | ); | 747 | ); |
| 748 | @memset(mf.memory_map.memory[@intCast(new_file_offset + next_size)..@intCast(old_file_offset + next_size)], 0); | ||
| 731 | } | 749 | } |
| 732 | 750 | ||
| 733 | node.next.setLocationAssumeCapacity(mf, new_next_offset, next_size); | 751 | node.next.setLocationAssumeCapacity(mf, new_next_offset, next_size); |
| ... | @@ -999,6 +1017,8 @@ fn realignNode( | ... | @@ -999,6 +1017,8 @@ fn realignNode( |
| 999 | gpa: std.mem.Allocator, | 1017 | gpa: std.mem.Allocator, |
| 1000 | ni: Node.Index, | 1018 | ni: Node.Index, |
| 1001 | new_alignment: std.mem.Alignment, | 1019 | new_alignment: std.mem.Alignment, |
| 1020 | try_backward: bool, | ||
| 1021 | set_alignment: bool, | ||
| 1002 | ) (Allocator.Error || Io.Cancelable || IoError)!void { | 1022 | ) (Allocator.Error || Io.Cancelable || IoError)!void { |
| 1003 | assert(ni != Node.Index.root); // currently unsupported | 1023 | assert(ni != Node.Index.root); // currently unsupported |
| 1004 | 1024 | ||
| ... | @@ -1009,7 +1029,12 @@ fn realignNode( | ... | @@ -1009,7 +1029,12 @@ fn realignNode( |
| 1009 | 1029 | ||
| 1010 | defer if (std.debug.runtime_safety) mf.verify(); | 1030 | defer if (std.debug.runtime_safety) mf.verify(); |
| 1011 | 1031 | ||
| 1032 | const prev_alignment = node.flags.alignment; | ||
| 1012 | node.flags.alignment = new_alignment; | 1033 | node.flags.alignment = new_alignment; |
| 1034 | defer { | ||
| 1035 | // alignment needs to be temporarily set for the resizes below | ||
| 1036 | if (!set_alignment) node.flags.alignment = prev_alignment; | ||
| 1037 | } | ||
| 1013 | 1038 | ||
| 1014 | const new_size = node.flags.alignment.forward(@intCast(size)); | 1039 | const new_size = node.flags.alignment.forward(@intCast(size)); |
| 1015 | if (new_alignment.check(@intCast(old_offset))) { | 1040 | if (new_alignment.check(@intCast(old_offset))) { |
| ... | @@ -1026,6 +1051,37 @@ fn realignNode( | ... | @@ -1026,6 +1051,37 @@ fn realignNode( |
| 1026 | }, | 1051 | }, |
| 1027 | }; | 1052 | }; |
| 1028 | 1053 | ||
| 1054 | if (try_backward) { | ||
| 1055 | const backward_offset = new_alignment.backward(old_offset); | ||
| 1056 | const prev_end = if (node.prev == .none) 0 else prev: { | ||
| 1057 | const prev_offset, const prev_size = node.prev.location(mf).resolve(mf); | ||
| 1058 | break :prev prev_offset + prev_size; | ||
| 1059 | }; | ||
| 1060 | |||
| 1061 | if (backward_offset >= prev_end) { | ||
| 1062 | try mf.ensureCapacityForSetLocation(gpa); | ||
| 1063 | |||
| 1064 | if (node.flags.has_content) { | ||
| 1065 | const old_file_offset = ni.fileLocation(mf, false).offset; | ||
| 1066 | const new_file_offset = (old_file_offset - old_offset) + backward_offset; | ||
| 1067 | @memmove( | ||
| 1068 | mf.memory_map.memory[@intCast(new_file_offset)..][0..@intCast(size)], | ||
| 1069 | mf.memory_map.memory[@intCast(old_file_offset)..][0..@intCast(size)], | ||
| 1070 | ); | ||
| 1071 | @memset(mf.memory_map.memory[@intCast(new_file_offset + size)..@intCast(old_file_offset + size)], 0); | ||
| 1072 | } | ||
| 1073 | |||
| 1074 | if (backward_offset + new_size <= trailing_end) { | ||
| 1075 | ni.setLocationAssumeCapacity(mf, backward_offset, new_size); | ||
| 1076 | } else { | ||
| 1077 | ni.setLocationAssumeCapacity(mf, backward_offset, size); | ||
| 1078 | try mf.resizeNode(gpa, ni, new_size); | ||
| 1079 | } | ||
| 1080 | |||
| 1081 | return; | ||
| 1082 | } | ||
| 1083 | } | ||
| 1084 | |||
| 1029 | const forward_offset = new_alignment.forward(@intCast(old_offset)); | 1085 | const forward_offset = new_alignment.forward(@intCast(old_offset)); |
| 1030 | if (forward_offset + new_size <= trailing_end) { | 1086 | if (forward_offset + new_size <= trailing_end) { |
| 1031 | // Shift into the free space if possible | 1087 | // Shift into the free space if possible |
test/standalone/shared_library/build.zig-2| ... | @@ -20,8 +20,6 @@ pub fn build(b: *std.Build) void { | ... | @@ -20,8 +20,6 @@ pub fn build(b: *std.Build) void { |
| 20 | if (!use_llvm and target.result.cpu.arch == .loongarch64) continue; // TODO | 20 | if (!use_llvm and target.result.cpu.arch == .loongarch64) continue; // TODO |
| 21 | if (!use_llvm and target.result.cpu.arch == .powerpc64le) continue; // TODO | 21 | if (!use_llvm and target.result.cpu.arch == .powerpc64le) continue; // TODO |
| 22 | if (!use_llvm and target.result.cpu.arch == .s390x) continue; // TODO | 22 | if (!use_llvm and target.result.cpu.arch == .s390x) continue; // TODO |
| 23 | if (!use_llvm and target.result.os.tag == .windows and target.result.abi == .gnu and dyn_libc) | ||
| 24 | continue; // TODO: sub-compilation of compiler_rt failed (failed to link with LLD: LibCInstallationNotAvailable) | ||
| 25 | 23 | ||
| 26 | const lib = b.addLibrary(.{ | 24 | const lib = b.addLibrary(.{ |
| 27 | .linkage = .dynamic, | 25 | .linkage = .dynamic, |