| 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 | 1500 | const gpa = self.base.comp.gpa; |
| 1501 | 1501 | var lp: LiteralPool = .{}; |
| 1502 | 1502 | defer lp.deinit(gpa); |
| 1503 | ||
| 1503 | 1504 | if (self.getZigObject()) |zo| { |
| 1504 | try zo.dedupLiterals(&lp, self); | |
| 1505 | try zo.resolveLiterals(&lp, self); | |
| 1505 | 1506 | } |
| 1506 | 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 | 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 | 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 | 4434 | const InsertResult = struct { |
| 4419 | 4435 | found_existing: bool, |
| 4436 | index: Index, | |
| 4420 | 4437 | atom: *Atom.Index, |
| 4421 | 4438 | }; |
| 4422 | 4439 | |
| ... | ... | @@ -4434,6 +4451,7 @@ pub const LiteralPool = struct { |
| 4434 | 4451 | } |
| 4435 | 4452 | return .{ |
| 4436 | 4453 | .found_existing = gop.found_existing, |
| 4454 | .index = @intCast(gop.index), | |
| 4437 | 4455 | .atom = &lp.values.items[gop.index], |
| 4438 | 4456 | }; |
| 4439 | 4457 | } |
| ... | ... | @@ -4472,6 +4490,8 @@ pub const LiteralPool = struct { |
| 4472 | 4490 | return key.hash(ctx.lp); |
| 4473 | 4491 | } |
| 4474 | 4492 | }; |
| 4493 | ||
| 4494 | pub const Index = u32; | |
| 4475 | 4495 | }; |
| 4476 | 4496 | |
| 4477 | 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 | 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 | 121 | const AddExtraOpts = struct { |
| 117 | 122 | thunk: ?u32 = null, |
| 118 | 123 | rel_index: ?u32 = null, |
| 119 | 124 | rel_count: ?u32 = null, |
| 120 | 125 | unwind_index: ?u32 = null, |
| 121 | 126 | unwind_count: ?u32 = null, |
| 127 | literal_index: ?u32 = null, | |
| 122 | 128 | }; |
| 123 | 129 | |
| 124 | 130 | pub fn addExtra(atom: *Atom, opts: AddExtraOpts, macho_file: *MachO) !void { |
| ... | ... | @@ -1177,7 +1183,7 @@ pub const Flags = packed struct { |
| 1177 | 1183 | /// Specifies whether this atom is alive or has been garbage collected. |
| 1178 | 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 | 1187 | visited: bool = false, |
| 1182 | 1188 | |
| 1183 | 1189 | /// Whether this atom has a range extension thunk. |
| ... | ... | @@ -1188,6 +1194,9 @@ pub const Flags = packed struct { |
| 1188 | 1194 | |
| 1189 | 1195 | /// Whether this atom has any unwind records. |
| 1190 | 1196 | unwind: bool = false, |
| 1197 | ||
| 1198 | /// Whether this atom has LiteralPool entry. | |
| 1199 | literal_pool: bool = false, | |
| 1191 | 1200 | }; |
| 1192 | 1201 | |
| 1193 | 1202 | pub const Extra = struct { |
| ... | ... | @@ -1205,6 +1214,9 @@ pub const Extra = struct { |
| 1205 | 1214 | |
| 1206 | 1215 | /// Count of relocations belonging to this atom. |
| 1207 | 1216 | unwind_count: u32 = 0, |
| 1217 | ||
| 1218 | /// Index into LiteralPool entry for this atom. | |
| 1219 | literal_index: u32 = 0, | |
| 1208 | 1220 | }; |
| 1209 | 1221 | |
| 1210 | 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 | 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 | 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 | 115 | var buffer = std.ArrayList(u8).init(gpa); |
| 119 | 116 | defer buffer.deinit(); |
| 120 | 117 | |
| ... | ... | @@ -126,10 +123,9 @@ pub fn dedupLiterals(self: InternalObject, lp: *MachO.LiteralPool, macho_file: * |
| 126 | 123 | const res = try lp.insert(gpa, header.type(), data); |
| 127 | 124 | if (!res.found_existing) { |
| 128 | 125 | res.atom.* = atom_index; |
| 129 | continue; | |
| 130 | 126 | } |
| 131 | atom.flags.alive = false; | |
| 132 | try killed_atoms.putNoClobber(atom_index, res.atom.*); | |
| 127 | atom.flags.literal_pool = true; | |
| 128 | try atom.addExtra(.{ .literal_index = res.index }, macho_file); | |
| 133 | 129 | } else if (Object.isPtrLiteral(header)) { |
| 134 | 130 | const atom = macho_file.getAtom(atom_index).?; |
| 135 | 131 | const relocs = atom.getRelocs(macho_file); |
| ... | ... | @@ -145,32 +141,45 @@ pub fn dedupLiterals(self: InternalObject, lp: *MachO.LiteralPool, macho_file: * |
| 145 | 141 | buffer.clearRetainingCapacity(); |
| 146 | 142 | if (!res.found_existing) { |
| 147 | 143 | res.atom.* = atom_index; |
| 148 | continue; | |
| 149 | 144 | } |
| 150 | atom.flags.alive = false; | |
| 151 | try killed_atoms.putNoClobber(atom_index, res.atom.*); | |
| 145 | atom.flags.literal_pool = true; | |
| 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 | 152 | for (self.atoms.items) |atom_index| { |
| 156 | if (killed_atoms.get(atom_index)) |_| continue; | |
| 157 | 153 | const atom = macho_file.getAtom(atom_index) orelse continue; |
| 158 | 154 | if (!atom.flags.alive) continue; |
| 159 | 155 | if (!atom.flags.relocs) continue; |
| 160 | 156 | |
| 161 | 157 | const relocs = blk: { |
| 162 | 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 | 160 | break :blk relocs[extra.rel_index..][0..extra.rel_count]; |
| 165 | 161 | }; |
| 166 | 162 | for (relocs) |*rel| switch (rel.tag) { |
| 167 | .local => if (killed_atoms.get(rel.target)) |new_target| { | |
| 168 | rel.target = new_target; | |
| 163 | .local => { | |
| 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 | 173 | .@"extern" => { |
| 171 | const target = rel.getTargetSymbol(macho_file); | |
| 172 | if (killed_atoms.get(target.atom)) |new_atom| { | |
| 173 | target.atom = new_atom; | |
| 174 | const target_sym = rel.getTargetSymbol(macho_file); | |
| 175 | if (target_sym.getAtom(macho_file)) |target_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 | 188 | for (self.symbols.items) |sym_index| { |
| 180 | 189 | const sym = macho_file.getSymbol(sym_index); |
| 181 | 190 | if (!sym.flags.objc_stubs) continue; |
| 182 | const extra = sym.getExtra(macho_file).?; | |
| 183 | if (killed_atoms.get(extra.objc_selrefs)) |new_atom| { | |
| 184 | try sym.addExtra(.{ .objc_selrefs = new_atom }, macho_file); | |
| 191 | var extra = sym.getExtra(macho_file).?; | |
| 192 | const atom = macho_file.getAtom(extra.objc_selrefs).?; | |
| 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 | 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 | 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 | 533 | var buffer = std.ArrayList(u8).init(gpa); |
| 537 | 534 | defer buffer.deinit(); |
| 538 | 535 | |
| ... | ... | @@ -548,10 +545,9 @@ pub fn dedupLiterals(self: Object, lp: *MachO.LiteralPool, macho_file: *MachO) ! |
| 548 | 545 | const res = try lp.insert(gpa, header.type(), atom_data); |
| 549 | 546 | if (!res.found_existing) { |
| 550 | 547 | res.atom.* = sub.atom; |
| 551 | continue; | |
| 552 | 548 | } |
| 553 | atom.flags.alive = false; | |
| 554 | try killed_atoms.putNoClobber(sub.atom, res.atom.*); | |
| 549 | atom.flags.literal_pool = true; | |
| 550 | try atom.addExtra(.{ .literal_index = res.index }, macho_file); | |
| 555 | 551 | } |
| 556 | 552 | } else if (isPtrLiteral(header)) { |
| 557 | 553 | for (subs.items) |sub| { |
| ... | ... | @@ -572,33 +568,46 @@ pub fn dedupLiterals(self: Object, lp: *MachO.LiteralPool, macho_file: *MachO) ! |
| 572 | 568 | buffer.clearRetainingCapacity(); |
| 573 | 569 | if (!res.found_existing) { |
| 574 | 570 | res.atom.* = sub.atom; |
| 575 | continue; | |
| 576 | 571 | } |
| 577 | atom.flags.alive = false; | |
| 578 | try killed_atoms.putNoClobber(sub.atom, res.atom.*); | |
| 572 | atom.flags.literal_pool = true; | |
| 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 | 580 | for (self.atoms.items) |atom_index| { |
| 584 | if (killed_atoms.get(atom_index)) |_| continue; | |
| 585 | 581 | const atom = macho_file.getAtom(atom_index) orelse continue; |
| 586 | 582 | if (!atom.flags.alive) continue; |
| 587 | 583 | if (!atom.flags.relocs) continue; |
| 588 | 584 | |
| 589 | 585 | const relocs = blk: { |
| 590 | 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 | 588 | break :blk relocs[extra.rel_index..][0..extra.rel_count]; |
| 593 | 589 | }; |
| 594 | 590 | for (relocs) |*rel| switch (rel.tag) { |
| 595 | .local => if (killed_atoms.get(rel.target)) |new_target| { | |
| 596 | rel.target = new_target; | |
| 591 | .local => { | |
| 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 | 601 | .@"extern" => { |
| 599 | const target = rel.getTargetSymbol(macho_file); | |
| 600 | if (killed_atoms.get(target.atom)) |new_atom| { | |
| 601 | target.atom = new_atom; | |
| 602 | const target_sym = rel.getTargetSymbol(macho_file); | |
| 603 | if (target_sym.getAtom(macho_file)) |target_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 | 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 | 325 | _ = self; |
| 319 | 326 | _ = lp; |
| 320 | 327 | _ = macho_file; |
test/link/macho.zig+211| ... | ... | @@ -38,6 +38,8 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step { |
| 38 | 38 | macho_step.dependOn(testLayout(b, .{ .target = default_target })); |
| 39 | 39 | macho_step.dependOn(testLinkingStaticLib(b, .{ .target = default_target })); |
| 40 | 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 | 43 | macho_step.dependOn(testMhExecuteHeader(b, .{ .target = default_target })); |
| 42 | 44 | macho_step.dependOn(testNoDeadStrip(b, .{ .target = default_target })); |
| 43 | 45 | macho_step.dependOn(testNoExportsDylib(b, .{ .target = default_target })); |
| ... | ... | @@ -914,6 +916,215 @@ fn testLinksection(b: *Build, opts: Options) *Step { |
| 914 | 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 | 1128 | fn testMhExecuteHeader(b: *Build, opts: Options) *Step { |
| 918 | 1129 | const test_step = addTestStep(b, "mh-execute-header", opts); |
| 919 | 1130 |