| author | |
| committer | |
| log | 8fc0c7dce163cab311bd7f088b7a953584e24a1e |
| tree | 76f55bd405fbaa8d834b06f667d1cde1eb8edd21 |
| parent | 434e69482ed29de26ceea16dbc5679f32281c502 |
* test non-ObjC literal deduping logic6 files changed, 316 insertions(+), 42 deletions(-)
src/link/MachO.zig+23-3| ... | @@ -1500,14 +1500,25 @@ pub fn dedupLiterals(self: *MachO) !void { | ... | @@ -1500,14 +1500,25 @@ pub fn dedupLiterals(self: *MachO) !void { |
| 1500 | const gpa = self.base.comp.gpa; | 1500 | const gpa = self.base.comp.gpa; |
| 1501 | var lp: LiteralPool = .{}; | 1501 | var lp: LiteralPool = .{}; |
| 1502 | defer lp.deinit(gpa); | 1502 | defer lp.deinit(gpa); |
| 1503 | |||
| 1503 | if (self.getZigObject()) |zo| { | 1504 | if (self.getZigObject()) |zo| { |
| 1504 | try zo.dedupLiterals(&lp, self); | 1505 | try zo.resolveLiterals(&lp, self); |
| 1505 | } | 1506 | } |
| 1506 | for (self.objects.items) |index| { | 1507 | for (self.objects.items) |index| { |
| 1507 | try self.getFile(index).?.object.dedupLiterals(&lp, self); | 1508 | try self.getFile(index).?.object.resolveLiterals(&lp, self); |
| 1508 | } | 1509 | } |
| 1509 | if (self.getInternalObject()) |object| { | 1510 | if (self.getInternalObject()) |object| { |
| 1510 | try object.dedupLiterals(&lp, self); | 1511 | try object.resolveLiterals(&lp, self); |
| 1512 | } | ||
| 1513 | |||
| 1514 | if (self.getZigObject()) |zo| { | ||
| 1515 | zo.dedupLiterals(lp, self); | ||
| 1516 | } | ||
| 1517 | for (self.objects.items) |index| { | ||
| 1518 | self.getFile(index).?.object.dedupLiterals(lp, self); | ||
| 1519 | } | ||
| 1520 | if (self.getInternalObject()) |object| { | ||
| 1521 | object.dedupLiterals(lp, self); | ||
| 1511 | } | 1522 | } |
| 1512 | } | 1523 | } |
| 1513 | 1524 | ||
| ... | @@ -4415,8 +4426,14 @@ pub const LiteralPool = struct { | ... | @@ -4415,8 +4426,14 @@ pub const LiteralPool = struct { |
| 4415 | lp.data.deinit(allocator); | 4426 | lp.data.deinit(allocator); |
| 4416 | } | 4427 | } |
| 4417 | 4428 | ||
| 4429 | pub fn getAtom(lp: LiteralPool, index: Index, macho_file: *MachO) *Atom { | ||
| 4430 | assert(index < lp.values.items.len); | ||
| 4431 | return macho_file.getAtom(lp.values.items[index]).?; | ||
| 4432 | } | ||
| 4433 | |||
| 4418 | const InsertResult = struct { | 4434 | const InsertResult = struct { |
| 4419 | found_existing: bool, | 4435 | found_existing: bool, |
| 4436 | index: Index, | ||
| 4420 | atom: *Atom.Index, | 4437 | atom: *Atom.Index, |
| 4421 | }; | 4438 | }; |
| 4422 | 4439 | ||
| ... | @@ -4434,6 +4451,7 @@ pub const LiteralPool = struct { | ... | @@ -4434,6 +4451,7 @@ pub const LiteralPool = struct { |
| 4434 | } | 4451 | } |
| 4435 | return .{ | 4452 | return .{ |
| 4436 | .found_existing = gop.found_existing, | 4453 | .found_existing = gop.found_existing, |
| 4454 | .index = @intCast(gop.index), | ||
| 4437 | .atom = &lp.values.items[gop.index], | 4455 | .atom = &lp.values.items[gop.index], |
| 4438 | }; | 4456 | }; |
| 4439 | } | 4457 | } |
| ... | @@ -4472,6 +4490,8 @@ pub const LiteralPool = struct { | ... | @@ -4472,6 +4490,8 @@ pub const LiteralPool = struct { |
| 4472 | return key.hash(ctx.lp); | 4490 | return key.hash(ctx.lp); |
| 4473 | } | 4491 | } |
| 4474 | }; | 4492 | }; |
| 4493 | |||
| 4494 | pub const Index = u32; | ||
| 4475 | }; | 4495 | }; |
| 4476 | 4496 | ||
| 4477 | const HotUpdateState = struct { | 4497 | const HotUpdateState = struct { |
src/link/MachO/Atom.zig+13-1| ... | @@ -113,12 +113,18 @@ pub fn getThunk(self: Atom, macho_file: *MachO) *Thunk { | ... | @@ -113,12 +113,18 @@ pub fn getThunk(self: Atom, macho_file: *MachO) *Thunk { |
| 113 | return macho_file.getThunk(extra.thunk); | 113 | return macho_file.getThunk(extra.thunk); |
| 114 | } | 114 | } |
| 115 | 115 | ||
| 116 | pub fn getLiteralPoolIndex(self: Atom, macho_file: *MachO) ?MachO.LiteralPool.Index { | ||
| 117 | if (!self.flags.literal_pool) return null; | ||
| 118 | return self.getExtra(macho_file).?.literal_index; | ||
| 119 | } | ||
| 120 | |||
| 116 | const AddExtraOpts = struct { | 121 | const AddExtraOpts = struct { |
| 117 | thunk: ?u32 = null, | 122 | thunk: ?u32 = null, |
| 118 | rel_index: ?u32 = null, | 123 | rel_index: ?u32 = null, |
| 119 | rel_count: ?u32 = null, | 124 | rel_count: ?u32 = null, |
| 120 | unwind_index: ?u32 = null, | 125 | unwind_index: ?u32 = null, |
| 121 | unwind_count: ?u32 = null, | 126 | unwind_count: ?u32 = null, |
| 127 | literal_index: ?u32 = null, | ||
| 122 | }; | 128 | }; |
| 123 | 129 | ||
| 124 | pub fn addExtra(atom: *Atom, opts: AddExtraOpts, macho_file: *MachO) !void { | 130 | pub fn addExtra(atom: *Atom, opts: AddExtraOpts, macho_file: *MachO) !void { |
| ... | @@ -1177,7 +1183,7 @@ pub const Flags = packed struct { | ... | @@ -1177,7 +1183,7 @@ pub const Flags = packed struct { |
| 1177 | /// Specifies whether this atom is alive or has been garbage collected. | 1183 | /// Specifies whether this atom is alive or has been garbage collected. |
| 1178 | alive: bool = true, | 1184 | alive: bool = true, |
| 1179 | 1185 | ||
| 1180 | /// Specifies if the atom has been visited during garbage collection. | 1186 | /// Specifies if this atom has been visited during garbage collection. |
| 1181 | visited: bool = false, | 1187 | visited: bool = false, |
| 1182 | 1188 | ||
| 1183 | /// Whether this atom has a range extension thunk. | 1189 | /// Whether this atom has a range extension thunk. |
| ... | @@ -1188,6 +1194,9 @@ pub const Flags = packed struct { | ... | @@ -1188,6 +1194,9 @@ pub const Flags = packed struct { |
| 1188 | 1194 | ||
| 1189 | /// Whether this atom has any unwind records. | 1195 | /// Whether this atom has any unwind records. |
| 1190 | unwind: bool = false, | 1196 | unwind: bool = false, |
| 1197 | |||
| 1198 | /// Whether this atom has LiteralPool entry. | ||
| 1199 | literal_pool: bool = false, | ||
| 1191 | }; | 1200 | }; |
| 1192 | 1201 | ||
| 1193 | pub const Extra = struct { | 1202 | pub const Extra = struct { |
| ... | @@ -1205,6 +1214,9 @@ pub const Extra = struct { | ... | @@ -1205,6 +1214,9 @@ pub const Extra = struct { |
| 1205 | 1214 | ||
| 1206 | /// Count of relocations belonging to this atom. | 1215 | /// Count of relocations belonging to this atom. |
| 1207 | unwind_count: u32 = 0, | 1216 | unwind_count: u32 = 0, |
| 1217 | |||
| 1218 | /// Index into LiteralPool entry for this atom. | ||
| 1219 | literal_index: u32 = 0, | ||
| 1208 | }; | 1220 | }; |
| 1209 | 1221 | ||
| 1210 | pub const Alignment = @import("../../InternPool.zig").Alignment; | 1222 | pub const Alignment = @import("../../InternPool.zig").Alignment; |
src/link/MachO/InternalObject.zig+35-20| ... | @@ -109,12 +109,9 @@ fn addObjcSelrefsSection(self: *InternalObject, methname_atom_index: Atom.Index, | ... | @@ -109,12 +109,9 @@ fn addObjcSelrefsSection(self: *InternalObject, methname_atom_index: Atom.Index, |
| 109 | return atom_index; | 109 | return atom_index; |
| 110 | } | 110 | } |
| 111 | 111 | ||
| 112 | pub fn dedupLiterals(self: InternalObject, lp: *MachO.LiteralPool, macho_file: *MachO) !void { | 112 | pub fn resolveLiterals(self: InternalObject, lp: *MachO.LiteralPool, macho_file: *MachO) !void { |
| 113 | const gpa = macho_file.base.comp.gpa; | 113 | const gpa = macho_file.base.comp.gpa; |
| 114 | 114 | ||
| 115 | var killed_atoms = std.AutoHashMap(Atom.Index, Atom.Index).init(gpa); | ||
| 116 | defer killed_atoms.deinit(); | ||
| 117 | |||
| 118 | var buffer = std.ArrayList(u8).init(gpa); | 115 | var buffer = std.ArrayList(u8).init(gpa); |
| 119 | defer buffer.deinit(); | 116 | defer buffer.deinit(); |
| 120 | 117 | ||
| ... | @@ -126,10 +123,9 @@ pub fn dedupLiterals(self: InternalObject, lp: *MachO.LiteralPool, macho_file: * | ... | @@ -126,10 +123,9 @@ pub fn dedupLiterals(self: InternalObject, lp: *MachO.LiteralPool, macho_file: * |
| 126 | const res = try lp.insert(gpa, header.type(), data); | 123 | const res = try lp.insert(gpa, header.type(), data); |
| 127 | if (!res.found_existing) { | 124 | if (!res.found_existing) { |
| 128 | res.atom.* = atom_index; | 125 | res.atom.* = atom_index; |
| 129 | continue; | ||
| 130 | } | 126 | } |
| 131 | atom.flags.alive = false; | 127 | atom.flags.literal_pool = true; |
| 132 | try killed_atoms.putNoClobber(atom_index, res.atom.*); | 128 | try atom.addExtra(.{ .literal_index = res.index }, macho_file); |
| 133 | } else if (Object.isPtrLiteral(header)) { | 129 | } else if (Object.isPtrLiteral(header)) { |
| 134 | const atom = macho_file.getAtom(atom_index).?; | 130 | const atom = macho_file.getAtom(atom_index).?; |
| 135 | const relocs = atom.getRelocs(macho_file); | 131 | const relocs = atom.getRelocs(macho_file); |
| ... | @@ -145,32 +141,45 @@ pub fn dedupLiterals(self: InternalObject, lp: *MachO.LiteralPool, macho_file: * | ... | @@ -145,32 +141,45 @@ pub fn dedupLiterals(self: InternalObject, lp: *MachO.LiteralPool, macho_file: * |
| 145 | buffer.clearRetainingCapacity(); | 141 | buffer.clearRetainingCapacity(); |
| 146 | if (!res.found_existing) { | 142 | if (!res.found_existing) { |
| 147 | res.atom.* = atom_index; | 143 | res.atom.* = atom_index; |
| 148 | continue; | ||
| 149 | } | 144 | } |
| 150 | atom.flags.alive = false; | 145 | atom.flags.literal_pool = true; |
| 151 | try killed_atoms.putNoClobber(atom_index, res.atom.*); | 146 | try atom.addExtra(.{ .literal_index = res.index }, macho_file); |
| 152 | } | 147 | } |
| 153 | } | 148 | } |
| 149 | } | ||
| 154 | 150 | ||
| 151 | pub fn dedupLiterals(self: InternalObject, lp: MachO.LiteralPool, macho_file: *MachO) void { | ||
| 155 | for (self.atoms.items) |atom_index| { | 152 | for (self.atoms.items) |atom_index| { |
| 156 | if (killed_atoms.get(atom_index)) |_| continue; | ||
| 157 | const atom = macho_file.getAtom(atom_index) orelse continue; | 153 | const atom = macho_file.getAtom(atom_index) orelse continue; |
| 158 | if (!atom.flags.alive) continue; | 154 | if (!atom.flags.alive) continue; |
| 159 | if (!atom.flags.relocs) continue; | 155 | if (!atom.flags.relocs) continue; |
| 160 | 156 | ||
| 161 | const relocs = blk: { | 157 | const relocs = blk: { |
| 162 | const extra = atom.getExtra(macho_file).?; | 158 | const extra = atom.getExtra(macho_file).?; |
| 163 | const relocs = slice.items(.relocs)[atom.n_sect].items; | 159 | const relocs = self.sections.items(.relocs)[atom.n_sect].items; |
| 164 | break :blk relocs[extra.rel_index..][0..extra.rel_count]; | 160 | break :blk relocs[extra.rel_index..][0..extra.rel_count]; |
| 165 | }; | 161 | }; |
| 166 | for (relocs) |*rel| switch (rel.tag) { | 162 | for (relocs) |*rel| switch (rel.tag) { |
| 167 | .local => if (killed_atoms.get(rel.target)) |new_target| { | 163 | .local => { |
| 168 | rel.target = new_target; | 164 | const target = macho_file.getAtom(rel.target).?; |
| 165 | if (target.getLiteralPoolIndex(macho_file)) |lp_index| { | ||
| 166 | const lp_atom = lp.getAtom(lp_index, macho_file); | ||
| 167 | if (target.atom_index != lp_atom.atom_index) { | ||
| 168 | target.flags.alive = false; | ||
| 169 | rel.target = lp_atom.atom_index; | ||
| 170 | } | ||
| 171 | } | ||
| 169 | }, | 172 | }, |
| 170 | .@"extern" => { | 173 | .@"extern" => { |
| 171 | const target = rel.getTargetSymbol(macho_file); | 174 | const target_sym = rel.getTargetSymbol(macho_file); |
| 172 | if (killed_atoms.get(target.atom)) |new_atom| { | 175 | if (target_sym.getAtom(macho_file)) |target_atom| { |
| 173 | target.atom = new_atom; | 176 | if (target_atom.getLiteralPoolIndex(macho_file)) |lp_index| { |
| 177 | const lp_atom = lp.getAtom(lp_index, macho_file); | ||
| 178 | if (target_atom.atom_index != lp_atom.atom_index) { | ||
| 179 | target_atom.flags.alive = false; | ||
| 180 | target_sym.atom = lp_atom.atom_index; | ||
| 181 | } | ||
| 182 | } | ||
| 174 | } | 183 | } |
| 175 | }, | 184 | }, |
| 176 | }; | 185 | }; |
| ... | @@ -179,9 +188,15 @@ pub fn dedupLiterals(self: InternalObject, lp: *MachO.LiteralPool, macho_file: * | ... | @@ -179,9 +188,15 @@ pub fn dedupLiterals(self: InternalObject, lp: *MachO.LiteralPool, macho_file: * |
| 179 | for (self.symbols.items) |sym_index| { | 188 | for (self.symbols.items) |sym_index| { |
| 180 | const sym = macho_file.getSymbol(sym_index); | 189 | const sym = macho_file.getSymbol(sym_index); |
| 181 | if (!sym.flags.objc_stubs) continue; | 190 | if (!sym.flags.objc_stubs) continue; |
| 182 | const extra = sym.getExtra(macho_file).?; | 191 | var extra = sym.getExtra(macho_file).?; |
| 183 | if (killed_atoms.get(extra.objc_selrefs)) |new_atom| { | 192 | const atom = macho_file.getAtom(extra.objc_selrefs).?; |
| 184 | try sym.addExtra(.{ .objc_selrefs = new_atom }, macho_file); | 193 | if (atom.getLiteralPoolIndex(macho_file)) |lp_index| { |
| 194 | const lp_atom = lp.getAtom(lp_index, macho_file); | ||
| 195 | if (atom.atom_index != lp_atom.atom_index) { | ||
| 196 | atom.flags.alive = false; | ||
| 197 | extra.objc_selrefs = lp_atom.atom_index; | ||
| 198 | sym.setExtra(extra, macho_file); | ||
| 199 | } | ||
| 185 | } | 200 | } |
| 186 | } | 201 | } |
| 187 | } | 202 | } |
src/link/MachO/Object.zig+26-17| ... | @@ -527,12 +527,9 @@ fn initPointerLiterals(self: *Object, macho_file: *MachO) !void { | ... | @@ -527,12 +527,9 @@ fn initPointerLiterals(self: *Object, macho_file: *MachO) !void { |
| 527 | } | 527 | } |
| 528 | } | 528 | } |
| 529 | 529 | ||
| 530 | pub fn dedupLiterals(self: Object, lp: *MachO.LiteralPool, macho_file: *MachO) !void { | 530 | pub fn resolveLiterals(self: Object, lp: *MachO.LiteralPool, macho_file: *MachO) !void { |
| 531 | const gpa = macho_file.base.comp.gpa; | 531 | const gpa = macho_file.base.comp.gpa; |
| 532 | 532 | ||
| 533 | var killed_atoms = std.AutoHashMap(Atom.Index, Atom.Index).init(gpa); | ||
| 534 | defer killed_atoms.deinit(); | ||
| 535 | |||
| 536 | var buffer = std.ArrayList(u8).init(gpa); | 533 | var buffer = std.ArrayList(u8).init(gpa); |
| 537 | defer buffer.deinit(); | 534 | defer buffer.deinit(); |
| 538 | 535 | ||
| ... | @@ -548,10 +545,9 @@ pub fn dedupLiterals(self: Object, lp: *MachO.LiteralPool, macho_file: *MachO) ! | ... | @@ -548,10 +545,9 @@ pub fn dedupLiterals(self: Object, lp: *MachO.LiteralPool, macho_file: *MachO) ! |
| 548 | const res = try lp.insert(gpa, header.type(), atom_data); | 545 | const res = try lp.insert(gpa, header.type(), atom_data); |
| 549 | if (!res.found_existing) { | 546 | if (!res.found_existing) { |
| 550 | res.atom.* = sub.atom; | 547 | res.atom.* = sub.atom; |
| 551 | continue; | ||
| 552 | } | 548 | } |
| 553 | atom.flags.alive = false; | 549 | atom.flags.literal_pool = true; |
| 554 | try killed_atoms.putNoClobber(sub.atom, res.atom.*); | 550 | try atom.addExtra(.{ .literal_index = res.index }, macho_file); |
| 555 | } | 551 | } |
| 556 | } else if (isPtrLiteral(header)) { | 552 | } else if (isPtrLiteral(header)) { |
| 557 | for (subs.items) |sub| { | 553 | for (subs.items) |sub| { |
| ... | @@ -572,33 +568,46 @@ pub fn dedupLiterals(self: Object, lp: *MachO.LiteralPool, macho_file: *MachO) ! | ... | @@ -572,33 +568,46 @@ pub fn dedupLiterals(self: Object, lp: *MachO.LiteralPool, macho_file: *MachO) ! |
| 572 | buffer.clearRetainingCapacity(); | 568 | buffer.clearRetainingCapacity(); |
| 573 | if (!res.found_existing) { | 569 | if (!res.found_existing) { |
| 574 | res.atom.* = sub.atom; | 570 | res.atom.* = sub.atom; |
| 575 | continue; | ||
| 576 | } | 571 | } |
| 577 | atom.flags.alive = false; | 572 | atom.flags.literal_pool = true; |
| 578 | try killed_atoms.putNoClobber(sub.atom, res.atom.*); | 573 | try atom.addExtra(.{ .literal_index = res.index }, macho_file); |
| 579 | } | 574 | } |
| 580 | } | 575 | } |
| 581 | } | 576 | } |
| 577 | } | ||
| 582 | 578 | ||
| 579 | pub fn dedupLiterals(self: Object, lp: MachO.LiteralPool, macho_file: *MachO) void { | ||
| 583 | for (self.atoms.items) |atom_index| { | 580 | for (self.atoms.items) |atom_index| { |
| 584 | if (killed_atoms.get(atom_index)) |_| continue; | ||
| 585 | const atom = macho_file.getAtom(atom_index) orelse continue; | 581 | const atom = macho_file.getAtom(atom_index) orelse continue; |
| 586 | if (!atom.flags.alive) continue; | 582 | if (!atom.flags.alive) continue; |
| 587 | if (!atom.flags.relocs) continue; | 583 | if (!atom.flags.relocs) continue; |
| 588 | 584 | ||
| 589 | const relocs = blk: { | 585 | const relocs = blk: { |
| 590 | const extra = atom.getExtra(macho_file).?; | 586 | const extra = atom.getExtra(macho_file).?; |
| 591 | const relocs = slice.items(.relocs)[atom.n_sect].items; | 587 | const relocs = self.sections.items(.relocs)[atom.n_sect].items; |
| 592 | break :blk relocs[extra.rel_index..][0..extra.rel_count]; | 588 | break :blk relocs[extra.rel_index..][0..extra.rel_count]; |
| 593 | }; | 589 | }; |
| 594 | for (relocs) |*rel| switch (rel.tag) { | 590 | for (relocs) |*rel| switch (rel.tag) { |
| 595 | .local => if (killed_atoms.get(rel.target)) |new_target| { | 591 | .local => { |
| 596 | rel.target = new_target; | 592 | const target = macho_file.getAtom(rel.target).?; |
| 593 | if (target.getLiteralPoolIndex(macho_file)) |lp_index| { | ||
| 594 | const lp_atom = lp.getAtom(lp_index, macho_file); | ||
| 595 | if (target.atom_index != lp_atom.atom_index) { | ||
| 596 | target.flags.alive = false; | ||
| 597 | rel.target = lp_atom.atom_index; | ||
| 598 | } | ||
| 599 | } | ||
| 597 | }, | 600 | }, |
| 598 | .@"extern" => { | 601 | .@"extern" => { |
| 599 | const target = rel.getTargetSymbol(macho_file); | 602 | const target_sym = rel.getTargetSymbol(macho_file); |
| 600 | if (killed_atoms.get(target.atom)) |new_atom| { | 603 | if (target_sym.getAtom(macho_file)) |target_atom| { |
| 601 | target.atom = new_atom; | 604 | if (target_atom.getLiteralPoolIndex(macho_file)) |lp_index| { |
| 605 | const lp_atom = lp.getAtom(lp_index, macho_file); | ||
| 606 | if (target_atom.atom_index != lp_atom.atom_index) { | ||
| 607 | target_atom.flags.alive = false; | ||
| 608 | target_sym.atom = lp_atom.atom_index; | ||
| 609 | } | ||
| 610 | } | ||
| 602 | } | 611 | } |
| 603 | }, | 612 | }, |
| 604 | }; | 613 | }; |
src/link/MachO/ZigObject.zig+8-1| ... | @@ -314,7 +314,14 @@ pub fn checkDuplicates(self: *ZigObject, dupes: anytype, macho_file: *MachO) !vo | ... | @@ -314,7 +314,14 @@ pub fn checkDuplicates(self: *ZigObject, dupes: anytype, macho_file: *MachO) !vo |
| 314 | } | 314 | } |
| 315 | } | 315 | } |
| 316 | 316 | ||
| 317 | pub fn dedupLiterals(self: *ZigObject, lp: *MachO.LiteralPool, macho_file: *MachO) !void { | 317 | pub fn resolveLiterals(self: *ZigObject, lp: *MachO.LiteralPool, macho_file: *MachO) !void { |
| 318 | _ = self; | ||
| 319 | _ = lp; | ||
| 320 | _ = macho_file; | ||
| 321 | // TODO | ||
| 322 | } | ||
| 323 | |||
| 324 | pub fn dedupLiterals(self: *ZigObject, lp: MachO.LiteralPool, macho_file: *MachO) void { | ||
| 318 | _ = self; | 325 | _ = self; |
| 319 | _ = lp; | 326 | _ = lp; |
| 320 | _ = macho_file; | 327 | _ = macho_file; |
test/link/macho.zig+211| ... | @@ -38,6 +38,8 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step { | ... | @@ -38,6 +38,8 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step { |
| 38 | macho_step.dependOn(testLayout(b, .{ .target = default_target })); | 38 | macho_step.dependOn(testLayout(b, .{ .target = default_target })); |
| 39 | macho_step.dependOn(testLinkingStaticLib(b, .{ .target = default_target })); | 39 | macho_step.dependOn(testLinkingStaticLib(b, .{ .target = default_target })); |
| 40 | macho_step.dependOn(testLinksection(b, .{ .target = default_target })); | 40 | macho_step.dependOn(testLinksection(b, .{ .target = default_target })); |
| 41 | macho_step.dependOn(testMergeLiterals(b, .{ .target = aarch64_target })); | ||
| 42 | macho_step.dependOn(testMergeLiterals2(b, .{ .target = aarch64_target })); | ||
| 41 | macho_step.dependOn(testMhExecuteHeader(b, .{ .target = default_target })); | 43 | macho_step.dependOn(testMhExecuteHeader(b, .{ .target = default_target })); |
| 42 | macho_step.dependOn(testNoDeadStrip(b, .{ .target = default_target })); | 44 | macho_step.dependOn(testNoDeadStrip(b, .{ .target = default_target })); |
| 43 | macho_step.dependOn(testNoExportsDylib(b, .{ .target = default_target })); | 45 | macho_step.dependOn(testNoExportsDylib(b, .{ .target = default_target })); |
| ... | @@ -914,6 +916,215 @@ fn testLinksection(b: *Build, opts: Options) *Step { | ... | @@ -914,6 +916,215 @@ fn testLinksection(b: *Build, opts: Options) *Step { |
| 914 | return test_step; | 916 | return test_step; |
| 915 | } | 917 | } |
| 916 | 918 | ||
| 919 | fn testMergeLiterals(b: *Build, opts: Options) *Step { | ||
| 920 | const test_step = addTestStep(b, "merge-literals", opts); | ||
| 921 | |||
| 922 | const a_o = addObject(b, opts, .{ .name = "a", .asm_source_bytes = | ||
| 923 | \\.globl _q1 | ||
| 924 | \\.globl _s1 | ||
| 925 | \\ | ||
| 926 | \\.align 4 | ||
| 927 | \\_q1: | ||
| 928 | \\ adrp x8, L._q1@PAGE | ||
| 929 | \\ ldr d0, [x8, L._q1@PAGEOFF] | ||
| 930 | \\ ret | ||
| 931 | \\ | ||
| 932 | \\.section __TEXT,__cstring,cstring_literals | ||
| 933 | \\l._s1: | ||
| 934 | \\ .asciz "hello" | ||
| 935 | \\ | ||
| 936 | \\.section __TEXT,__literal8,8byte_literals | ||
| 937 | \\.align 8 | ||
| 938 | \\L._q1: | ||
| 939 | \\ .double 1.2345 | ||
| 940 | \\ | ||
| 941 | \\.section __DATA,__data | ||
| 942 | \\.align 8 | ||
| 943 | \\_s1: | ||
| 944 | \\ .quad l._s1 | ||
| 945 | }); | ||
| 946 | |||
| 947 | const b_o = addObject(b, opts, .{ .name = "b", .asm_source_bytes = | ||
| 948 | \\.globl _q2 | ||
| 949 | \\.globl _s2 | ||
| 950 | \\.globl _s3 | ||
| 951 | \\ | ||
| 952 | \\.align 4 | ||
| 953 | \\_q2: | ||
| 954 | \\ adrp x8, L._q2@PAGE | ||
| 955 | \\ ldr d0, [x8, L._q2@PAGEOFF] | ||
| 956 | \\ ret | ||
| 957 | \\ | ||
| 958 | \\.section __TEXT,__cstring,cstring_literals | ||
| 959 | \\l._s2: | ||
| 960 | \\ .asciz "hello" | ||
| 961 | \\l._s3: | ||
| 962 | \\ .asciz "world" | ||
| 963 | \\ | ||
| 964 | \\.section __TEXT,__literal8,8byte_literals | ||
| 965 | \\.align 8 | ||
| 966 | \\L._q2: | ||
| 967 | \\ .double 1.2345 | ||
| 968 | \\ | ||
| 969 | \\.section __DATA,__data | ||
| 970 | \\.align 8 | ||
| 971 | \\_s2: | ||
| 972 | \\ .quad l._s2 | ||
| 973 | \\_s3: | ||
| 974 | \\ .quad l._s3 | ||
| 975 | }); | ||
| 976 | |||
| 977 | const main_o = addObject(b, opts, .{ .name = "main", .c_source_bytes = | ||
| 978 | \\#include <stdio.h> | ||
| 979 | \\extern double q1(); | ||
| 980 | \\extern double q2(); | ||
| 981 | \\extern const char* s1; | ||
| 982 | \\extern const char* s2; | ||
| 983 | \\extern const char* s3; | ||
| 984 | \\int main() { | ||
| 985 | \\ printf("%s, %s, %s, %f, %f", s1, s2, s3, q1(), q2()); | ||
| 986 | \\ return 0; | ||
| 987 | \\} | ||
| 988 | }); | ||
| 989 | |||
| 990 | { | ||
| 991 | const exe = addExecutable(b, opts, .{ .name = "main1" }); | ||
| 992 | exe.addObject(a_o); | ||
| 993 | exe.addObject(b_o); | ||
| 994 | exe.addObject(main_o); | ||
| 995 | |||
| 996 | const run = addRunArtifact(exe); | ||
| 997 | run.expectStdOutEqual("hello, hello, world, 1.234500, 1.234500"); | ||
| 998 | test_step.dependOn(&run.step); | ||
| 999 | |||
| 1000 | const check = exe.checkObject(); | ||
| 1001 | check.dumpSection("__TEXT,__const"); | ||
| 1002 | check.checkContains("\x8d\x97n\x12\x83\xc0\xf3?"); | ||
| 1003 | check.dumpSection("__TEXT,__cstring"); | ||
| 1004 | check.checkContains("hello\x00world\x00%s, %s, %s, %f, %f\x00"); | ||
| 1005 | test_step.dependOn(&check.step); | ||
| 1006 | } | ||
| 1007 | |||
| 1008 | { | ||
| 1009 | const exe = addExecutable(b, opts, .{ .name = "main2" }); | ||
| 1010 | exe.addObject(b_o); | ||
| 1011 | exe.addObject(a_o); | ||
| 1012 | exe.addObject(main_o); | ||
| 1013 | |||
| 1014 | const run = addRunArtifact(exe); | ||
| 1015 | run.expectStdOutEqual("hello, hello, world, 1.234500, 1.234500"); | ||
| 1016 | test_step.dependOn(&run.step); | ||
| 1017 | |||
| 1018 | const check = exe.checkObject(); | ||
| 1019 | check.dumpSection("__TEXT,__const"); | ||
| 1020 | check.checkContains("\x8d\x97n\x12\x83\xc0\xf3?"); | ||
| 1021 | check.dumpSection("__TEXT,__cstring"); | ||
| 1022 | check.checkContains("hello\x00world\x00%s, %s, %s, %f, %f\x00"); | ||
| 1023 | test_step.dependOn(&check.step); | ||
| 1024 | } | ||
| 1025 | |||
| 1026 | { | ||
| 1027 | const c_o = addObject(b, opts, .{ .name = "c" }); | ||
| 1028 | c_o.addObject(a_o); | ||
| 1029 | c_o.addObject(b_o); | ||
| 1030 | c_o.addObject(main_o); | ||
| 1031 | |||
| 1032 | const exe = addExecutable(b, opts, .{ .name = "main3" }); | ||
| 1033 | exe.addObject(c_o); | ||
| 1034 | |||
| 1035 | const run = addRunArtifact(exe); | ||
| 1036 | run.expectStdOutEqual("hello, hello, world, 1.234500, 1.234500"); | ||
| 1037 | test_step.dependOn(&run.step); | ||
| 1038 | |||
| 1039 | const check = exe.checkObject(); | ||
| 1040 | check.dumpSection("__TEXT,__const"); | ||
| 1041 | check.checkContains("\x8d\x97n\x12\x83\xc0\xf3?"); | ||
| 1042 | check.dumpSection("__TEXT,__cstring"); | ||
| 1043 | check.checkContains("hello\x00world\x00%s, %s, %s, %f, %f\x00"); | ||
| 1044 | test_step.dependOn(&check.step); | ||
| 1045 | } | ||
| 1046 | |||
| 1047 | return test_step; | ||
| 1048 | } | ||
| 1049 | |||
| 1050 | /// This particular test case will generate invalid machine code that will segfault at runtime. | ||
| 1051 | /// However, this is by design as we want to test that the linker does not panic when linking it | ||
| 1052 | /// which is also the case for the system linker and lld - linking succeeds, runtime segfaults. | ||
| 1053 | /// It should also be mentioned that runtime segfault is not due to the linker but faulty input asm. | ||
| 1054 | fn testMergeLiterals2(b: *Build, opts: Options) *Step { | ||
| 1055 | const test_step = addTestStep(b, "merge-literals-2", opts); | ||
| 1056 | |||
| 1057 | const a_o = addObject(b, opts, .{ .name = "a", .asm_source_bytes = | ||
| 1058 | \\.globl _q1 | ||
| 1059 | \\.globl _s1 | ||
| 1060 | \\ | ||
| 1061 | \\.align 4 | ||
| 1062 | \\_q1: | ||
| 1063 | \\ adrp x0, L._q1@PAGE | ||
| 1064 | \\ ldr x0, [x0, L._q1@PAGEOFF] | ||
| 1065 | \\ ret | ||
| 1066 | \\ | ||
| 1067 | \\.section __TEXT,__cstring,cstring_literals | ||
| 1068 | \\_s1: | ||
| 1069 | \\ .asciz "hello" | ||
| 1070 | \\ | ||
| 1071 | \\.section __TEXT,__literal8,8byte_literals | ||
| 1072 | \\.align 8 | ||
| 1073 | \\L._q1: | ||
| 1074 | \\ .double 1.2345 | ||
| 1075 | }); | ||
| 1076 | |||
| 1077 | const b_o = addObject(b, opts, .{ .name = "b", .asm_source_bytes = | ||
| 1078 | \\.globl _q2 | ||
| 1079 | \\.globl _s2 | ||
| 1080 | \\.globl _s3 | ||
| 1081 | \\ | ||
| 1082 | \\.align 4 | ||
| 1083 | \\_q2: | ||
| 1084 | \\ adrp x0, L._q2@PAGE | ||
| 1085 | \\ ldr x0, [x0, L._q2@PAGEOFF] | ||
| 1086 | \\ ret | ||
| 1087 | \\ | ||
| 1088 | \\.section __TEXT,__cstring,cstring_literals | ||
| 1089 | \\_s2: | ||
| 1090 | \\ .asciz "hello" | ||
| 1091 | \\_s3: | ||
| 1092 | \\ .asciz "world" | ||
| 1093 | \\ | ||
| 1094 | \\.section __TEXT,__literal8,8byte_literals | ||
| 1095 | \\.align 8 | ||
| 1096 | \\L._q2: | ||
| 1097 | \\ .double 1.2345 | ||
| 1098 | }); | ||
| 1099 | |||
| 1100 | const main_o = addObject(b, opts, .{ .name = "main", .c_source_bytes = | ||
| 1101 | \\#include <stdio.h> | ||
| 1102 | \\extern double q1(); | ||
| 1103 | \\extern double q2(); | ||
| 1104 | \\extern const char* s1; | ||
| 1105 | \\extern const char* s2; | ||
| 1106 | \\extern const char* s3; | ||
| 1107 | \\int main() { | ||
| 1108 | \\ printf("%s, %s, %s, %f, %f", s1, s2, s3, q1(), q2()); | ||
| 1109 | \\ return 0; | ||
| 1110 | \\} | ||
| 1111 | }); | ||
| 1112 | |||
| 1113 | const exe = addExecutable(b, opts, .{ .name = "main1" }); | ||
| 1114 | exe.addObject(a_o); | ||
| 1115 | exe.addObject(b_o); | ||
| 1116 | exe.addObject(main_o); | ||
| 1117 | |||
| 1118 | const check = exe.checkObject(); | ||
| 1119 | check.dumpSection("__TEXT,__const"); | ||
| 1120 | check.checkContains("\x8d\x97n\x12\x83\xc0\xf3?"); | ||
| 1121 | check.dumpSection("__TEXT,__cstring"); | ||
| 1122 | check.checkContains("hello\x00world\x00%s, %s, %s, %f, %f\x00"); | ||
| 1123 | test_step.dependOn(&check.step); | ||
| 1124 | |||
| 1125 | return test_step; | ||
| 1126 | } | ||
| 1127 | |||
| 917 | fn testMhExecuteHeader(b: *Build, opts: Options) *Step { | 1128 | fn testMhExecuteHeader(b: *Build, opts: Options) *Step { |
| 918 | const test_step = addTestStep(b, "mh-execute-header", opts); | 1129 | const test_step = addTestStep(b, "mh-execute-header", opts); |
| 919 | 1130 |