link.MachO: multi-thread first round of sha256 hashing

when computing the adhoc code signature
This commit is contained in:
Andrew Kelley 2022-10-22 16:03:59 -07:00
parent e67c756b91
commit 4a2f1e748e
3 changed files with 62 additions and 28 deletions

View File

@ -625,7 +625,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
try self.writeHeader(ncmds, @intCast(u32, lc_buffer.items.len + headers_buf.items.len));
if (codesig) |*csig| {
try self.writeCodeSignature(csig, codesig_offset.?); // code signing always comes last
try self.writeCodeSignature(comp, csig, codesig_offset.?); // code signing always comes last
}
if (self.d_sym) |*d_sym| {
@ -4037,13 +4037,13 @@ fn writeCodeSignaturePadding(
return @intCast(u32, offset);
}
fn writeCodeSignature(self: *MachO, code_sig: *CodeSignature, offset: u32) !void {
fn writeCodeSignature(self: *MachO, comp: *const Compilation, code_sig: *CodeSignature, offset: u32) !void {
const seg = self.getSegment(self.text_section_index.?);
var buffer = std.ArrayList(u8).init(self.base.allocator);
defer buffer.deinit();
try buffer.ensureTotalCapacityPrecise(code_sig.size());
try code_sig.writeAdhocSignature(self.base.allocator, .{
try code_sig.writeAdhocSignature(comp, .{
.file = self.base.file.?,
.exec_seg_base = seg.fileoff,
.exec_seg_limit = seg.filesize,

View File

@ -1,4 +1,6 @@
const CodeSignature = @This();
const Compilation = @import("../../Compilation.zig");
const WaitGroup = @import("../../WaitGroup.zig");
const std = @import("std");
const assert = std.debug.assert;
@ -258,17 +260,19 @@ pub const WriteOpts = struct {
pub fn writeAdhocSignature(
self: *CodeSignature,
allocator: Allocator,
comp: *const Compilation,
opts: WriteOpts,
writer: anytype,
) !void {
const gpa = comp.gpa;
var header: macho.SuperBlob = .{
.magic = macho.CSMAGIC_EMBEDDED_SIGNATURE,
.length = @sizeOf(macho.SuperBlob),
.count = 0,
};
var blobs = std.ArrayList(Blob).init(allocator);
var blobs = std.ArrayList(Blob).init(gpa);
defer blobs.deinit();
self.code_directory.inner.execSegBase = opts.exec_seg_base;
@ -276,37 +280,49 @@ pub fn writeAdhocSignature(
self.code_directory.inner.execSegFlags = if (opts.output_mode == .Exe) macho.CS_EXECSEG_MAIN_BINARY else 0;
self.code_directory.inner.codeLimit = opts.file_size;
const total_pages = mem.alignForward(opts.file_size, self.page_size) / self.page_size;
const total_pages = @intCast(u32, mem.alignForward(opts.file_size, self.page_size) / self.page_size);
var buffer = try allocator.alloc(u8, self.page_size);
defer allocator.free(buffer);
try self.code_directory.code_slots.ensureTotalCapacityPrecise(allocator, total_pages);
try self.code_directory.code_slots.ensureTotalCapacityPrecise(gpa, total_pages);
self.code_directory.code_slots.items.len = total_pages;
self.code_directory.inner.nCodeSlots += total_pages;
// Calculate hash for each page (in file) and write it to the buffer
var hash: [hash_size]u8 = undefined;
var i: usize = 0;
while (i < total_pages) : (i += 1) {
const fstart = i * self.page_size;
const fsize = if (fstart + self.page_size > opts.file_size)
opts.file_size - fstart
else
self.page_size;
const len = try opts.file.preadAll(buffer, fstart);
assert(fsize <= len);
var wg: WaitGroup = .{};
{
const results = try gpa.alloc(fs.File.PReadError!usize, total_pages);
defer gpa.free(results);
{
const buffer = try gpa.alloc(u8, self.page_size * total_pages);
defer gpa.free(buffer);
Sha256.hash(buffer[0..fsize], &hash, .{});
wg.reset();
defer wg.wait();
self.code_directory.code_slots.appendAssumeCapacity(hash);
self.code_directory.inner.nCodeSlots += 1;
var i: usize = 0;
while (i < total_pages) : (i += 1) {
const fstart = i * self.page_size;
const fsize = if (fstart + self.page_size > opts.file_size)
opts.file_size - fstart
else
self.page_size;
const out_hash = &self.code_directory.code_slots.items[i];
wg.start();
try comp.thread_pool.spawn(workerSha256Hash, .{
opts.file, fstart, buffer[0..fsize], out_hash, &results[i], &wg,
});
}
}
for (results) |result| _ = try result;
}
try blobs.append(.{ .code_directory = &self.code_directory });
header.length += @sizeOf(macho.BlobIndex);
header.count += 1;
var hash: [hash_size]u8 = undefined;
if (self.requirements) |*req| {
var buf = std.ArrayList(u8).init(allocator);
var buf = std.ArrayList(u8).init(gpa);
defer buf.deinit();
try req.write(buf.writer());
Sha256.hash(buf.items, &hash, .{});
@ -318,7 +334,7 @@ pub fn writeAdhocSignature(
}
if (self.entitlements) |*ents| {
var buf = std.ArrayList(u8).init(allocator);
var buf = std.ArrayList(u8).init(gpa);
defer buf.deinit();
try ents.write(buf.writer());
Sha256.hash(buf.items, &hash, .{});
@ -356,6 +372,19 @@ pub fn writeAdhocSignature(
}
}
fn workerSha256Hash(
file: fs.File,
fstart: usize,
buffer: []u8,
hash: *[hash_size]u8,
err: *fs.File.PReadError!usize,
wg: *WaitGroup,
) void {
defer wg.finish();
err.* = file.preadAll(buffer, fstart);
Sha256.hash(buffer, hash, .{});
}
pub fn size(self: CodeSignature) u32 {
var ssize: u32 = @sizeOf(macho.SuperBlob) + @sizeOf(macho.BlobIndex) + self.code_directory.size();
if (self.requirements) |req| {

View File

@ -3035,14 +3035,19 @@ pub const Zld = struct {
return @intCast(u32, offset);
}
fn writeCodeSignature(self: *Zld, code_sig: *CodeSignature, offset: u32) !void {
fn writeCodeSignature(
self: *Zld,
comp: *const Compilation,
code_sig: *CodeSignature,
offset: u32,
) !void {
const seg_id = self.getSegmentByName("__TEXT").?;
const seg = self.segments.items[seg_id];
var buffer = std.ArrayList(u8).init(self.gpa);
defer buffer.deinit();
try buffer.ensureTotalCapacityPrecise(code_sig.size());
try code_sig.writeAdhocSignature(self.gpa, .{
try code_sig.writeAdhocSignature(comp, .{
.file = self.file,
.exec_seg_base = seg.fileoff,
.exec_seg_limit = seg.filesize,
@ -4379,7 +4384,7 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr
try zld.writeHeader(ncmds, @intCast(u32, lc_buffer.items.len + headers_buf.items.len));
if (codesig) |*csig| {
try zld.writeCodeSignature(csig, codesig_offset.?); // code signing always comes last
try zld.writeCodeSignature(comp, csig, codesig_offset.?); // code signing always comes last
}
}