| author | |
| committer | |
| log | d997ddaa102bb9ba5f1e8480b8c78f7d102b5512 |
| tree | 57905ad345e6e4e7cebdb4597b6790f073dfa0b1 |
| parent | e9a00ba7f4ef2546cd0c98559002431c749374fe |
| parent | c3fb30803f4fbe62abb4bfad348c585e9ab80234 |
| signature |
AstGen: disallow fields and decls from sharing names51 files changed, 1263 insertions(+), 1323 deletions(-)
CMakeLists.txt+2-2| ... | @@ -613,7 +613,7 @@ set(ZIG_STAGE2_SOURCES | ... | @@ -613,7 +613,7 @@ set(ZIG_STAGE2_SOURCES |
| 613 | src/link/Elf/relocatable.zig | 613 | src/link/Elf/relocatable.zig |
| 614 | src/link/Elf/relocation.zig | 614 | src/link/Elf/relocation.zig |
| 615 | src/link/Elf/synthetic_sections.zig | 615 | src/link/Elf/synthetic_sections.zig |
| 616 | src/link/Elf/thunks.zig | 616 | src/link/Elf/Thunk.zig |
| 617 | src/link/MachO.zig | 617 | src/link/MachO.zig |
| 618 | src/link/MachO/Archive.zig | 618 | src/link/MachO/Archive.zig |
| 619 | src/link/MachO/Atom.zig | 619 | src/link/MachO/Atom.zig |
| ... | @@ -638,7 +638,7 @@ set(ZIG_STAGE2_SOURCES | ... | @@ -638,7 +638,7 @@ set(ZIG_STAGE2_SOURCES |
| 638 | src/link/MachO/load_commands.zig | 638 | src/link/MachO/load_commands.zig |
| 639 | src/link/MachO/relocatable.zig | 639 | src/link/MachO/relocatable.zig |
| 640 | src/link/MachO/synthetic.zig | 640 | src/link/MachO/synthetic.zig |
| 641 | src/link/MachO/thunks.zig | 641 | src/link/MachO/Thunk.zig |
| 642 | src/link/MachO/uuid.zig | 642 | src/link/MachO/uuid.zig |
| 643 | src/link/NvPtx.zig | 643 | src/link/NvPtx.zig |
| 644 | src/link/Plan9.zig | 644 | src/link/Plan9.zig |
lib/std/crypto/poly1305.zig+5-5| ... | @@ -12,7 +12,7 @@ pub const Poly1305 = struct { | ... | @@ -12,7 +12,7 @@ pub const Poly1305 = struct { |
| 12 | // accumulated hash | 12 | // accumulated hash |
| 13 | h: [3]u64 = [_]u64{ 0, 0, 0 }, | 13 | h: [3]u64 = [_]u64{ 0, 0, 0 }, |
| 14 | // random number added at the end (from the secret key) | 14 | // random number added at the end (from the secret key) |
| 15 | pad: [2]u64, | 15 | end_pad: [2]u64, |
| 16 | // how many bytes are waiting to be processed in a partial block | 16 | // how many bytes are waiting to be processed in a partial block |
| 17 | leftover: usize = 0, | 17 | leftover: usize = 0, |
| 18 | // partial block buffer | 18 | // partial block buffer |
| ... | @@ -24,7 +24,7 @@ pub const Poly1305 = struct { | ... | @@ -24,7 +24,7 @@ pub const Poly1305 = struct { |
| 24 | mem.readInt(u64, key[0..8], .little) & 0x0ffffffc0fffffff, | 24 | mem.readInt(u64, key[0..8], .little) & 0x0ffffffc0fffffff, |
| 25 | mem.readInt(u64, key[8..16], .little) & 0x0ffffffc0ffffffc, | 25 | mem.readInt(u64, key[8..16], .little) & 0x0ffffffc0ffffffc, |
| 26 | }, | 26 | }, |
| 27 | .pad = [_]u64{ | 27 | .end_pad = [_]u64{ |
| 28 | mem.readInt(u64, key[16..24], .little), | 28 | mem.readInt(u64, key[16..24], .little), |
| 29 | mem.readInt(u64, key[24..32], .little), | 29 | mem.readInt(u64, key[24..32], .little), |
| 30 | }, | 30 | }, |
| ... | @@ -177,9 +177,9 @@ pub const Poly1305 = struct { | ... | @@ -177,9 +177,9 @@ pub const Poly1305 = struct { |
| 177 | h1 ^= mask & (h1 ^ h_p1); | 177 | h1 ^= mask & (h1 ^ h_p1); |
| 178 | 178 | ||
| 179 | // Add the first half of the key, we intentionally don't use @addWithOverflow() here. | 179 | // Add the first half of the key, we intentionally don't use @addWithOverflow() here. |
| 180 | st.h[0] = h0 +% st.pad[0]; | 180 | st.h[0] = h0 +% st.end_pad[0]; |
| 181 | const c = ((h0 & st.pad[0]) | ((h0 | st.pad[0]) & ~st.h[0])) >> 63; | 181 | const c = ((h0 & st.end_pad[0]) | ((h0 | st.end_pad[0]) & ~st.h[0])) >> 63; |
| 182 | st.h[1] = h1 +% st.pad[1] +% c; | 182 | st.h[1] = h1 +% st.end_pad[1] +% c; |
| 183 | 183 | ||
| 184 | mem.writeInt(u64, out[0..8], st.h[0], .little); | 184 | mem.writeInt(u64, out[0..8], st.h[0], .little); |
| 185 | mem.writeInt(u64, out[8..16], st.h[1], .little); | 185 | mem.writeInt(u64, out[8..16], st.h[1], .little); |
lib/std/debug/Pdb.zig+61-62| ... | @@ -63,18 +63,18 @@ pub fn deinit(self: *Pdb) void { | ... | @@ -63,18 +63,18 @@ pub fn deinit(self: *Pdb) void { |
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | pub fn parseDbiStream(self: *Pdb) !void { | 65 | pub fn parseDbiStream(self: *Pdb) !void { |
| 66 | var stream = self.getStream(pdb.StreamType.Dbi) orelse | 66 | var stream = self.getStream(pdb.StreamType.dbi) orelse |
| 67 | return error.InvalidDebugInfo; | 67 | return error.InvalidDebugInfo; |
| 68 | const reader = stream.reader(); | 68 | const reader = stream.reader(); |
| 69 | 69 | ||
| 70 | const header = try reader.readStruct(std.pdb.DbiStreamHeader); | 70 | const header = try reader.readStruct(std.pdb.DbiStreamHeader); |
| 71 | if (header.VersionHeader != 19990903) // V70, only value observed by LLVM team | 71 | if (header.version_header != 19990903) // V70, only value observed by LLVM team |
| 72 | return error.UnknownPDBVersion; | 72 | return error.UnknownPDBVersion; |
| 73 | // if (header.Age != age) | 73 | // if (header.Age != age) |
| 74 | // return error.UnmatchingPDB; | 74 | // return error.UnmatchingPDB; |
| 75 | 75 | ||
| 76 | const mod_info_size = header.ModInfoSize; | 76 | const mod_info_size = header.mod_info_size; |
| 77 | const section_contrib_size = header.SectionContributionSize; | 77 | const section_contrib_size = header.section_contribution_size; |
| 78 | 78 | ||
| 79 | var modules = std.ArrayList(Module).init(self.allocator); | 79 | var modules = std.ArrayList(Module).init(self.allocator); |
| 80 | errdefer modules.deinit(); | 80 | errdefer modules.deinit(); |
| ... | @@ -143,7 +143,7 @@ pub fn parseDbiStream(self: *Pdb) !void { | ... | @@ -143,7 +143,7 @@ pub fn parseDbiStream(self: *Pdb) !void { |
| 143 | } | 143 | } |
| 144 | 144 | ||
| 145 | pub fn parseInfoStream(self: *Pdb) !void { | 145 | pub fn parseInfoStream(self: *Pdb) !void { |
| 146 | var stream = self.getStream(pdb.StreamType.Pdb) orelse | 146 | var stream = self.getStream(pdb.StreamType.pdb) orelse |
| 147 | return error.InvalidDebugInfo; | 147 | return error.InvalidDebugInfo; |
| 148 | const reader = stream.reader(); | 148 | const reader = stream.reader(); |
| 149 | 149 | ||
| ... | @@ -168,23 +168,23 @@ pub fn parseInfoStream(self: *Pdb) !void { | ... | @@ -168,23 +168,23 @@ pub fn parseInfoStream(self: *Pdb) !void { |
| 168 | try reader.readNoEof(name_bytes); | 168 | try reader.readNoEof(name_bytes); |
| 169 | 169 | ||
| 170 | const HashTableHeader = extern struct { | 170 | const HashTableHeader = extern struct { |
| 171 | Size: u32, | 171 | size: u32, |
| 172 | Capacity: u32, | 172 | capacity: u32, |
| 173 | 173 | ||
| 174 | fn maxLoad(cap: u32) u32 { | 174 | fn maxLoad(cap: u32) u32 { |
| 175 | return cap * 2 / 3 + 1; | 175 | return cap * 2 / 3 + 1; |
| 176 | } | 176 | } |
| 177 | }; | 177 | }; |
| 178 | const hash_tbl_hdr = try reader.readStruct(HashTableHeader); | 178 | const hash_tbl_hdr = try reader.readStruct(HashTableHeader); |
| 179 | if (hash_tbl_hdr.Capacity == 0) | 179 | if (hash_tbl_hdr.capacity == 0) |
| 180 | return error.InvalidDebugInfo; | 180 | return error.InvalidDebugInfo; |
| 181 | 181 | ||
| 182 | if (hash_tbl_hdr.Size > HashTableHeader.maxLoad(hash_tbl_hdr.Capacity)) | 182 | if (hash_tbl_hdr.size > HashTableHeader.maxLoad(hash_tbl_hdr.capacity)) |
| 183 | return error.InvalidDebugInfo; | 183 | return error.InvalidDebugInfo; |
| 184 | 184 | ||
| 185 | const present = try readSparseBitVector(&reader, self.allocator); | 185 | const present = try readSparseBitVector(&reader, self.allocator); |
| 186 | defer self.allocator.free(present); | 186 | defer self.allocator.free(present); |
| 187 | if (present.len != hash_tbl_hdr.Size) | 187 | if (present.len != hash_tbl_hdr.size) |
| 188 | return error.InvalidDebugInfo; | 188 | return error.InvalidDebugInfo; |
| 189 | const deleted = try readSparseBitVector(&reader, self.allocator); | 189 | const deleted = try readSparseBitVector(&reader, self.allocator); |
| 190 | defer self.allocator.free(deleted); | 190 | defer self.allocator.free(deleted); |
| ... | @@ -212,19 +212,19 @@ pub fn getSymbolName(self: *Pdb, module: *Module, address: u64) ?[]const u8 { | ... | @@ -212,19 +212,19 @@ pub fn getSymbolName(self: *Pdb, module: *Module, address: u64) ?[]const u8 { |
| 212 | 212 | ||
| 213 | var symbol_i: usize = 0; | 213 | var symbol_i: usize = 0; |
| 214 | while (symbol_i != module.symbols.len) { | 214 | while (symbol_i != module.symbols.len) { |
| 215 | const prefix = @as(*align(1) pdb.RecordPrefix, @ptrCast(&module.symbols[symbol_i])); | 215 | const prefix: *align(1) pdb.RecordPrefix = @ptrCast(&module.symbols[symbol_i]); |
| 216 | if (prefix.RecordLen < 2) | 216 | if (prefix.record_len < 2) |
| 217 | return null; | 217 | return null; |
| 218 | switch (prefix.RecordKind) { | 218 | switch (prefix.record_kind) { |
| 219 | .S_LPROC32, .S_GPROC32 => { | 219 | .lproc32, .gproc32 => { |
| 220 | const proc_sym = @as(*align(1) pdb.ProcSym, @ptrCast(&module.symbols[symbol_i + @sizeOf(pdb.RecordPrefix)])); | 220 | const proc_sym: *align(1) pdb.ProcSym = @ptrCast(&module.symbols[symbol_i + @sizeOf(pdb.RecordPrefix)]); |
| 221 | if (address >= proc_sym.CodeOffset and address < proc_sym.CodeOffset + proc_sym.CodeSize) { | 221 | if (address >= proc_sym.code_offset and address < proc_sym.code_offset + proc_sym.code_size) { |
| 222 | return std.mem.sliceTo(@as([*:0]u8, @ptrCast(&proc_sym.Name[0])), 0); | 222 | return std.mem.sliceTo(@as([*:0]u8, @ptrCast(&proc_sym.name[0])), 0); |
| 223 | } | 223 | } |
| 224 | }, | 224 | }, |
| 225 | else => {}, | 225 | else => {}, |
| 226 | } | 226 | } |
| 227 | symbol_i += prefix.RecordLen + @sizeOf(u16); | 227 | symbol_i += prefix.record_len + @sizeOf(u16); |
| 228 | } | 228 | } |
| 229 | 229 | ||
| 230 | return null; | 230 | return null; |
| ... | @@ -238,44 +238,44 @@ pub fn getLineNumberInfo(self: *Pdb, module: *Module, address: u64) !std.debug.S | ... | @@ -238,44 +238,44 @@ pub fn getLineNumberInfo(self: *Pdb, module: *Module, address: u64) !std.debug.S |
| 238 | var skip_len: usize = undefined; | 238 | var skip_len: usize = undefined; |
| 239 | const checksum_offset = module.checksum_offset orelse return error.MissingDebugInfo; | 239 | const checksum_offset = module.checksum_offset orelse return error.MissingDebugInfo; |
| 240 | while (sect_offset != subsect_info.len) : (sect_offset += skip_len) { | 240 | while (sect_offset != subsect_info.len) : (sect_offset += skip_len) { |
| 241 | const subsect_hdr = @as(*align(1) pdb.DebugSubsectionHeader, @ptrCast(&subsect_info[sect_offset])); | 241 | const subsect_hdr: *align(1) pdb.DebugSubsectionHeader = @ptrCast(&subsect_info[sect_offset]); |
| 242 | skip_len = subsect_hdr.Length; | 242 | skip_len = subsect_hdr.length; |
| 243 | sect_offset += @sizeOf(pdb.DebugSubsectionHeader); | 243 | sect_offset += @sizeOf(pdb.DebugSubsectionHeader); |
| 244 | 244 | ||
| 245 | switch (subsect_hdr.Kind) { | 245 | switch (subsect_hdr.kind) { |
| 246 | .Lines => { | 246 | .lines => { |
| 247 | var line_index = sect_offset; | 247 | var line_index = sect_offset; |
| 248 | 248 | ||
| 249 | const line_hdr = @as(*align(1) pdb.LineFragmentHeader, @ptrCast(&subsect_info[line_index])); | 249 | const line_hdr: *align(1) pdb.LineFragmentHeader = @ptrCast(&subsect_info[line_index]); |
| 250 | if (line_hdr.RelocSegment == 0) | 250 | if (line_hdr.reloc_segment == 0) |
| 251 | return error.MissingDebugInfo; | 251 | return error.MissingDebugInfo; |
| 252 | line_index += @sizeOf(pdb.LineFragmentHeader); | 252 | line_index += @sizeOf(pdb.LineFragmentHeader); |
| 253 | const frag_vaddr_start = line_hdr.RelocOffset; | 253 | const frag_vaddr_start = line_hdr.reloc_offset; |
| 254 | const frag_vaddr_end = frag_vaddr_start + line_hdr.CodeSize; | 254 | const frag_vaddr_end = frag_vaddr_start + line_hdr.code_size; |
| 255 | 255 | ||
| 256 | if (address >= frag_vaddr_start and address < frag_vaddr_end) { | 256 | if (address >= frag_vaddr_start and address < frag_vaddr_end) { |
| 257 | // There is an unknown number of LineBlockFragmentHeaders (and their accompanying line and column records) | 257 | // There is an unknown number of LineBlockFragmentHeaders (and their accompanying line and column records) |
| 258 | // from now on. We will iterate through them, and eventually find a SourceLocation that we're interested in, | 258 | // from now on. We will iterate through them, and eventually find a SourceLocation that we're interested in, |
| 259 | // breaking out to :subsections. If not, we will make sure to not read anything outside of this subsection. | 259 | // breaking out to :subsections. If not, we will make sure to not read anything outside of this subsection. |
| 260 | const subsection_end_index = sect_offset + subsect_hdr.Length; | 260 | const subsection_end_index = sect_offset + subsect_hdr.length; |
| 261 | 261 | ||
| 262 | while (line_index < subsection_end_index) { | 262 | while (line_index < subsection_end_index) { |
| 263 | const block_hdr = @as(*align(1) pdb.LineBlockFragmentHeader, @ptrCast(&subsect_info[line_index])); | 263 | const block_hdr: *align(1) pdb.LineBlockFragmentHeader = @ptrCast(&subsect_info[line_index]); |
| 264 | line_index += @sizeOf(pdb.LineBlockFragmentHeader); | 264 | line_index += @sizeOf(pdb.LineBlockFragmentHeader); |
| 265 | const start_line_index = line_index; | 265 | const start_line_index = line_index; |
| 266 | 266 | ||
| 267 | const has_column = line_hdr.Flags.LF_HaveColumns; | 267 | const has_column = line_hdr.flags.have_columns; |
| 268 | 268 | ||
| 269 | // All line entries are stored inside their line block by ascending start address. | 269 | // All line entries are stored inside their line block by ascending start address. |
| 270 | // Heuristic: we want to find the last line entry | 270 | // Heuristic: we want to find the last line entry |
| 271 | // that has a vaddr_start <= address. | 271 | // that has a vaddr_start <= address. |
| 272 | // This is done with a simple linear search. | 272 | // This is done with a simple linear search. |
| 273 | var line_i: u32 = 0; | 273 | var line_i: u32 = 0; |
| 274 | while (line_i < block_hdr.NumLines) : (line_i += 1) { | 274 | while (line_i < block_hdr.num_lines) : (line_i += 1) { |
| 275 | const line_num_entry = @as(*align(1) pdb.LineNumberEntry, @ptrCast(&subsect_info[line_index])); | 275 | const line_num_entry: *align(1) pdb.LineNumberEntry = @ptrCast(&subsect_info[line_index]); |
| 276 | line_index += @sizeOf(pdb.LineNumberEntry); | 276 | line_index += @sizeOf(pdb.LineNumberEntry); |
| 277 | 277 | ||
| 278 | const vaddr_start = frag_vaddr_start + line_num_entry.Offset; | 278 | const vaddr_start = frag_vaddr_start + line_num_entry.offset; |
| 279 | if (address < vaddr_start) { | 279 | if (address < vaddr_start) { |
| 280 | break; | 280 | break; |
| 281 | } | 281 | } |
| ... | @@ -283,28 +283,27 @@ pub fn getLineNumberInfo(self: *Pdb, module: *Module, address: u64) !std.debug.S | ... | @@ -283,28 +283,27 @@ pub fn getLineNumberInfo(self: *Pdb, module: *Module, address: u64) !std.debug.S |
| 283 | 283 | ||
| 284 | // line_i == 0 would mean that no matching pdb.LineNumberEntry was found. | 284 | // line_i == 0 would mean that no matching pdb.LineNumberEntry was found. |
| 285 | if (line_i > 0) { | 285 | if (line_i > 0) { |
| 286 | const subsect_index = checksum_offset + block_hdr.NameIndex; | 286 | const subsect_index = checksum_offset + block_hdr.name_index; |
| 287 | const chksum_hdr = @as(*align(1) pdb.FileChecksumEntryHeader, @ptrCast(&module.subsect_info[subsect_index])); | 287 | const chksum_hdr: *align(1) pdb.FileChecksumEntryHeader = @ptrCast(&module.subsect_info[subsect_index]); |
| 288 | const strtab_offset = @sizeOf(pdb.StringTableHeader) + chksum_hdr.FileNameOffset; | 288 | const strtab_offset = @sizeOf(pdb.StringTableHeader) + chksum_hdr.file_name_offset; |
| 289 | try self.string_table.?.seekTo(strtab_offset); | 289 | try self.string_table.?.seekTo(strtab_offset); |
| 290 | const source_file_name = try self.string_table.?.reader().readUntilDelimiterAlloc(self.allocator, 0, 1024); | 290 | const source_file_name = try self.string_table.?.reader().readUntilDelimiterAlloc(self.allocator, 0, 1024); |
| 291 | 291 | ||
| 292 | const line_entry_idx = line_i - 1; | 292 | const line_entry_idx = line_i - 1; |
| 293 | 293 | ||
| 294 | const column = if (has_column) blk: { | 294 | const column = if (has_column) blk: { |
| 295 | const start_col_index = start_line_index + @sizeOf(pdb.LineNumberEntry) * block_hdr.NumLines; | 295 | const start_col_index = start_line_index + @sizeOf(pdb.LineNumberEntry) * block_hdr.num_lines; |
| 296 | const col_index = start_col_index + @sizeOf(pdb.ColumnNumberEntry) * line_entry_idx; | 296 | const col_index = start_col_index + @sizeOf(pdb.ColumnNumberEntry) * line_entry_idx; |
| 297 | const col_num_entry = @as(*align(1) pdb.ColumnNumberEntry, @ptrCast(&subsect_info[col_index])); | 297 | const col_num_entry: *align(1) pdb.ColumnNumberEntry = @ptrCast(&subsect_info[col_index]); |
| 298 | break :blk col_num_entry.StartColumn; | 298 | break :blk col_num_entry.start_column; |
| 299 | } else 0; | 299 | } else 0; |
| 300 | 300 | ||
| 301 | const found_line_index = start_line_index + line_entry_idx * @sizeOf(pdb.LineNumberEntry); | 301 | const found_line_index = start_line_index + line_entry_idx * @sizeOf(pdb.LineNumberEntry); |
| 302 | const line_num_entry: *align(1) pdb.LineNumberEntry = @ptrCast(&subsect_info[found_line_index]); | 302 | const line_num_entry: *align(1) pdb.LineNumberEntry = @ptrCast(&subsect_info[found_line_index]); |
| 303 | const flags: *align(1) pdb.LineNumberEntry.Flags = @ptrCast(&line_num_entry.Flags); | ||
| 304 | 303 | ||
| 305 | return .{ | 304 | return .{ |
| 306 | .file_name = source_file_name, | 305 | .file_name = source_file_name, |
| 307 | .line = flags.Start, | 306 | .line = line_num_entry.flags.start, |
| 308 | .column = column, | 307 | .column = column, |
| 309 | }; | 308 | }; |
| 310 | } | 309 | } |
| ... | @@ -335,12 +334,12 @@ pub fn getModule(self: *Pdb, index: usize) !?*Module { | ... | @@ -335,12 +334,12 @@ pub fn getModule(self: *Pdb, index: usize) !?*Module { |
| 335 | return mod; | 334 | return mod; |
| 336 | 335 | ||
| 337 | // At most one can be non-zero. | 336 | // At most one can be non-zero. |
| 338 | if (mod.mod_info.C11ByteSize != 0 and mod.mod_info.C13ByteSize != 0) | 337 | if (mod.mod_info.c11_byte_size != 0 and mod.mod_info.c13_byte_size != 0) |
| 339 | return error.InvalidDebugInfo; | 338 | return error.InvalidDebugInfo; |
| 340 | if (mod.mod_info.C13ByteSize == 0) | 339 | if (mod.mod_info.c13_byte_size == 0) |
| 341 | return error.InvalidDebugInfo; | 340 | return error.InvalidDebugInfo; |
| 342 | 341 | ||
| 343 | const stream = self.getStreamById(mod.mod_info.ModuleSymStream) orelse | 342 | const stream = self.getStreamById(mod.mod_info.module_sym_stream) orelse |
| 344 | return error.MissingDebugInfo; | 343 | return error.MissingDebugInfo; |
| 345 | const reader = stream.reader(); | 344 | const reader = stream.reader(); |
| 346 | 345 | ||
| ... | @@ -348,23 +347,23 @@ pub fn getModule(self: *Pdb, index: usize) !?*Module { | ... | @@ -348,23 +347,23 @@ pub fn getModule(self: *Pdb, index: usize) !?*Module { |
| 348 | if (signature != 4) | 347 | if (signature != 4) |
| 349 | return error.InvalidDebugInfo; | 348 | return error.InvalidDebugInfo; |
| 350 | 349 | ||
| 351 | mod.symbols = try self.allocator.alloc(u8, mod.mod_info.SymByteSize - 4); | 350 | mod.symbols = try self.allocator.alloc(u8, mod.mod_info.sym_byte_size - 4); |
| 352 | errdefer self.allocator.free(mod.symbols); | 351 | errdefer self.allocator.free(mod.symbols); |
| 353 | try reader.readNoEof(mod.symbols); | 352 | try reader.readNoEof(mod.symbols); |
| 354 | 353 | ||
| 355 | mod.subsect_info = try self.allocator.alloc(u8, mod.mod_info.C13ByteSize); | 354 | mod.subsect_info = try self.allocator.alloc(u8, mod.mod_info.c13_byte_size); |
| 356 | errdefer self.allocator.free(mod.subsect_info); | 355 | errdefer self.allocator.free(mod.subsect_info); |
| 357 | try reader.readNoEof(mod.subsect_info); | 356 | try reader.readNoEof(mod.subsect_info); |
| 358 | 357 | ||
| 359 | var sect_offset: usize = 0; | 358 | var sect_offset: usize = 0; |
| 360 | var skip_len: usize = undefined; | 359 | var skip_len: usize = undefined; |
| 361 | while (sect_offset != mod.subsect_info.len) : (sect_offset += skip_len) { | 360 | while (sect_offset != mod.subsect_info.len) : (sect_offset += skip_len) { |
| 362 | const subsect_hdr = @as(*align(1) pdb.DebugSubsectionHeader, @ptrCast(&mod.subsect_info[sect_offset])); | 361 | const subsect_hdr: *align(1) pdb.DebugSubsectionHeader = @ptrCast(&mod.subsect_info[sect_offset]); |
| 363 | skip_len = subsect_hdr.Length; | 362 | skip_len = subsect_hdr.length; |
| 364 | sect_offset += @sizeOf(pdb.DebugSubsectionHeader); | 363 | sect_offset += @sizeOf(pdb.DebugSubsectionHeader); |
| 365 | 364 | ||
| 366 | switch (subsect_hdr.Kind) { | 365 | switch (subsect_hdr.kind) { |
| 367 | .FileChecksums => { | 366 | .file_checksums => { |
| 368 | mod.checksum_offset = sect_offset; | 367 | mod.checksum_offset = sect_offset; |
| 369 | break; | 368 | break; |
| 370 | }, | 369 | }, |
| ... | @@ -401,30 +400,30 @@ const Msf = struct { | ... | @@ -401,30 +400,30 @@ const Msf = struct { |
| 401 | const superblock = try in.readStruct(pdb.SuperBlock); | 400 | const superblock = try in.readStruct(pdb.SuperBlock); |
| 402 | 401 | ||
| 403 | // Sanity checks | 402 | // Sanity checks |
| 404 | if (!std.mem.eql(u8, &superblock.FileMagic, pdb.SuperBlock.file_magic)) | 403 | if (!std.mem.eql(u8, &superblock.file_magic, pdb.SuperBlock.expect_magic)) |
| 405 | return error.InvalidDebugInfo; | 404 | return error.InvalidDebugInfo; |
| 406 | if (superblock.FreeBlockMapBlock != 1 and superblock.FreeBlockMapBlock != 2) | 405 | if (superblock.free_block_map_block != 1 and superblock.free_block_map_block != 2) |
| 407 | return error.InvalidDebugInfo; | 406 | return error.InvalidDebugInfo; |
| 408 | const file_len = try file.getEndPos(); | 407 | const file_len = try file.getEndPos(); |
| 409 | if (superblock.NumBlocks * superblock.BlockSize != file_len) | 408 | if (superblock.num_blocks * superblock.block_size != file_len) |
| 410 | return error.InvalidDebugInfo; | 409 | return error.InvalidDebugInfo; |
| 411 | switch (superblock.BlockSize) { | 410 | switch (superblock.block_size) { |
| 412 | // llvm only supports 4096 but we can handle any of these values | 411 | // llvm only supports 4096 but we can handle any of these values |
| 413 | 512, 1024, 2048, 4096 => {}, | 412 | 512, 1024, 2048, 4096 => {}, |
| 414 | else => return error.InvalidDebugInfo, | 413 | else => return error.InvalidDebugInfo, |
| 415 | } | 414 | } |
| 416 | 415 | ||
| 417 | const dir_block_count = blockCountFromSize(superblock.NumDirectoryBytes, superblock.BlockSize); | 416 | const dir_block_count = blockCountFromSize(superblock.num_directory_bytes, superblock.block_size); |
| 418 | if (dir_block_count > superblock.BlockSize / @sizeOf(u32)) | 417 | if (dir_block_count > superblock.block_size / @sizeOf(u32)) |
| 419 | return error.UnhandledBigDirectoryStream; // cf. BlockMapAddr comment. | 418 | return error.UnhandledBigDirectoryStream; // cf. BlockMapAddr comment. |
| 420 | 419 | ||
| 421 | try file.seekTo(superblock.BlockSize * superblock.BlockMapAddr); | 420 | try file.seekTo(superblock.block_size * superblock.block_map_addr); |
| 422 | const dir_blocks = try allocator.alloc(u32, dir_block_count); | 421 | const dir_blocks = try allocator.alloc(u32, dir_block_count); |
| 423 | for (dir_blocks) |*b| { | 422 | for (dir_blocks) |*b| { |
| 424 | b.* = try in.readInt(u32, .little); | 423 | b.* = try in.readInt(u32, .little); |
| 425 | } | 424 | } |
| 426 | var directory = MsfStream.init( | 425 | var directory = MsfStream.init( |
| 427 | superblock.BlockSize, | 426 | superblock.block_size, |
| 428 | file, | 427 | file, |
| 429 | dir_blocks, | 428 | dir_blocks, |
| 430 | ); | 429 | ); |
| ... | @@ -440,7 +439,7 @@ const Msf = struct { | ... | @@ -440,7 +439,7 @@ const Msf = struct { |
| 440 | const Nil = 0xFFFFFFFF; | 439 | const Nil = 0xFFFFFFFF; |
| 441 | for (stream_sizes) |*s| { | 440 | for (stream_sizes) |*s| { |
| 442 | const size = try directory.reader().readInt(u32, .little); | 441 | const size = try directory.reader().readInt(u32, .little); |
| 443 | s.* = if (size == Nil) 0 else blockCountFromSize(size, superblock.BlockSize); | 442 | s.* = if (size == Nil) 0 else blockCountFromSize(size, superblock.block_size); |
| 444 | } | 443 | } |
| 445 | 444 | ||
| 446 | const streams = try allocator.alloc(MsfStream, stream_count); | 445 | const streams = try allocator.alloc(MsfStream, stream_count); |
| ... | @@ -455,15 +454,15 @@ const Msf = struct { | ... | @@ -455,15 +454,15 @@ const Msf = struct { |
| 455 | var j: u32 = 0; | 454 | var j: u32 = 0; |
| 456 | while (j < size) : (j += 1) { | 455 | while (j < size) : (j += 1) { |
| 457 | const block_id = try directory.reader().readInt(u32, .little); | 456 | const block_id = try directory.reader().readInt(u32, .little); |
| 458 | const n = (block_id % superblock.BlockSize); | 457 | const n = (block_id % superblock.block_size); |
| 459 | // 0 is for pdb.SuperBlock, 1 and 2 for FPMs. | 458 | // 0 is for pdb.SuperBlock, 1 and 2 for FPMs. |
| 460 | if (block_id == 0 or n == 1 or n == 2 or block_id * superblock.BlockSize > file_len) | 459 | if (block_id == 0 or n == 1 or n == 2 or block_id * superblock.block_size > file_len) |
| 461 | return error.InvalidBlockIndex; | 460 | return error.InvalidBlockIndex; |
| 462 | blocks[j] = block_id; | 461 | blocks[j] = block_id; |
| 463 | } | 462 | } |
| 464 | 463 | ||
| 465 | stream.* = MsfStream.init( | 464 | stream.* = MsfStream.init( |
| 466 | superblock.BlockSize, | 465 | superblock.block_size, |
| 467 | file, | 466 | file, |
| 468 | blocks, | 467 | blocks, |
| 469 | ); | 468 | ); |
| ... | @@ -471,7 +470,7 @@ const Msf = struct { | ... | @@ -471,7 +470,7 @@ const Msf = struct { |
| 471 | } | 470 | } |
| 472 | 471 | ||
| 473 | const end = directory.pos; | 472 | const end = directory.pos; |
| 474 | if (end - begin != superblock.NumDirectoryBytes) | 473 | if (end - begin != superblock.num_directory_bytes) |
| 475 | return error.InvalidStreamDirectory; | 474 | return error.InvalidStreamDirectory; |
| 476 | 475 | ||
| 477 | return Msf{ | 476 | return Msf{ |
lib/std/debug/SelfInfo.zig+5-5| ... | @@ -732,14 +732,14 @@ pub const Module = switch (native_os) { | ... | @@ -732,14 +732,14 @@ pub const Module = switch (native_os) { |
| 732 | fn getSymbolFromPdb(self: *@This(), relocated_address: usize) !?std.debug.Symbol { | 732 | fn getSymbolFromPdb(self: *@This(), relocated_address: usize) !?std.debug.Symbol { |
| 733 | var coff_section: *align(1) const coff.SectionHeader = undefined; | 733 | var coff_section: *align(1) const coff.SectionHeader = undefined; |
| 734 | const mod_index = for (self.pdb.?.sect_contribs) |sect_contrib| { | 734 | const mod_index = for (self.pdb.?.sect_contribs) |sect_contrib| { |
| 735 | if (sect_contrib.Section > self.coff_section_headers.len) continue; | 735 | if (sect_contrib.section > self.coff_section_headers.len) continue; |
| 736 | // Remember that SectionContribEntry.Section is 1-based. | 736 | // Remember that SectionContribEntry.Section is 1-based. |
| 737 | coff_section = &self.coff_section_headers[sect_contrib.Section - 1]; | 737 | coff_section = &self.coff_section_headers[sect_contrib.section - 1]; |
| 738 | 738 | ||
| 739 | const vaddr_start = coff_section.virtual_address + sect_contrib.Offset; | 739 | const vaddr_start = coff_section.virtual_address + sect_contrib.offset; |
| 740 | const vaddr_end = vaddr_start + sect_contrib.Size; | 740 | const vaddr_end = vaddr_start + sect_contrib.size; |
| 741 | if (relocated_address >= vaddr_start and relocated_address < vaddr_end) { | 741 | if (relocated_address >= vaddr_start and relocated_address < vaddr_end) { |
| 742 | break sect_contrib.ModuleIndex; | 742 | break sect_contrib.module_index; |
| 743 | } | 743 | } |
| 744 | } else { | 744 | } else { |
| 745 | // we have no information to add to the address | 745 | // we have no information to add to the address |
lib/std/enums.zig+1-1| ... | @@ -1501,7 +1501,7 @@ test values { | ... | @@ -1501,7 +1501,7 @@ test values { |
| 1501 | X, | 1501 | X, |
| 1502 | Y, | 1502 | Y, |
| 1503 | Z, | 1503 | Z, |
| 1504 | pub const X = 1; | 1504 | const A = 1; |
| 1505 | }; | 1505 | }; |
| 1506 | try testing.expectEqualSlices(E, &.{ .X, .Y, .Z }, values(E)); | 1506 | try testing.expectEqualSlices(E, &.{ .X, .Y, .Z }, values(E)); |
| 1507 | } | 1507 | } |
lib/std/heap/sbrk_allocator.zig+1-3| ... | @@ -7,7 +7,7 @@ const assert = std.debug.assert; | ... | @@ -7,7 +7,7 @@ const assert = std.debug.assert; |
| 7 | 7 | ||
| 8 | pub fn SbrkAllocator(comptime sbrk: *const fn (n: usize) usize) type { | 8 | pub fn SbrkAllocator(comptime sbrk: *const fn (n: usize) usize) type { |
| 9 | return struct { | 9 | return struct { |
| 10 | pub const vtable = Allocator.VTable{ | 10 | pub const vtable: Allocator.VTable = .{ |
| 11 | .alloc = alloc, | 11 | .alloc = alloc, |
| 12 | .resize = resize, | 12 | .resize = resize, |
| 13 | .free = free, | 13 | .free = free, |
| ... | @@ -15,8 +15,6 @@ pub fn SbrkAllocator(comptime sbrk: *const fn (n: usize) usize) type { | ... | @@ -15,8 +15,6 @@ pub fn SbrkAllocator(comptime sbrk: *const fn (n: usize) usize) type { |
| 15 | 15 | ||
| 16 | pub const Error = Allocator.Error; | 16 | pub const Error = Allocator.Error; |
| 17 | 17 | ||
| 18 | lock: std.Thread.Mutex = .{}, | ||
| 19 | |||
| 20 | const max_usize = math.maxInt(usize); | 18 | const max_usize = math.maxInt(usize); |
| 21 | const ushift = math.Log2Int(usize); | 19 | const ushift = math.Log2Int(usize); |
| 22 | const bigpage_size = 64 * 1024; | 20 | const bigpage_size = 64 * 1024; |
lib/std/meta.zig+2-2| ... | @@ -294,7 +294,7 @@ test declarations { | ... | @@ -294,7 +294,7 @@ test declarations { |
| 294 | pub fn a() void {} | 294 | pub fn a() void {} |
| 295 | }; | 295 | }; |
| 296 | const U1 = union { | 296 | const U1 = union { |
| 297 | a: u8, | 297 | b: u8, |
| 298 | 298 | ||
| 299 | pub fn a() void {} | 299 | pub fn a() void {} |
| 300 | }; | 300 | }; |
| ... | @@ -334,7 +334,7 @@ test declarationInfo { | ... | @@ -334,7 +334,7 @@ test declarationInfo { |
| 334 | pub fn a() void {} | 334 | pub fn a() void {} |
| 335 | }; | 335 | }; |
| 336 | const U1 = union { | 336 | const U1 = union { |
| 337 | a: u8, | 337 | b: u8, |
| 338 | 338 | ||
| 339 | pub fn a() void {} | 339 | pub fn a() void {} |
| 340 | }; | 340 | }; |
lib/std/os/uefi/device_path.zig+30-30| ... | @@ -4,38 +4,38 @@ const uefi = std.os.uefi; | ... | @@ -4,38 +4,38 @@ const uefi = std.os.uefi; |
| 4 | const Guid = uefi.Guid; | 4 | const Guid = uefi.Guid; |
| 5 | 5 | ||
| 6 | pub const DevicePath = union(Type) { | 6 | pub const DevicePath = union(Type) { |
| 7 | Hardware: Hardware, | 7 | hardware: Hardware, |
| 8 | Acpi: Acpi, | 8 | acpi: Acpi, |
| 9 | Messaging: Messaging, | 9 | messaging: Messaging, |
| 10 | Media: Media, | 10 | media: Media, |
| 11 | BiosBootSpecification: BiosBootSpecification, | 11 | bios_boot_specification: BiosBootSpecification, |
| 12 | End: End, | 12 | end: End, |
| 13 | 13 | ||
| 14 | pub const Type = enum(u8) { | 14 | pub const Type = enum(u8) { |
| 15 | Hardware = 0x01, | 15 | hardware = 0x01, |
| 16 | Acpi = 0x02, | 16 | acpi = 0x02, |
| 17 | Messaging = 0x03, | 17 | messaging = 0x03, |
| 18 | Media = 0x04, | 18 | media = 0x04, |
| 19 | BiosBootSpecification = 0x05, | 19 | bios_boot_specification = 0x05, |
| 20 | End = 0x7f, | 20 | end = 0x7f, |
| 21 | _, | 21 | _, |
| 22 | }; | 22 | }; |
| 23 | 23 | ||
| 24 | pub const Hardware = union(Subtype) { | 24 | pub const Hardware = union(Subtype) { |
| 25 | Pci: *const PciDevicePath, | 25 | pci: *const PciDevicePath, |
| 26 | PcCard: *const PcCardDevicePath, | 26 | pc_card: *const PcCardDevicePath, |
| 27 | MemoryMapped: *const MemoryMappedDevicePath, | 27 | memory_mapped: *const MemoryMappedDevicePath, |
| 28 | Vendor: *const VendorDevicePath, | 28 | vendor: *const VendorDevicePath, |
| 29 | Controller: *const ControllerDevicePath, | 29 | controller: *const ControllerDevicePath, |
| 30 | Bmc: *const BmcDevicePath, | 30 | bmc: *const BmcDevicePath, |
| 31 | 31 | ||
| 32 | pub const Subtype = enum(u8) { | 32 | pub const Subtype = enum(u8) { |
| 33 | Pci = 1, | 33 | pci = 1, |
| 34 | PcCard = 2, | 34 | pc_card = 2, |
| 35 | MemoryMapped = 3, | 35 | memory_mapped = 3, |
| 36 | Vendor = 4, | 36 | vendor = 4, |
| 37 | Controller = 5, | 37 | controller = 5, |
| 38 | Bmc = 6, | 38 | bmc = 6, |
| 39 | _, | 39 | _, |
| 40 | }; | 40 | }; |
| 41 | 41 | ||
| ... | @@ -151,14 +151,14 @@ pub const DevicePath = union(Type) { | ... | @@ -151,14 +151,14 @@ pub const DevicePath = union(Type) { |
| 151 | }; | 151 | }; |
| 152 | 152 | ||
| 153 | pub const Acpi = union(Subtype) { | 153 | pub const Acpi = union(Subtype) { |
| 154 | Acpi: *const BaseAcpiDevicePath, | 154 | acpi: *const BaseAcpiDevicePath, |
| 155 | ExpandedAcpi: *const ExpandedAcpiDevicePath, | 155 | expanded_acpi: *const ExpandedAcpiDevicePath, |
| 156 | Adr: *const AdrDevicePath, | 156 | adr: *const AdrDevicePath, |
| 157 | 157 | ||
| 158 | pub const Subtype = enum(u8) { | 158 | pub const Subtype = enum(u8) { |
| 159 | Acpi = 1, | 159 | acpi = 1, |
| 160 | ExpandedAcpi = 2, | 160 | expanded_acpi = 2, |
| 161 | Adr = 3, | 161 | adr = 3, |
| 162 | _, | 162 | _, |
| 163 | }; | 163 | }; |
| 164 | 164 |
lib/std/pdb.zig+321-322| ... | @@ -20,297 +20,297 @@ const ArrayList = std.ArrayList; | ... | @@ -20,297 +20,297 @@ const ArrayList = std.ArrayList; |
| 20 | 20 | ||
| 21 | /// https://llvm.org/docs/PDB/DbiStream.html#stream-header | 21 | /// https://llvm.org/docs/PDB/DbiStream.html#stream-header |
| 22 | pub const DbiStreamHeader = extern struct { | 22 | pub const DbiStreamHeader = extern struct { |
| 23 | VersionSignature: i32, | 23 | version_signature: i32, |
| 24 | VersionHeader: u32, | 24 | version_header: u32, |
| 25 | Age: u32, | 25 | age: u32, |
| 26 | GlobalStreamIndex: u16, | 26 | global_stream_index: u16, |
| 27 | BuildNumber: u16, | 27 | build_number: u16, |
| 28 | PublicStreamIndex: u16, | 28 | public_stream_index: u16, |
| 29 | PdbDllVersion: u16, | 29 | pdb_dll_version: u16, |
| 30 | SymRecordStream: u16, | 30 | sym_record_stream: u16, |
| 31 | PdbDllRbld: u16, | 31 | pdb_dll_rbld: u16, |
| 32 | ModInfoSize: u32, | 32 | mod_info_size: u32, |
| 33 | SectionContributionSize: u32, | 33 | section_contribution_size: u32, |
| 34 | SectionMapSize: u32, | 34 | section_map_size: u32, |
| 35 | SourceInfoSize: i32, | 35 | source_info_size: i32, |
| 36 | TypeServerSize: i32, | 36 | type_server_size: i32, |
| 37 | MFCTypeServerIndex: u32, | 37 | mfc_type_server_index: u32, |
| 38 | OptionalDbgHeaderSize: i32, | 38 | optional_dbg_header_size: i32, |
| 39 | ECSubstreamSize: i32, | 39 | ec_substream_size: i32, |
| 40 | Flags: u16, | 40 | flags: u16, |
| 41 | Machine: u16, | 41 | machine: u16, |
| 42 | Padding: u32, | 42 | padding: u32, |
| 43 | }; | 43 | }; |
| 44 | 44 | ||
| 45 | pub const SectionContribEntry = extern struct { | 45 | pub const SectionContribEntry = extern struct { |
| 46 | /// COFF Section index, 1-based | 46 | /// COFF Section index, 1-based |
| 47 | Section: u16, | 47 | section: u16, |
| 48 | Padding1: [2]u8, | 48 | padding1: [2]u8, |
| 49 | Offset: u32, | 49 | offset: u32, |
| 50 | Size: u32, | 50 | size: u32, |
| 51 | Characteristics: u32, | 51 | characteristics: u32, |
| 52 | ModuleIndex: u16, | 52 | module_index: u16, |
| 53 | Padding2: [2]u8, | 53 | padding2: [2]u8, |
| 54 | DataCrc: u32, | 54 | data_crc: u32, |
| 55 | RelocCrc: u32, | 55 | reloc_crc: u32, |
| 56 | }; | 56 | }; |
| 57 | 57 | ||
| 58 | pub const ModInfo = extern struct { | 58 | pub const ModInfo = extern struct { |
| 59 | Unused1: u32, | 59 | unused1: u32, |
| 60 | SectionContr: SectionContribEntry, | 60 | section_contr: SectionContribEntry, |
| 61 | Flags: u16, | 61 | flags: u16, |
| 62 | ModuleSymStream: u16, | 62 | module_sym_stream: u16, |
| 63 | SymByteSize: u32, | 63 | sym_byte_size: u32, |
| 64 | C11ByteSize: u32, | 64 | c11_byte_size: u32, |
| 65 | C13ByteSize: u32, | 65 | c13_byte_size: u32, |
| 66 | SourceFileCount: u16, | 66 | source_file_count: u16, |
| 67 | Padding: [2]u8, | 67 | padding: [2]u8, |
| 68 | Unused2: u32, | 68 | unused2: u32, |
| 69 | SourceFileNameIndex: u32, | 69 | source_file_name_index: u32, |
| 70 | PdbFilePathNameIndex: u32, | 70 | pdb_file_path_name_index: u32, |
| 71 | // These fields are variable length | 71 | // These fields are variable length |
| 72 | //ModuleName: char[], | 72 | //module_name: char[], |
| 73 | //ObjFileName: char[], | 73 | //obj_file_name: char[], |
| 74 | }; | 74 | }; |
| 75 | 75 | ||
| 76 | pub const SectionMapHeader = extern struct { | 76 | pub const SectionMapHeader = extern struct { |
| 77 | /// Number of segment descriptors | 77 | /// Number of segment descriptors |
| 78 | Count: u16, | 78 | count: u16, |
| 79 | 79 | ||
| 80 | /// Number of logical segment descriptors | 80 | /// Number of logical segment descriptors |
| 81 | LogCount: u16, | 81 | log_count: u16, |
| 82 | }; | 82 | }; |
| 83 | 83 | ||
| 84 | pub const SectionMapEntry = extern struct { | 84 | pub const SectionMapEntry = extern struct { |
| 85 | /// See the SectionMapEntryFlags enum below. | 85 | /// See the SectionMapEntryFlags enum below. |
| 86 | Flags: u16, | 86 | flags: u16, |
| 87 | 87 | ||
| 88 | /// Logical overlay number | 88 | /// Logical overlay number |
| 89 | Ovl: u16, | 89 | ovl: u16, |
| 90 | 90 | ||
| 91 | /// Group index into descriptor array. | 91 | /// Group index into descriptor array. |
| 92 | Group: u16, | 92 | group: u16, |
| 93 | Frame: u16, | 93 | frame: u16, |
| 94 | 94 | ||
| 95 | /// Byte index of segment / group name in string table, or 0xFFFF. | 95 | /// Byte index of segment / group name in string table, or 0xFFFF. |
| 96 | SectionName: u16, | 96 | section_name: u16, |
| 97 | 97 | ||
| 98 | /// Byte index of class in string table, or 0xFFFF. | 98 | /// Byte index of class in string table, or 0xFFFF. |
| 99 | ClassName: u16, | 99 | class_name: u16, |
| 100 | 100 | ||
| 101 | /// Byte offset of the logical segment within physical segment. If group is set in flags, this is the offset of the group. | 101 | /// Byte offset of the logical segment within physical segment. If group is set in flags, this is the offset of the group. |
| 102 | Offset: u32, | 102 | offset: u32, |
| 103 | 103 | ||
| 104 | /// Byte count of the segment or group. | 104 | /// Byte count of the segment or group. |
| 105 | SectionLength: u32, | 105 | section_length: u32, |
| 106 | }; | 106 | }; |
| 107 | 107 | ||
| 108 | pub const StreamType = enum(u16) { | 108 | pub const StreamType = enum(u16) { |
| 109 | Pdb = 1, | 109 | pdb = 1, |
| 110 | Tpi = 2, | 110 | tpi = 2, |
| 111 | Dbi = 3, | 111 | dbi = 3, |
| 112 | Ipi = 4, | 112 | ipi = 4, |
| 113 | }; | 113 | }; |
| 114 | 114 | ||
| 115 | /// Duplicate copy of SymbolRecordKind, but using the official CV names. Useful | 115 | /// Duplicate copy of SymbolRecordKind, but using the official CV names. Useful |
| 116 | /// for reference purposes and when dealing with unknown record types. | 116 | /// for reference purposes and when dealing with unknown record types. |
| 117 | pub const SymbolKind = enum(u16) { | 117 | pub const SymbolKind = enum(u16) { |
| 118 | S_COMPILE = 1, | 118 | compile = 1, |
| 119 | S_REGISTER_16t = 2, | 119 | register_16t = 2, |
| 120 | S_CONSTANT_16t = 3, | 120 | constant_16t = 3, |
| 121 | S_UDT_16t = 4, | 121 | udt_16t = 4, |
| 122 | S_SSEARCH = 5, | 122 | ssearch = 5, |
| 123 | S_SKIP = 7, | 123 | skip = 7, |
| 124 | S_CVRESERVE = 8, | 124 | cvreserve = 8, |
| 125 | S_OBJNAME_ST = 9, | 125 | objname_st = 9, |
| 126 | S_ENDARG = 10, | 126 | endarg = 10, |
| 127 | S_COBOLUDT_16t = 11, | 127 | coboludt_16t = 11, |
| 128 | S_MANYREG_16t = 12, | 128 | manyreg_16t = 12, |
| 129 | S_RETURN = 13, | 129 | @"return" = 13, |
| 130 | S_ENTRYTHIS = 14, | 130 | entrythis = 14, |
| 131 | S_BPREL16 = 256, | 131 | bprel16 = 256, |
| 132 | S_LDATA16 = 257, | 132 | ldata16 = 257, |
| 133 | S_GDATA16 = 258, | 133 | gdata16 = 258, |
| 134 | S_PUB16 = 259, | 134 | pub16 = 259, |
| 135 | S_LPROC16 = 260, | 135 | lproc16 = 260, |
| 136 | S_GPROC16 = 261, | 136 | gproc16 = 261, |
| 137 | S_THUNK16 = 262, | 137 | thunk16 = 262, |
| 138 | S_BLOCK16 = 263, | 138 | block16 = 263, |
| 139 | S_WITH16 = 264, | 139 | with16 = 264, |
| 140 | S_LABEL16 = 265, | 140 | label16 = 265, |
| 141 | S_CEXMODEL16 = 266, | 141 | cexmodel16 = 266, |
| 142 | S_VFTABLE16 = 267, | 142 | vftable16 = 267, |
| 143 | S_REGREL16 = 268, | 143 | regrel16 = 268, |
| 144 | S_BPREL32_16t = 512, | 144 | bprel32_16t = 512, |
| 145 | S_LDATA32_16t = 513, | 145 | ldata32_16t = 513, |
| 146 | S_GDATA32_16t = 514, | 146 | gdata32_16t = 514, |
| 147 | S_PUB32_16t = 515, | 147 | pub32_16t = 515, |
| 148 | S_LPROC32_16t = 516, | 148 | lproc32_16t = 516, |
| 149 | S_GPROC32_16t = 517, | 149 | gproc32_16t = 517, |
| 150 | S_THUNK32_ST = 518, | 150 | thunk32_st = 518, |
| 151 | S_BLOCK32_ST = 519, | 151 | block32_st = 519, |
| 152 | S_WITH32_ST = 520, | 152 | with32_st = 520, |
| 153 | S_LABEL32_ST = 521, | 153 | label32_st = 521, |
| 154 | S_CEXMODEL32 = 522, | 154 | cexmodel32 = 522, |
| 155 | S_VFTABLE32_16t = 523, | 155 | vftable32_16t = 523, |
| 156 | S_REGREL32_16t = 524, | 156 | regrel32_16t = 524, |
| 157 | S_LTHREAD32_16t = 525, | 157 | lthread32_16t = 525, |
| 158 | S_GTHREAD32_16t = 526, | 158 | gthread32_16t = 526, |
| 159 | S_SLINK32 = 527, | 159 | slink32 = 527, |
| 160 | S_LPROCMIPS_16t = 768, | 160 | lprocmips_16t = 768, |
| 161 | S_GPROCMIPS_16t = 769, | 161 | gprocmips_16t = 769, |
| 162 | S_PROCREF_ST = 1024, | 162 | procref_st = 1024, |
| 163 | S_DATAREF_ST = 1025, | 163 | dataref_st = 1025, |
| 164 | S_ALIGN = 1026, | 164 | @"align" = 1026, |
| 165 | S_LPROCREF_ST = 1027, | 165 | lprocref_st = 1027, |
| 166 | S_OEM = 1028, | 166 | oem = 1028, |
| 167 | S_TI16_MAX = 4096, | 167 | ti16_max = 4096, |
| 168 | S_REGISTER_ST = 4097, | 168 | register_st = 4097, |
| 169 | S_CONSTANT_ST = 4098, | 169 | constant_st = 4098, |
| 170 | S_UDT_ST = 4099, | 170 | udt_st = 4099, |
| 171 | S_COBOLUDT_ST = 4100, | 171 | coboludt_st = 4100, |
| 172 | S_MANYREG_ST = 4101, | 172 | manyreg_st = 4101, |
| 173 | S_BPREL32_ST = 4102, | 173 | bprel32_st = 4102, |
| 174 | S_LDATA32_ST = 4103, | 174 | ldata32_st = 4103, |
| 175 | S_GDATA32_ST = 4104, | 175 | gdata32_st = 4104, |
| 176 | S_PUB32_ST = 4105, | 176 | pub32_st = 4105, |
| 177 | S_LPROC32_ST = 4106, | 177 | lproc32_st = 4106, |
| 178 | S_GPROC32_ST = 4107, | 178 | gproc32_st = 4107, |
| 179 | S_VFTABLE32 = 4108, | 179 | vftable32 = 4108, |
| 180 | S_REGREL32_ST = 4109, | 180 | regrel32_st = 4109, |
| 181 | S_LTHREAD32_ST = 4110, | 181 | lthread32_st = 4110, |
| 182 | S_GTHREAD32_ST = 4111, | 182 | gthread32_st = 4111, |
| 183 | S_LPROCMIPS_ST = 4112, | 183 | lprocmips_st = 4112, |
| 184 | S_GPROCMIPS_ST = 4113, | 184 | gprocmips_st = 4113, |
| 185 | S_COMPILE2_ST = 4115, | 185 | compile2_st = 4115, |
| 186 | S_MANYREG2_ST = 4116, | 186 | manyreg2_st = 4116, |
| 187 | S_LPROCIA64_ST = 4117, | 187 | lprocia64_st = 4117, |
| 188 | S_GPROCIA64_ST = 4118, | 188 | gprocia64_st = 4118, |
| 189 | S_LOCALSLOT_ST = 4119, | 189 | localslot_st = 4119, |
| 190 | S_PARAMSLOT_ST = 4120, | 190 | paramslot_st = 4120, |
| 191 | S_ANNOTATION = 4121, | 191 | annotation = 4121, |
| 192 | S_GMANPROC_ST = 4122, | 192 | gmanproc_st = 4122, |
| 193 | S_LMANPROC_ST = 4123, | 193 | lmanproc_st = 4123, |
| 194 | S_RESERVED1 = 4124, | 194 | reserved1 = 4124, |
| 195 | S_RESERVED2 = 4125, | 195 | reserved2 = 4125, |
| 196 | S_RESERVED3 = 4126, | 196 | reserved3 = 4126, |
| 197 | S_RESERVED4 = 4127, | 197 | reserved4 = 4127, |
| 198 | S_LMANDATA_ST = 4128, | 198 | lmandata_st = 4128, |
| 199 | S_GMANDATA_ST = 4129, | 199 | gmandata_st = 4129, |
| 200 | S_MANFRAMEREL_ST = 4130, | 200 | manframerel_st = 4130, |
| 201 | S_MANREGISTER_ST = 4131, | 201 | manregister_st = 4131, |
| 202 | S_MANSLOT_ST = 4132, | 202 | manslot_st = 4132, |
| 203 | S_MANMANYREG_ST = 4133, | 203 | manmanyreg_st = 4133, |
| 204 | S_MANREGREL_ST = 4134, | 204 | manregrel_st = 4134, |
| 205 | S_MANMANYREG2_ST = 4135, | 205 | manmanyreg2_st = 4135, |
| 206 | S_MANTYPREF = 4136, | 206 | mantypref = 4136, |
| 207 | S_UNAMESPACE_ST = 4137, | 207 | unamespace_st = 4137, |
| 208 | S_ST_MAX = 4352, | 208 | st_max = 4352, |
| 209 | S_WITH32 = 4356, | 209 | with32 = 4356, |
| 210 | S_MANYREG = 4362, | 210 | manyreg = 4362, |
| 211 | S_LPROCMIPS = 4372, | 211 | lprocmips = 4372, |
| 212 | S_GPROCMIPS = 4373, | 212 | gprocmips = 4373, |
| 213 | S_MANYREG2 = 4375, | 213 | manyreg2 = 4375, |
| 214 | S_LPROCIA64 = 4376, | 214 | lprocia64 = 4376, |
| 215 | S_GPROCIA64 = 4377, | 215 | gprocia64 = 4377, |
| 216 | S_LOCALSLOT = 4378, | 216 | localslot = 4378, |
| 217 | S_PARAMSLOT = 4379, | 217 | paramslot = 4379, |
| 218 | S_MANFRAMEREL = 4382, | 218 | manframerel = 4382, |
| 219 | S_MANREGISTER = 4383, | 219 | manregister = 4383, |
| 220 | S_MANSLOT = 4384, | 220 | manslot = 4384, |
| 221 | S_MANMANYREG = 4385, | 221 | manmanyreg = 4385, |
| 222 | S_MANREGREL = 4386, | 222 | manregrel = 4386, |
| 223 | S_MANMANYREG2 = 4387, | 223 | manmanyreg2 = 4387, |
| 224 | S_UNAMESPACE = 4388, | 224 | unamespace = 4388, |
| 225 | S_DATAREF = 4390, | 225 | dataref = 4390, |
| 226 | S_ANNOTATIONREF = 4392, | 226 | annotationref = 4392, |
| 227 | S_TOKENREF = 4393, | 227 | tokenref = 4393, |
| 228 | S_GMANPROC = 4394, | 228 | gmanproc = 4394, |
| 229 | S_LMANPROC = 4395, | 229 | lmanproc = 4395, |
| 230 | S_ATTR_FRAMEREL = 4398, | 230 | attr_framerel = 4398, |
| 231 | S_ATTR_REGISTER = 4399, | 231 | attr_register = 4399, |
| 232 | S_ATTR_REGREL = 4400, | 232 | attr_regrel = 4400, |
| 233 | S_ATTR_MANYREG = 4401, | 233 | attr_manyreg = 4401, |
| 234 | S_SEPCODE = 4402, | 234 | sepcode = 4402, |
| 235 | S_LOCAL_2005 = 4403, | 235 | local_2005 = 4403, |
| 236 | S_DEFRANGE_2005 = 4404, | 236 | defrange_2005 = 4404, |
| 237 | S_DEFRANGE2_2005 = 4405, | 237 | defrange2_2005 = 4405, |
| 238 | S_DISCARDED = 4411, | 238 | discarded = 4411, |
| 239 | S_LPROCMIPS_ID = 4424, | 239 | lprocmips_id = 4424, |
| 240 | S_GPROCMIPS_ID = 4425, | 240 | gprocmips_id = 4425, |
| 241 | S_LPROCIA64_ID = 4426, | 241 | lprocia64_id = 4426, |
| 242 | S_GPROCIA64_ID = 4427, | 242 | gprocia64_id = 4427, |
| 243 | S_DEFRANGE_HLSL = 4432, | 243 | defrange_hlsl = 4432, |
| 244 | S_GDATA_HLSL = 4433, | 244 | gdata_hlsl = 4433, |
| 245 | S_LDATA_HLSL = 4434, | 245 | ldata_hlsl = 4434, |
| 246 | S_LOCAL_DPC_GROUPSHARED = 4436, | 246 | local_dpc_groupshared = 4436, |
| 247 | S_DEFRANGE_DPC_PTR_TAG = 4439, | 247 | defrange_dpc_ptr_tag = 4439, |
| 248 | S_DPC_SYM_TAG_MAP = 4440, | 248 | dpc_sym_tag_map = 4440, |
| 249 | S_ARMSWITCHTABLE = 4441, | 249 | armswitchtable = 4441, |
| 250 | S_POGODATA = 4444, | 250 | pogodata = 4444, |
| 251 | S_INLINESITE2 = 4445, | 251 | inlinesite2 = 4445, |
| 252 | S_MOD_TYPEREF = 4447, | 252 | mod_typeref = 4447, |
| 253 | S_REF_MINIPDB = 4448, | 253 | ref_minipdb = 4448, |
| 254 | S_PDBMAP = 4449, | 254 | pdbmap = 4449, |
| 255 | S_GDATA_HLSL32 = 4450, | 255 | gdata_hlsl32 = 4450, |
| 256 | S_LDATA_HLSL32 = 4451, | 256 | ldata_hlsl32 = 4451, |
| 257 | S_GDATA_HLSL32_EX = 4452, | 257 | gdata_hlsl32_ex = 4452, |
| 258 | S_LDATA_HLSL32_EX = 4453, | 258 | ldata_hlsl32_ex = 4453, |
| 259 | S_FASTLINK = 4455, | 259 | fastlink = 4455, |
| 260 | S_INLINEES = 4456, | 260 | inlinees = 4456, |
| 261 | S_END = 6, | 261 | end = 6, |
| 262 | S_INLINESITE_END = 4430, | 262 | inlinesite_end = 4430, |
| 263 | S_PROC_ID_END = 4431, | 263 | proc_id_end = 4431, |
| 264 | S_THUNK32 = 4354, | 264 | thunk32 = 4354, |
| 265 | S_TRAMPOLINE = 4396, | 265 | trampoline = 4396, |
| 266 | S_SECTION = 4406, | 266 | section = 4406, |
| 267 | S_COFFGROUP = 4407, | 267 | coffgroup = 4407, |
| 268 | S_EXPORT = 4408, | 268 | @"export" = 4408, |
| 269 | S_LPROC32 = 4367, | 269 | lproc32 = 4367, |
| 270 | S_GPROC32 = 4368, | 270 | gproc32 = 4368, |
| 271 | S_LPROC32_ID = 4422, | 271 | lproc32_id = 4422, |
| 272 | S_GPROC32_ID = 4423, | 272 | gproc32_id = 4423, |
| 273 | S_LPROC32_DPC = 4437, | 273 | lproc32_dpc = 4437, |
| 274 | S_LPROC32_DPC_ID = 4438, | 274 | lproc32_dpc_id = 4438, |
| 275 | S_REGISTER = 4358, | 275 | register = 4358, |
| 276 | S_PUB32 = 4366, | 276 | pub32 = 4366, |
| 277 | S_PROCREF = 4389, | 277 | procref = 4389, |
| 278 | S_LPROCREF = 4391, | 278 | lprocref = 4391, |
| 279 | S_ENVBLOCK = 4413, | 279 | envblock = 4413, |
| 280 | S_INLINESITE = 4429, | 280 | inlinesite = 4429, |
| 281 | S_LOCAL = 4414, | 281 | local = 4414, |
| 282 | S_DEFRANGE = 4415, | 282 | defrange = 4415, |
| 283 | S_DEFRANGE_SUBFIELD = 4416, | 283 | defrange_subfield = 4416, |
| 284 | S_DEFRANGE_REGISTER = 4417, | 284 | defrange_register = 4417, |
| 285 | S_DEFRANGE_FRAMEPOINTER_REL = 4418, | 285 | defrange_framepointer_rel = 4418, |
| 286 | S_DEFRANGE_SUBFIELD_REGISTER = 4419, | 286 | defrange_subfield_register = 4419, |
| 287 | S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE = 4420, | 287 | defrange_framepointer_rel_full_scope = 4420, |
| 288 | S_DEFRANGE_REGISTER_REL = 4421, | 288 | defrange_register_rel = 4421, |
| 289 | S_BLOCK32 = 4355, | 289 | block32 = 4355, |
| 290 | S_LABEL32 = 4357, | 290 | label32 = 4357, |
| 291 | S_OBJNAME = 4353, | 291 | objname = 4353, |
| 292 | S_COMPILE2 = 4374, | 292 | compile2 = 4374, |
| 293 | S_COMPILE3 = 4412, | 293 | compile3 = 4412, |
| 294 | S_FRAMEPROC = 4114, | 294 | frameproc = 4114, |
| 295 | S_CALLSITEINFO = 4409, | 295 | callsiteinfo = 4409, |
| 296 | S_FILESTATIC = 4435, | 296 | filestatic = 4435, |
| 297 | S_HEAPALLOCSITE = 4446, | 297 | heapallocsite = 4446, |
| 298 | S_FRAMECOOKIE = 4410, | 298 | framecookie = 4410, |
| 299 | S_CALLEES = 4442, | 299 | callees = 4442, |
| 300 | S_CALLERS = 4443, | 300 | callers = 4443, |
| 301 | S_UDT = 4360, | 301 | udt = 4360, |
| 302 | S_COBOLUDT = 4361, | 302 | coboludt = 4361, |
| 303 | S_BUILDINFO = 4428, | 303 | buildinfo = 4428, |
| 304 | S_BPREL32 = 4363, | 304 | bprel32 = 4363, |
| 305 | S_REGREL32 = 4369, | 305 | regrel32 = 4369, |
| 306 | S_CONSTANT = 4359, | 306 | constant = 4359, |
| 307 | S_MANCONSTANT = 4397, | 307 | manconstant = 4397, |
| 308 | S_LDATA32 = 4364, | 308 | ldata32 = 4364, |
| 309 | S_GDATA32 = 4365, | 309 | gdata32 = 4365, |
| 310 | S_LMANDATA = 4380, | 310 | lmandata = 4380, |
| 311 | S_GMANDATA = 4381, | 311 | gmandata = 4381, |
| 312 | S_LTHREAD32 = 4370, | 312 | lthread32 = 4370, |
| 313 | S_GTHREAD32 = 4371, | 313 | gthread32 = 4371, |
| 314 | }; | 314 | }; |
| 315 | 315 | ||
| 316 | pub const TypeIndex = u32; | 316 | pub const TypeIndex = u32; |
| ... | @@ -320,28 +320,28 @@ pub const TypeIndex = u32; | ... | @@ -320,28 +320,28 @@ pub const TypeIndex = u32; |
| 320 | // we should define RecordPrefix as part of the ProcSym structure. | 320 | // we should define RecordPrefix as part of the ProcSym structure. |
| 321 | // This might be important when we start generating PDB in self-hosted with our own PE linker. | 321 | // This might be important when we start generating PDB in self-hosted with our own PE linker. |
| 322 | pub const ProcSym = extern struct { | 322 | pub const ProcSym = extern struct { |
| 323 | Parent: u32, | 323 | parent: u32, |
| 324 | End: u32, | 324 | end: u32, |
| 325 | Next: u32, | 325 | next: u32, |
| 326 | CodeSize: u32, | 326 | code_size: u32, |
| 327 | DbgStart: u32, | 327 | dbg_start: u32, |
| 328 | DbgEnd: u32, | 328 | dbg_end: u32, |
| 329 | FunctionType: TypeIndex, | 329 | function_type: TypeIndex, |
| 330 | CodeOffset: u32, | 330 | code_offset: u32, |
| 331 | Segment: u16, | 331 | segment: u16, |
| 332 | Flags: ProcSymFlags, | 332 | flags: ProcSymFlags, |
| 333 | Name: [1]u8, // null-terminated | 333 | name: [1]u8, // null-terminated |
| 334 | }; | 334 | }; |
| 335 | 335 | ||
| 336 | pub const ProcSymFlags = packed struct { | 336 | pub const ProcSymFlags = packed struct { |
| 337 | HasFP: bool, | 337 | has_fp: bool, |
| 338 | HasIRET: bool, | 338 | has_iret: bool, |
| 339 | HasFRET: bool, | 339 | has_fret: bool, |
| 340 | IsNoReturn: bool, | 340 | is_no_return: bool, |
| 341 | IsUnreachable: bool, | 341 | is_unreachable: bool, |
| 342 | HasCustomCallingConv: bool, | 342 | has_custom_calling_conv: bool, |
| 343 | IsNoInline: bool, | 343 | is_no_inline: bool, |
| 344 | HasOptimizedDebugInfo: bool, | 344 | has_optimized_debug_info: bool, |
| 345 | }; | 345 | }; |
| 346 | 346 | ||
| 347 | pub const SectionContrSubstreamVersion = enum(u32) { | 347 | pub const SectionContrSubstreamVersion = enum(u32) { |
| ... | @@ -351,11 +351,11 @@ pub const SectionContrSubstreamVersion = enum(u32) { | ... | @@ -351,11 +351,11 @@ pub const SectionContrSubstreamVersion = enum(u32) { |
| 351 | }; | 351 | }; |
| 352 | 352 | ||
| 353 | pub const RecordPrefix = extern struct { | 353 | pub const RecordPrefix = extern struct { |
| 354 | /// Record length, starting from &RecordKind. | 354 | /// Record length, starting from &record_kind. |
| 355 | RecordLen: u16, | 355 | record_len: u16, |
| 356 | 356 | ||
| 357 | /// Record kind enum (SymRecordKind or TypeRecordKind) | 357 | /// Record kind enum (SymRecordKind or TypeRecordKind) |
| 358 | RecordKind: SymbolKind, | 358 | record_kind: SymbolKind, |
| 359 | }; | 359 | }; |
| 360 | 360 | ||
| 361 | /// The following variable length array appears immediately after the header. | 361 | /// The following variable length array appears immediately after the header. |
| ... | @@ -364,19 +364,19 @@ pub const RecordPrefix = extern struct { | ... | @@ -364,19 +364,19 @@ pub const RecordPrefix = extern struct { |
| 364 | /// Each `LineBlockFragmentHeader` as specified below. | 364 | /// Each `LineBlockFragmentHeader` as specified below. |
| 365 | pub const LineFragmentHeader = extern struct { | 365 | pub const LineFragmentHeader = extern struct { |
| 366 | /// Code offset of line contribution. | 366 | /// Code offset of line contribution. |
| 367 | RelocOffset: u32, | 367 | reloc_offset: u32, |
| 368 | 368 | ||
| 369 | /// Code segment of line contribution. | 369 | /// Code segment of line contribution. |
| 370 | RelocSegment: u16, | 370 | reloc_segment: u16, |
| 371 | Flags: LineFlags, | 371 | flags: LineFlags, |
| 372 | 372 | ||
| 373 | /// Code size of this line contribution. | 373 | /// Code size of this line contribution. |
| 374 | CodeSize: u32, | 374 | code_size: u32, |
| 375 | }; | 375 | }; |
| 376 | 376 | ||
| 377 | pub const LineFlags = packed struct { | 377 | pub const LineFlags = packed struct { |
| 378 | /// CV_LINES_HAVE_COLUMNS | 378 | /// CV_LINES_HAVE_COLUMNS |
| 379 | LF_HaveColumns: bool, | 379 | have_columns: bool, |
| 380 | unused: u15, | 380 | unused: u15, |
| 381 | }; | 381 | }; |
| 382 | 382 | ||
| ... | @@ -389,110 +389,109 @@ pub const LineBlockFragmentHeader = extern struct { | ... | @@ -389,110 +389,109 @@ pub const LineBlockFragmentHeader = extern struct { |
| 389 | /// checksums buffer. The checksum entry then | 389 | /// checksums buffer. The checksum entry then |
| 390 | /// contains another offset into the string | 390 | /// contains another offset into the string |
| 391 | /// table of the actual name. | 391 | /// table of the actual name. |
| 392 | NameIndex: u32, | 392 | name_index: u32, |
| 393 | NumLines: u32, | 393 | num_lines: u32, |
| 394 | 394 | ||
| 395 | /// code size of block, in bytes | 395 | /// code size of block, in bytes |
| 396 | BlockSize: u32, | 396 | block_size: u32, |
| 397 | }; | 397 | }; |
| 398 | 398 | ||
| 399 | pub const LineNumberEntry = extern struct { | 399 | pub const LineNumberEntry = extern struct { |
| 400 | /// Offset to start of code bytes for line number | 400 | /// Offset to start of code bytes for line number |
| 401 | Offset: u32, | 401 | offset: u32, |
| 402 | Flags: u32, | 402 | flags: Flags, |
| 403 | 403 | ||
| 404 | /// TODO runtime crash when I make the actual type of Flags this | 404 | pub const Flags = packed struct(u32) { |
| 405 | pub const Flags = packed struct { | ||
| 406 | /// Start line number | 405 | /// Start line number |
| 407 | Start: u24, | 406 | start: u24, |
| 408 | /// Delta of lines to the end of the expression. Still unclear. | 407 | /// Delta of lines to the end of the expression. Still unclear. |
| 409 | // TODO figure out the point of this field. | 408 | // TODO figure out the point of this field. |
| 410 | End: u7, | 409 | end: u7, |
| 411 | IsStatement: bool, | 410 | is_statement: bool, |
| 412 | }; | 411 | }; |
| 413 | }; | 412 | }; |
| 414 | 413 | ||
| 415 | pub const ColumnNumberEntry = extern struct { | 414 | pub const ColumnNumberEntry = extern struct { |
| 416 | StartColumn: u16, | 415 | start_column: u16, |
| 417 | EndColumn: u16, | 416 | end_column: u16, |
| 418 | }; | 417 | }; |
| 419 | 418 | ||
| 420 | /// Checksum bytes follow. | 419 | /// Checksum bytes follow. |
| 421 | pub const FileChecksumEntryHeader = extern struct { | 420 | pub const FileChecksumEntryHeader = extern struct { |
| 422 | /// Byte offset of filename in global string table. | 421 | /// Byte offset of filename in global string table. |
| 423 | FileNameOffset: u32, | 422 | file_name_offset: u32, |
| 424 | /// Number of bytes of checksum. | 423 | /// Number of bytes of checksum. |
| 425 | ChecksumSize: u8, | 424 | checksum_size: u8, |
| 426 | /// FileChecksumKind | 425 | /// FileChecksumKind |
| 427 | ChecksumKind: u8, | 426 | checksum_kind: u8, |
| 428 | }; | 427 | }; |
| 429 | 428 | ||
| 430 | pub const DebugSubsectionKind = enum(u32) { | 429 | pub const DebugSubsectionKind = enum(u32) { |
| 431 | None = 0, | 430 | none = 0, |
| 432 | Symbols = 0xf1, | 431 | symbols = 0xf1, |
| 433 | Lines = 0xf2, | 432 | lines = 0xf2, |
| 434 | StringTable = 0xf3, | 433 | string_table = 0xf3, |
| 435 | FileChecksums = 0xf4, | 434 | file_checksums = 0xf4, |
| 436 | FrameData = 0xf5, | 435 | frame_data = 0xf5, |
| 437 | InlineeLines = 0xf6, | 436 | inlinee_lines = 0xf6, |
| 438 | CrossScopeImports = 0xf7, | 437 | cross_scope_imports = 0xf7, |
| 439 | CrossScopeExports = 0xf8, | 438 | cross_scope_exports = 0xf8, |
| 440 | 439 | ||
| 441 | // These appear to relate to .Net assembly info. | 440 | // These appear to relate to .Net assembly info. |
| 442 | ILLines = 0xf9, | 441 | il_lines = 0xf9, |
| 443 | FuncMDTokenMap = 0xfa, | 442 | func_md_token_map = 0xfa, |
| 444 | TypeMDTokenMap = 0xfb, | 443 | type_md_token_map = 0xfb, |
| 445 | MergedAssemblyInput = 0xfc, | 444 | merged_assembly_input = 0xfc, |
| 446 | 445 | ||
| 447 | CoffSymbolRVA = 0xfd, | 446 | coff_symbol_rva = 0xfd, |
| 448 | }; | 447 | }; |
| 449 | 448 | ||
| 450 | pub const DebugSubsectionHeader = extern struct { | 449 | pub const DebugSubsectionHeader = extern struct { |
| 451 | /// codeview::DebugSubsectionKind enum | 450 | /// codeview::DebugSubsectionKind enum |
| 452 | Kind: DebugSubsectionKind, | 451 | kind: DebugSubsectionKind, |
| 453 | 452 | ||
| 454 | /// number of bytes occupied by this record. | 453 | /// number of bytes occupied by this record. |
| 455 | Length: u32, | 454 | length: u32, |
| 456 | }; | 455 | }; |
| 457 | 456 | ||
| 458 | pub const StringTableHeader = extern struct { | 457 | pub const StringTableHeader = extern struct { |
| 459 | /// PDBStringTableSignature | 458 | /// PDBStringTableSignature |
| 460 | Signature: u32, | 459 | signature: u32, |
| 461 | /// 1 or 2 | 460 | /// 1 or 2 |
| 462 | HashVersion: u32, | 461 | hash_version: u32, |
| 463 | /// Number of bytes of names buffer. | 462 | /// Number of bytes of names buffer. |
| 464 | ByteSize: u32, | 463 | byte_size: u32, |
| 465 | }; | 464 | }; |
| 466 | 465 | ||
| 467 | // https://llvm.org/docs/PDB/MsfFile.html#the-superblock | 466 | // https://llvm.org/docs/PDB/MsfFile.html#the-superblock |
| 468 | pub const SuperBlock = extern struct { | 467 | pub const SuperBlock = extern struct { |
| 469 | /// The LLVM docs list a space between C / C++ but empirically this is not the case. | 468 | /// The LLVM docs list a space between C / C++ but empirically this is not the case. |
| 470 | pub const file_magic = "Microsoft C/C++ MSF 7.00\r\n\x1a\x44\x53\x00\x00\x00"; | 469 | pub const expect_magic = "Microsoft C/C++ MSF 7.00\r\n\x1a\x44\x53\x00\x00\x00"; |
| 471 | 470 | ||
| 472 | FileMagic: [file_magic.len]u8, | 471 | file_magic: [expect_magic.len]u8, |
| 473 | 472 | ||
| 474 | /// The block size of the internal file system. Valid values are 512, 1024, | 473 | /// The block size of the internal file system. Valid values are 512, 1024, |
| 475 | /// 2048, and 4096 bytes. Certain aspects of the MSF file layout vary depending | 474 | /// 2048, and 4096 bytes. Certain aspects of the MSF file layout vary depending |
| 476 | /// on the block sizes. For the purposes of LLVM, we handle only block sizes of | 475 | /// on the block sizes. For the purposes of LLVM, we handle only block sizes of |
| 477 | /// 4KiB, and all further discussion assumes a block size of 4KiB. | 476 | /// 4KiB, and all further discussion assumes a block size of 4KiB. |
| 478 | BlockSize: u32, | 477 | block_size: u32, |
| 479 | 478 | ||
| 480 | /// The index of a block within the file, at which begins a bitfield representing | 479 | /// The index of a block within the file, at which begins a bitfield representing |
| 481 | /// the set of all blocks within the file which are “free” (i.e. the data within | 480 | /// the set of all blocks within the file which are “free” (i.e. the data within |
| 482 | /// that block is not used). See The Free Block Map for more information. Important: | 481 | /// that block is not used). See The Free Block Map for more information. Important: |
| 483 | /// FreeBlockMapBlock can only be 1 or 2! | 482 | /// FreeBlockMapBlock can only be 1 or 2! |
| 484 | FreeBlockMapBlock: u32, | 483 | free_block_map_block: u32, |
| 485 | 484 | ||
| 486 | /// The total number of blocks in the file. NumBlocks * BlockSize should equal the | 485 | /// The total number of blocks in the file. NumBlocks * BlockSize should equal the |
| 487 | /// size of the file on disk. | 486 | /// size of the file on disk. |
| 488 | NumBlocks: u32, | 487 | num_blocks: u32, |
| 489 | 488 | ||
| 490 | /// The size of the stream directory, in bytes. The stream directory contains | 489 | /// The size of the stream directory, in bytes. The stream directory contains |
| 491 | /// information about each stream’s size and the set of blocks that it occupies. | 490 | /// information about each stream’s size and the set of blocks that it occupies. |
| 492 | /// It will be described in more detail later. | 491 | /// It will be described in more detail later. |
| 493 | NumDirectoryBytes: u32, | 492 | num_directory_bytes: u32, |
| 494 | 493 | ||
| 495 | Unknown: u32, | 494 | unknown: u32, |
| 496 | /// The index of a block within the MSF file. At this block is an array of | 495 | /// The index of a block within the MSF file. At this block is an array of |
| 497 | /// ulittle32_t’s listing the blocks that the stream directory resides on. | 496 | /// ulittle32_t’s listing the blocks that the stream directory resides on. |
| 498 | /// For large MSF files, the stream directory (which describes the block | 497 | /// For large MSF files, the stream directory (which describes the block |
| ... | @@ -508,5 +507,5 @@ pub const SuperBlock = extern struct { | ... | @@ -508,5 +507,5 @@ pub const SuperBlock = extern struct { |
| 508 | // This would mean the Stream Directory is bigger than BlockSize / sizeof(u32) | 507 | // This would mean the Stream Directory is bigger than BlockSize / sizeof(u32) |
| 509 | // blocks. We're not even close to this with a 1GB pdb file, and LLVM didn't | 508 | // blocks. We're not even close to this with a 1GB pdb file, and LLVM didn't |
| 510 | // implement it so we're kind of safe making this assumption for now. | 509 | // implement it so we're kind of safe making this assumption for now. |
| 511 | BlockMapAddr: u32, | 510 | block_map_addr: u32, |
| 512 | }; | 511 | }; |
lib/std/zig/AstGen.zig+152-196| ... | @@ -4053,7 +4053,7 @@ fn fnDecl( | ... | @@ -4053,7 +4053,7 @@ fn fnDecl( |
| 4053 | // The source slice is added towards the *end* of this function. | 4053 | // The source slice is added towards the *end* of this function. |
| 4054 | astgen.src_hasher.update(std.mem.asBytes(&astgen.source_column)); | 4054 | astgen.src_hasher.update(std.mem.asBytes(&astgen.source_column)); |
| 4055 | 4055 | ||
| 4056 | // missing function name already happened in scanDecls() | 4056 | // missing function name already happened in scanContainer() |
| 4057 | const fn_name_token = fn_proto.name_token orelse return error.AnalysisFail; | 4057 | const fn_name_token = fn_proto.name_token orelse return error.AnalysisFail; |
| 4058 | 4058 | ||
| 4059 | // We insert this at the beginning so that its instruction index marks the | 4059 | // We insert this at the beginning so that its instruction index marks the |
| ... | @@ -5019,7 +5019,7 @@ fn structDeclInner( | ... | @@ -5019,7 +5019,7 @@ fn structDeclInner( |
| 5019 | } | 5019 | } |
| 5020 | }; | 5020 | }; |
| 5021 | 5021 | ||
| 5022 | const decl_count = try astgen.scanDecls(&namespace, container_decl.ast.members); | 5022 | const decl_count = try astgen.scanContainer(&namespace, container_decl.ast.members, .@"struct"); |
| 5023 | const field_count: u32 = @intCast(container_decl.ast.members.len - decl_count); | 5023 | const field_count: u32 = @intCast(container_decl.ast.members.len - decl_count); |
| 5024 | 5024 | ||
| 5025 | const bits_per_field = 4; | 5025 | const bits_per_field = 4; |
| ... | @@ -5088,15 +5088,6 @@ fn structDeclInner( | ... | @@ -5088,15 +5088,6 @@ fn structDeclInner( |
| 5088 | astgen.src_hasher.update(tree.getNodeSource(backing_int_node)); | 5088 | astgen.src_hasher.update(tree.getNodeSource(backing_int_node)); |
| 5089 | } | 5089 | } |
| 5090 | 5090 | ||
| 5091 | var sfba = std.heap.stackFallback(256, astgen.arena); | ||
| 5092 | const sfba_allocator = sfba.get(); | ||
| 5093 | |||
| 5094 | var duplicate_names = std.AutoArrayHashMap(Zir.NullTerminatedString, std.ArrayListUnmanaged(Ast.TokenIndex)).init(sfba_allocator); | ||
| 5095 | try duplicate_names.ensureTotalCapacity(field_count); | ||
| 5096 | |||
| 5097 | // When there aren't errors, use this to avoid a second iteration. | ||
| 5098 | var any_duplicate = false; | ||
| 5099 | |||
| 5100 | var known_non_opv = false; | 5091 | var known_non_opv = false; |
| 5101 | var known_comptime_only = false; | 5092 | var known_comptime_only = false; |
| 5102 | var any_comptime_fields = false; | 5093 | var any_comptime_fields = false; |
| ... | @@ -5117,16 +5108,6 @@ fn structDeclInner( | ... | @@ -5117,16 +5108,6 @@ fn structDeclInner( |
| 5117 | assert(!member.ast.tuple_like); | 5108 | assert(!member.ast.tuple_like); |
| 5118 | 5109 | ||
| 5119 | wip_members.appendToField(@intFromEnum(field_name)); | 5110 | wip_members.appendToField(@intFromEnum(field_name)); |
| 5120 | |||
| 5121 | const gop = try duplicate_names.getOrPut(field_name); | ||
| 5122 | |||
| 5123 | if (gop.found_existing) { | ||
| 5124 | try gop.value_ptr.append(sfba_allocator, member.ast.main_token); | ||
| 5125 | any_duplicate = true; | ||
| 5126 | } else { | ||
| 5127 | gop.value_ptr.* = .{}; | ||
| 5128 | try gop.value_ptr.append(sfba_allocator, member.ast.main_token); | ||
| 5129 | } | ||
| 5130 | } else if (!member.ast.tuple_like) { | 5111 | } else if (!member.ast.tuple_like) { |
| 5131 | return astgen.failTok(member.ast.main_token, "tuple field has a name", .{}); | 5112 | return astgen.failTok(member.ast.main_token, "tuple field has a name", .{}); |
| 5132 | } | 5113 | } |
| ... | @@ -5211,32 +5192,6 @@ fn structDeclInner( | ... | @@ -5211,32 +5192,6 @@ fn structDeclInner( |
| 5211 | } | 5192 | } |
| 5212 | } | 5193 | } |
| 5213 | 5194 | ||
| 5214 | if (any_duplicate) { | ||
| 5215 | var it = duplicate_names.iterator(); | ||
| 5216 | |||
| 5217 | while (it.next()) |entry| { | ||
| 5218 | const record = entry.value_ptr.*; | ||
| 5219 | if (record.items.len > 1) { | ||
| 5220 | var error_notes = std.ArrayList(u32).init(astgen.arena); | ||
| 5221 | |||
| 5222 | for (record.items[1..]) |duplicate| { | ||
| 5223 | try error_notes.append(try astgen.errNoteTok(duplicate, "duplicate field here", .{})); | ||
| 5224 | } | ||
| 5225 | |||
| 5226 | try error_notes.append(try astgen.errNoteNode(node, "struct declared here", .{})); | ||
| 5227 | |||
| 5228 | try astgen.appendErrorTokNotes( | ||
| 5229 | record.items[0], | ||
| 5230 | "duplicate struct field name", | ||
| 5231 | .{}, | ||
| 5232 | error_notes.items, | ||
| 5233 | ); | ||
| 5234 | } | ||
| 5235 | } | ||
| 5236 | |||
| 5237 | return error.AnalysisFail; | ||
| 5238 | } | ||
| 5239 | |||
| 5240 | var fields_hash: std.zig.SrcHash = undefined; | 5195 | var fields_hash: std.zig.SrcHash = undefined; |
| 5241 | astgen.src_hasher.final(&fields_hash); | 5196 | astgen.src_hasher.final(&fields_hash); |
| 5242 | 5197 | ||
| ... | @@ -5317,7 +5272,7 @@ fn unionDeclInner( | ... | @@ -5317,7 +5272,7 @@ fn unionDeclInner( |
| 5317 | }; | 5272 | }; |
| 5318 | defer block_scope.unstack(); | 5273 | defer block_scope.unstack(); |
| 5319 | 5274 | ||
| 5320 | const decl_count = try astgen.scanDecls(&namespace, members); | 5275 | const decl_count = try astgen.scanContainer(&namespace, members, .@"union"); |
| 5321 | const field_count: u32 = @intCast(members.len - decl_count); | 5276 | const field_count: u32 = @intCast(members.len - decl_count); |
| 5322 | 5277 | ||
| 5323 | if (layout != .auto and (auto_enum_tok != null or arg_node != 0)) { | 5278 | if (layout != .auto and (auto_enum_tok != null or arg_node != 0)) { |
| ... | @@ -5348,15 +5303,6 @@ fn unionDeclInner( | ... | @@ -5348,15 +5303,6 @@ fn unionDeclInner( |
| 5348 | astgen.src_hasher.update(astgen.tree.getNodeSource(arg_node)); | 5303 | astgen.src_hasher.update(astgen.tree.getNodeSource(arg_node)); |
| 5349 | } | 5304 | } |
| 5350 | 5305 | ||
| 5351 | var sfba = std.heap.stackFallback(256, astgen.arena); | ||
| 5352 | const sfba_allocator = sfba.get(); | ||
| 5353 | |||
| 5354 | var duplicate_names = std.AutoArrayHashMap(Zir.NullTerminatedString, std.ArrayListUnmanaged(Ast.TokenIndex)).init(sfba_allocator); | ||
| 5355 | try duplicate_names.ensureTotalCapacity(field_count); | ||
| 5356 | |||
| 5357 | // When there aren't errors, use this to avoid a second iteration. | ||
| 5358 | var any_duplicate = false; | ||
| 5359 | |||
| 5360 | for (members) |member_node| { | 5306 | for (members) |member_node| { |
| 5361 | var member = switch (try containerMember(&block_scope, &namespace.base, &wip_members, member_node)) { | 5307 | var member = switch (try containerMember(&block_scope, &namespace.base, &wip_members, member_node)) { |
| 5362 | .decl => continue, | 5308 | .decl => continue, |
| ... | @@ -5374,16 +5320,6 @@ fn unionDeclInner( | ... | @@ -5374,16 +5320,6 @@ fn unionDeclInner( |
| 5374 | const field_name = try astgen.identAsString(member.ast.main_token); | 5320 | const field_name = try astgen.identAsString(member.ast.main_token); |
| 5375 | wip_members.appendToField(@intFromEnum(field_name)); | 5321 | wip_members.appendToField(@intFromEnum(field_name)); |
| 5376 | 5322 | ||
| 5377 | const gop = try duplicate_names.getOrPut(field_name); | ||
| 5378 | |||
| 5379 | if (gop.found_existing) { | ||
| 5380 | try gop.value_ptr.append(sfba_allocator, member.ast.main_token); | ||
| 5381 | any_duplicate = true; | ||
| 5382 | } else { | ||
| 5383 | gop.value_ptr.* = .{}; | ||
| 5384 | try gop.value_ptr.append(sfba_allocator, member.ast.main_token); | ||
| 5385 | } | ||
| 5386 | |||
| 5387 | const doc_comment_index = try astgen.docCommentAsString(member.firstToken()); | 5323 | const doc_comment_index = try astgen.docCommentAsString(member.firstToken()); |
| 5388 | wip_members.appendToField(@intFromEnum(doc_comment_index)); | 5324 | wip_members.appendToField(@intFromEnum(doc_comment_index)); |
| 5389 | 5325 | ||
| ... | @@ -5438,32 +5374,6 @@ fn unionDeclInner( | ... | @@ -5438,32 +5374,6 @@ fn unionDeclInner( |
| 5438 | } | 5374 | } |
| 5439 | } | 5375 | } |
| 5440 | 5376 | ||
| 5441 | if (any_duplicate) { | ||
| 5442 | var it = duplicate_names.iterator(); | ||
| 5443 | |||
| 5444 | while (it.next()) |entry| { | ||
| 5445 | const record = entry.value_ptr.*; | ||
| 5446 | if (record.items.len > 1) { | ||
| 5447 | var error_notes = std.ArrayList(u32).init(astgen.arena); | ||
| 5448 | |||
| 5449 | for (record.items[1..]) |duplicate| { | ||
| 5450 | try error_notes.append(try astgen.errNoteTok(duplicate, "duplicate field here", .{})); | ||
| 5451 | } | ||
| 5452 | |||
| 5453 | try error_notes.append(try astgen.errNoteNode(node, "union declared here", .{})); | ||
| 5454 | |||
| 5455 | try astgen.appendErrorTokNotes( | ||
| 5456 | record.items[0], | ||
| 5457 | "duplicate union field name", | ||
| 5458 | .{}, | ||
| 5459 | error_notes.items, | ||
| 5460 | ); | ||
| 5461 | } | ||
| 5462 | } | ||
| 5463 | |||
| 5464 | return error.AnalysisFail; | ||
| 5465 | } | ||
| 5466 | |||
| 5467 | var fields_hash: std.zig.SrcHash = undefined; | 5377 | var fields_hash: std.zig.SrcHash = undefined; |
| 5468 | astgen.src_hasher.final(&fields_hash); | 5378 | astgen.src_hasher.final(&fields_hash); |
| 5469 | 5379 | ||
| ... | @@ -5666,7 +5576,7 @@ fn containerDecl( | ... | @@ -5666,7 +5576,7 @@ fn containerDecl( |
| 5666 | }; | 5576 | }; |
| 5667 | defer block_scope.unstack(); | 5577 | defer block_scope.unstack(); |
| 5668 | 5578 | ||
| 5669 | _ = try astgen.scanDecls(&namespace, container_decl.ast.members); | 5579 | _ = try astgen.scanContainer(&namespace, container_decl.ast.members, .@"enum"); |
| 5670 | namespace.base.tag = .namespace; | 5580 | namespace.base.tag = .namespace; |
| 5671 | 5581 | ||
| 5672 | const arg_inst: Zir.Inst.Ref = if (container_decl.ast.arg != 0) | 5582 | const arg_inst: Zir.Inst.Ref = if (container_decl.ast.arg != 0) |
| ... | @@ -5687,15 +5597,6 @@ fn containerDecl( | ... | @@ -5687,15 +5597,6 @@ fn containerDecl( |
| 5687 | } | 5597 | } |
| 5688 | astgen.src_hasher.update(&.{@intFromBool(nonexhaustive)}); | 5598 | astgen.src_hasher.update(&.{@intFromBool(nonexhaustive)}); |
| 5689 | 5599 | ||
| 5690 | var sfba = std.heap.stackFallback(256, astgen.arena); | ||
| 5691 | const sfba_allocator = sfba.get(); | ||
| 5692 | |||
| 5693 | var duplicate_names = std.AutoArrayHashMap(Zir.NullTerminatedString, std.ArrayListUnmanaged(Ast.TokenIndex)).init(sfba_allocator); | ||
| 5694 | try duplicate_names.ensureTotalCapacity(counts.total_fields); | ||
| 5695 | |||
| 5696 | // When there aren't errors, use this to avoid a second iteration. | ||
| 5697 | var any_duplicate = false; | ||
| 5698 | |||
| 5699 | for (container_decl.ast.members) |member_node| { | 5600 | for (container_decl.ast.members) |member_node| { |
| 5700 | if (member_node == counts.nonexhaustive_node) | 5601 | if (member_node == counts.nonexhaustive_node) |
| 5701 | continue; | 5602 | continue; |
| ... | @@ -5712,16 +5613,6 @@ fn containerDecl( | ... | @@ -5712,16 +5613,6 @@ fn containerDecl( |
| 5712 | const field_name = try astgen.identAsString(member.ast.main_token); | 5613 | const field_name = try astgen.identAsString(member.ast.main_token); |
| 5713 | wip_members.appendToField(@intFromEnum(field_name)); | 5614 | wip_members.appendToField(@intFromEnum(field_name)); |
| 5714 | 5615 | ||
| 5715 | const gop = try duplicate_names.getOrPut(field_name); | ||
| 5716 | |||
| 5717 | if (gop.found_existing) { | ||
| 5718 | try gop.value_ptr.append(sfba_allocator, member.ast.main_token); | ||
| 5719 | any_duplicate = true; | ||
| 5720 | } else { | ||
| 5721 | gop.value_ptr.* = .{}; | ||
| 5722 | try gop.value_ptr.append(sfba_allocator, member.ast.main_token); | ||
| 5723 | } | ||
| 5724 | |||
| 5725 | const doc_comment_index = try astgen.docCommentAsString(member.firstToken()); | 5616 | const doc_comment_index = try astgen.docCommentAsString(member.firstToken()); |
| 5726 | wip_members.appendToField(@intFromEnum(doc_comment_index)); | 5617 | wip_members.appendToField(@intFromEnum(doc_comment_index)); |
| 5727 | 5618 | ||
| ... | @@ -5748,32 +5639,6 @@ fn containerDecl( | ... | @@ -5748,32 +5639,6 @@ fn containerDecl( |
| 5748 | } | 5639 | } |
| 5749 | } | 5640 | } |
| 5750 | 5641 | ||
| 5751 | if (any_duplicate) { | ||
| 5752 | var it = duplicate_names.iterator(); | ||
| 5753 | |||
| 5754 | while (it.next()) |entry| { | ||
| 5755 | const record = entry.value_ptr.*; | ||
| 5756 | if (record.items.len > 1) { | ||
| 5757 | var error_notes = std.ArrayList(u32).init(astgen.arena); | ||
| 5758 | |||
| 5759 | for (record.items[1..]) |duplicate| { | ||
| 5760 | try error_notes.append(try astgen.errNoteTok(duplicate, "duplicate field here", .{})); | ||
| 5761 | } | ||
| 5762 | |||
| 5763 | try error_notes.append(try astgen.errNoteNode(node, "enum declared here", .{})); | ||
| 5764 | |||
| 5765 | try astgen.appendErrorTokNotes( | ||
| 5766 | record.items[0], | ||
| 5767 | "duplicate enum field name", | ||
| 5768 | .{}, | ||
| 5769 | error_notes.items, | ||
| 5770 | ); | ||
| 5771 | } | ||
| 5772 | } | ||
| 5773 | |||
| 5774 | return error.AnalysisFail; | ||
| 5775 | } | ||
| 5776 | |||
| 5777 | if (!block_scope.isEmpty()) { | 5642 | if (!block_scope.isEmpty()) { |
| 5778 | _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value); | 5643 | _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value); |
| 5779 | } | 5644 | } |
| ... | @@ -5833,7 +5698,7 @@ fn containerDecl( | ... | @@ -5833,7 +5698,7 @@ fn containerDecl( |
| 5833 | }; | 5698 | }; |
| 5834 | defer block_scope.unstack(); | 5699 | defer block_scope.unstack(); |
| 5835 | 5700 | ||
| 5836 | const decl_count = try astgen.scanDecls(&namespace, container_decl.ast.members); | 5701 | const decl_count = try astgen.scanContainer(&namespace, container_decl.ast.members, .@"opaque"); |
| 5837 | 5702 | ||
| 5838 | var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, 0, 0, 0); | 5703 | var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, 0, 0, 0); |
| 5839 | defer wip_members.deinit(); | 5704 | defer wip_members.deinit(); |
| ... | @@ -13594,31 +13459,67 @@ fn advanceSourceCursor(astgen: *AstGen, end: usize) void { | ... | @@ -13594,31 +13459,67 @@ fn advanceSourceCursor(astgen: *AstGen, end: usize) void { |
| 13594 | astgen.source_column = column; | 13459 | astgen.source_column = column; |
| 13595 | } | 13460 | } |
| 13596 | 13461 | ||
| 13597 | fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const Ast.Node.Index) !u32 { | 13462 | /// Detects name conflicts for decls and fields, and populates `namespace.decls` with all named declarations. |
| 13463 | /// Returns the number of declarations in the namespace, including unnamed declarations (e.g. `comptime` decls). | ||
| 13464 | fn scanContainer( | ||
| 13465 | astgen: *AstGen, | ||
| 13466 | namespace: *Scope.Namespace, | ||
| 13467 | members: []const Ast.Node.Index, | ||
| 13468 | container_kind: enum { @"struct", @"union", @"enum", @"opaque" }, | ||
| 13469 | ) !u32 { | ||
| 13598 | const gpa = astgen.gpa; | 13470 | const gpa = astgen.gpa; |
| 13599 | const tree = astgen.tree; | 13471 | const tree = astgen.tree; |
| 13600 | const node_tags = tree.nodes.items(.tag); | 13472 | const node_tags = tree.nodes.items(.tag); |
| 13601 | const main_tokens = tree.nodes.items(.main_token); | 13473 | const main_tokens = tree.nodes.items(.main_token); |
| 13602 | const token_tags = tree.tokens.items(.tag); | 13474 | const token_tags = tree.tokens.items(.tag); |
| 13603 | 13475 | ||
| 13604 | // We don't have shadowing for test names, so we just track those for duplicate reporting locally. | 13476 | // This type forms a linked list of source tokens declaring the same name. |
| 13605 | var named_tests: std.AutoHashMapUnmanaged(Zir.NullTerminatedString, Ast.Node.Index) = .{}; | 13477 | const NameEntry = struct { |
| 13606 | var decltests: std.AutoHashMapUnmanaged(Zir.NullTerminatedString, Ast.Node.Index) = .{}; | 13478 | tok: Ast.TokenIndex, |
| 13479 | /// Using a linked list here simplifies memory management, and is acceptable since | ||
| 13480 | ///ewntries are only allocated in error situations. The entries are allocated into the | ||
| 13481 | /// AstGen arena. | ||
| 13482 | next: ?*@This(), | ||
| 13483 | }; | ||
| 13484 | |||
| 13485 | // The maps below are allocated into this SFBA to avoid using the GPA for small namespaces. | ||
| 13486 | var sfba_state = std.heap.stackFallback(512, astgen.gpa); | ||
| 13487 | const sfba = sfba_state.get(); | ||
| 13488 | |||
| 13489 | var names: std.AutoArrayHashMapUnmanaged(Zir.NullTerminatedString, NameEntry) = .{}; | ||
| 13490 | var test_names: std.AutoArrayHashMapUnmanaged(Zir.NullTerminatedString, NameEntry) = .{}; | ||
| 13491 | var decltest_names: std.AutoArrayHashMapUnmanaged(Zir.NullTerminatedString, NameEntry) = .{}; | ||
| 13607 | defer { | 13492 | defer { |
| 13608 | named_tests.deinit(gpa); | 13493 | names.deinit(sfba); |
| 13609 | decltests.deinit(gpa); | 13494 | test_names.deinit(sfba); |
| 13495 | decltest_names.deinit(sfba); | ||
| 13610 | } | 13496 | } |
| 13611 | 13497 | ||
| 13498 | var any_duplicates = false; | ||
| 13612 | var decl_count: u32 = 0; | 13499 | var decl_count: u32 = 0; |
| 13613 | for (members) |member_node| { | 13500 | for (members) |member_node| { |
| 13614 | const name_token = switch (node_tags[member_node]) { | 13501 | const Kind = enum { decl, field }; |
| 13502 | const kind: Kind, const name_token = switch (node_tags[member_node]) { | ||
| 13503 | .container_field_init, | ||
| 13504 | .container_field_align, | ||
| 13505 | .container_field, | ||
| 13506 | => blk: { | ||
| 13507 | var full = tree.fullContainerField(member_node).?; | ||
| 13508 | switch (container_kind) { | ||
| 13509 | .@"struct", .@"opaque" => {}, | ||
| 13510 | .@"union", .@"enum" => full.convertToNonTupleLike(astgen.tree.nodes), | ||
| 13511 | } | ||
| 13512 | if (full.ast.tuple_like) continue; | ||
| 13513 | break :blk .{ .field, full.ast.main_token }; | ||
| 13514 | }, | ||
| 13515 | |||
| 13615 | .global_var_decl, | 13516 | .global_var_decl, |
| 13616 | .local_var_decl, | 13517 | .local_var_decl, |
| 13617 | .simple_var_decl, | 13518 | .simple_var_decl, |
| 13618 | .aligned_var_decl, | 13519 | .aligned_var_decl, |
| 13619 | => blk: { | 13520 | => blk: { |
| 13620 | decl_count += 1; | 13521 | decl_count += 1; |
| 13621 | break :blk main_tokens[member_node] + 1; | 13522 | break :blk .{ .decl, main_tokens[member_node] + 1 }; |
| 13622 | }, | 13523 | }, |
| 13623 | 13524 | ||
| 13624 | .fn_proto_simple, | 13525 | .fn_proto_simple, |
| ... | @@ -13630,12 +13531,10 @@ fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const Ast. | ... | @@ -13630,12 +13531,10 @@ fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const Ast. |
| 13630 | decl_count += 1; | 13531 | decl_count += 1; |
| 13631 | const ident = main_tokens[member_node] + 1; | 13532 | const ident = main_tokens[member_node] + 1; |
| 13632 | if (token_tags[ident] != .identifier) { | 13533 | if (token_tags[ident] != .identifier) { |
| 13633 | switch (astgen.failNode(member_node, "missing function name", .{})) { | 13534 | try astgen.appendErrorNode(member_node, "missing function name", .{}); |
| 13634 | error.AnalysisFail => continue, | 13535 | continue; |
| 13635 | error.OutOfMemory => return error.OutOfMemory, | ||
| 13636 | } | ||
| 13637 | } | 13536 | } |
| 13638 | break :blk ident; | 13537 | break :blk .{ .decl, ident }; |
| 13639 | }, | 13538 | }, |
| 13640 | 13539 | ||
| 13641 | .@"comptime", .@"usingnamespace" => { | 13540 | .@"comptime", .@"usingnamespace" => { |
| ... | @@ -13648,70 +13547,87 @@ fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const Ast. | ... | @@ -13648,70 +13547,87 @@ fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const Ast. |
| 13648 | // We don't want shadowing detection here, and test names work a bit differently, so | 13547 | // We don't want shadowing detection here, and test names work a bit differently, so |
| 13649 | // we must do the redeclaration detection ourselves. | 13548 | // we must do the redeclaration detection ourselves. |
| 13650 | const test_name_token = main_tokens[member_node] + 1; | 13549 | const test_name_token = main_tokens[member_node] + 1; |
| 13550 | const new_ent: NameEntry = .{ | ||
| 13551 | .tok = test_name_token, | ||
| 13552 | .next = null, | ||
| 13553 | }; | ||
| 13651 | switch (token_tags[test_name_token]) { | 13554 | switch (token_tags[test_name_token]) { |
| 13652 | else => {}, // unnamed test | 13555 | else => {}, // unnamed test |
| 13653 | .string_literal => { | 13556 | .string_literal => { |
| 13654 | const name = try astgen.strLitAsString(test_name_token); | 13557 | const name = try astgen.strLitAsString(test_name_token); |
| 13655 | const gop = try named_tests.getOrPut(gpa, name.index); | 13558 | const gop = try test_names.getOrPut(sfba, name.index); |
| 13656 | if (gop.found_existing) { | 13559 | if (gop.found_existing) { |
| 13657 | const name_slice = astgen.string_bytes.items[@intFromEnum(name.index)..][0..name.len]; | 13560 | var e = gop.value_ptr; |
| 13658 | const name_duped = try gpa.dupe(u8, name_slice); | 13561 | while (e.next) |n| e = n; |
| 13659 | defer gpa.free(name_duped); | 13562 | e.next = try astgen.arena.create(NameEntry); |
| 13660 | try astgen.appendErrorNodeNotes(member_node, "duplicate test name '{s}'", .{name_duped}, &.{ | 13563 | e.next.?.* = new_ent; |
| 13661 | try astgen.errNoteNode(gop.value_ptr.*, "other test here", .{}), | 13564 | any_duplicates = true; |
| 13662 | }); | ||
| 13663 | } else { | 13565 | } else { |
| 13664 | gop.value_ptr.* = member_node; | 13566 | gop.value_ptr.* = new_ent; |
| 13665 | } | 13567 | } |
| 13666 | }, | 13568 | }, |
| 13667 | .identifier => { | 13569 | .identifier => { |
| 13668 | const name = try astgen.identAsString(test_name_token); | 13570 | const name = try astgen.identAsString(test_name_token); |
| 13669 | const gop = try decltests.getOrPut(gpa, name); | 13571 | const gop = try decltest_names.getOrPut(sfba, name); |
| 13670 | if (gop.found_existing) { | 13572 | if (gop.found_existing) { |
| 13671 | const name_slice = mem.span(astgen.nullTerminatedString(name)); | 13573 | var e = gop.value_ptr; |
| 13672 | const name_duped = try gpa.dupe(u8, name_slice); | 13574 | while (e.next) |n| e = n; |
| 13673 | defer gpa.free(name_duped); | 13575 | e.next = try astgen.arena.create(NameEntry); |
| 13674 | try astgen.appendErrorNodeNotes(member_node, "duplicate decltest '{s}'", .{name_duped}, &.{ | 13576 | e.next.?.* = new_ent; |
| 13675 | try astgen.errNoteNode(gop.value_ptr.*, "other decltest here", .{}), | 13577 | any_duplicates = true; |
| 13676 | }); | ||
| 13677 | } else { | 13578 | } else { |
| 13678 | gop.value_ptr.* = member_node; | 13579 | gop.value_ptr.* = new_ent; |
| 13679 | } | 13580 | } |
| 13680 | }, | 13581 | }, |
| 13681 | } | 13582 | } |
| 13682 | continue; | 13583 | continue; |
| 13683 | }, | 13584 | }, |
| 13684 | 13585 | ||
| 13685 | else => continue, | 13586 | else => unreachable, |
| 13686 | }; | 13587 | }; |
| 13687 | 13588 | ||
| 13589 | const name_str_index = try astgen.identAsString(name_token); | ||
| 13590 | |||
| 13591 | if (kind == .decl) { | ||
| 13592 | // Put the name straight into `decls`, even if there are compile errors. | ||
| 13593 | // This avoids incorrect "undeclared identifier" errors later on. | ||
| 13594 | try namespace.decls.put(gpa, name_str_index, member_node); | ||
| 13595 | } | ||
| 13596 | |||
| 13597 | { | ||
| 13598 | const gop = try names.getOrPut(sfba, name_str_index); | ||
| 13599 | const new_ent: NameEntry = .{ | ||
| 13600 | .tok = name_token, | ||
| 13601 | .next = null, | ||
| 13602 | }; | ||
| 13603 | if (gop.found_existing) { | ||
| 13604 | var e = gop.value_ptr; | ||
| 13605 | while (e.next) |n| e = n; | ||
| 13606 | e.next = try astgen.arena.create(NameEntry); | ||
| 13607 | e.next.?.* = new_ent; | ||
| 13608 | any_duplicates = true; | ||
| 13609 | continue; | ||
| 13610 | } else { | ||
| 13611 | gop.value_ptr.* = new_ent; | ||
| 13612 | } | ||
| 13613 | } | ||
| 13614 | |||
| 13615 | // For fields, we only needed the duplicate check! Decls have some more checks to do, though. | ||
| 13616 | switch (kind) { | ||
| 13617 | .decl => {}, | ||
| 13618 | .field => continue, | ||
| 13619 | } | ||
| 13620 | |||
| 13688 | const token_bytes = astgen.tree.tokenSlice(name_token); | 13621 | const token_bytes = astgen.tree.tokenSlice(name_token); |
| 13689 | if (token_bytes[0] != '@' and isPrimitive(token_bytes)) { | 13622 | if (token_bytes[0] != '@' and isPrimitive(token_bytes)) { |
| 13690 | switch (astgen.failTokNotes(name_token, "name shadows primitive '{s}'", .{ | 13623 | try astgen.appendErrorTokNotes(name_token, "name shadows primitive '{s}'", .{ |
| 13691 | token_bytes, | 13624 | token_bytes, |
| 13692 | }, &[_]u32{ | 13625 | }, &.{ |
| 13693 | try astgen.errNoteTok(name_token, "consider using @\"{s}\" to disambiguate", .{ | 13626 | try astgen.errNoteTok(name_token, "consider using @\"{s}\" to disambiguate", .{ |
| 13694 | token_bytes, | 13627 | token_bytes, |
| 13695 | }), | 13628 | }), |
| 13696 | })) { | 13629 | }); |
| 13697 | error.AnalysisFail => continue, | 13630 | continue; |
| 13698 | error.OutOfMemory => return error.OutOfMemory, | ||
| 13699 | } | ||
| 13700 | } | ||
| 13701 | |||
| 13702 | const name_str_index = try astgen.identAsString(name_token); | ||
| 13703 | const gop = try namespace.decls.getOrPut(gpa, name_str_index); | ||
| 13704 | if (gop.found_existing) { | ||
| 13705 | const name = try gpa.dupe(u8, mem.span(astgen.nullTerminatedString(name_str_index))); | ||
| 13706 | defer gpa.free(name); | ||
| 13707 | switch (astgen.failNodeNotes(member_node, "redeclaration of '{s}'", .{ | ||
| 13708 | name, | ||
| 13709 | }, &[_]u32{ | ||
| 13710 | try astgen.errNoteNode(gop.value_ptr.*, "other declaration here", .{}), | ||
| 13711 | })) { | ||
| 13712 | error.AnalysisFail => continue, | ||
| 13713 | error.OutOfMemory => return error.OutOfMemory, | ||
| 13714 | } | ||
| 13715 | } | 13631 | } |
| 13716 | 13632 | ||
| 13717 | var s = namespace.parent; | 13633 | var s = namespace.parent; |
| ... | @@ -13719,30 +13635,32 @@ fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const Ast. | ... | @@ -13719,30 +13635,32 @@ fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const Ast. |
| 13719 | .local_val => { | 13635 | .local_val => { |
| 13720 | const local_val = s.cast(Scope.LocalVal).?; | 13636 | const local_val = s.cast(Scope.LocalVal).?; |
| 13721 | if (local_val.name == name_str_index) { | 13637 | if (local_val.name == name_str_index) { |
| 13722 | return astgen.failTokNotes(name_token, "declaration '{s}' shadows {s} from outer scope", .{ | 13638 | try astgen.appendErrorTokNotes(name_token, "declaration '{s}' shadows {s} from outer scope", .{ |
| 13723 | token_bytes, @tagName(local_val.id_cat), | 13639 | token_bytes, @tagName(local_val.id_cat), |
| 13724 | }, &[_]u32{ | 13640 | }, &.{ |
| 13725 | try astgen.errNoteTok( | 13641 | try astgen.errNoteTok( |
| 13726 | local_val.token_src, | 13642 | local_val.token_src, |
| 13727 | "previous declaration here", | 13643 | "previous declaration here", |
| 13728 | .{}, | 13644 | .{}, |
| 13729 | ), | 13645 | ), |
| 13730 | }); | 13646 | }); |
| 13647 | break; | ||
| 13731 | } | 13648 | } |
| 13732 | s = local_val.parent; | 13649 | s = local_val.parent; |
| 13733 | }, | 13650 | }, |
| 13734 | .local_ptr => { | 13651 | .local_ptr => { |
| 13735 | const local_ptr = s.cast(Scope.LocalPtr).?; | 13652 | const local_ptr = s.cast(Scope.LocalPtr).?; |
| 13736 | if (local_ptr.name == name_str_index) { | 13653 | if (local_ptr.name == name_str_index) { |
| 13737 | return astgen.failTokNotes(name_token, "declaration '{s}' shadows {s} from outer scope", .{ | 13654 | try astgen.appendErrorTokNotes(name_token, "declaration '{s}' shadows {s} from outer scope", .{ |
| 13738 | token_bytes, @tagName(local_ptr.id_cat), | 13655 | token_bytes, @tagName(local_ptr.id_cat), |
| 13739 | }, &[_]u32{ | 13656 | }, &.{ |
| 13740 | try astgen.errNoteTok( | 13657 | try astgen.errNoteTok( |
| 13741 | local_ptr.token_src, | 13658 | local_ptr.token_src, |
| 13742 | "previous declaration here", | 13659 | "previous declaration here", |
| 13743 | .{}, | 13660 | .{}, |
| 13744 | ), | 13661 | ), |
| 13745 | }); | 13662 | }); |
| 13663 | break; | ||
| 13746 | } | 13664 | } |
| 13747 | s = local_ptr.parent; | 13665 | s = local_ptr.parent; |
| 13748 | }, | 13666 | }, |
| ... | @@ -13751,8 +13669,46 @@ fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const Ast. | ... | @@ -13751,8 +13669,46 @@ fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const Ast. |
| 13751 | .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent, | 13669 | .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent, |
| 13752 | .top => break, | 13670 | .top => break, |
| 13753 | }; | 13671 | }; |
| 13754 | gop.value_ptr.* = member_node; | ||
| 13755 | } | 13672 | } |
| 13673 | |||
| 13674 | if (!any_duplicates) return decl_count; | ||
| 13675 | |||
| 13676 | for (names.keys(), names.values()) |name, first| { | ||
| 13677 | if (first.next == null) continue; | ||
| 13678 | var notes: std.ArrayListUnmanaged(u32) = .{}; | ||
| 13679 | var prev: NameEntry = first; | ||
| 13680 | while (prev.next) |cur| : (prev = cur.*) { | ||
| 13681 | try notes.append(astgen.arena, try astgen.errNoteTok(cur.tok, "duplicate name here", .{})); | ||
| 13682 | } | ||
| 13683 | try notes.append(astgen.arena, try astgen.errNoteNode(namespace.node, "{s} declared here", .{@tagName(container_kind)})); | ||
| 13684 | const name_duped = try astgen.arena.dupe(u8, mem.span(astgen.nullTerminatedString(name))); | ||
| 13685 | try astgen.appendErrorTokNotes(first.tok, "duplicate {s} member name '{s}'", .{ @tagName(container_kind), name_duped }, notes.items); | ||
| 13686 | } | ||
| 13687 | |||
| 13688 | for (test_names.keys(), test_names.values()) |name, first| { | ||
| 13689 | if (first.next == null) continue; | ||
| 13690 | var notes: std.ArrayListUnmanaged(u32) = .{}; | ||
| 13691 | var prev: NameEntry = first; | ||
| 13692 | while (prev.next) |cur| : (prev = cur.*) { | ||
| 13693 | try notes.append(astgen.arena, try astgen.errNoteTok(cur.tok, "duplicate test here", .{})); | ||
| 13694 | } | ||
| 13695 | try notes.append(astgen.arena, try astgen.errNoteNode(namespace.node, "{s} declared here", .{@tagName(container_kind)})); | ||
| 13696 | const name_duped = try astgen.arena.dupe(u8, mem.span(astgen.nullTerminatedString(name))); | ||
| 13697 | try astgen.appendErrorTokNotes(first.tok, "duplicate test name '{s}'", .{name_duped}, notes.items); | ||
| 13698 | } | ||
| 13699 | |||
| 13700 | for (decltest_names.keys(), decltest_names.values()) |name, first| { | ||
| 13701 | if (first.next == null) continue; | ||
| 13702 | var notes: std.ArrayListUnmanaged(u32) = .{}; | ||
| 13703 | var prev: NameEntry = first; | ||
| 13704 | while (prev.next) |cur| : (prev = cur.*) { | ||
| 13705 | try notes.append(astgen.arena, try astgen.errNoteTok(cur.tok, "duplicate decltest here", .{})); | ||
| 13706 | } | ||
| 13707 | try notes.append(astgen.arena, try astgen.errNoteNode(namespace.node, "{s} declared here", .{@tagName(container_kind)})); | ||
| 13708 | const name_duped = try astgen.arena.dupe(u8, mem.span(astgen.nullTerminatedString(name))); | ||
| 13709 | try astgen.appendErrorTokNotes(first.tok, "duplicate decltest '{s}'", .{name_duped}, notes.items); | ||
| 13710 | } | ||
| 13711 | |||
| 13756 | return decl_count; | 13712 | return decl_count; |
| 13757 | } | 13713 | } |
| 13758 | 13714 |
src/arch/aarch64/bits.zig+4-4| ... | @@ -1069,7 +1069,7 @@ pub const Instruction = union(enum) { | ... | @@ -1069,7 +1069,7 @@ pub const Instruction = union(enum) { |
| 1069 | }; | 1069 | }; |
| 1070 | } | 1070 | } |
| 1071 | 1071 | ||
| 1072 | fn bitfield( | 1072 | fn initBitfield( |
| 1073 | opc: u2, | 1073 | opc: u2, |
| 1074 | n: u1, | 1074 | n: u1, |
| 1075 | rd: Register, | 1075 | rd: Register, |
| ... | @@ -1579,7 +1579,7 @@ pub const Instruction = union(enum) { | ... | @@ -1579,7 +1579,7 @@ pub const Instruction = union(enum) { |
| 1579 | 64 => 0b1, | 1579 | 64 => 0b1, |
| 1580 | else => unreachable, // unexpected register size | 1580 | else => unreachable, // unexpected register size |
| 1581 | }; | 1581 | }; |
| 1582 | return bitfield(0b00, n, rd, rn, immr, imms); | 1582 | return initBitfield(0b00, n, rd, rn, immr, imms); |
| 1583 | } | 1583 | } |
| 1584 | 1584 | ||
| 1585 | pub fn bfm(rd: Register, rn: Register, immr: u6, imms: u6) Instruction { | 1585 | pub fn bfm(rd: Register, rn: Register, immr: u6, imms: u6) Instruction { |
| ... | @@ -1588,7 +1588,7 @@ pub const Instruction = union(enum) { | ... | @@ -1588,7 +1588,7 @@ pub const Instruction = union(enum) { |
| 1588 | 64 => 0b1, | 1588 | 64 => 0b1, |
| 1589 | else => unreachable, // unexpected register size | 1589 | else => unreachable, // unexpected register size |
| 1590 | }; | 1590 | }; |
| 1591 | return bitfield(0b01, n, rd, rn, immr, imms); | 1591 | return initBitfield(0b01, n, rd, rn, immr, imms); |
| 1592 | } | 1592 | } |
| 1593 | 1593 | ||
| 1594 | pub fn ubfm(rd: Register, rn: Register, immr: u6, imms: u6) Instruction { | 1594 | pub fn ubfm(rd: Register, rn: Register, immr: u6, imms: u6) Instruction { |
| ... | @@ -1597,7 +1597,7 @@ pub const Instruction = union(enum) { | ... | @@ -1597,7 +1597,7 @@ pub const Instruction = union(enum) { |
| 1597 | 64 => 0b1, | 1597 | 64 => 0b1, |
| 1598 | else => unreachable, // unexpected register size | 1598 | else => unreachable, // unexpected register size |
| 1599 | }; | 1599 | }; |
| 1600 | return bitfield(0b10, n, rd, rn, immr, imms); | 1600 | return initBitfield(0b10, n, rd, rn, immr, imms); |
| 1601 | } | 1601 | } |
| 1602 | 1602 | ||
| 1603 | pub fn asrImmediate(rd: Register, rn: Register, shift: u6) Instruction { | 1603 | pub fn asrImmediate(rd: Register, rn: Register, shift: u6) Instruction { |
src/arch/arm/bits.zig+10-10| ... | @@ -662,7 +662,7 @@ pub const Instruction = union(enum) { | ... | @@ -662,7 +662,7 @@ pub const Instruction = union(enum) { |
| 662 | }; | 662 | }; |
| 663 | } | 663 | } |
| 664 | 664 | ||
| 665 | fn multiply( | 665 | fn initMultiply( |
| 666 | cond: Condition, | 666 | cond: Condition, |
| 667 | set_cond: u1, | 667 | set_cond: u1, |
| 668 | rd: Register, | 668 | rd: Register, |
| ... | @@ -864,7 +864,7 @@ pub const Instruction = union(enum) { | ... | @@ -864,7 +864,7 @@ pub const Instruction = union(enum) { |
| 864 | }; | 864 | }; |
| 865 | } | 865 | } |
| 866 | 866 | ||
| 867 | fn branch(cond: Condition, offset: i26, link: u1) Instruction { | 867 | fn initBranch(cond: Condition, offset: i26, link: u1) Instruction { |
| 868 | return Instruction{ | 868 | return Instruction{ |
| 869 | .branch = .{ | 869 | .branch = .{ |
| 870 | .cond = @intFromEnum(cond), | 870 | .cond = @intFromEnum(cond), |
| ... | @@ -900,7 +900,7 @@ pub const Instruction = union(enum) { | ... | @@ -900,7 +900,7 @@ pub const Instruction = union(enum) { |
| 900 | }; | 900 | }; |
| 901 | } | 901 | } |
| 902 | 902 | ||
| 903 | fn breakpoint(imm: u16) Instruction { | 903 | fn initBreakpoint(imm: u16) Instruction { |
| 904 | return Instruction{ | 904 | return Instruction{ |
| 905 | .breakpoint = .{ | 905 | .breakpoint = .{ |
| 906 | .imm12 = @as(u12, @truncate(imm >> 4)), | 906 | .imm12 = @as(u12, @truncate(imm >> 4)), |
| ... | @@ -1087,19 +1087,19 @@ pub const Instruction = union(enum) { | ... | @@ -1087,19 +1087,19 @@ pub const Instruction = union(enum) { |
| 1087 | // Multiply | 1087 | // Multiply |
| 1088 | 1088 | ||
| 1089 | pub fn mul(cond: Condition, rd: Register, rn: Register, rm: Register) Instruction { | 1089 | pub fn mul(cond: Condition, rd: Register, rn: Register, rm: Register) Instruction { |
| 1090 | return multiply(cond, 0, rd, rn, rm, null); | 1090 | return initMultiply(cond, 0, rd, rn, rm, null); |
| 1091 | } | 1091 | } |
| 1092 | 1092 | ||
| 1093 | pub fn muls(cond: Condition, rd: Register, rn: Register, rm: Register) Instruction { | 1093 | pub fn muls(cond: Condition, rd: Register, rn: Register, rm: Register) Instruction { |
| 1094 | return multiply(cond, 1, rd, rn, rm, null); | 1094 | return initMultiply(cond, 1, rd, rn, rm, null); |
| 1095 | } | 1095 | } |
| 1096 | 1096 | ||
| 1097 | pub fn mla(cond: Condition, rd: Register, rn: Register, rm: Register, ra: Register) Instruction { | 1097 | pub fn mla(cond: Condition, rd: Register, rn: Register, rm: Register, ra: Register) Instruction { |
| 1098 | return multiply(cond, 0, rd, rn, rm, ra); | 1098 | return initMultiply(cond, 0, rd, rn, rm, ra); |
| 1099 | } | 1099 | } |
| 1100 | 1100 | ||
| 1101 | pub fn mlas(cond: Condition, rd: Register, rn: Register, rm: Register, ra: Register) Instruction { | 1101 | pub fn mlas(cond: Condition, rd: Register, rn: Register, rm: Register, ra: Register) Instruction { |
| 1102 | return multiply(cond, 1, rd, rn, rm, ra); | 1102 | return initMultiply(cond, 1, rd, rn, rm, ra); |
| 1103 | } | 1103 | } |
| 1104 | 1104 | ||
| 1105 | // Multiply long | 1105 | // Multiply long |
| ... | @@ -1261,11 +1261,11 @@ pub const Instruction = union(enum) { | ... | @@ -1261,11 +1261,11 @@ pub const Instruction = union(enum) { |
| 1261 | // Branch | 1261 | // Branch |
| 1262 | 1262 | ||
| 1263 | pub fn b(cond: Condition, offset: i26) Instruction { | 1263 | pub fn b(cond: Condition, offset: i26) Instruction { |
| 1264 | return branch(cond, offset, 0); | 1264 | return initBranch(cond, offset, 0); |
| 1265 | } | 1265 | } |
| 1266 | 1266 | ||
| 1267 | pub fn bl(cond: Condition, offset: i26) Instruction { | 1267 | pub fn bl(cond: Condition, offset: i26) Instruction { |
| 1268 | return branch(cond, offset, 1); | 1268 | return initBranch(cond, offset, 1); |
| 1269 | } | 1269 | } |
| 1270 | 1270 | ||
| 1271 | // Branch and exchange | 1271 | // Branch and exchange |
| ... | @@ -1289,7 +1289,7 @@ pub const Instruction = union(enum) { | ... | @@ -1289,7 +1289,7 @@ pub const Instruction = union(enum) { |
| 1289 | // Breakpoint | 1289 | // Breakpoint |
| 1290 | 1290 | ||
| 1291 | pub fn bkpt(imm: u16) Instruction { | 1291 | pub fn bkpt(imm: u16) Instruction { |
| 1292 | return breakpoint(imm); | 1292 | return initBreakpoint(imm); |
| 1293 | } | 1293 | } |
| 1294 | 1294 | ||
| 1295 | // Aliases | 1295 | // Aliases |
src/arch/x86_64/CodeGen.zig+1-1| ... | @@ -15563,7 +15563,7 @@ fn genLazySymbolRef( | ... | @@ -15563,7 +15563,7 @@ fn genLazySymbolRef( |
| 15563 | .mov => try self.asmRegisterMemory( | 15563 | .mov => try self.asmRegisterMemory( |
| 15564 | .{ ._, tag }, | 15564 | .{ ._, tag }, |
| 15565 | reg.to64(), | 15565 | reg.to64(), |
| 15566 | Memory.sib(.qword, .{ .base = .{ .reg = reg.to64() } }), | 15566 | Memory.initSib(.qword, .{ .base = .{ .reg = reg.to64() } }), |
| 15567 | ), | 15567 | ), |
| 15568 | else => unreachable, | 15568 | else => unreachable, |
| 15569 | } | 15569 | } |
src/arch/x86_64/Disassembler.zig+8-8| ... | @@ -95,7 +95,7 @@ pub fn next(dis: *Disassembler) Error!?Instruction { | ... | @@ -95,7 +95,7 @@ pub fn next(dis: *Disassembler) Error!?Instruction { |
| 95 | 95 | ||
| 96 | if (modrm.rip()) { | 96 | if (modrm.rip()) { |
| 97 | return inst(act_enc, .{ | 97 | return inst(act_enc, .{ |
| 98 | .op1 = .{ .mem = Memory.rip(Memory.PtrSize.fromBitSize(act_enc.data.ops[0].memBitSize()), disp) }, | 98 | .op1 = .{ .mem = Memory.initRip(Memory.PtrSize.fromBitSize(act_enc.data.ops[0].memBitSize()), disp) }, |
| 99 | .op2 = op2, | 99 | .op2 = op2, |
| 100 | }); | 100 | }); |
| 101 | } | 101 | } |
| ... | @@ -106,7 +106,7 @@ pub fn next(dis: *Disassembler) Error!?Instruction { | ... | @@ -106,7 +106,7 @@ pub fn next(dis: *Disassembler) Error!?Instruction { |
| 106 | else | 106 | else |
| 107 | parseGpRegister(modrm.op2, prefixes.rex.b, prefixes.rex, 64); | 107 | parseGpRegister(modrm.op2, prefixes.rex.b, prefixes.rex, 64); |
| 108 | return inst(act_enc, .{ | 108 | return inst(act_enc, .{ |
| 109 | .op1 = .{ .mem = Memory.sib(Memory.PtrSize.fromBitSize(act_enc.data.ops[0].memBitSize()), .{ | 109 | .op1 = .{ .mem = Memory.initSib(Memory.PtrSize.fromBitSize(act_enc.data.ops[0].memBitSize()), .{ |
| 110 | .base = if (base) |base_reg| .{ .reg = base_reg } else .none, | 110 | .base = if (base) |base_reg| .{ .reg = base_reg } else .none, |
| 111 | .scale_index = scale_index, | 111 | .scale_index = scale_index, |
| 112 | .disp = disp, | 112 | .disp = disp, |
| ... | @@ -119,14 +119,14 @@ pub fn next(dis: *Disassembler) Error!?Instruction { | ... | @@ -119,14 +119,14 @@ pub fn next(dis: *Disassembler) Error!?Instruction { |
| 119 | const offset = try dis.parseOffset(); | 119 | const offset = try dis.parseOffset(); |
| 120 | return inst(enc, .{ | 120 | return inst(enc, .{ |
| 121 | .op1 = .{ .reg = Register.rax.toBitSize(enc.data.ops[0].regBitSize()) }, | 121 | .op1 = .{ .reg = Register.rax.toBitSize(enc.data.ops[0].regBitSize()) }, |
| 122 | .op2 = .{ .mem = Memory.moffs(seg, offset) }, | 122 | .op2 = .{ .mem = Memory.initMoffs(seg, offset) }, |
| 123 | }); | 123 | }); |
| 124 | }, | 124 | }, |
| 125 | .td => { | 125 | .td => { |
| 126 | const seg = segmentRegister(prefixes.legacy); | 126 | const seg = segmentRegister(prefixes.legacy); |
| 127 | const offset = try dis.parseOffset(); | 127 | const offset = try dis.parseOffset(); |
| 128 | return inst(enc, .{ | 128 | return inst(enc, .{ |
| 129 | .op1 = .{ .mem = Memory.moffs(seg, offset) }, | 129 | .op1 = .{ .mem = Memory.initMoffs(seg, offset) }, |
| 130 | .op2 = .{ .reg = Register.rax.toBitSize(enc.data.ops[1].regBitSize()) }, | 130 | .op2 = .{ .reg = Register.rax.toBitSize(enc.data.ops[1].regBitSize()) }, |
| 131 | }); | 131 | }); |
| 132 | }, | 132 | }, |
| ... | @@ -153,7 +153,7 @@ pub fn next(dis: *Disassembler) Error!?Instruction { | ... | @@ -153,7 +153,7 @@ pub fn next(dis: *Disassembler) Error!?Instruction { |
| 153 | 153 | ||
| 154 | if (modrm.rip()) { | 154 | if (modrm.rip()) { |
| 155 | return inst(enc, .{ | 155 | return inst(enc, .{ |
| 156 | .op1 = .{ .mem = Memory.rip(Memory.PtrSize.fromBitSize(dst_bit_size), disp) }, | 156 | .op1 = .{ .mem = Memory.initRip(Memory.PtrSize.fromBitSize(dst_bit_size), disp) }, |
| 157 | .op2 = .{ .reg = parseGpRegister(modrm.op1, prefixes.rex.r, prefixes.rex, src_bit_size) }, | 157 | .op2 = .{ .reg = parseGpRegister(modrm.op1, prefixes.rex.r, prefixes.rex, src_bit_size) }, |
| 158 | .op3 = op3, | 158 | .op3 = op3, |
| 159 | }); | 159 | }); |
| ... | @@ -165,7 +165,7 @@ pub fn next(dis: *Disassembler) Error!?Instruction { | ... | @@ -165,7 +165,7 @@ pub fn next(dis: *Disassembler) Error!?Instruction { |
| 165 | else | 165 | else |
| 166 | parseGpRegister(modrm.op2, prefixes.rex.b, prefixes.rex, 64); | 166 | parseGpRegister(modrm.op2, prefixes.rex.b, prefixes.rex, 64); |
| 167 | return inst(enc, .{ | 167 | return inst(enc, .{ |
| 168 | .op1 = .{ .mem = Memory.sib(Memory.PtrSize.fromBitSize(dst_bit_size), .{ | 168 | .op1 = .{ .mem = Memory.initSib(Memory.PtrSize.fromBitSize(dst_bit_size), .{ |
| 169 | .base = if (base) |base_reg| .{ .reg = base_reg } else .none, | 169 | .base = if (base) |base_reg| .{ .reg = base_reg } else .none, |
| 170 | .scale_index = scale_index, | 170 | .scale_index = scale_index, |
| 171 | .disp = disp, | 171 | .disp = disp, |
| ... | @@ -203,7 +203,7 @@ pub fn next(dis: *Disassembler) Error!?Instruction { | ... | @@ -203,7 +203,7 @@ pub fn next(dis: *Disassembler) Error!?Instruction { |
| 203 | if (modrm.rip()) { | 203 | if (modrm.rip()) { |
| 204 | return inst(enc, .{ | 204 | return inst(enc, .{ |
| 205 | .op1 = .{ .reg = parseGpRegister(modrm.op1, prefixes.rex.r, prefixes.rex, dst_bit_size) }, | 205 | .op1 = .{ .reg = parseGpRegister(modrm.op1, prefixes.rex.r, prefixes.rex, dst_bit_size) }, |
| 206 | .op2 = .{ .mem = Memory.rip(Memory.PtrSize.fromBitSize(src_bit_size), disp) }, | 206 | .op2 = .{ .mem = Memory.initRip(Memory.PtrSize.fromBitSize(src_bit_size), disp) }, |
| 207 | .op3 = op3, | 207 | .op3 = op3, |
| 208 | }); | 208 | }); |
| 209 | } | 209 | } |
| ... | @@ -215,7 +215,7 @@ pub fn next(dis: *Disassembler) Error!?Instruction { | ... | @@ -215,7 +215,7 @@ pub fn next(dis: *Disassembler) Error!?Instruction { |
| 215 | parseGpRegister(modrm.op2, prefixes.rex.b, prefixes.rex, 64); | 215 | parseGpRegister(modrm.op2, prefixes.rex.b, prefixes.rex, 64); |
| 216 | return inst(enc, .{ | 216 | return inst(enc, .{ |
| 217 | .op1 = .{ .reg = parseGpRegister(modrm.op1, prefixes.rex.r, prefixes.rex, dst_bit_size) }, | 217 | .op1 = .{ .reg = parseGpRegister(modrm.op1, prefixes.rex.r, prefixes.rex, dst_bit_size) }, |
| 218 | .op2 = .{ .mem = Memory.sib(Memory.PtrSize.fromBitSize(src_bit_size), .{ | 218 | .op2 = .{ .mem = Memory.initSib(Memory.PtrSize.fromBitSize(src_bit_size), .{ |
| 219 | .base = if (base) |base_reg| .{ .reg = base_reg } else .none, | 219 | .base = if (base) |base_reg| .{ .reg = base_reg } else .none, |
| 220 | .scale_index = scale_index, | 220 | .scale_index = scale_index, |
| 221 | .disp = disp, | 221 | .disp = disp, |
src/arch/x86_64/Lower.zig+21-21| ... | @@ -200,13 +200,13 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { | ... | @@ -200,13 +200,13 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { |
| 200 | }); | 200 | }); |
| 201 | try lower.emit(.none, .lea, &.{ | 201 | try lower.emit(.none, .lea, &.{ |
| 202 | .{ .reg = inst.data.ri.r1 }, | 202 | .{ .reg = inst.data.ri.r1 }, |
| 203 | .{ .mem = Memory.sib(.qword, .{ | 203 | .{ .mem = Memory.initSib(.qword, .{ |
| 204 | .base = .{ .reg = inst.data.ri.r1 }, | 204 | .base = .{ .reg = inst.data.ri.r1 }, |
| 205 | .disp = -page_size, | 205 | .disp = -page_size, |
| 206 | }) }, | 206 | }) }, |
| 207 | }); | 207 | }); |
| 208 | try lower.emit(.none, .@"test", &.{ | 208 | try lower.emit(.none, .@"test", &.{ |
| 209 | .{ .mem = Memory.sib(.dword, .{ | 209 | .{ .mem = Memory.initSib(.dword, .{ |
| 210 | .base = .{ .reg = inst.data.ri.r1 }, | 210 | .base = .{ .reg = inst.data.ri.r1 }, |
| 211 | }) }, | 211 | }) }, |
| 212 | .{ .reg = inst.data.ri.r1.to32() }, | 212 | .{ .reg = inst.data.ri.r1.to32() }, |
| ... | @@ -220,7 +220,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { | ... | @@ -220,7 +220,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { |
| 220 | var offset = page_size; | 220 | var offset = page_size; |
| 221 | while (offset < @as(i32, @bitCast(inst.data.ri.i))) : (offset += page_size) { | 221 | while (offset < @as(i32, @bitCast(inst.data.ri.i))) : (offset += page_size) { |
| 222 | try lower.emit(.none, .@"test", &.{ | 222 | try lower.emit(.none, .@"test", &.{ |
| 223 | .{ .mem = Memory.sib(.dword, .{ | 223 | .{ .mem = Memory.initSib(.dword, .{ |
| 224 | .base = .{ .reg = inst.data.ri.r1 }, | 224 | .base = .{ .reg = inst.data.ri.r1 }, |
| 225 | .disp = -offset, | 225 | .disp = -offset, |
| 226 | }) }, | 226 | }) }, |
| ... | @@ -246,7 +246,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { | ... | @@ -246,7 +246,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { |
| 246 | }, | 246 | }, |
| 247 | .pseudo_probe_adjust_loop_rr => { | 247 | .pseudo_probe_adjust_loop_rr => { |
| 248 | try lower.emit(.none, .@"test", &.{ | 248 | try lower.emit(.none, .@"test", &.{ |
| 249 | .{ .mem = Memory.sib(.dword, .{ | 249 | .{ .mem = Memory.initSib(.dword, .{ |
| 250 | .base = .{ .reg = inst.data.rr.r1 }, | 250 | .base = .{ .reg = inst.data.rr.r1 }, |
| 251 | .scale_index = .{ .scale = 1, .index = inst.data.rr.r2 }, | 251 | .scale_index = .{ .scale = 1, .index = inst.data.rr.r2 }, |
| 252 | .disp = -page_size, | 252 | .disp = -page_size, |
| ... | @@ -417,7 +417,7 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) | ... | @@ -417,7 +417,7 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) |
| 417 | lower.result_insts[lower.result_insts_len] = | 417 | lower.result_insts[lower.result_insts_len] = |
| 418 | try Instruction.new(.none, .lea, &[_]Operand{ | 418 | try Instruction.new(.none, .lea, &[_]Operand{ |
| 419 | .{ .reg = .rdi }, | 419 | .{ .reg = .rdi }, |
| 420 | .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) }, | 420 | .{ .mem = Memory.initRip(mem_op.sib.ptr_size, 0) }, |
| 421 | }); | 421 | }); |
| 422 | lower.result_insts_len += 1; | 422 | lower.result_insts_len += 1; |
| 423 | _ = lower.reloc(.{ | 423 | _ = lower.reloc(.{ |
| ... | @@ -430,7 +430,7 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) | ... | @@ -430,7 +430,7 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) |
| 430 | lower.result_insts_len += 1; | 430 | lower.result_insts_len += 1; |
| 431 | _ = lower.reloc(.{ .linker_dtpoff = sym_index }, 0); | 431 | _ = lower.reloc(.{ .linker_dtpoff = sym_index }, 0); |
| 432 | emit_mnemonic = .lea; | 432 | emit_mnemonic = .lea; |
| 433 | break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{ | 433 | break :op .{ .mem = Memory.initSib(mem_op.sib.ptr_size, .{ |
| 434 | .base = .{ .reg = .rax }, | 434 | .base = .{ .reg = .rax }, |
| 435 | .disp = std.math.minInt(i32), | 435 | .disp = std.math.minInt(i32), |
| 436 | }) }; | 436 | }) }; |
| ... | @@ -439,12 +439,12 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) | ... | @@ -439,12 +439,12 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) |
| 439 | lower.result_insts[lower.result_insts_len] = | 439 | lower.result_insts[lower.result_insts_len] = |
| 440 | try Instruction.new(.none, .mov, &[_]Operand{ | 440 | try Instruction.new(.none, .mov, &[_]Operand{ |
| 441 | .{ .reg = .rax }, | 441 | .{ .reg = .rax }, |
| 442 | .{ .mem = Memory.sib(.qword, .{ .base = .{ .reg = .fs } }) }, | 442 | .{ .mem = Memory.initSib(.qword, .{ .base = .{ .reg = .fs } }) }, |
| 443 | }); | 443 | }); |
| 444 | lower.result_insts_len += 1; | 444 | lower.result_insts_len += 1; |
| 445 | _ = lower.reloc(.{ .linker_reloc = sym_index }, 0); | 445 | _ = lower.reloc(.{ .linker_reloc = sym_index }, 0); |
| 446 | emit_mnemonic = .lea; | 446 | emit_mnemonic = .lea; |
| 447 | break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{ | 447 | break :op .{ .mem = Memory.initSib(mem_op.sib.ptr_size, .{ |
| 448 | .base = .{ .reg = .rax }, | 448 | .base = .{ .reg = .rax }, |
| 449 | .disp = std.math.minInt(i32), | 449 | .disp = std.math.minInt(i32), |
| 450 | }) }; | 450 | }) }; |
| ... | @@ -455,7 +455,7 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) | ... | @@ -455,7 +455,7 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) |
| 455 | if (lower.pic) switch (mnemonic) { | 455 | if (lower.pic) switch (mnemonic) { |
| 456 | .lea => { | 456 | .lea => { |
| 457 | if (elf_sym.flags.is_extern_ptr) emit_mnemonic = .mov; | 457 | if (elf_sym.flags.is_extern_ptr) emit_mnemonic = .mov; |
| 458 | break :op .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) }; | 458 | break :op .{ .mem = Memory.initRip(mem_op.sib.ptr_size, 0) }; |
| 459 | }, | 459 | }, |
| 460 | .mov => { | 460 | .mov => { |
| 461 | if (elf_sym.flags.is_extern_ptr) { | 461 | if (elf_sym.flags.is_extern_ptr) { |
| ... | @@ -463,25 +463,25 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) | ... | @@ -463,25 +463,25 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) |
| 463 | lower.result_insts[lower.result_insts_len] = | 463 | lower.result_insts[lower.result_insts_len] = |
| 464 | try Instruction.new(.none, .mov, &[_]Operand{ | 464 | try Instruction.new(.none, .mov, &[_]Operand{ |
| 465 | .{ .reg = reg.to64() }, | 465 | .{ .reg = reg.to64() }, |
| 466 | .{ .mem = Memory.rip(.qword, 0) }, | 466 | .{ .mem = Memory.initRip(.qword, 0) }, |
| 467 | }); | 467 | }); |
| 468 | lower.result_insts_len += 1; | 468 | lower.result_insts_len += 1; |
| 469 | break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{ .base = .{ | 469 | break :op .{ .mem = Memory.initSib(mem_op.sib.ptr_size, .{ .base = .{ |
| 470 | .reg = reg.to64(), | 470 | .reg = reg.to64(), |
| 471 | } }) }; | 471 | } }) }; |
| 472 | } | 472 | } |
| 473 | break :op .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) }; | 473 | break :op .{ .mem = Memory.initRip(mem_op.sib.ptr_size, 0) }; |
| 474 | }, | 474 | }, |
| 475 | else => unreachable, | 475 | else => unreachable, |
| 476 | } else switch (mnemonic) { | 476 | } else switch (mnemonic) { |
| 477 | .call => break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{ | 477 | .call => break :op .{ .mem = Memory.initSib(mem_op.sib.ptr_size, .{ |
| 478 | .base = .{ .reg = .ds }, | 478 | .base = .{ .reg = .ds }, |
| 479 | }) }, | 479 | }) }, |
| 480 | .lea => { | 480 | .lea => { |
| 481 | emit_mnemonic = .mov; | 481 | emit_mnemonic = .mov; |
| 482 | break :op .{ .imm = Immediate.s(0) }; | 482 | break :op .{ .imm = Immediate.s(0) }; |
| 483 | }, | 483 | }, |
| 484 | .mov => break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{ | 484 | .mov => break :op .{ .mem = Memory.initSib(mem_op.sib.ptr_size, .{ |
| 485 | .base = .{ .reg = .ds }, | 485 | .base = .{ .reg = .ds }, |
| 486 | }) }, | 486 | }) }, |
| 487 | else => unreachable, | 487 | else => unreachable, |
| ... | @@ -495,12 +495,12 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) | ... | @@ -495,12 +495,12 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) |
| 495 | lower.result_insts[lower.result_insts_len] = | 495 | lower.result_insts[lower.result_insts_len] = |
| 496 | try Instruction.new(.none, .mov, &[_]Operand{ | 496 | try Instruction.new(.none, .mov, &[_]Operand{ |
| 497 | .{ .reg = .rdi }, | 497 | .{ .reg = .rdi }, |
| 498 | .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) }, | 498 | .{ .mem = Memory.initRip(mem_op.sib.ptr_size, 0) }, |
| 499 | }); | 499 | }); |
| 500 | lower.result_insts_len += 1; | 500 | lower.result_insts_len += 1; |
| 501 | lower.result_insts[lower.result_insts_len] = | 501 | lower.result_insts[lower.result_insts_len] = |
| 502 | try Instruction.new(.none, .call, &[_]Operand{ | 502 | try Instruction.new(.none, .call, &[_]Operand{ |
| 503 | .{ .mem = Memory.sib(.qword, .{ .base = .{ .reg = .rdi } }) }, | 503 | .{ .mem = Memory.initSib(.qword, .{ .base = .{ .reg = .rdi } }) }, |
| 504 | }); | 504 | }); |
| 505 | lower.result_insts_len += 1; | 505 | lower.result_insts_len += 1; |
| 506 | emit_mnemonic = .mov; | 506 | emit_mnemonic = .mov; |
| ... | @@ -511,7 +511,7 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) | ... | @@ -511,7 +511,7 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) |
| 511 | break :op switch (mnemonic) { | 511 | break :op switch (mnemonic) { |
| 512 | .lea => { | 512 | .lea => { |
| 513 | if (macho_sym.flags.is_extern_ptr) emit_mnemonic = .mov; | 513 | if (macho_sym.flags.is_extern_ptr) emit_mnemonic = .mov; |
| 514 | break :op .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) }; | 514 | break :op .{ .mem = Memory.initRip(mem_op.sib.ptr_size, 0) }; |
| 515 | }, | 515 | }, |
| 516 | .mov => { | 516 | .mov => { |
| 517 | if (macho_sym.flags.is_extern_ptr) { | 517 | if (macho_sym.flags.is_extern_ptr) { |
| ... | @@ -519,14 +519,14 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) | ... | @@ -519,14 +519,14 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) |
| 519 | lower.result_insts[lower.result_insts_len] = | 519 | lower.result_insts[lower.result_insts_len] = |
| 520 | try Instruction.new(.none, .mov, &[_]Operand{ | 520 | try Instruction.new(.none, .mov, &[_]Operand{ |
| 521 | .{ .reg = reg.to64() }, | 521 | .{ .reg = reg.to64() }, |
| 522 | .{ .mem = Memory.rip(.qword, 0) }, | 522 | .{ .mem = Memory.initRip(.qword, 0) }, |
| 523 | }); | 523 | }); |
| 524 | lower.result_insts_len += 1; | 524 | lower.result_insts_len += 1; |
| 525 | break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{ .base = .{ | 525 | break :op .{ .mem = Memory.initSib(mem_op.sib.ptr_size, .{ .base = .{ |
| 526 | .reg = reg.to64(), | 526 | .reg = reg.to64(), |
| 527 | } }) }; | 527 | } }) }; |
| 528 | } | 528 | } |
| 529 | break :op .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) }; | 529 | break :op .{ .mem = Memory.initRip(mem_op.sib.ptr_size, 0) }; |
| 530 | }, | 530 | }, |
| 531 | else => unreachable, | 531 | else => unreachable, |
| 532 | }; | 532 | }; |
| ... | @@ -701,7 +701,7 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void { | ... | @@ -701,7 +701,7 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void { |
| 701 | }, extra.off); | 701 | }, extra.off); |
| 702 | break :ops &.{ | 702 | break :ops &.{ |
| 703 | .{ .reg = reg }, | 703 | .{ .reg = reg }, |
| 704 | .{ .mem = Memory.rip(Memory.PtrSize.fromBitSize(reg.bitSize()), 0) }, | 704 | .{ .mem = Memory.initRip(Memory.PtrSize.fromBitSize(reg.bitSize()), 0) }, |
| 705 | }; | 705 | }; |
| 706 | }, | 706 | }, |
| 707 | else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }), | 707 | else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }), |
src/arch/x86_64/Mir.zig+3-3| ... | @@ -1234,9 +1234,9 @@ pub const Memory = struct { | ... | @@ -1234,9 +1234,9 @@ pub const Memory = struct { |
| 1234 | .rm => { | 1234 | .rm => { |
| 1235 | if (mem.info.base == .reg and @as(Register, @enumFromInt(mem.base)) == .rip) { | 1235 | if (mem.info.base == .reg and @as(Register, @enumFromInt(mem.base)) == .rip) { |
| 1236 | assert(mem.info.index == .none and mem.info.scale == .@"1"); | 1236 | assert(mem.info.index == .none and mem.info.scale == .@"1"); |
| 1237 | return encoder.Instruction.Memory.rip(mem.info.size, @bitCast(mem.off)); | 1237 | return encoder.Instruction.Memory.initRip(mem.info.size, @bitCast(mem.off)); |
| 1238 | } | 1238 | } |
| 1239 | return encoder.Instruction.Memory.sib(mem.info.size, .{ | 1239 | return encoder.Instruction.Memory.initSib(mem.info.size, .{ |
| 1240 | .disp = @bitCast(mem.off), | 1240 | .disp = @bitCast(mem.off), |
| 1241 | .base = switch (mem.info.base) { | 1241 | .base = switch (mem.info.base) { |
| 1242 | .none => .none, | 1242 | .none => .none, |
| ... | @@ -1258,7 +1258,7 @@ pub const Memory = struct { | ... | @@ -1258,7 +1258,7 @@ pub const Memory = struct { |
| 1258 | }, | 1258 | }, |
| 1259 | .off => { | 1259 | .off => { |
| 1260 | assert(mem.info.base == .reg); | 1260 | assert(mem.info.base == .reg); |
| 1261 | return encoder.Instruction.Memory.moffs( | 1261 | return encoder.Instruction.Memory.initMoffs( |
| 1262 | @enumFromInt(mem.base), | 1262 | @enumFromInt(mem.base), |
| 1263 | @as(u64, mem.extra) << 32 | mem.off, | 1263 | @as(u64, mem.extra) << 32 | mem.off, |
| 1264 | ); | 1264 | ); |
src/arch/x86_64/encoder.zig+77-77| ... | @@ -110,12 +110,12 @@ pub const Instruction = struct { | ... | @@ -110,12 +110,12 @@ pub const Instruction = struct { |
| 110 | offset: u64, | 110 | offset: u64, |
| 111 | }; | 111 | }; |
| 112 | 112 | ||
| 113 | pub fn moffs(reg: Register, offset: u64) Memory { | 113 | pub fn initMoffs(reg: Register, offset: u64) Memory { |
| 114 | assert(reg.class() == .segment); | 114 | assert(reg.class() == .segment); |
| 115 | return .{ .moffs = .{ .seg = reg, .offset = offset } }; | 115 | return .{ .moffs = .{ .seg = reg, .offset = offset } }; |
| 116 | } | 116 | } |
| 117 | 117 | ||
| 118 | pub fn sib(ptr_size: PtrSize, args: struct { | 118 | pub fn initSib(ptr_size: PtrSize, args: struct { |
| 119 | disp: i32 = 0, | 119 | disp: i32 = 0, |
| 120 | base: Base = .none, | 120 | base: Base = .none, |
| 121 | scale_index: ?ScaleIndex = null, | 121 | scale_index: ?ScaleIndex = null, |
| ... | @@ -129,7 +129,7 @@ pub const Instruction = struct { | ... | @@ -129,7 +129,7 @@ pub const Instruction = struct { |
| 129 | } }; | 129 | } }; |
| 130 | } | 130 | } |
| 131 | 131 | ||
| 132 | pub fn rip(ptr_size: PtrSize, displacement: i32) Memory { | 132 | pub fn initRip(ptr_size: PtrSize, displacement: i32) Memory { |
| 133 | return .{ .rip = .{ .ptr_size = ptr_size, .disp = displacement } }; | 133 | return .{ .rip = .{ .ptr_size = ptr_size, .disp = displacement } }; |
| 134 | } | 134 | } |
| 135 | 135 | ||
| ... | @@ -1266,7 +1266,7 @@ test "lower MI encoding" { | ... | @@ -1266,7 +1266,7 @@ test "lower MI encoding" { |
| 1266 | try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000"); | 1266 | try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000"); |
| 1267 | 1267 | ||
| 1268 | try enc.encode(.mov, &.{ | 1268 | try enc.encode(.mov, &.{ |
| 1269 | .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .r12 } }) }, | 1269 | .{ .mem = Instruction.Memory.initSib(.byte, .{ .base = .{ .reg = .r12 } }) }, |
| 1270 | .{ .imm = Instruction.Immediate.u(0x10) }, | 1270 | .{ .imm = Instruction.Immediate.u(0x10) }, |
| 1271 | }); | 1271 | }); |
| 1272 | try expectEqualHexStrings("\x41\xC6\x04\x24\x10", enc.code(), "mov BYTE PTR [r12], 0x10"); | 1272 | try expectEqualHexStrings("\x41\xC6\x04\x24\x10", enc.code(), "mov BYTE PTR [r12], 0x10"); |
| ... | @@ -1290,13 +1290,13 @@ test "lower MI encoding" { | ... | @@ -1290,13 +1290,13 @@ test "lower MI encoding" { |
| 1290 | try expectEqualHexStrings("\x48\xc7\xc0\x10\x00\x00\x00", enc.code(), "mov rax, 0x10"); | 1290 | try expectEqualHexStrings("\x48\xc7\xc0\x10\x00\x00\x00", enc.code(), "mov rax, 0x10"); |
| 1291 | 1291 | ||
| 1292 | try enc.encode(.mov, &.{ | 1292 | try enc.encode(.mov, &.{ |
| 1293 | .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .r11 } }) }, | 1293 | .{ .mem = Instruction.Memory.initSib(.dword, .{ .base = .{ .reg = .r11 } }) }, |
| 1294 | .{ .imm = Instruction.Immediate.u(0x10) }, | 1294 | .{ .imm = Instruction.Immediate.u(0x10) }, |
| 1295 | }); | 1295 | }); |
| 1296 | try expectEqualHexStrings("\x41\xc7\x03\x10\x00\x00\x00", enc.code(), "mov DWORD PTR [r11], 0x10"); | 1296 | try expectEqualHexStrings("\x41\xc7\x03\x10\x00\x00\x00", enc.code(), "mov DWORD PTR [r11], 0x10"); |
| 1297 | 1297 | ||
| 1298 | try enc.encode(.mov, &.{ | 1298 | try enc.encode(.mov, &.{ |
| 1299 | .{ .mem = Instruction.Memory.rip(.qword, 0x10) }, | 1299 | .{ .mem = Instruction.Memory.initRip(.qword, 0x10) }, |
| 1300 | .{ .imm = Instruction.Immediate.u(0x10) }, | 1300 | .{ .imm = Instruction.Immediate.u(0x10) }, |
| 1301 | }); | 1301 | }); |
| 1302 | try expectEqualHexStrings( | 1302 | try expectEqualHexStrings( |
| ... | @@ -1306,25 +1306,25 @@ test "lower MI encoding" { | ... | @@ -1306,25 +1306,25 @@ test "lower MI encoding" { |
| 1306 | ); | 1306 | ); |
| 1307 | 1307 | ||
| 1308 | try enc.encode(.mov, &.{ | 1308 | try enc.encode(.mov, &.{ |
| 1309 | .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .rbp }, .disp = -8 }) }, | 1309 | .{ .mem = Instruction.Memory.initSib(.qword, .{ .base = .{ .reg = .rbp }, .disp = -8 }) }, |
| 1310 | .{ .imm = Instruction.Immediate.u(0x10) }, | 1310 | .{ .imm = Instruction.Immediate.u(0x10) }, |
| 1311 | }); | 1311 | }); |
| 1312 | try expectEqualHexStrings("\x48\xc7\x45\xf8\x10\x00\x00\x00", enc.code(), "mov QWORD PTR [rbp - 8], 0x10"); | 1312 | try expectEqualHexStrings("\x48\xc7\x45\xf8\x10\x00\x00\x00", enc.code(), "mov QWORD PTR [rbp - 8], 0x10"); |
| 1313 | 1313 | ||
| 1314 | try enc.encode(.mov, &.{ | 1314 | try enc.encode(.mov, &.{ |
| 1315 | .{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp }, .disp = -2 }) }, | 1315 | .{ .mem = Instruction.Memory.initSib(.word, .{ .base = .{ .reg = .rbp }, .disp = -2 }) }, |
| 1316 | .{ .imm = Instruction.Immediate.s(-16) }, | 1316 | .{ .imm = Instruction.Immediate.s(-16) }, |
| 1317 | }); | 1317 | }); |
| 1318 | try expectEqualHexStrings("\x66\xC7\x45\xFE\xF0\xFF", enc.code(), "mov WORD PTR [rbp - 2], -16"); | 1318 | try expectEqualHexStrings("\x66\xC7\x45\xFE\xF0\xFF", enc.code(), "mov WORD PTR [rbp - 2], -16"); |
| 1319 | 1319 | ||
| 1320 | try enc.encode(.mov, &.{ | 1320 | try enc.encode(.mov, &.{ |
| 1321 | .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .rbp }, .disp = -1 }) }, | 1321 | .{ .mem = Instruction.Memory.initSib(.byte, .{ .base = .{ .reg = .rbp }, .disp = -1 }) }, |
| 1322 | .{ .imm = Instruction.Immediate.u(0x10) }, | 1322 | .{ .imm = Instruction.Immediate.u(0x10) }, |
| 1323 | }); | 1323 | }); |
| 1324 | try expectEqualHexStrings("\xC6\x45\xFF\x10", enc.code(), "mov BYTE PTR [rbp - 1], 0x10"); | 1324 | try expectEqualHexStrings("\xC6\x45\xFF\x10", enc.code(), "mov BYTE PTR [rbp - 1], 0x10"); |
| 1325 | 1325 | ||
| 1326 | try enc.encode(.mov, &.{ | 1326 | try enc.encode(.mov, &.{ |
| 1327 | .{ .mem = Instruction.Memory.sib(.qword, .{ | 1327 | .{ .mem = Instruction.Memory.initSib(.qword, .{ |
| 1328 | .base = .{ .reg = .ds }, | 1328 | .base = .{ .reg = .ds }, |
| 1329 | .disp = 0x10000000, | 1329 | .disp = 0x10000000, |
| 1330 | .scale_index = .{ .scale = 2, .index = .rcx }, | 1330 | .scale_index = .{ .scale = 2, .index = .rcx }, |
| ... | @@ -1338,13 +1338,13 @@ test "lower MI encoding" { | ... | @@ -1338,13 +1338,13 @@ test "lower MI encoding" { |
| 1338 | ); | 1338 | ); |
| 1339 | 1339 | ||
| 1340 | try enc.encode(.adc, &.{ | 1340 | try enc.encode(.adc, &.{ |
| 1341 | .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .rbp }, .disp = -0x10 }) }, | 1341 | .{ .mem = Instruction.Memory.initSib(.byte, .{ .base = .{ .reg = .rbp }, .disp = -0x10 }) }, |
| 1342 | .{ .imm = Instruction.Immediate.u(0x10) }, | 1342 | .{ .imm = Instruction.Immediate.u(0x10) }, |
| 1343 | }); | 1343 | }); |
| 1344 | try expectEqualHexStrings("\x80\x55\xF0\x10", enc.code(), "adc BYTE PTR [rbp - 0x10], 0x10"); | 1344 | try expectEqualHexStrings("\x80\x55\xF0\x10", enc.code(), "adc BYTE PTR [rbp - 0x10], 0x10"); |
| 1345 | 1345 | ||
| 1346 | try enc.encode(.adc, &.{ | 1346 | try enc.encode(.adc, &.{ |
| 1347 | .{ .mem = Instruction.Memory.rip(.qword, 0) }, | 1347 | .{ .mem = Instruction.Memory.initRip(.qword, 0) }, |
| 1348 | .{ .imm = Instruction.Immediate.u(0x10) }, | 1348 | .{ .imm = Instruction.Immediate.u(0x10) }, |
| 1349 | }); | 1349 | }); |
| 1350 | try expectEqualHexStrings("\x48\x83\x15\x00\x00\x00\x00\x10", enc.code(), "adc QWORD PTR [rip], 0x10"); | 1350 | try expectEqualHexStrings("\x48\x83\x15\x00\x00\x00\x00\x10", enc.code(), "adc QWORD PTR [rip], 0x10"); |
| ... | @@ -1356,7 +1356,7 @@ test "lower MI encoding" { | ... | @@ -1356,7 +1356,7 @@ test "lower MI encoding" { |
| 1356 | try expectEqualHexStrings("\x48\x83\xD0\x10", enc.code(), "adc rax, 0x10"); | 1356 | try expectEqualHexStrings("\x48\x83\xD0\x10", enc.code(), "adc rax, 0x10"); |
| 1357 | 1357 | ||
| 1358 | try enc.encode(.add, &.{ | 1358 | try enc.encode(.add, &.{ |
| 1359 | .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .rdx }, .disp = -8 }) }, | 1359 | .{ .mem = Instruction.Memory.initSib(.dword, .{ .base = .{ .reg = .rdx }, .disp = -8 }) }, |
| 1360 | .{ .imm = Instruction.Immediate.u(0x10) }, | 1360 | .{ .imm = Instruction.Immediate.u(0x10) }, |
| 1361 | }); | 1361 | }); |
| 1362 | try expectEqualHexStrings("\x83\x42\xF8\x10", enc.code(), "add DWORD PTR [rdx - 8], 0x10"); | 1362 | try expectEqualHexStrings("\x83\x42\xF8\x10", enc.code(), "add DWORD PTR [rdx - 8], 0x10"); |
| ... | @@ -1368,13 +1368,13 @@ test "lower MI encoding" { | ... | @@ -1368,13 +1368,13 @@ test "lower MI encoding" { |
| 1368 | try expectEqualHexStrings("\x48\x83\xC0\x10", enc.code(), "add rax, 0x10"); | 1368 | try expectEqualHexStrings("\x48\x83\xC0\x10", enc.code(), "add rax, 0x10"); |
| 1369 | 1369 | ||
| 1370 | try enc.encode(.add, &.{ | 1370 | try enc.encode(.add, &.{ |
| 1371 | .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .rbp }, .disp = -0x10 }) }, | 1371 | .{ .mem = Instruction.Memory.initSib(.qword, .{ .base = .{ .reg = .rbp }, .disp = -0x10 }) }, |
| 1372 | .{ .imm = Instruction.Immediate.s(-0x10) }, | 1372 | .{ .imm = Instruction.Immediate.s(-0x10) }, |
| 1373 | }); | 1373 | }); |
| 1374 | try expectEqualHexStrings("\x48\x83\x45\xF0\xF0", enc.code(), "add QWORD PTR [rbp - 0x10], -0x10"); | 1374 | try expectEqualHexStrings("\x48\x83\x45\xF0\xF0", enc.code(), "add QWORD PTR [rbp - 0x10], -0x10"); |
| 1375 | 1375 | ||
| 1376 | try enc.encode(.@"and", &.{ | 1376 | try enc.encode(.@"and", &.{ |
| 1377 | .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .ds }, .disp = 0x10000000 }) }, | 1377 | .{ .mem = Instruction.Memory.initSib(.dword, .{ .base = .{ .reg = .ds }, .disp = 0x10000000 }) }, |
| 1378 | .{ .imm = Instruction.Immediate.u(0x10) }, | 1378 | .{ .imm = Instruction.Immediate.u(0x10) }, |
| 1379 | }); | 1379 | }); |
| 1380 | try expectEqualHexStrings( | 1380 | try expectEqualHexStrings( |
| ... | @@ -1384,7 +1384,7 @@ test "lower MI encoding" { | ... | @@ -1384,7 +1384,7 @@ test "lower MI encoding" { |
| 1384 | ); | 1384 | ); |
| 1385 | 1385 | ||
| 1386 | try enc.encode(.@"and", &.{ | 1386 | try enc.encode(.@"and", &.{ |
| 1387 | .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .es }, .disp = 0x10000000 }) }, | 1387 | .{ .mem = Instruction.Memory.initSib(.dword, .{ .base = .{ .reg = .es }, .disp = 0x10000000 }) }, |
| 1388 | .{ .imm = Instruction.Immediate.u(0x10) }, | 1388 | .{ .imm = Instruction.Immediate.u(0x10) }, |
| 1389 | }); | 1389 | }); |
| 1390 | try expectEqualHexStrings( | 1390 | try expectEqualHexStrings( |
| ... | @@ -1394,7 +1394,7 @@ test "lower MI encoding" { | ... | @@ -1394,7 +1394,7 @@ test "lower MI encoding" { |
| 1394 | ); | 1394 | ); |
| 1395 | 1395 | ||
| 1396 | try enc.encode(.@"and", &.{ | 1396 | try enc.encode(.@"and", &.{ |
| 1397 | .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .r12 }, .disp = 0x10000000 }) }, | 1397 | .{ .mem = Instruction.Memory.initSib(.dword, .{ .base = .{ .reg = .r12 }, .disp = 0x10000000 }) }, |
| 1398 | .{ .imm = Instruction.Immediate.u(0x10) }, | 1398 | .{ .imm = Instruction.Immediate.u(0x10) }, |
| 1399 | }); | 1399 | }); |
| 1400 | try expectEqualHexStrings( | 1400 | try expectEqualHexStrings( |
| ... | @@ -1404,7 +1404,7 @@ test "lower MI encoding" { | ... | @@ -1404,7 +1404,7 @@ test "lower MI encoding" { |
| 1404 | ); | 1404 | ); |
| 1405 | 1405 | ||
| 1406 | try enc.encode(.sub, &.{ | 1406 | try enc.encode(.sub, &.{ |
| 1407 | .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .r11 }, .disp = 0x10000000 }) }, | 1407 | .{ .mem = Instruction.Memory.initSib(.dword, .{ .base = .{ .reg = .r11 }, .disp = 0x10000000 }) }, |
| 1408 | .{ .imm = Instruction.Immediate.u(0x10) }, | 1408 | .{ .imm = Instruction.Immediate.u(0x10) }, |
| 1409 | }); | 1409 | }); |
| 1410 | try expectEqualHexStrings( | 1410 | try expectEqualHexStrings( |
| ... | @@ -1419,25 +1419,25 @@ test "lower RM encoding" { | ... | @@ -1419,25 +1419,25 @@ test "lower RM encoding" { |
| 1419 | 1419 | ||
| 1420 | try enc.encode(.mov, &.{ | 1420 | try enc.encode(.mov, &.{ |
| 1421 | .{ .reg = .rax }, | 1421 | .{ .reg = .rax }, |
| 1422 | .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .r11 } }) }, | 1422 | .{ .mem = Instruction.Memory.initSib(.qword, .{ .base = .{ .reg = .r11 } }) }, |
| 1423 | }); | 1423 | }); |
| 1424 | try expectEqualHexStrings("\x49\x8b\x03", enc.code(), "mov rax, QWORD PTR [r11]"); | 1424 | try expectEqualHexStrings("\x49\x8b\x03", enc.code(), "mov rax, QWORD PTR [r11]"); |
| 1425 | 1425 | ||
| 1426 | try enc.encode(.mov, &.{ | 1426 | try enc.encode(.mov, &.{ |
| 1427 | .{ .reg = .rbx }, | 1427 | .{ .reg = .rbx }, |
| 1428 | .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = 0x10 }) }, | 1428 | .{ .mem = Instruction.Memory.initSib(.qword, .{ .base = .{ .reg = .ds }, .disp = 0x10 }) }, |
| 1429 | }); | 1429 | }); |
| 1430 | try expectEqualHexStrings("\x48\x8B\x1C\x25\x10\x00\x00\x00", enc.code(), "mov rbx, QWORD PTR ds:0x10"); | 1430 | try expectEqualHexStrings("\x48\x8B\x1C\x25\x10\x00\x00\x00", enc.code(), "mov rbx, QWORD PTR ds:0x10"); |
| 1431 | 1431 | ||
| 1432 | try enc.encode(.mov, &.{ | 1432 | try enc.encode(.mov, &.{ |
| 1433 | .{ .reg = .rax }, | 1433 | .{ .reg = .rax }, |
| 1434 | .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .rbp }, .disp = -4 }) }, | 1434 | .{ .mem = Instruction.Memory.initSib(.qword, .{ .base = .{ .reg = .rbp }, .disp = -4 }) }, |
| 1435 | }); | 1435 | }); |
| 1436 | try expectEqualHexStrings("\x48\x8B\x45\xFC", enc.code(), "mov rax, QWORD PTR [rbp - 4]"); | 1436 | try expectEqualHexStrings("\x48\x8B\x45\xFC", enc.code(), "mov rax, QWORD PTR [rbp - 4]"); |
| 1437 | 1437 | ||
| 1438 | try enc.encode(.mov, &.{ | 1438 | try enc.encode(.mov, &.{ |
| 1439 | .{ .reg = .rax }, | 1439 | .{ .reg = .rax }, |
| 1440 | .{ .mem = Instruction.Memory.sib(.qword, .{ | 1440 | .{ .mem = Instruction.Memory.initSib(.qword, .{ |
| 1441 | .base = .{ .reg = .rbp }, | 1441 | .base = .{ .reg = .rbp }, |
| 1442 | .scale_index = .{ .scale = 1, .index = .rcx }, | 1442 | .scale_index = .{ .scale = 1, .index = .rcx }, |
| 1443 | .disp = -8, | 1443 | .disp = -8, |
| ... | @@ -1447,7 +1447,7 @@ test "lower RM encoding" { | ... | @@ -1447,7 +1447,7 @@ test "lower RM encoding" { |
| 1447 | 1447 | ||
| 1448 | try enc.encode(.mov, &.{ | 1448 | try enc.encode(.mov, &.{ |
| 1449 | .{ .reg = .eax }, | 1449 | .{ .reg = .eax }, |
| 1450 | .{ .mem = Instruction.Memory.sib(.dword, .{ | 1450 | .{ .mem = Instruction.Memory.initSib(.dword, .{ |
| 1451 | .base = .{ .reg = .rbp }, | 1451 | .base = .{ .reg = .rbp }, |
| 1452 | .scale_index = .{ .scale = 4, .index = .rdx }, | 1452 | .scale_index = .{ .scale = 4, .index = .rdx }, |
| 1453 | .disp = -4, | 1453 | .disp = -4, |
| ... | @@ -1457,7 +1457,7 @@ test "lower RM encoding" { | ... | @@ -1457,7 +1457,7 @@ test "lower RM encoding" { |
| 1457 | 1457 | ||
| 1458 | try enc.encode(.mov, &.{ | 1458 | try enc.encode(.mov, &.{ |
| 1459 | .{ .reg = .rax }, | 1459 | .{ .reg = .rax }, |
| 1460 | .{ .mem = Instruction.Memory.sib(.qword, .{ | 1460 | .{ .mem = Instruction.Memory.initSib(.qword, .{ |
| 1461 | .base = .{ .reg = .rbp }, | 1461 | .base = .{ .reg = .rbp }, |
| 1462 | .scale_index = .{ .scale = 8, .index = .rcx }, | 1462 | .scale_index = .{ .scale = 8, .index = .rcx }, |
| 1463 | .disp = -8, | 1463 | .disp = -8, |
| ... | @@ -1467,7 +1467,7 @@ test "lower RM encoding" { | ... | @@ -1467,7 +1467,7 @@ test "lower RM encoding" { |
| 1467 | 1467 | ||
| 1468 | try enc.encode(.mov, &.{ | 1468 | try enc.encode(.mov, &.{ |
| 1469 | .{ .reg = .r8b }, | 1469 | .{ .reg = .r8b }, |
| 1470 | .{ .mem = Instruction.Memory.sib(.byte, .{ | 1470 | .{ .mem = Instruction.Memory.initSib(.byte, .{ |
| 1471 | .base = .{ .reg = .rsi }, | 1471 | .base = .{ .reg = .rsi }, |
| 1472 | .scale_index = .{ .scale = 1, .index = .rcx }, | 1472 | .scale_index = .{ .scale = 1, .index = .rcx }, |
| 1473 | .disp = -24, | 1473 | .disp = -24, |
| ... | @@ -1483,7 +1483,7 @@ test "lower RM encoding" { | ... | @@ -1483,7 +1483,7 @@ test "lower RM encoding" { |
| 1483 | try expectEqualHexStrings("\x48\x8C\xC8", enc.code(), "mov rax, cs"); | 1483 | try expectEqualHexStrings("\x48\x8C\xC8", enc.code(), "mov rax, cs"); |
| 1484 | 1484 | ||
| 1485 | try enc.encode(.mov, &.{ | 1485 | try enc.encode(.mov, &.{ |
| 1486 | .{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp }, .disp = -16 }) }, | 1486 | .{ .mem = Instruction.Memory.initSib(.word, .{ .base = .{ .reg = .rbp }, .disp = -16 }) }, |
| 1487 | .{ .reg = .fs }, | 1487 | .{ .reg = .fs }, |
| 1488 | }); | 1488 | }); |
| 1489 | try expectEqualHexStrings("\x8C\x65\xF0", enc.code(), "mov WORD PTR [rbp - 16], fs"); | 1489 | try expectEqualHexStrings("\x8C\x65\xF0", enc.code(), "mov WORD PTR [rbp - 16], fs"); |
| ... | @@ -1514,19 +1514,19 @@ test "lower RM encoding" { | ... | @@ -1514,19 +1514,19 @@ test "lower RM encoding" { |
| 1514 | 1514 | ||
| 1515 | try enc.encode(.movsx, &.{ | 1515 | try enc.encode(.movsx, &.{ |
| 1516 | .{ .reg = .eax }, | 1516 | .{ .reg = .eax }, |
| 1517 | .{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp } }) }, | 1517 | .{ .mem = Instruction.Memory.initSib(.word, .{ .base = .{ .reg = .rbp } }) }, |
| 1518 | }); | 1518 | }); |
| 1519 | try expectEqualHexStrings("\x0F\xBF\x45\x00", enc.code(), "movsx eax, BYTE PTR [rbp]"); | 1519 | try expectEqualHexStrings("\x0F\xBF\x45\x00", enc.code(), "movsx eax, BYTE PTR [rbp]"); |
| 1520 | 1520 | ||
| 1521 | try enc.encode(.movsx, &.{ | 1521 | try enc.encode(.movsx, &.{ |
| 1522 | .{ .reg = .eax }, | 1522 | .{ .reg = .eax }, |
| 1523 | .{ .mem = Instruction.Memory.sib(.byte, .{ .scale_index = .{ .index = .rax, .scale = 2 } }) }, | 1523 | .{ .mem = Instruction.Memory.initSib(.byte, .{ .scale_index = .{ .index = .rax, .scale = 2 } }) }, |
| 1524 | }); | 1524 | }); |
| 1525 | try expectEqualHexStrings("\x0F\xBE\x04\x45\x00\x00\x00\x00", enc.code(), "movsx eax, BYTE PTR [rax * 2]"); | 1525 | try expectEqualHexStrings("\x0F\xBE\x04\x45\x00\x00\x00\x00", enc.code(), "movsx eax, BYTE PTR [rax * 2]"); |
| 1526 | 1526 | ||
| 1527 | try enc.encode(.movsx, &.{ | 1527 | try enc.encode(.movsx, &.{ |
| 1528 | .{ .reg = .ax }, | 1528 | .{ .reg = .ax }, |
| 1529 | .{ .mem = Instruction.Memory.rip(.byte, 0x10) }, | 1529 | .{ .mem = Instruction.Memory.initRip(.byte, 0x10) }, |
| 1530 | }); | 1530 | }); |
| 1531 | try expectEqualHexStrings("\x66\x0F\xBE\x05\x10\x00\x00\x00", enc.code(), "movsx ax, BYTE PTR [rip + 0x10]"); | 1531 | try expectEqualHexStrings("\x66\x0F\xBE\x05\x10\x00\x00\x00", enc.code(), "movsx ax, BYTE PTR [rip + 0x10]"); |
| 1532 | 1532 | ||
| ... | @@ -1544,37 +1544,37 @@ test "lower RM encoding" { | ... | @@ -1544,37 +1544,37 @@ test "lower RM encoding" { |
| 1544 | 1544 | ||
| 1545 | try enc.encode(.lea, &.{ | 1545 | try enc.encode(.lea, &.{ |
| 1546 | .{ .reg = .rax }, | 1546 | .{ .reg = .rax }, |
| 1547 | .{ .mem = Instruction.Memory.rip(.qword, 0x10) }, | 1547 | .{ .mem = Instruction.Memory.initRip(.qword, 0x10) }, |
| 1548 | }); | 1548 | }); |
| 1549 | try expectEqualHexStrings("\x48\x8D\x05\x10\x00\x00\x00", enc.code(), "lea rax, QWORD PTR [rip + 0x10]"); | 1549 | try expectEqualHexStrings("\x48\x8D\x05\x10\x00\x00\x00", enc.code(), "lea rax, QWORD PTR [rip + 0x10]"); |
| 1550 | 1550 | ||
| 1551 | try enc.encode(.lea, &.{ | 1551 | try enc.encode(.lea, &.{ |
| 1552 | .{ .reg = .rax }, | 1552 | .{ .reg = .rax }, |
| 1553 | .{ .mem = Instruction.Memory.rip(.dword, 0x10) }, | 1553 | .{ .mem = Instruction.Memory.initRip(.dword, 0x10) }, |
| 1554 | }); | 1554 | }); |
| 1555 | try expectEqualHexStrings("\x48\x8D\x05\x10\x00\x00\x00", enc.code(), "lea rax, DWORD PTR [rip + 0x10]"); | 1555 | try expectEqualHexStrings("\x48\x8D\x05\x10\x00\x00\x00", enc.code(), "lea rax, DWORD PTR [rip + 0x10]"); |
| 1556 | 1556 | ||
| 1557 | try enc.encode(.lea, &.{ | 1557 | try enc.encode(.lea, &.{ |
| 1558 | .{ .reg = .eax }, | 1558 | .{ .reg = .eax }, |
| 1559 | .{ .mem = Instruction.Memory.rip(.dword, 0x10) }, | 1559 | .{ .mem = Instruction.Memory.initRip(.dword, 0x10) }, |
| 1560 | }); | 1560 | }); |
| 1561 | try expectEqualHexStrings("\x8D\x05\x10\x00\x00\x00", enc.code(), "lea eax, DWORD PTR [rip + 0x10]"); | 1561 | try expectEqualHexStrings("\x8D\x05\x10\x00\x00\x00", enc.code(), "lea eax, DWORD PTR [rip + 0x10]"); |
| 1562 | 1562 | ||
| 1563 | try enc.encode(.lea, &.{ | 1563 | try enc.encode(.lea, &.{ |
| 1564 | .{ .reg = .eax }, | 1564 | .{ .reg = .eax }, |
| 1565 | .{ .mem = Instruction.Memory.rip(.word, 0x10) }, | 1565 | .{ .mem = Instruction.Memory.initRip(.word, 0x10) }, |
| 1566 | }); | 1566 | }); |
| 1567 | try expectEqualHexStrings("\x8D\x05\x10\x00\x00\x00", enc.code(), "lea eax, WORD PTR [rip + 0x10]"); | 1567 | try expectEqualHexStrings("\x8D\x05\x10\x00\x00\x00", enc.code(), "lea eax, WORD PTR [rip + 0x10]"); |
| 1568 | 1568 | ||
| 1569 | try enc.encode(.lea, &.{ | 1569 | try enc.encode(.lea, &.{ |
| 1570 | .{ .reg = .ax }, | 1570 | .{ .reg = .ax }, |
| 1571 | .{ .mem = Instruction.Memory.rip(.byte, 0x10) }, | 1571 | .{ .mem = Instruction.Memory.initRip(.byte, 0x10) }, |
| 1572 | }); | 1572 | }); |
| 1573 | try expectEqualHexStrings("\x66\x8D\x05\x10\x00\x00\x00", enc.code(), "lea ax, BYTE PTR [rip + 0x10]"); | 1573 | try expectEqualHexStrings("\x66\x8D\x05\x10\x00\x00\x00", enc.code(), "lea ax, BYTE PTR [rip + 0x10]"); |
| 1574 | 1574 | ||
| 1575 | try enc.encode(.lea, &.{ | 1575 | try enc.encode(.lea, &.{ |
| 1576 | .{ .reg = .rsi }, | 1576 | .{ .reg = .rsi }, |
| 1577 | .{ .mem = Instruction.Memory.sib(.qword, .{ | 1577 | .{ .mem = Instruction.Memory.initSib(.qword, .{ |
| 1578 | .base = .{ .reg = .rbp }, | 1578 | .base = .{ .reg = .rbp }, |
| 1579 | .scale_index = .{ .scale = 1, .index = .rcx }, | 1579 | .scale_index = .{ .scale = 1, .index = .rcx }, |
| 1580 | }) }, | 1580 | }) }, |
| ... | @@ -1583,31 +1583,31 @@ test "lower RM encoding" { | ... | @@ -1583,31 +1583,31 @@ test "lower RM encoding" { |
| 1583 | 1583 | ||
| 1584 | try enc.encode(.add, &.{ | 1584 | try enc.encode(.add, &.{ |
| 1585 | .{ .reg = .r11 }, | 1585 | .{ .reg = .r11 }, |
| 1586 | .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = 0x10000000 }) }, | 1586 | .{ .mem = Instruction.Memory.initSib(.qword, .{ .base = .{ .reg = .ds }, .disp = 0x10000000 }) }, |
| 1587 | }); | 1587 | }); |
| 1588 | try expectEqualHexStrings("\x4C\x03\x1C\x25\x00\x00\x00\x10", enc.code(), "add r11, QWORD PTR ds:0x10000000"); | 1588 | try expectEqualHexStrings("\x4C\x03\x1C\x25\x00\x00\x00\x10", enc.code(), "add r11, QWORD PTR ds:0x10000000"); |
| 1589 | 1589 | ||
| 1590 | try enc.encode(.add, &.{ | 1590 | try enc.encode(.add, &.{ |
| 1591 | .{ .reg = .r12b }, | 1591 | .{ .reg = .r12b }, |
| 1592 | .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .ds }, .disp = 0x10000000 }) }, | 1592 | .{ .mem = Instruction.Memory.initSib(.byte, .{ .base = .{ .reg = .ds }, .disp = 0x10000000 }) }, |
| 1593 | }); | 1593 | }); |
| 1594 | try expectEqualHexStrings("\x44\x02\x24\x25\x00\x00\x00\x10", enc.code(), "add r11b, BYTE PTR ds:0x10000000"); | 1594 | try expectEqualHexStrings("\x44\x02\x24\x25\x00\x00\x00\x10", enc.code(), "add r11b, BYTE PTR ds:0x10000000"); |
| 1595 | 1595 | ||
| 1596 | try enc.encode(.add, &.{ | 1596 | try enc.encode(.add, &.{ |
| 1597 | .{ .reg = .r12b }, | 1597 | .{ .reg = .r12b }, |
| 1598 | .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .fs }, .disp = 0x10000000 }) }, | 1598 | .{ .mem = Instruction.Memory.initSib(.byte, .{ .base = .{ .reg = .fs }, .disp = 0x10000000 }) }, |
| 1599 | }); | 1599 | }); |
| 1600 | try expectEqualHexStrings("\x64\x44\x02\x24\x25\x00\x00\x00\x10", enc.code(), "add r11b, BYTE PTR fs:0x10000000"); | 1600 | try expectEqualHexStrings("\x64\x44\x02\x24\x25\x00\x00\x00\x10", enc.code(), "add r11b, BYTE PTR fs:0x10000000"); |
| 1601 | 1601 | ||
| 1602 | try enc.encode(.sub, &.{ | 1602 | try enc.encode(.sub, &.{ |
| 1603 | .{ .reg = .r11 }, | 1603 | .{ .reg = .r11 }, |
| 1604 | .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .r13 }, .disp = 0x10000000 }) }, | 1604 | .{ .mem = Instruction.Memory.initSib(.qword, .{ .base = .{ .reg = .r13 }, .disp = 0x10000000 }) }, |
| 1605 | }); | 1605 | }); |
| 1606 | try expectEqualHexStrings("\x4D\x2B\x9D\x00\x00\x00\x10", enc.code(), "sub r11, QWORD PTR [r13 + 0x10000000]"); | 1606 | try expectEqualHexStrings("\x4D\x2B\x9D\x00\x00\x00\x10", enc.code(), "sub r11, QWORD PTR [r13 + 0x10000000]"); |
| 1607 | 1607 | ||
| 1608 | try enc.encode(.sub, &.{ | 1608 | try enc.encode(.sub, &.{ |
| 1609 | .{ .reg = .r11 }, | 1609 | .{ .reg = .r11 }, |
| 1610 | .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .r12 }, .disp = 0x10000000 }) }, | 1610 | .{ .mem = Instruction.Memory.initSib(.qword, .{ .base = .{ .reg = .r12 }, .disp = 0x10000000 }) }, |
| 1611 | }); | 1611 | }); |
| 1612 | try expectEqualHexStrings("\x4D\x2B\x9C\x24\x00\x00\x00\x10", enc.code(), "sub r11, QWORD PTR [r12 + 0x10000000]"); | 1612 | try expectEqualHexStrings("\x4D\x2B\x9C\x24\x00\x00\x00\x10", enc.code(), "sub r11, QWORD PTR [r12 + 0x10000000]"); |
| 1613 | 1613 | ||
| ... | @@ -1630,7 +1630,7 @@ test "lower RMI encoding" { | ... | @@ -1630,7 +1630,7 @@ test "lower RMI encoding" { |
| 1630 | 1630 | ||
| 1631 | try enc.encode(.imul, &.{ | 1631 | try enc.encode(.imul, &.{ |
| 1632 | .{ .reg = .r11 }, | 1632 | .{ .reg = .r11 }, |
| 1633 | .{ .mem = Instruction.Memory.rip(.qword, -16) }, | 1633 | .{ .mem = Instruction.Memory.initRip(.qword, -16) }, |
| 1634 | .{ .imm = Instruction.Immediate.s(-1024) }, | 1634 | .{ .imm = Instruction.Immediate.s(-1024) }, |
| 1635 | }); | 1635 | }); |
| 1636 | try expectEqualHexStrings( | 1636 | try expectEqualHexStrings( |
| ... | @@ -1641,7 +1641,7 @@ test "lower RMI encoding" { | ... | @@ -1641,7 +1641,7 @@ test "lower RMI encoding" { |
| 1641 | 1641 | ||
| 1642 | try enc.encode(.imul, &.{ | 1642 | try enc.encode(.imul, &.{ |
| 1643 | .{ .reg = .bx }, | 1643 | .{ .reg = .bx }, |
| 1644 | .{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp }, .disp = -16 }) }, | 1644 | .{ .mem = Instruction.Memory.initSib(.word, .{ .base = .{ .reg = .rbp }, .disp = -16 }) }, |
| 1645 | .{ .imm = Instruction.Immediate.s(-1024) }, | 1645 | .{ .imm = Instruction.Immediate.s(-1024) }, |
| 1646 | }); | 1646 | }); |
| 1647 | try expectEqualHexStrings( | 1647 | try expectEqualHexStrings( |
| ... | @@ -1652,7 +1652,7 @@ test "lower RMI encoding" { | ... | @@ -1652,7 +1652,7 @@ test "lower RMI encoding" { |
| 1652 | 1652 | ||
| 1653 | try enc.encode(.imul, &.{ | 1653 | try enc.encode(.imul, &.{ |
| 1654 | .{ .reg = .bx }, | 1654 | .{ .reg = .bx }, |
| 1655 | .{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp }, .disp = -16 }) }, | 1655 | .{ .mem = Instruction.Memory.initSib(.word, .{ .base = .{ .reg = .rbp }, .disp = -16 }) }, |
| 1656 | .{ .imm = Instruction.Immediate.u(1024) }, | 1656 | .{ .imm = Instruction.Immediate.u(1024) }, |
| 1657 | }); | 1657 | }); |
| 1658 | try expectEqualHexStrings( | 1658 | try expectEqualHexStrings( |
| ... | @@ -1672,19 +1672,19 @@ test "lower MR encoding" { | ... | @@ -1672,19 +1672,19 @@ test "lower MR encoding" { |
| 1672 | try expectEqualHexStrings("\x48\x89\xD8", enc.code(), "mov rax, rbx"); | 1672 | try expectEqualHexStrings("\x48\x89\xD8", enc.code(), "mov rax, rbx"); |
| 1673 | 1673 | ||
| 1674 | try enc.encode(.mov, &.{ | 1674 | try enc.encode(.mov, &.{ |
| 1675 | .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .rbp }, .disp = -4 }) }, | 1675 | .{ .mem = Instruction.Memory.initSib(.qword, .{ .base = .{ .reg = .rbp }, .disp = -4 }) }, |
| 1676 | .{ .reg = .r11 }, | 1676 | .{ .reg = .r11 }, |
| 1677 | }); | 1677 | }); |
| 1678 | try expectEqualHexStrings("\x4c\x89\x5d\xfc", enc.code(), "mov QWORD PTR [rbp - 4], r11"); | 1678 | try expectEqualHexStrings("\x4c\x89\x5d\xfc", enc.code(), "mov QWORD PTR [rbp - 4], r11"); |
| 1679 | 1679 | ||
| 1680 | try enc.encode(.mov, &.{ | 1680 | try enc.encode(.mov, &.{ |
| 1681 | .{ .mem = Instruction.Memory.rip(.qword, 0x10) }, | 1681 | .{ .mem = Instruction.Memory.initRip(.qword, 0x10) }, |
| 1682 | .{ .reg = .r12 }, | 1682 | .{ .reg = .r12 }, |
| 1683 | }); | 1683 | }); |
| 1684 | try expectEqualHexStrings("\x4C\x89\x25\x10\x00\x00\x00", enc.code(), "mov QWORD PTR [rip + 0x10], r12"); | 1684 | try expectEqualHexStrings("\x4C\x89\x25\x10\x00\x00\x00", enc.code(), "mov QWORD PTR [rip + 0x10], r12"); |
| 1685 | 1685 | ||
| 1686 | try enc.encode(.mov, &.{ | 1686 | try enc.encode(.mov, &.{ |
| 1687 | .{ .mem = Instruction.Memory.sib(.qword, .{ | 1687 | .{ .mem = Instruction.Memory.initSib(.qword, .{ |
| 1688 | .base = .{ .reg = .r11 }, | 1688 | .base = .{ .reg = .r11 }, |
| 1689 | .scale_index = .{ .scale = 2, .index = .r12 }, | 1689 | .scale_index = .{ .scale = 2, .index = .r12 }, |
| 1690 | .disp = 0x10, | 1690 | .disp = 0x10, |
| ... | @@ -1694,13 +1694,13 @@ test "lower MR encoding" { | ... | @@ -1694,13 +1694,13 @@ test "lower MR encoding" { |
| 1694 | try expectEqualHexStrings("\x4F\x89\x6C\x63\x10", enc.code(), "mov QWORD PTR [r11 + 2 * r12 + 0x10], r13"); | 1694 | try expectEqualHexStrings("\x4F\x89\x6C\x63\x10", enc.code(), "mov QWORD PTR [r11 + 2 * r12 + 0x10], r13"); |
| 1695 | 1695 | ||
| 1696 | try enc.encode(.mov, &.{ | 1696 | try enc.encode(.mov, &.{ |
| 1697 | .{ .mem = Instruction.Memory.rip(.word, -0x10) }, | 1697 | .{ .mem = Instruction.Memory.initRip(.word, -0x10) }, |
| 1698 | .{ .reg = .r12w }, | 1698 | .{ .reg = .r12w }, |
| 1699 | }); | 1699 | }); |
| 1700 | try expectEqualHexStrings("\x66\x44\x89\x25\xF0\xFF\xFF\xFF", enc.code(), "mov WORD PTR [rip - 0x10], r12w"); | 1700 | try expectEqualHexStrings("\x66\x44\x89\x25\xF0\xFF\xFF\xFF", enc.code(), "mov WORD PTR [rip - 0x10], r12w"); |
| 1701 | 1701 | ||
| 1702 | try enc.encode(.mov, &.{ | 1702 | try enc.encode(.mov, &.{ |
| 1703 | .{ .mem = Instruction.Memory.sib(.byte, .{ | 1703 | .{ .mem = Instruction.Memory.initSib(.byte, .{ |
| 1704 | .base = .{ .reg = .r11 }, | 1704 | .base = .{ .reg = .r11 }, |
| 1705 | .scale_index = .{ .scale = 2, .index = .r12 }, | 1705 | .scale_index = .{ .scale = 2, .index = .r12 }, |
| 1706 | .disp = 0x10, | 1706 | .disp = 0x10, |
| ... | @@ -1710,25 +1710,25 @@ test "lower MR encoding" { | ... | @@ -1710,25 +1710,25 @@ test "lower MR encoding" { |
| 1710 | try expectEqualHexStrings("\x47\x88\x6C\x63\x10", enc.code(), "mov BYTE PTR [r11 + 2 * r12 + 0x10], r13b"); | 1710 | try expectEqualHexStrings("\x47\x88\x6C\x63\x10", enc.code(), "mov BYTE PTR [r11 + 2 * r12 + 0x10], r13b"); |
| 1711 | 1711 | ||
| 1712 | try enc.encode(.add, &.{ | 1712 | try enc.encode(.add, &.{ |
| 1713 | .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .ds }, .disp = 0x10000000 }) }, | 1713 | .{ .mem = Instruction.Memory.initSib(.byte, .{ .base = .{ .reg = .ds }, .disp = 0x10000000 }) }, |
| 1714 | .{ .reg = .r12b }, | 1714 | .{ .reg = .r12b }, |
| 1715 | }); | 1715 | }); |
| 1716 | try expectEqualHexStrings("\x44\x00\x24\x25\x00\x00\x00\x10", enc.code(), "add BYTE PTR ds:0x10000000, r12b"); | 1716 | try expectEqualHexStrings("\x44\x00\x24\x25\x00\x00\x00\x10", enc.code(), "add BYTE PTR ds:0x10000000, r12b"); |
| 1717 | 1717 | ||
| 1718 | try enc.encode(.add, &.{ | 1718 | try enc.encode(.add, &.{ |
| 1719 | .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .ds }, .disp = 0x10000000 }) }, | 1719 | .{ .mem = Instruction.Memory.initSib(.dword, .{ .base = .{ .reg = .ds }, .disp = 0x10000000 }) }, |
| 1720 | .{ .reg = .r12d }, | 1720 | .{ .reg = .r12d }, |
| 1721 | }); | 1721 | }); |
| 1722 | try expectEqualHexStrings("\x44\x01\x24\x25\x00\x00\x00\x10", enc.code(), "add DWORD PTR [ds:0x10000000], r12d"); | 1722 | try expectEqualHexStrings("\x44\x01\x24\x25\x00\x00\x00\x10", enc.code(), "add DWORD PTR [ds:0x10000000], r12d"); |
| 1723 | 1723 | ||
| 1724 | try enc.encode(.add, &.{ | 1724 | try enc.encode(.add, &.{ |
| 1725 | .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .gs }, .disp = 0x10000000 }) }, | 1725 | .{ .mem = Instruction.Memory.initSib(.dword, .{ .base = .{ .reg = .gs }, .disp = 0x10000000 }) }, |
| 1726 | .{ .reg = .r12d }, | 1726 | .{ .reg = .r12d }, |
| 1727 | }); | 1727 | }); |
| 1728 | try expectEqualHexStrings("\x65\x44\x01\x24\x25\x00\x00\x00\x10", enc.code(), "add DWORD PTR [gs:0x10000000], r12d"); | 1728 | try expectEqualHexStrings("\x65\x44\x01\x24\x25\x00\x00\x00\x10", enc.code(), "add DWORD PTR [gs:0x10000000], r12d"); |
| 1729 | 1729 | ||
| 1730 | try enc.encode(.sub, &.{ | 1730 | try enc.encode(.sub, &.{ |
| 1731 | .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .r11 }, .disp = 0x10000000 }) }, | 1731 | .{ .mem = Instruction.Memory.initSib(.qword, .{ .base = .{ .reg = .r11 }, .disp = 0x10000000 }) }, |
| 1732 | .{ .reg = .r12 }, | 1732 | .{ .reg = .r12 }, |
| 1733 | }); | 1733 | }); |
| 1734 | try expectEqualHexStrings("\x4D\x29\xA3\x00\x00\x00\x10", enc.code(), "sub QWORD PTR [r11 + 0x10000000], r12"); | 1734 | try expectEqualHexStrings("\x4D\x29\xA3\x00\x00\x00\x10", enc.code(), "sub QWORD PTR [r11 + 0x10000000], r12"); |
| ... | @@ -1743,12 +1743,12 @@ test "lower M encoding" { | ... | @@ -1743,12 +1743,12 @@ test "lower M encoding" { |
| 1743 | try expectEqualHexStrings("\x41\xFF\xD4", enc.code(), "call r12"); | 1743 | try expectEqualHexStrings("\x41\xFF\xD4", enc.code(), "call r12"); |
| 1744 | 1744 | ||
| 1745 | try enc.encode(.call, &.{ | 1745 | try enc.encode(.call, &.{ |
| 1746 | .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .r12 } }) }, | 1746 | .{ .mem = Instruction.Memory.initSib(.qword, .{ .base = .{ .reg = .r12 } }) }, |
| 1747 | }); | 1747 | }); |
| 1748 | try expectEqualHexStrings("\x41\xFF\x14\x24", enc.code(), "call QWORD PTR [r12]"); | 1748 | try expectEqualHexStrings("\x41\xFF\x14\x24", enc.code(), "call QWORD PTR [r12]"); |
| 1749 | 1749 | ||
| 1750 | try enc.encode(.call, &.{ | 1750 | try enc.encode(.call, &.{ |
| 1751 | .{ .mem = Instruction.Memory.sib(.qword, .{ | 1751 | .{ .mem = Instruction.Memory.initSib(.qword, .{ |
| 1752 | .base = .none, | 1752 | .base = .none, |
| 1753 | .scale_index = .{ .index = .r11, .scale = 2 }, | 1753 | .scale_index = .{ .index = .r11, .scale = 2 }, |
| 1754 | }) }, | 1754 | }) }, |
| ... | @@ -1756,7 +1756,7 @@ test "lower M encoding" { | ... | @@ -1756,7 +1756,7 @@ test "lower M encoding" { |
| 1756 | try expectEqualHexStrings("\x42\xFF\x14\x5D\x00\x00\x00\x00", enc.code(), "call QWORD PTR [r11 * 2]"); | 1756 | try expectEqualHexStrings("\x42\xFF\x14\x5D\x00\x00\x00\x00", enc.code(), "call QWORD PTR [r11 * 2]"); |
| 1757 | 1757 | ||
| 1758 | try enc.encode(.call, &.{ | 1758 | try enc.encode(.call, &.{ |
| 1759 | .{ .mem = Instruction.Memory.sib(.qword, .{ | 1759 | .{ .mem = Instruction.Memory.initSib(.qword, .{ |
| 1760 | .base = .none, | 1760 | .base = .none, |
| 1761 | .scale_index = .{ .index = .r12, .scale = 2 }, | 1761 | .scale_index = .{ .index = .r12, .scale = 2 }, |
| 1762 | }) }, | 1762 | }) }, |
| ... | @@ -1764,7 +1764,7 @@ test "lower M encoding" { | ... | @@ -1764,7 +1764,7 @@ test "lower M encoding" { |
| 1764 | try expectEqualHexStrings("\x42\xFF\x14\x65\x00\x00\x00\x00", enc.code(), "call QWORD PTR [r12 * 2]"); | 1764 | try expectEqualHexStrings("\x42\xFF\x14\x65\x00\x00\x00\x00", enc.code(), "call QWORD PTR [r12 * 2]"); |
| 1765 | 1765 | ||
| 1766 | try enc.encode(.call, &.{ | 1766 | try enc.encode(.call, &.{ |
| 1767 | .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .gs } }) }, | 1767 | .{ .mem = Instruction.Memory.initSib(.qword, .{ .base = .{ .reg = .gs } }) }, |
| 1768 | }); | 1768 | }); |
| 1769 | try expectEqualHexStrings("\x65\xFF\x14\x25\x00\x00\x00\x00", enc.code(), "call gs:0x0"); | 1769 | try expectEqualHexStrings("\x65\xFF\x14\x25\x00\x00\x00\x00", enc.code(), "call gs:0x0"); |
| 1770 | 1770 | ||
| ... | @@ -1774,22 +1774,22 @@ test "lower M encoding" { | ... | @@ -1774,22 +1774,22 @@ test "lower M encoding" { |
| 1774 | try expectEqualHexStrings("\xE8\x00\x00\x00\x00", enc.code(), "call 0x0"); | 1774 | try expectEqualHexStrings("\xE8\x00\x00\x00\x00", enc.code(), "call 0x0"); |
| 1775 | 1775 | ||
| 1776 | try enc.encode(.push, &.{ | 1776 | try enc.encode(.push, &.{ |
| 1777 | .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .rbp } }) }, | 1777 | .{ .mem = Instruction.Memory.initSib(.qword, .{ .base = .{ .reg = .rbp } }) }, |
| 1778 | }); | 1778 | }); |
| 1779 | try expectEqualHexStrings("\xFF\x75\x00", enc.code(), "push QWORD PTR [rbp]"); | 1779 | try expectEqualHexStrings("\xFF\x75\x00", enc.code(), "push QWORD PTR [rbp]"); |
| 1780 | 1780 | ||
| 1781 | try enc.encode(.push, &.{ | 1781 | try enc.encode(.push, &.{ |
| 1782 | .{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp } }) }, | 1782 | .{ .mem = Instruction.Memory.initSib(.word, .{ .base = .{ .reg = .rbp } }) }, |
| 1783 | }); | 1783 | }); |
| 1784 | try expectEqualHexStrings("\x66\xFF\x75\x00", enc.code(), "push QWORD PTR [rbp]"); | 1784 | try expectEqualHexStrings("\x66\xFF\x75\x00", enc.code(), "push QWORD PTR [rbp]"); |
| 1785 | 1785 | ||
| 1786 | try enc.encode(.pop, &.{ | 1786 | try enc.encode(.pop, &.{ |
| 1787 | .{ .mem = Instruction.Memory.rip(.qword, 0) }, | 1787 | .{ .mem = Instruction.Memory.initRip(.qword, 0) }, |
| 1788 | }); | 1788 | }); |
| 1789 | try expectEqualHexStrings("\x8F\x05\x00\x00\x00\x00", enc.code(), "pop QWORD PTR [rip]"); | 1789 | try expectEqualHexStrings("\x8F\x05\x00\x00\x00\x00", enc.code(), "pop QWORD PTR [rip]"); |
| 1790 | 1790 | ||
| 1791 | try enc.encode(.pop, &.{ | 1791 | try enc.encode(.pop, &.{ |
| 1792 | .{ .mem = Instruction.Memory.rip(.word, 0) }, | 1792 | .{ .mem = Instruction.Memory.initRip(.word, 0) }, |
| 1793 | }); | 1793 | }); |
| 1794 | try expectEqualHexStrings("\x66\x8F\x05\x00\x00\x00\x00", enc.code(), "pop WORD PTR [rbp]"); | 1794 | try expectEqualHexStrings("\x66\x8F\x05\x00\x00\x00\x00", enc.code(), "pop WORD PTR [rbp]"); |
| 1795 | 1795 | ||
| ... | @@ -1870,48 +1870,48 @@ test "lower FD/TD encoding" { | ... | @@ -1870,48 +1870,48 @@ test "lower FD/TD encoding" { |
| 1870 | 1870 | ||
| 1871 | try enc.encode(.mov, &.{ | 1871 | try enc.encode(.mov, &.{ |
| 1872 | .{ .reg = .rax }, | 1872 | .{ .reg = .rax }, |
| 1873 | .{ .mem = Instruction.Memory.moffs(.cs, 0x10) }, | 1873 | .{ .mem = Instruction.Memory.initMoffs(.cs, 0x10) }, |
| 1874 | }); | 1874 | }); |
| 1875 | try expectEqualHexStrings("\x2E\x48\xA1\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs rax, cs:0x10"); | 1875 | try expectEqualHexStrings("\x2E\x48\xA1\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs rax, cs:0x10"); |
| 1876 | 1876 | ||
| 1877 | try enc.encode(.mov, &.{ | 1877 | try enc.encode(.mov, &.{ |
| 1878 | .{ .reg = .eax }, | 1878 | .{ .reg = .eax }, |
| 1879 | .{ .mem = Instruction.Memory.moffs(.fs, 0x10) }, | 1879 | .{ .mem = Instruction.Memory.initMoffs(.fs, 0x10) }, |
| 1880 | }); | 1880 | }); |
| 1881 | try expectEqualHexStrings("\x64\xA1\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs eax, fs:0x10"); | 1881 | try expectEqualHexStrings("\x64\xA1\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs eax, fs:0x10"); |
| 1882 | 1882 | ||
| 1883 | try enc.encode(.mov, &.{ | 1883 | try enc.encode(.mov, &.{ |
| 1884 | .{ .reg = .ax }, | 1884 | .{ .reg = .ax }, |
| 1885 | .{ .mem = Instruction.Memory.moffs(.gs, 0x10) }, | 1885 | .{ .mem = Instruction.Memory.initMoffs(.gs, 0x10) }, |
| 1886 | }); | 1886 | }); |
| 1887 | try expectEqualHexStrings("\x65\x66\xA1\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs ax, gs:0x10"); | 1887 | try expectEqualHexStrings("\x65\x66\xA1\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs ax, gs:0x10"); |
| 1888 | 1888 | ||
| 1889 | try enc.encode(.mov, &.{ | 1889 | try enc.encode(.mov, &.{ |
| 1890 | .{ .reg = .al }, | 1890 | .{ .reg = .al }, |
| 1891 | .{ .mem = Instruction.Memory.moffs(.ds, 0x10) }, | 1891 | .{ .mem = Instruction.Memory.initMoffs(.ds, 0x10) }, |
| 1892 | }); | 1892 | }); |
| 1893 | try expectEqualHexStrings("\xA0\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs al, ds:0x10"); | 1893 | try expectEqualHexStrings("\xA0\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs al, ds:0x10"); |
| 1894 | 1894 | ||
| 1895 | try enc.encode(.mov, &.{ | 1895 | try enc.encode(.mov, &.{ |
| 1896 | .{ .mem = Instruction.Memory.moffs(.cs, 0x10) }, | 1896 | .{ .mem = Instruction.Memory.initMoffs(.cs, 0x10) }, |
| 1897 | .{ .reg = .rax }, | 1897 | .{ .reg = .rax }, |
| 1898 | }); | 1898 | }); |
| 1899 | try expectEqualHexStrings("\x2E\x48\xA3\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs cs:0x10, rax"); | 1899 | try expectEqualHexStrings("\x2E\x48\xA3\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs cs:0x10, rax"); |
| 1900 | 1900 | ||
| 1901 | try enc.encode(.mov, &.{ | 1901 | try enc.encode(.mov, &.{ |
| 1902 | .{ .mem = Instruction.Memory.moffs(.fs, 0x10) }, | 1902 | .{ .mem = Instruction.Memory.initMoffs(.fs, 0x10) }, |
| 1903 | .{ .reg = .eax }, | 1903 | .{ .reg = .eax }, |
| 1904 | }); | 1904 | }); |
| 1905 | try expectEqualHexStrings("\x64\xA3\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs fs:0x10, eax"); | 1905 | try expectEqualHexStrings("\x64\xA3\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs fs:0x10, eax"); |
| 1906 | 1906 | ||
| 1907 | try enc.encode(.mov, &.{ | 1907 | try enc.encode(.mov, &.{ |
| 1908 | .{ .mem = Instruction.Memory.moffs(.gs, 0x10) }, | 1908 | .{ .mem = Instruction.Memory.initMoffs(.gs, 0x10) }, |
| 1909 | .{ .reg = .ax }, | 1909 | .{ .reg = .ax }, |
| 1910 | }); | 1910 | }); |
| 1911 | try expectEqualHexStrings("\x65\x66\xA3\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs gs:0x10, ax"); | 1911 | try expectEqualHexStrings("\x65\x66\xA3\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs gs:0x10, ax"); |
| 1912 | 1912 | ||
| 1913 | try enc.encode(.mov, &.{ | 1913 | try enc.encode(.mov, &.{ |
| 1914 | .{ .mem = Instruction.Memory.moffs(.ds, 0x10) }, | 1914 | .{ .mem = Instruction.Memory.initMoffs(.ds, 0x10) }, |
| 1915 | .{ .reg = .al }, | 1915 | .{ .reg = .al }, |
| 1916 | }); | 1916 | }); |
| 1917 | try expectEqualHexStrings("\xA2\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs ds:0x10, al"); | 1917 | try expectEqualHexStrings("\xA2\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs ds:0x10, al"); |
| ... | @@ -1949,16 +1949,16 @@ test "invalid instruction" { | ... | @@ -1949,16 +1949,16 @@ test "invalid instruction" { |
| 1949 | .{ .reg = .al }, | 1949 | .{ .reg = .al }, |
| 1950 | }); | 1950 | }); |
| 1951 | try invalidInstruction(.call, &.{ | 1951 | try invalidInstruction(.call, &.{ |
| 1952 | .{ .mem = Instruction.Memory.rip(.dword, 0) }, | 1952 | .{ .mem = Instruction.Memory.initRip(.dword, 0) }, |
| 1953 | }); | 1953 | }); |
| 1954 | try invalidInstruction(.call, &.{ | 1954 | try invalidInstruction(.call, &.{ |
| 1955 | .{ .mem = Instruction.Memory.rip(.word, 0) }, | 1955 | .{ .mem = Instruction.Memory.initRip(.word, 0) }, |
| 1956 | }); | 1956 | }); |
| 1957 | try invalidInstruction(.call, &.{ | 1957 | try invalidInstruction(.call, &.{ |
| 1958 | .{ .mem = Instruction.Memory.rip(.byte, 0) }, | 1958 | .{ .mem = Instruction.Memory.initRip(.byte, 0) }, |
| 1959 | }); | 1959 | }); |
| 1960 | try invalidInstruction(.mov, &.{ | 1960 | try invalidInstruction(.mov, &.{ |
| 1961 | .{ .mem = Instruction.Memory.rip(.word, 0x10) }, | 1961 | .{ .mem = Instruction.Memory.initRip(.word, 0x10) }, |
| 1962 | .{ .reg = .r12 }, | 1962 | .{ .reg = .r12 }, |
| 1963 | }); | 1963 | }); |
| 1964 | try invalidInstruction(.lea, &.{ | 1964 | try invalidInstruction(.lea, &.{ |
| ... | @@ -1967,7 +1967,7 @@ test "invalid instruction" { | ... | @@ -1967,7 +1967,7 @@ test "invalid instruction" { |
| 1967 | }); | 1967 | }); |
| 1968 | try invalidInstruction(.lea, &.{ | 1968 | try invalidInstruction(.lea, &.{ |
| 1969 | .{ .reg = .al }, | 1969 | .{ .reg = .al }, |
| 1970 | .{ .mem = Instruction.Memory.rip(.byte, 0) }, | 1970 | .{ .mem = Instruction.Memory.initRip(.byte, 0) }, |
| 1971 | }); | 1971 | }); |
| 1972 | try invalidInstruction(.pop, &.{ | 1972 | try invalidInstruction(.pop, &.{ |
| 1973 | .{ .reg = .r12b }, | 1973 | .{ .reg = .r12b }, |
| ... | @@ -1992,7 +1992,7 @@ fn cannotEncode(mnemonic: Instruction.Mnemonic, ops: []const Instruction.Operand | ... | @@ -1992,7 +1992,7 @@ fn cannotEncode(mnemonic: Instruction.Mnemonic, ops: []const Instruction.Operand |
| 1992 | 1992 | ||
| 1993 | test "cannot encode" { | 1993 | test "cannot encode" { |
| 1994 | try cannotEncode(.@"test", &.{ | 1994 | try cannotEncode(.@"test", &.{ |
| 1995 | .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .r12 } }) }, | 1995 | .{ .mem = Instruction.Memory.initSib(.byte, .{ .base = .{ .reg = .r12 } }) }, |
| 1996 | .{ .reg = .ah }, | 1996 | .{ .reg = .ah }, |
| 1997 | }); | 1997 | }); |
| 1998 | try cannotEncode(.@"test", &.{ | 1998 | try cannotEncode(.@"test", &.{ |
| ... | @@ -2369,7 +2369,7 @@ const Assembler = struct { | ... | @@ -2369,7 +2369,7 @@ const Assembler = struct { |
| 2369 | if (res.rip) { | 2369 | if (res.rip) { |
| 2370 | if (res.base != null or res.scale_index != null or res.offset != null) | 2370 | if (res.base != null or res.scale_index != null or res.offset != null) |
| 2371 | return error.InvalidMemoryOperand; | 2371 | return error.InvalidMemoryOperand; |
| 2372 | return Instruction.Memory.rip(ptr_size orelse .qword, res.disp orelse 0); | 2372 | return Instruction.Memory.initRip(ptr_size orelse .qword, res.disp orelse 0); |
| 2373 | } | 2373 | } |
| 2374 | if (res.base) |base| { | 2374 | if (res.base) |base| { |
| 2375 | if (res.rip) | 2375 | if (res.rip) |
| ... | @@ -2377,9 +2377,9 @@ const Assembler = struct { | ... | @@ -2377,9 +2377,9 @@ const Assembler = struct { |
| 2377 | if (res.offset) |offset| { | 2377 | if (res.offset) |offset| { |
| 2378 | if (res.scale_index != null or res.disp != null) | 2378 | if (res.scale_index != null or res.disp != null) |
| 2379 | return error.InvalidMemoryOperand; | 2379 | return error.InvalidMemoryOperand; |
| 2380 | return Instruction.Memory.moffs(base, offset); | 2380 | return Instruction.Memory.initMoffs(base, offset); |
| 2381 | } | 2381 | } |
| 2382 | return Instruction.Memory.sib(ptr_size orelse .qword, .{ | 2382 | return Instruction.Memory.initSib(ptr_size orelse .qword, .{ |
| 2383 | .base = .{ .reg = base }, | 2383 | .base = .{ .reg = base }, |
| 2384 | .scale_index = res.scale_index, | 2384 | .scale_index = res.scale_index, |
| 2385 | .disp = res.disp orelse 0, | 2385 | .disp = res.disp orelse 0, |
src/codegen.zig+2-11| ... | @@ -836,16 +836,6 @@ pub const GenResult = union(enum) { | ... | @@ -836,16 +836,6 @@ pub const GenResult = union(enum) { |
| 836 | /// Traditionally, this corresponds to emitting a relocation in a relocatable object file. | 836 | /// Traditionally, this corresponds to emitting a relocation in a relocatable object file. |
| 837 | lea_symbol: u32, | 837 | lea_symbol: u32, |
| 838 | }; | 838 | }; |
| 839 | |||
| 840 | fn fail( | ||
| 841 | gpa: Allocator, | ||
| 842 | src_loc: Zcu.LazySrcLoc, | ||
| 843 | comptime format: []const u8, | ||
| 844 | args: anytype, | ||
| 845 | ) Allocator.Error!GenResult { | ||
| 846 | const msg = try ErrorMsg.create(gpa, src_loc, format, args); | ||
| 847 | return .{ .fail = msg }; | ||
| 848 | } | ||
| 849 | }; | 839 | }; |
| 850 | 840 | ||
| 851 | fn genNavRef( | 841 | fn genNavRef( |
| ... | @@ -935,7 +925,8 @@ fn genNavRef( | ... | @@ -935,7 +925,8 @@ fn genNavRef( |
| 935 | const atom = p9.getAtom(atom_index); | 925 | const atom = p9.getAtom(atom_index); |
| 936 | return .{ .mcv = .{ .memory = atom.getOffsetTableAddress(p9) } }; | 926 | return .{ .mcv = .{ .memory = atom.getOffsetTableAddress(p9) } }; |
| 937 | } else { | 927 | } else { |
| 938 | return GenResult.fail(gpa, src_loc, "TODO genNavRef for target {}", .{target}); | 928 | const msg = try ErrorMsg.create(gpa, src_loc, "TODO genNavRef for target {}", .{target}); |
| 929 | return .{ .fail = msg }; | ||
| 939 | } | 930 | } |
| 940 | } | 931 | } |
| 941 | 932 |
src/codegen/llvm/BitcodeReader.zig+9-9| ... | @@ -33,9 +33,9 @@ pub const Block = struct { | ... | @@ -33,9 +33,9 @@ pub const Block = struct { |
| 33 | .abbrevs = .{ .abbrevs = .{} }, | 33 | .abbrevs = .{ .abbrevs = .{} }, |
| 34 | }; | 34 | }; |
| 35 | 35 | ||
| 36 | const set_bid: u32 = 1; | 36 | const set_bid_id: u32 = 1; |
| 37 | const block_name: u32 = 2; | 37 | const block_name_id: u32 = 2; |
| 38 | const set_record_name: u32 = 3; | 38 | const set_record_name_id: u32 = 3; |
| 39 | 39 | ||
| 40 | fn deinit(info: *Info, allocator: std.mem.Allocator) void { | 40 | fn deinit(info: *Info, allocator: std.mem.Allocator) void { |
| 41 | allocator.free(info.block_name); | 41 | allocator.free(info.block_name); |
| ... | @@ -61,7 +61,7 @@ pub const Record = struct { | ... | @@ -61,7 +61,7 @@ pub const Record = struct { |
| 61 | assert(record.id == Abbrev.Builtin.define_abbrev.toRecordId()); | 61 | assert(record.id == Abbrev.Builtin.define_abbrev.toRecordId()); |
| 62 | var i: usize = 0; | 62 | var i: usize = 0; |
| 63 | while (i < record.operands.len) switch (record.operands[i]) { | 63 | while (i < record.operands.len) switch (record.operands[i]) { |
| 64 | Abbrev.Operand.literal => { | 64 | Abbrev.Operand.literal_id => { |
| 65 | try operands.append(.{ .literal = record.operands[i + 1] }); | 65 | try operands.append(.{ .literal = record.operands[i + 1] }); |
| 66 | i += 2; | 66 | i += 2; |
| 67 | }, | 67 | }, |
| ... | @@ -211,7 +211,7 @@ fn nextRecord(bc: *BitcodeReader) !?Record { | ... | @@ -211,7 +211,7 @@ fn nextRecord(bc: *BitcodeReader) !?Record { |
| 211 | .align_32_bits, .block_len => return error.UnsupportedArrayElement, | 211 | .align_32_bits, .block_len => return error.UnsupportedArrayElement, |
| 212 | .abbrev_op => switch (try bc.readFixed(u1, 1)) { | 212 | .abbrev_op => switch (try bc.readFixed(u1, 1)) { |
| 213 | 1 => try operands.appendSlice(&.{ | 213 | 1 => try operands.appendSlice(&.{ |
| 214 | Abbrev.Operand.literal, | 214 | Abbrev.Operand.literal_id, |
| 215 | try bc.readVbr(u64, 8), | 215 | try bc.readVbr(u64, 8), |
| 216 | }), | 216 | }), |
| 217 | 0 => { | 217 | 0 => { |
| ... | @@ -334,9 +334,9 @@ fn parseBlockInfoBlock(bc: *BitcodeReader) !void { | ... | @@ -334,9 +334,9 @@ fn parseBlockInfoBlock(bc: *BitcodeReader) !void { |
| 334 | try record.toOwnedAbbrev(bc.allocator), | 334 | try record.toOwnedAbbrev(bc.allocator), |
| 335 | ); | 335 | ); |
| 336 | }, | 336 | }, |
| 337 | Block.Info.set_bid => block_id = std.math.cast(u32, record.operands[0]) orelse | 337 | Block.Info.set_bid_id => block_id = std.math.cast(u32, record.operands[0]) orelse |
| 338 | return error.Overflow, | 338 | return error.Overflow, |
| 339 | Block.Info.block_name => if (bc.keep_names) { | 339 | Block.Info.block_name_id => if (bc.keep_names) { |
| 340 | const gop = try bc.block_info.getOrPut(bc.allocator, block_id orelse | 340 | const gop = try bc.block_info.getOrPut(bc.allocator, block_id orelse |
| 341 | return error.UnspecifiedBlockId); | 341 | return error.UnspecifiedBlockId); |
| 342 | if (!gop.found_existing) gop.value_ptr.* = Block.Info.default; | 342 | if (!gop.found_existing) gop.value_ptr.* = Block.Info.default; |
| ... | @@ -346,7 +346,7 @@ fn parseBlockInfoBlock(bc: *BitcodeReader) !void { | ... | @@ -346,7 +346,7 @@ fn parseBlockInfoBlock(bc: *BitcodeReader) !void { |
| 346 | byte.* = std.math.cast(u8, operand) orelse return error.InvalidName; | 346 | byte.* = std.math.cast(u8, operand) orelse return error.InvalidName; |
| 347 | gop.value_ptr.block_name = name; | 347 | gop.value_ptr.block_name = name; |
| 348 | }, | 348 | }, |
| 349 | Block.Info.set_record_name => if (bc.keep_names) { | 349 | Block.Info.set_record_name_id => if (bc.keep_names) { |
| 350 | const gop = try bc.block_info.getOrPut(bc.allocator, block_id orelse | 350 | const gop = try bc.block_info.getOrPut(bc.allocator, block_id orelse |
| 351 | return error.UnspecifiedBlockId); | 351 | return error.UnspecifiedBlockId); |
| 352 | if (!gop.found_existing) gop.value_ptr.* = Block.Info.default; | 352 | if (!gop.found_existing) gop.value_ptr.* = Block.Info.default; |
| ... | @@ -467,7 +467,7 @@ const Abbrev = struct { | ... | @@ -467,7 +467,7 @@ const Abbrev = struct { |
| 467 | block_len, | 467 | block_len, |
| 468 | abbrev_op, | 468 | abbrev_op, |
| 469 | 469 | ||
| 470 | const literal = std.math.maxInt(u64); | 470 | const literal_id = std.math.maxInt(u64); |
| 471 | const Encoding = enum(u3) { | 471 | const Encoding = enum(u3) { |
| 472 | fixed = 1, | 472 | fixed = 1, |
| 473 | vbr = 2, | 473 | vbr = 2, |
src/link/Elf.zig+84-3| ... | @@ -3467,7 +3467,7 @@ fn updateSectionSizes(self: *Elf) !void { | ... | @@ -3467,7 +3467,7 @@ fn updateSectionSizes(self: *Elf) !void { |
| 3467 | if (atom_list.items.len == 0) continue; | 3467 | if (atom_list.items.len == 0) continue; |
| 3468 | 3468 | ||
| 3469 | // Create jump/branch range extenders if needed. | 3469 | // Create jump/branch range extenders if needed. |
| 3470 | try thunks.createThunks(shdr, @intCast(shndx), self); | 3470 | try self.createThunks(shdr, @intCast(shndx)); |
| 3471 | } | 3471 | } |
| 3472 | } | 3472 | } |
| 3473 | 3473 | ||
| ... | @@ -5576,6 +5576,88 @@ fn defaultEntrySymbolName(cpu_arch: std.Target.Cpu.Arch) []const u8 { | ... | @@ -5576,6 +5576,88 @@ fn defaultEntrySymbolName(cpu_arch: std.Target.Cpu.Arch) []const u8 { |
| 5576 | }; | 5576 | }; |
| 5577 | } | 5577 | } |
| 5578 | 5578 | ||
| 5579 | fn createThunks(elf_file: *Elf, shdr: *elf.Elf64_Shdr, shndx: u32) !void { | ||
| 5580 | const gpa = elf_file.base.comp.gpa; | ||
| 5581 | const cpu_arch = elf_file.getTarget().cpu.arch; | ||
| 5582 | // A branch will need an extender if its target is larger than | ||
| 5583 | // `2^(jump_bits - 1) - margin` where margin is some arbitrary number. | ||
| 5584 | const max_distance = switch (cpu_arch) { | ||
| 5585 | .aarch64 => 0x500_000, | ||
| 5586 | .x86_64, .riscv64 => unreachable, | ||
| 5587 | else => @panic("unhandled arch"), | ||
| 5588 | }; | ||
| 5589 | const atoms = elf_file.sections.items(.atom_list)[shndx].items; | ||
| 5590 | assert(atoms.len > 0); | ||
| 5591 | |||
| 5592 | for (atoms) |ref| { | ||
| 5593 | elf_file.atom(ref).?.value = -1; | ||
| 5594 | } | ||
| 5595 | |||
| 5596 | var i: usize = 0; | ||
| 5597 | while (i < atoms.len) { | ||
| 5598 | const start = i; | ||
| 5599 | const start_atom = elf_file.atom(atoms[start]).?; | ||
| 5600 | assert(start_atom.alive); | ||
| 5601 | start_atom.value = try advanceSection(shdr, start_atom.size, start_atom.alignment); | ||
| 5602 | i += 1; | ||
| 5603 | |||
| 5604 | while (i < atoms.len) : (i += 1) { | ||
| 5605 | const atom_ptr = elf_file.atom(atoms[i]).?; | ||
| 5606 | assert(atom_ptr.alive); | ||
| 5607 | if (@as(i64, @intCast(atom_ptr.alignment.forward(shdr.sh_size))) - start_atom.value >= max_distance) | ||
| 5608 | break; | ||
| 5609 | atom_ptr.value = try advanceSection(shdr, atom_ptr.size, atom_ptr.alignment); | ||
| 5610 | } | ||
| 5611 | |||
| 5612 | // Insert a thunk at the group end | ||
| 5613 | const thunk_index = try elf_file.addThunk(); | ||
| 5614 | const thunk_ptr = elf_file.thunk(thunk_index); | ||
| 5615 | thunk_ptr.output_section_index = shndx; | ||
| 5616 | |||
| 5617 | // Scan relocs in the group and create trampolines for any unreachable callsite | ||
| 5618 | for (atoms[start..i]) |ref| { | ||
| 5619 | const atom_ptr = elf_file.atom(ref).?; | ||
| 5620 | const file_ptr = atom_ptr.file(elf_file).?; | ||
| 5621 | log.debug("atom({}) {s}", .{ ref, atom_ptr.name(elf_file) }); | ||
| 5622 | for (atom_ptr.relocs(elf_file)) |rel| { | ||
| 5623 | const is_reachable = switch (cpu_arch) { | ||
| 5624 | .aarch64 => r: { | ||
| 5625 | const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_type()); | ||
| 5626 | if (r_type != .CALL26 and r_type != .JUMP26) break :r true; | ||
| 5627 | const target_ref = file_ptr.resolveSymbol(rel.r_sym(), elf_file); | ||
| 5628 | const target = elf_file.symbol(target_ref).?; | ||
| 5629 | if (target.flags.has_plt) break :r false; | ||
| 5630 | if (atom_ptr.output_section_index != target.output_section_index) break :r false; | ||
| 5631 | const target_atom = target.atom(elf_file).?; | ||
| 5632 | if (target_atom.value == -1) break :r false; | ||
| 5633 | const saddr = atom_ptr.address(elf_file) + @as(i64, @intCast(rel.r_offset)); | ||
| 5634 | const taddr = target.address(.{}, elf_file); | ||
| 5635 | _ = math.cast(i28, taddr + rel.r_addend - saddr) orelse break :r false; | ||
| 5636 | break :r true; | ||
| 5637 | }, | ||
| 5638 | .x86_64, .riscv64 => unreachable, | ||
| 5639 | else => @panic("unsupported arch"), | ||
| 5640 | }; | ||
| 5641 | if (is_reachable) continue; | ||
| 5642 | const target = file_ptr.resolveSymbol(rel.r_sym(), elf_file); | ||
| 5643 | try thunk_ptr.symbols.put(gpa, target, {}); | ||
| 5644 | } | ||
| 5645 | atom_ptr.addExtra(.{ .thunk = thunk_index }, elf_file); | ||
| 5646 | } | ||
| 5647 | |||
| 5648 | thunk_ptr.value = try advanceSection(shdr, thunk_ptr.size(elf_file), Atom.Alignment.fromNonzeroByteUnits(2)); | ||
| 5649 | |||
| 5650 | log.debug("thunk({d}) : {}", .{ thunk_index, thunk_ptr.fmt(elf_file) }); | ||
| 5651 | } | ||
| 5652 | } | ||
| 5653 | fn advanceSection(shdr: *elf.Elf64_Shdr, adv_size: u64, alignment: Atom.Alignment) !i64 { | ||
| 5654 | const offset = alignment.forward(shdr.sh_size); | ||
| 5655 | const padding = offset - shdr.sh_size; | ||
| 5656 | shdr.sh_size += padding + adv_size; | ||
| 5657 | shdr.sh_addralign = @max(shdr.sh_addralign, alignment.toByteUnits() orelse 1); | ||
| 5658 | return @intCast(offset); | ||
| 5659 | } | ||
| 5660 | |||
| 5579 | const std = @import("std"); | 5661 | const std = @import("std"); |
| 5580 | const build_options = @import("build_options"); | 5662 | const build_options = @import("build_options"); |
| 5581 | const builtin = @import("builtin"); | 5663 | const builtin = @import("builtin"); |
| ... | @@ -5598,7 +5680,6 @@ const musl = @import("../musl.zig"); | ... | @@ -5598,7 +5680,6 @@ const musl = @import("../musl.zig"); |
| 5598 | const relocatable = @import("Elf/relocatable.zig"); | 5680 | const relocatable = @import("Elf/relocatable.zig"); |
| 5599 | const relocation = @import("Elf/relocation.zig"); | 5681 | const relocation = @import("Elf/relocation.zig"); |
| 5600 | const target_util = @import("../target.zig"); | 5682 | const target_util = @import("../target.zig"); |
| 5601 | const thunks = @import("Elf/thunks.zig"); | ||
| 5602 | const trace = @import("../tracy.zig").trace; | 5683 | const trace = @import("../tracy.zig").trace; |
| 5603 | const synthetic_sections = @import("Elf/synthetic_sections.zig"); | 5684 | const synthetic_sections = @import("Elf/synthetic_sections.zig"); |
| 5604 | 5685 | ||
| ... | @@ -5636,7 +5717,7 @@ const PltGotSection = synthetic_sections.PltGotSection; | ... | @@ -5636,7 +5717,7 @@ const PltGotSection = synthetic_sections.PltGotSection; |
| 5636 | const SharedObject = @import("Elf/SharedObject.zig"); | 5717 | const SharedObject = @import("Elf/SharedObject.zig"); |
| 5637 | const Symbol = @import("Elf/Symbol.zig"); | 5718 | const Symbol = @import("Elf/Symbol.zig"); |
| 5638 | const StringTable = @import("StringTable.zig"); | 5719 | const StringTable = @import("StringTable.zig"); |
| 5639 | const Thunk = thunks.Thunk; | 5720 | const Thunk = @import("Elf/Thunk.zig"); |
| 5640 | const Value = @import("../Value.zig"); | 5721 | const Value = @import("../Value.zig"); |
| 5641 | const VerneedSection = synthetic_sections.VerneedSection; | 5722 | const VerneedSection = synthetic_sections.VerneedSection; |
| 5642 | const ZigObject = @import("Elf/ZigObject.zig"); | 5723 | const ZigObject = @import("Elf/ZigObject.zig"); |
src/link/Elf/Atom.zig+1-1| ... | @@ -2251,6 +2251,6 @@ const Fde = eh_frame.Fde; | ... | @@ -2251,6 +2251,6 @@ const Fde = eh_frame.Fde; |
| 2251 | const File = @import("file.zig").File; | 2251 | const File = @import("file.zig").File; |
| 2252 | const Object = @import("Object.zig"); | 2252 | const Object = @import("Object.zig"); |
| 2253 | const Symbol = @import("Symbol.zig"); | 2253 | const Symbol = @import("Symbol.zig"); |
| 2254 | const Thunk = @import("thunks.zig").Thunk; | 2254 | const Thunk = @import("Thunk.zig"); |
| 2255 | const ZigObject = @import("ZigObject.zig"); | 2255 | const ZigObject = @import("ZigObject.zig"); |
| 2256 | const dev = @import("../../dev.zig"); | 2256 | const dev = @import("../../dev.zig"); |
src/link/Elf/Thunk.zig created+144| ... | @@ -0,0 +1,144 @@ | ||
| 1 | value: i64 = 0, | ||
| 2 | output_section_index: u32 = 0, | ||
| 3 | symbols: std.AutoArrayHashMapUnmanaged(Elf.Ref, void) = .{}, | ||
| 4 | output_symtab_ctx: Elf.SymtabCtx = .{}, | ||
| 5 | |||
| 6 | pub fn deinit(thunk: *Thunk, allocator: Allocator) void { | ||
| 7 | thunk.symbols.deinit(allocator); | ||
| 8 | } | ||
| 9 | |||
| 10 | pub fn size(thunk: Thunk, elf_file: *Elf) usize { | ||
| 11 | const cpu_arch = elf_file.getTarget().cpu.arch; | ||
| 12 | return thunk.symbols.keys().len * trampolineSize(cpu_arch); | ||
| 13 | } | ||
| 14 | |||
| 15 | pub fn address(thunk: Thunk, elf_file: *Elf) i64 { | ||
| 16 | const shdr = elf_file.sections.items(.shdr)[thunk.output_section_index]; | ||
| 17 | return @as(i64, @intCast(shdr.sh_addr)) + thunk.value; | ||
| 18 | } | ||
| 19 | |||
| 20 | pub fn targetAddress(thunk: Thunk, ref: Elf.Ref, elf_file: *Elf) i64 { | ||
| 21 | const cpu_arch = elf_file.getTarget().cpu.arch; | ||
| 22 | return thunk.address(elf_file) + @as(i64, @intCast(thunk.symbols.getIndex(ref).? * trampolineSize(cpu_arch))); | ||
| 23 | } | ||
| 24 | |||
| 25 | pub fn write(thunk: Thunk, elf_file: *Elf, writer: anytype) !void { | ||
| 26 | switch (elf_file.getTarget().cpu.arch) { | ||
| 27 | .aarch64 => try aarch64.write(thunk, elf_file, writer), | ||
| 28 | .x86_64, .riscv64 => unreachable, | ||
| 29 | else => @panic("unhandled arch"), | ||
| 30 | } | ||
| 31 | } | ||
| 32 | |||
| 33 | pub fn calcSymtabSize(thunk: *Thunk, elf_file: *Elf) void { | ||
| 34 | thunk.output_symtab_ctx.nlocals = @as(u32, @intCast(thunk.symbols.keys().len)); | ||
| 35 | for (thunk.symbols.keys()) |ref| { | ||
| 36 | const sym = elf_file.symbol(ref).?; | ||
| 37 | thunk.output_symtab_ctx.strsize += @as(u32, @intCast(sym.name(elf_file).len + "$thunk".len + 1)); | ||
| 38 | } | ||
| 39 | } | ||
| 40 | |||
| 41 | pub fn writeSymtab(thunk: Thunk, elf_file: *Elf) void { | ||
| 42 | const cpu_arch = elf_file.getTarget().cpu.arch; | ||
| 43 | for (thunk.symbols.keys(), thunk.output_symtab_ctx.ilocal..) |ref, ilocal| { | ||
| 44 | const sym = elf_file.symbol(ref).?; | ||
| 45 | const st_name = @as(u32, @intCast(elf_file.strtab.items.len)); | ||
| 46 | elf_file.strtab.appendSliceAssumeCapacity(sym.name(elf_file)); | ||
| 47 | elf_file.strtab.appendSliceAssumeCapacity("$thunk"); | ||
| 48 | elf_file.strtab.appendAssumeCapacity(0); | ||
| 49 | elf_file.symtab.items[ilocal] = .{ | ||
| 50 | .st_name = st_name, | ||
| 51 | .st_info = elf.STT_FUNC, | ||
| 52 | .st_other = 0, | ||
| 53 | .st_shndx = @intCast(thunk.output_section_index), | ||
| 54 | .st_value = @intCast(thunk.targetAddress(ref, elf_file)), | ||
| 55 | .st_size = trampolineSize(cpu_arch), | ||
| 56 | }; | ||
| 57 | } | ||
| 58 | } | ||
| 59 | |||
| 60 | fn trampolineSize(cpu_arch: std.Target.Cpu.Arch) usize { | ||
| 61 | return switch (cpu_arch) { | ||
| 62 | .aarch64 => aarch64.trampoline_size, | ||
| 63 | .x86_64, .riscv64 => unreachable, | ||
| 64 | else => @panic("unhandled arch"), | ||
| 65 | }; | ||
| 66 | } | ||
| 67 | |||
| 68 | pub fn format( | ||
| 69 | thunk: Thunk, | ||
| 70 | comptime unused_fmt_string: []const u8, | ||
| 71 | options: std.fmt.FormatOptions, | ||
| 72 | writer: anytype, | ||
| 73 | ) !void { | ||
| 74 | _ = thunk; | ||
| 75 | _ = unused_fmt_string; | ||
| 76 | _ = options; | ||
| 77 | _ = writer; | ||
| 78 | @compileError("do not format Thunk directly"); | ||
| 79 | } | ||
| 80 | |||
| 81 | pub fn fmt(thunk: Thunk, elf_file: *Elf) std.fmt.Formatter(format2) { | ||
| 82 | return .{ .data = .{ | ||
| 83 | .thunk = thunk, | ||
| 84 | .elf_file = elf_file, | ||
| 85 | } }; | ||
| 86 | } | ||
| 87 | |||
| 88 | const FormatContext = struct { | ||
| 89 | thunk: Thunk, | ||
| 90 | elf_file: *Elf, | ||
| 91 | }; | ||
| 92 | |||
| 93 | fn format2( | ||
| 94 | ctx: FormatContext, | ||
| 95 | comptime unused_fmt_string: []const u8, | ||
| 96 | options: std.fmt.FormatOptions, | ||
| 97 | writer: anytype, | ||
| 98 | ) !void { | ||
| 99 | _ = options; | ||
| 100 | _ = unused_fmt_string; | ||
| 101 | const thunk = ctx.thunk; | ||
| 102 | const elf_file = ctx.elf_file; | ||
| 103 | try writer.print("@{x} : size({x})\n", .{ thunk.value, thunk.size(elf_file) }); | ||
| 104 | for (thunk.symbols.keys()) |ref| { | ||
| 105 | const sym = elf_file.symbol(ref).?; | ||
| 106 | try writer.print(" {} : {s} : @{x}\n", .{ ref, sym.name(elf_file), sym.value }); | ||
| 107 | } | ||
| 108 | } | ||
| 109 | |||
| 110 | pub const Index = u32; | ||
| 111 | |||
| 112 | const aarch64 = struct { | ||
| 113 | fn write(thunk: Thunk, elf_file: *Elf, writer: anytype) !void { | ||
| 114 | for (thunk.symbols.keys(), 0..) |ref, i| { | ||
| 115 | const sym = elf_file.symbol(ref).?; | ||
| 116 | const saddr = thunk.address(elf_file) + @as(i64, @intCast(i * trampoline_size)); | ||
| 117 | const taddr = sym.address(.{}, elf_file); | ||
| 118 | const pages = try util.calcNumberOfPages(saddr, taddr); | ||
| 119 | try writer.writeInt(u32, Instruction.adrp(.x16, pages).toU32(), .little); | ||
| 120 | const off: u12 = @truncate(@as(u64, @bitCast(taddr))); | ||
| 121 | try writer.writeInt(u32, Instruction.add(.x16, .x16, off, false).toU32(), .little); | ||
| 122 | try writer.writeInt(u32, Instruction.br(.x16).toU32(), .little); | ||
| 123 | } | ||
| 124 | } | ||
| 125 | |||
| 126 | const trampoline_size = 3 * @sizeOf(u32); | ||
| 127 | |||
| 128 | const util = @import("../aarch64.zig"); | ||
| 129 | const Instruction = util.Instruction; | ||
| 130 | }; | ||
| 131 | |||
| 132 | const assert = std.debug.assert; | ||
| 133 | const elf = std.elf; | ||
| 134 | const log = std.log.scoped(.link); | ||
| 135 | const math = std.math; | ||
| 136 | const mem = std.mem; | ||
| 137 | const std = @import("std"); | ||
| 138 | |||
| 139 | const Allocator = mem.Allocator; | ||
| 140 | const Atom = @import("Atom.zig"); | ||
| 141 | const Elf = @import("../Elf.zig"); | ||
| 142 | const Symbol = @import("Symbol.zig"); | ||
| 143 | |||
| 144 | const Thunk = @This(); | ||
src/link/Elf/thunks.zig deleted-234| ... | @@ -1,234 +0,0 @@ | ||
| 1 | pub fn createThunks(shdr: *elf.Elf64_Shdr, shndx: u32, elf_file: *Elf) !void { | ||
| 2 | const gpa = elf_file.base.comp.gpa; | ||
| 3 | const cpu_arch = elf_file.getTarget().cpu.arch; | ||
| 4 | const max_distance = maxAllowedDistance(cpu_arch); | ||
| 5 | const atoms = elf_file.sections.items(.atom_list)[shndx].items; | ||
| 6 | assert(atoms.len > 0); | ||
| 7 | |||
| 8 | for (atoms) |ref| { | ||
| 9 | elf_file.atom(ref).?.value = -1; | ||
| 10 | } | ||
| 11 | |||
| 12 | var i: usize = 0; | ||
| 13 | while (i < atoms.len) { | ||
| 14 | const start = i; | ||
| 15 | const start_atom = elf_file.atom(atoms[start]).?; | ||
| 16 | assert(start_atom.alive); | ||
| 17 | start_atom.value = try advance(shdr, start_atom.size, start_atom.alignment); | ||
| 18 | i += 1; | ||
| 19 | |||
| 20 | while (i < atoms.len) : (i += 1) { | ||
| 21 | const atom = elf_file.atom(atoms[i]).?; | ||
| 22 | assert(atom.alive); | ||
| 23 | if (@as(i64, @intCast(atom.alignment.forward(shdr.sh_size))) - start_atom.value >= max_distance) | ||
| 24 | break; | ||
| 25 | atom.value = try advance(shdr, atom.size, atom.alignment); | ||
| 26 | } | ||
| 27 | |||
| 28 | // Insert a thunk at the group end | ||
| 29 | const thunk_index = try elf_file.addThunk(); | ||
| 30 | const thunk = elf_file.thunk(thunk_index); | ||
| 31 | thunk.output_section_index = shndx; | ||
| 32 | |||
| 33 | // Scan relocs in the group and create trampolines for any unreachable callsite | ||
| 34 | for (atoms[start..i]) |ref| { | ||
| 35 | const atom = elf_file.atom(ref).?; | ||
| 36 | const file = atom.file(elf_file).?; | ||
| 37 | log.debug("atom({}) {s}", .{ ref, atom.name(elf_file) }); | ||
| 38 | for (atom.relocs(elf_file)) |rel| { | ||
| 39 | const is_reachable = switch (cpu_arch) { | ||
| 40 | .aarch64 => aarch64.isReachable(atom, rel, elf_file), | ||
| 41 | .x86_64, .riscv64 => unreachable, | ||
| 42 | else => @panic("unsupported arch"), | ||
| 43 | }; | ||
| 44 | if (is_reachable) continue; | ||
| 45 | const target = file.resolveSymbol(rel.r_sym(), elf_file); | ||
| 46 | try thunk.symbols.put(gpa, target, {}); | ||
| 47 | } | ||
| 48 | atom.addExtra(.{ .thunk = thunk_index }, elf_file); | ||
| 49 | } | ||
| 50 | |||
| 51 | thunk.value = try advance(shdr, thunk.size(elf_file), Atom.Alignment.fromNonzeroByteUnits(2)); | ||
| 52 | |||
| 53 | log.debug("thunk({d}) : {}", .{ thunk_index, thunk.fmt(elf_file) }); | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | fn advance(shdr: *elf.Elf64_Shdr, size: u64, alignment: Atom.Alignment) !i64 { | ||
| 58 | const offset = alignment.forward(shdr.sh_size); | ||
| 59 | const padding = offset - shdr.sh_size; | ||
| 60 | shdr.sh_size += padding + size; | ||
| 61 | shdr.sh_addralign = @max(shdr.sh_addralign, alignment.toByteUnits() orelse 1); | ||
| 62 | return @intCast(offset); | ||
| 63 | } | ||
| 64 | |||
| 65 | /// A branch will need an extender if its target is larger than | ||
| 66 | /// `2^(jump_bits - 1) - margin` where margin is some arbitrary number. | ||
| 67 | fn maxAllowedDistance(cpu_arch: std.Target.Cpu.Arch) u32 { | ||
| 68 | return switch (cpu_arch) { | ||
| 69 | .aarch64 => 0x500_000, | ||
| 70 | .x86_64, .riscv64 => unreachable, | ||
| 71 | else => @panic("unhandled arch"), | ||
| 72 | }; | ||
| 73 | } | ||
| 74 | |||
| 75 | pub const Thunk = struct { | ||
| 76 | value: i64 = 0, | ||
| 77 | output_section_index: u32 = 0, | ||
| 78 | symbols: std.AutoArrayHashMapUnmanaged(Elf.Ref, void) = .{}, | ||
| 79 | output_symtab_ctx: Elf.SymtabCtx = .{}, | ||
| 80 | |||
| 81 | pub fn deinit(thunk: *Thunk, allocator: Allocator) void { | ||
| 82 | thunk.symbols.deinit(allocator); | ||
| 83 | } | ||
| 84 | |||
| 85 | pub fn size(thunk: Thunk, elf_file: *Elf) usize { | ||
| 86 | const cpu_arch = elf_file.getTarget().cpu.arch; | ||
| 87 | return thunk.symbols.keys().len * trampolineSize(cpu_arch); | ||
| 88 | } | ||
| 89 | |||
| 90 | pub fn address(thunk: Thunk, elf_file: *Elf) i64 { | ||
| 91 | const shdr = elf_file.sections.items(.shdr)[thunk.output_section_index]; | ||
| 92 | return @as(i64, @intCast(shdr.sh_addr)) + thunk.value; | ||
| 93 | } | ||
| 94 | |||
| 95 | pub fn targetAddress(thunk: Thunk, ref: Elf.Ref, elf_file: *Elf) i64 { | ||
| 96 | const cpu_arch = elf_file.getTarget().cpu.arch; | ||
| 97 | return thunk.address(elf_file) + @as(i64, @intCast(thunk.symbols.getIndex(ref).? * trampolineSize(cpu_arch))); | ||
| 98 | } | ||
| 99 | |||
| 100 | pub fn write(thunk: Thunk, elf_file: *Elf, writer: anytype) !void { | ||
| 101 | switch (elf_file.getTarget().cpu.arch) { | ||
| 102 | .aarch64 => try aarch64.write(thunk, elf_file, writer), | ||
| 103 | .x86_64, .riscv64 => unreachable, | ||
| 104 | else => @panic("unhandled arch"), | ||
| 105 | } | ||
| 106 | } | ||
| 107 | |||
| 108 | pub fn calcSymtabSize(thunk: *Thunk, elf_file: *Elf) void { | ||
| 109 | thunk.output_symtab_ctx.nlocals = @as(u32, @intCast(thunk.symbols.keys().len)); | ||
| 110 | for (thunk.symbols.keys()) |ref| { | ||
| 111 | const sym = elf_file.symbol(ref).?; | ||
| 112 | thunk.output_symtab_ctx.strsize += @as(u32, @intCast(sym.name(elf_file).len + "$thunk".len + 1)); | ||
| 113 | } | ||
| 114 | } | ||
| 115 | |||
| 116 | pub fn writeSymtab(thunk: Thunk, elf_file: *Elf) void { | ||
| 117 | const cpu_arch = elf_file.getTarget().cpu.arch; | ||
| 118 | for (thunk.symbols.keys(), thunk.output_symtab_ctx.ilocal..) |ref, ilocal| { | ||
| 119 | const sym = elf_file.symbol(ref).?; | ||
| 120 | const st_name = @as(u32, @intCast(elf_file.strtab.items.len)); | ||
| 121 | elf_file.strtab.appendSliceAssumeCapacity(sym.name(elf_file)); | ||
| 122 | elf_file.strtab.appendSliceAssumeCapacity("$thunk"); | ||
| 123 | elf_file.strtab.appendAssumeCapacity(0); | ||
| 124 | elf_file.symtab.items[ilocal] = .{ | ||
| 125 | .st_name = st_name, | ||
| 126 | .st_info = elf.STT_FUNC, | ||
| 127 | .st_other = 0, | ||
| 128 | .st_shndx = @intCast(thunk.output_section_index), | ||
| 129 | .st_value = @intCast(thunk.targetAddress(ref, elf_file)), | ||
| 130 | .st_size = trampolineSize(cpu_arch), | ||
| 131 | }; | ||
| 132 | } | ||
| 133 | } | ||
| 134 | |||
| 135 | fn trampolineSize(cpu_arch: std.Target.Cpu.Arch) usize { | ||
| 136 | return switch (cpu_arch) { | ||
| 137 | .aarch64 => aarch64.trampoline_size, | ||
| 138 | .x86_64, .riscv64 => unreachable, | ||
| 139 | else => @panic("unhandled arch"), | ||
| 140 | }; | ||
| 141 | } | ||
| 142 | |||
| 143 | pub fn format( | ||
| 144 | thunk: Thunk, | ||
| 145 | comptime unused_fmt_string: []const u8, | ||
| 146 | options: std.fmt.FormatOptions, | ||
| 147 | writer: anytype, | ||
| 148 | ) !void { | ||
| 149 | _ = thunk; | ||
| 150 | _ = unused_fmt_string; | ||
| 151 | _ = options; | ||
| 152 | _ = writer; | ||
| 153 | @compileError("do not format Thunk directly"); | ||
| 154 | } | ||
| 155 | |||
| 156 | pub fn fmt(thunk: Thunk, elf_file: *Elf) std.fmt.Formatter(format2) { | ||
| 157 | return .{ .data = .{ | ||
| 158 | .thunk = thunk, | ||
| 159 | .elf_file = elf_file, | ||
| 160 | } }; | ||
| 161 | } | ||
| 162 | |||
| 163 | const FormatContext = struct { | ||
| 164 | thunk: Thunk, | ||
| 165 | elf_file: *Elf, | ||
| 166 | }; | ||
| 167 | |||
| 168 | fn format2( | ||
| 169 | ctx: FormatContext, | ||
| 170 | comptime unused_fmt_string: []const u8, | ||
| 171 | options: std.fmt.FormatOptions, | ||
| 172 | writer: anytype, | ||
| 173 | ) !void { | ||
| 174 | _ = options; | ||
| 175 | _ = unused_fmt_string; | ||
| 176 | const thunk = ctx.thunk; | ||
| 177 | const elf_file = ctx.elf_file; | ||
| 178 | try writer.print("@{x} : size({x})\n", .{ thunk.value, thunk.size(elf_file) }); | ||
| 179 | for (thunk.symbols.keys()) |ref| { | ||
| 180 | const sym = elf_file.symbol(ref).?; | ||
| 181 | try writer.print(" {} : {s} : @{x}\n", .{ ref, sym.name(elf_file), sym.value }); | ||
| 182 | } | ||
| 183 | } | ||
| 184 | |||
| 185 | pub const Index = u32; | ||
| 186 | }; | ||
| 187 | |||
| 188 | const aarch64 = struct { | ||
| 189 | fn isReachable(atom: *const Atom, rel: elf.Elf64_Rela, elf_file: *Elf) bool { | ||
| 190 | const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_type()); | ||
| 191 | if (r_type != .CALL26 and r_type != .JUMP26) return true; | ||
| 192 | const file = atom.file(elf_file).?; | ||
| 193 | const target_ref = file.resolveSymbol(rel.r_sym(), elf_file); | ||
| 194 | const target = elf_file.symbol(target_ref).?; | ||
| 195 | if (target.flags.has_plt) return false; | ||
| 196 | if (atom.output_section_index != target.output_section_index) return false; | ||
| 197 | const target_atom = target.atom(elf_file).?; | ||
| 198 | if (target_atom.value == -1) return false; | ||
| 199 | const saddr = atom.address(elf_file) + @as(i64, @intCast(rel.r_offset)); | ||
| 200 | const taddr = target.address(.{}, elf_file); | ||
| 201 | _ = math.cast(i28, taddr + rel.r_addend - saddr) orelse return false; | ||
| 202 | return true; | ||
| 203 | } | ||
| 204 | |||
| 205 | fn write(thunk: Thunk, elf_file: *Elf, writer: anytype) !void { | ||
| 206 | for (thunk.symbols.keys(), 0..) |ref, i| { | ||
| 207 | const sym = elf_file.symbol(ref).?; | ||
| 208 | const saddr = thunk.address(elf_file) + @as(i64, @intCast(i * trampoline_size)); | ||
| 209 | const taddr = sym.address(.{}, elf_file); | ||
| 210 | const pages = try util.calcNumberOfPages(saddr, taddr); | ||
| 211 | try writer.writeInt(u32, Instruction.adrp(.x16, pages).toU32(), .little); | ||
| 212 | const off: u12 = @truncate(@as(u64, @bitCast(taddr))); | ||
| 213 | try writer.writeInt(u32, Instruction.add(.x16, .x16, off, false).toU32(), .little); | ||
| 214 | try writer.writeInt(u32, Instruction.br(.x16).toU32(), .little); | ||
| 215 | } | ||
| 216 | } | ||
| 217 | |||
| 218 | const trampoline_size = 3 * @sizeOf(u32); | ||
| 219 | |||
| 220 | const util = @import("../aarch64.zig"); | ||
| 221 | const Instruction = util.Instruction; | ||
| 222 | }; | ||
| 223 | |||
| 224 | const assert = std.debug.assert; | ||
| 225 | const elf = std.elf; | ||
| 226 | const log = std.log.scoped(.link); | ||
| 227 | const math = std.math; | ||
| 228 | const mem = std.mem; | ||
| 229 | const std = @import("std"); | ||
| 230 | |||
| 231 | const Allocator = mem.Allocator; | ||
| 232 | const Atom = @import("Atom.zig"); | ||
| 233 | const Elf = @import("../Elf.zig"); | ||
| 234 | const Symbol = @import("Symbol.zig"); | ||
src/link/MachO.zig+111-19| ... | @@ -64,10 +64,10 @@ stubs_helper: StubsHelperSection = .{}, | ... | @@ -64,10 +64,10 @@ stubs_helper: StubsHelperSection = .{}, |
| 64 | objc_stubs: ObjcStubsSection = .{}, | 64 | objc_stubs: ObjcStubsSection = .{}, |
| 65 | la_symbol_ptr: LaSymbolPtrSection = .{}, | 65 | la_symbol_ptr: LaSymbolPtrSection = .{}, |
| 66 | tlv_ptr: TlvPtrSection = .{}, | 66 | tlv_ptr: TlvPtrSection = .{}, |
| 67 | rebase: Rebase = .{}, | 67 | rebase_section: Rebase = .{}, |
| 68 | bind: Bind = .{}, | 68 | bind_section: Bind = .{}, |
| 69 | weak_bind: WeakBind = .{}, | 69 | weak_bind_section: WeakBind = .{}, |
| 70 | lazy_bind: LazyBind = .{}, | 70 | lazy_bind_section: LazyBind = .{}, |
| 71 | export_trie: ExportTrie = .{}, | 71 | export_trie: ExportTrie = .{}, |
| 72 | unwind_info: UnwindInfo = .{}, | 72 | unwind_info: UnwindInfo = .{}, |
| 73 | data_in_code: DataInCode = .{}, | 73 | data_in_code: DataInCode = .{}, |
| ... | @@ -324,10 +324,10 @@ pub fn deinit(self: *MachO) void { | ... | @@ -324,10 +324,10 @@ pub fn deinit(self: *MachO) void { |
| 324 | self.stubs.deinit(gpa); | 324 | self.stubs.deinit(gpa); |
| 325 | self.objc_stubs.deinit(gpa); | 325 | self.objc_stubs.deinit(gpa); |
| 326 | self.tlv_ptr.deinit(gpa); | 326 | self.tlv_ptr.deinit(gpa); |
| 327 | self.rebase.deinit(gpa); | 327 | self.rebase_section.deinit(gpa); |
| 328 | self.bind.deinit(gpa); | 328 | self.bind_section.deinit(gpa); |
| 329 | self.weak_bind.deinit(gpa); | 329 | self.weak_bind_section.deinit(gpa); |
| 330 | self.lazy_bind.deinit(gpa); | 330 | self.lazy_bind_section.deinit(gpa); |
| 331 | self.export_trie.deinit(gpa); | 331 | self.export_trie.deinit(gpa); |
| 332 | self.unwind_info.deinit(gpa); | 332 | self.unwind_info.deinit(gpa); |
| 333 | self.data_in_code.deinit(gpa); | 333 | self.data_in_code.deinit(gpa); |
| ... | @@ -2005,7 +2005,7 @@ fn calcSectionSizeWorker(self: *MachO, sect_id: u8) void { | ... | @@ -2005,7 +2005,7 @@ fn calcSectionSizeWorker(self: *MachO, sect_id: u8) void { |
| 2005 | fn createThunksWorker(self: *MachO, sect_id: u8) void { | 2005 | fn createThunksWorker(self: *MachO, sect_id: u8) void { |
| 2006 | const tracy = trace(@src()); | 2006 | const tracy = trace(@src()); |
| 2007 | defer tracy.end(); | 2007 | defer tracy.end(); |
| 2008 | thunks.createThunks(sect_id, self) catch |err| { | 2008 | self.createThunks(sect_id) catch |err| { |
| 2009 | const header = self.sections.items(.header)[sect_id]; | 2009 | const header = self.sections.items(.header)[sect_id]; |
| 2010 | self.reportUnexpectedError("failed to create thunks and calculate size of section '{s},{s}': {s}", .{ | 2010 | self.reportUnexpectedError("failed to create thunks and calculate size of section '{s},{s}': {s}", .{ |
| 2011 | header.segName(), | 2011 | header.segName(), |
| ... | @@ -2562,7 +2562,7 @@ fn updateLazyBindSizeWorker(self: *MachO) void { | ... | @@ -2562,7 +2562,7 @@ fn updateLazyBindSizeWorker(self: *MachO) void { |
| 2562 | defer tracy.end(); | 2562 | defer tracy.end(); |
| 2563 | const doWork = struct { | 2563 | const doWork = struct { |
| 2564 | fn doWork(macho_file: *MachO) !void { | 2564 | fn doWork(macho_file: *MachO) !void { |
| 2565 | try macho_file.lazy_bind.updateSize(macho_file); | 2565 | try macho_file.lazy_bind_section.updateSize(macho_file); |
| 2566 | const sect_id = macho_file.stubs_helper_sect_index.?; | 2566 | const sect_id = macho_file.stubs_helper_sect_index.?; |
| 2567 | const out = &macho_file.sections.items(.out)[sect_id]; | 2567 | const out = &macho_file.sections.items(.out)[sect_id]; |
| 2568 | var stream = std.io.fixedBufferStream(out.items); | 2568 | var stream = std.io.fixedBufferStream(out.items); |
| ... | @@ -2585,9 +2585,9 @@ pub fn updateLinkeditSizeWorker(self: *MachO, tag: enum { | ... | @@ -2585,9 +2585,9 @@ pub fn updateLinkeditSizeWorker(self: *MachO, tag: enum { |
| 2585 | data_in_code, | 2585 | data_in_code, |
| 2586 | }) void { | 2586 | }) void { |
| 2587 | const res = switch (tag) { | 2587 | const res = switch (tag) { |
| 2588 | .rebase => self.rebase.updateSize(self), | 2588 | .rebase => self.rebase_section.updateSize(self), |
| 2589 | .bind => self.bind.updateSize(self), | 2589 | .bind => self.bind_section.updateSize(self), |
| 2590 | .weak_bind => self.weak_bind.updateSize(self), | 2590 | .weak_bind => self.weak_bind_section.updateSize(self), |
| 2591 | .export_trie => self.export_trie.updateSize(self), | 2591 | .export_trie => self.export_trie.updateSize(self), |
| 2592 | .data_in_code => self.data_in_code.updateSize(self), | 2592 | .data_in_code => self.data_in_code.updateSize(self), |
| 2593 | }; | 2593 | }; |
| ... | @@ -2640,13 +2640,13 @@ fn writeDyldInfo(self: *MachO) !void { | ... | @@ -2640,13 +2640,13 @@ fn writeDyldInfo(self: *MachO) !void { |
| 2640 | var stream = std.io.fixedBufferStream(buffer); | 2640 | var stream = std.io.fixedBufferStream(buffer); |
| 2641 | const writer = stream.writer(); | 2641 | const writer = stream.writer(); |
| 2642 | 2642 | ||
| 2643 | try self.rebase.write(writer); | 2643 | try self.rebase_section.write(writer); |
| 2644 | try stream.seekTo(cmd.bind_off - base_off); | 2644 | try stream.seekTo(cmd.bind_off - base_off); |
| 2645 | try self.bind.write(writer); | 2645 | try self.bind_section.write(writer); |
| 2646 | try stream.seekTo(cmd.weak_bind_off - base_off); | 2646 | try stream.seekTo(cmd.weak_bind_off - base_off); |
| 2647 | try self.weak_bind.write(writer); | 2647 | try self.weak_bind_section.write(writer); |
| 2648 | try stream.seekTo(cmd.lazy_bind_off - base_off); | 2648 | try stream.seekTo(cmd.lazy_bind_off - base_off); |
| 2649 | try self.lazy_bind.write(writer); | 2649 | try self.lazy_bind_section.write(writer); |
| 2650 | try stream.seekTo(cmd.export_off - base_off); | 2650 | try stream.seekTo(cmd.export_off - base_off); |
| 2651 | try self.export_trie.write(writer); | 2651 | try self.export_trie.write(writer); |
| 2652 | try self.base.file.?.pwriteAll(buffer, cmd.rebase_off); | 2652 | try self.base.file.?.pwriteAll(buffer, cmd.rebase_off); |
| ... | @@ -4602,7 +4602,6 @@ const load_commands = @import("MachO/load_commands.zig"); | ... | @@ -4602,7 +4602,6 @@ const load_commands = @import("MachO/load_commands.zig"); |
| 4602 | const relocatable = @import("MachO/relocatable.zig"); | 4602 | const relocatable = @import("MachO/relocatable.zig"); |
| 4603 | const tapi = @import("tapi.zig"); | 4603 | const tapi = @import("tapi.zig"); |
| 4604 | const target_util = @import("../target.zig"); | 4604 | const target_util = @import("../target.zig"); |
| 4605 | const thunks = @import("MachO/thunks.zig"); | ||
| 4606 | const trace = @import("../tracy.zig").trace; | 4605 | const trace = @import("../tracy.zig").trace; |
| 4607 | const synthetic = @import("MachO/synthetic.zig"); | 4606 | const synthetic = @import("MachO/synthetic.zig"); |
| 4608 | 4607 | ||
| ... | @@ -4641,7 +4640,7 @@ const StringTable = @import("StringTable.zig"); | ... | @@ -4641,7 +4640,7 @@ const StringTable = @import("StringTable.zig"); |
| 4641 | const StubsSection = synthetic.StubsSection; | 4640 | const StubsSection = synthetic.StubsSection; |
| 4642 | const StubsHelperSection = synthetic.StubsHelperSection; | 4641 | const StubsHelperSection = synthetic.StubsHelperSection; |
| 4643 | const Symbol = @import("MachO/Symbol.zig"); | 4642 | const Symbol = @import("MachO/Symbol.zig"); |
| 4644 | const Thunk = thunks.Thunk; | 4643 | const Thunk = @import("MachO/Thunk.zig"); |
| 4645 | const TlvPtrSection = synthetic.TlvPtrSection; | 4644 | const TlvPtrSection = synthetic.TlvPtrSection; |
| 4646 | const Value = @import("../Value.zig"); | 4645 | const Value = @import("../Value.zig"); |
| 4647 | const UnwindInfo = @import("MachO/UnwindInfo.zig"); | 4646 | const UnwindInfo = @import("MachO/UnwindInfo.zig"); |
| ... | @@ -5292,3 +5291,96 @@ pub const KernE = enum(u32) { | ... | @@ -5292,3 +5291,96 @@ pub const KernE = enum(u32) { |
| 5292 | NOT_FOUND = 56, | 5291 | NOT_FOUND = 56, |
| 5293 | _, | 5292 | _, |
| 5294 | }; | 5293 | }; |
| 5294 | |||
| 5295 | fn createThunks(macho_file: *MachO, sect_id: u8) !void { | ||
| 5296 | const tracy = trace(@src()); | ||
| 5297 | defer tracy.end(); | ||
| 5298 | |||
| 5299 | const gpa = macho_file.base.comp.gpa; | ||
| 5300 | const slice = macho_file.sections.slice(); | ||
| 5301 | const header = &slice.items(.header)[sect_id]; | ||
| 5302 | const thnks = &slice.items(.thunks)[sect_id]; | ||
| 5303 | const atoms = slice.items(.atoms)[sect_id].items; | ||
| 5304 | assert(atoms.len > 0); | ||
| 5305 | |||
| 5306 | for (atoms) |ref| { | ||
| 5307 | ref.getAtom(macho_file).?.value = @bitCast(@as(i64, -1)); | ||
| 5308 | } | ||
| 5309 | |||
| 5310 | var i: usize = 0; | ||
| 5311 | while (i < atoms.len) { | ||
| 5312 | const start = i; | ||
| 5313 | const start_atom = atoms[start].getAtom(macho_file).?; | ||
| 5314 | assert(start_atom.isAlive()); | ||
| 5315 | start_atom.value = advanceSection(header, start_atom.size, start_atom.alignment); | ||
| 5316 | i += 1; | ||
| 5317 | |||
| 5318 | while (i < atoms.len and | ||
| 5319 | header.size - start_atom.value < max_allowed_distance) : (i += 1) | ||
| 5320 | { | ||
| 5321 | const atom = atoms[i].getAtom(macho_file).?; | ||
| 5322 | assert(atom.isAlive()); | ||
| 5323 | atom.value = advanceSection(header, atom.size, atom.alignment); | ||
| 5324 | } | ||
| 5325 | |||
| 5326 | // Insert a thunk at the group end | ||
| 5327 | const thunk_index = try macho_file.addThunk(); | ||
| 5328 | const thunk = macho_file.getThunk(thunk_index); | ||
| 5329 | thunk.out_n_sect = sect_id; | ||
| 5330 | try thnks.append(gpa, thunk_index); | ||
| 5331 | |||
| 5332 | // Scan relocs in the group and create trampolines for any unreachable callsite | ||
| 5333 | try scanThunkRelocs(thunk_index, gpa, atoms[start..i], macho_file); | ||
| 5334 | thunk.value = advanceSection(header, thunk.size(), .@"4"); | ||
| 5335 | |||
| 5336 | log.debug("thunk({d}) : {}", .{ thunk_index, thunk.fmt(macho_file) }); | ||
| 5337 | } | ||
| 5338 | } | ||
| 5339 | |||
| 5340 | fn advanceSection(sect: *macho.section_64, adv_size: u64, alignment: Atom.Alignment) u64 { | ||
| 5341 | const offset = alignment.forward(sect.size); | ||
| 5342 | const padding = offset - sect.size; | ||
| 5343 | sect.size += padding + adv_size; | ||
| 5344 | sect.@"align" = @max(sect.@"align", alignment.toLog2Units()); | ||
| 5345 | return offset; | ||
| 5346 | } | ||
| 5347 | |||
| 5348 | fn scanThunkRelocs(thunk_index: Thunk.Index, gpa: Allocator, atoms: []const MachO.Ref, macho_file: *MachO) !void { | ||
| 5349 | const tracy = trace(@src()); | ||
| 5350 | defer tracy.end(); | ||
| 5351 | |||
| 5352 | const thunk = macho_file.getThunk(thunk_index); | ||
| 5353 | |||
| 5354 | for (atoms) |ref| { | ||
| 5355 | const atom = ref.getAtom(macho_file).?; | ||
| 5356 | log.debug("atom({d}) {s}", .{ atom.atom_index, atom.getName(macho_file) }); | ||
| 5357 | for (atom.getRelocs(macho_file)) |rel| { | ||
| 5358 | if (rel.type != .branch) continue; | ||
| 5359 | if (isReachable(atom, rel, macho_file)) continue; | ||
| 5360 | try thunk.symbols.put(gpa, rel.getTargetSymbolRef(atom.*, macho_file), {}); | ||
| 5361 | } | ||
| 5362 | atom.addExtra(.{ .thunk = thunk_index }, macho_file); | ||
| 5363 | } | ||
| 5364 | } | ||
| 5365 | |||
| 5366 | fn isReachable(atom: *const Atom, rel: Relocation, macho_file: *MachO) bool { | ||
| 5367 | const target = rel.getTargetSymbol(atom.*, macho_file); | ||
| 5368 | if (target.getSectionFlags().stubs or target.getSectionFlags().objc_stubs) return false; | ||
| 5369 | if (atom.out_n_sect != target.getOutputSectionIndex(macho_file)) return false; | ||
| 5370 | const target_atom = target.getAtom(macho_file).?; | ||
| 5371 | if (target_atom.value == @as(u64, @bitCast(@as(i64, -1)))) return false; | ||
| 5372 | const saddr = @as(i64, @intCast(atom.getAddress(macho_file))) + @as(i64, @intCast(rel.offset - atom.off)); | ||
| 5373 | const taddr: i64 = @intCast(rel.getTargetAddress(atom.*, macho_file)); | ||
| 5374 | _ = math.cast(i28, taddr + rel.addend - saddr) orelse return false; | ||
| 5375 | return true; | ||
| 5376 | } | ||
| 5377 | |||
| 5378 | /// Branch instruction has 26 bits immediate but is 4 byte aligned. | ||
| 5379 | const jump_bits = @bitSizeOf(i28); | ||
| 5380 | const max_distance = (1 << (jump_bits - 1)); | ||
| 5381 | |||
| 5382 | /// A branch will need an extender if its target is larger than | ||
| 5383 | /// `2^(jump_bits - 1) - margin` where margin is some arbitrary number. | ||
| 5384 | /// mold uses 5MiB margin, while ld64 uses 4MiB margin. We will follow mold | ||
| 5385 | /// and assume margin to be 5MiB. | ||
| 5386 | const max_allowed_distance = max_distance - 0x500_000; |
src/link/MachO/Atom.zig+1-1| ... | @@ -1220,6 +1220,6 @@ const MachO = @import("../MachO.zig"); | ... | @@ -1220,6 +1220,6 @@ const MachO = @import("../MachO.zig"); |
| 1220 | const Object = @import("Object.zig"); | 1220 | const Object = @import("Object.zig"); |
| 1221 | const Relocation = @import("Relocation.zig"); | 1221 | const Relocation = @import("Relocation.zig"); |
| 1222 | const Symbol = @import("Symbol.zig"); | 1222 | const Symbol = @import("Symbol.zig"); |
| 1223 | const Thunk = @import("thunks.zig").Thunk; | 1223 | const Thunk = @import("Thunk.zig"); |
| 1224 | const UnwindInfo = @import("UnwindInfo.zig"); | 1224 | const UnwindInfo = @import("UnwindInfo.zig"); |
| 1225 | const dev = @import("../../dev.zig"); | 1225 | const dev = @import("../../dev.zig"); |
src/link/MachO/Thunk.zig created+125| ... | @@ -0,0 +1,125 @@ | ||
| 1 | value: u64 = 0, | ||
| 2 | out_n_sect: u8 = 0, | ||
| 3 | symbols: std.AutoArrayHashMapUnmanaged(MachO.Ref, void) = .{}, | ||
| 4 | output_symtab_ctx: MachO.SymtabCtx = .{}, | ||
| 5 | |||
| 6 | pub fn deinit(thunk: *Thunk, allocator: Allocator) void { | ||
| 7 | thunk.symbols.deinit(allocator); | ||
| 8 | } | ||
| 9 | |||
| 10 | pub fn size(thunk: Thunk) usize { | ||
| 11 | return thunk.symbols.keys().len * trampoline_size; | ||
| 12 | } | ||
| 13 | |||
| 14 | pub fn getAddress(thunk: Thunk, macho_file: *MachO) u64 { | ||
| 15 | const header = macho_file.sections.items(.header)[thunk.out_n_sect]; | ||
| 16 | return header.addr + thunk.value; | ||
| 17 | } | ||
| 18 | |||
| 19 | pub fn getTargetAddress(thunk: Thunk, ref: MachO.Ref, macho_file: *MachO) u64 { | ||
| 20 | return thunk.getAddress(macho_file) + thunk.symbols.getIndex(ref).? * trampoline_size; | ||
| 21 | } | ||
| 22 | |||
| 23 | pub fn write(thunk: Thunk, macho_file: *MachO, writer: anytype) !void { | ||
| 24 | for (thunk.symbols.keys(), 0..) |ref, i| { | ||
| 25 | const sym = ref.getSymbol(macho_file).?; | ||
| 26 | const saddr = thunk.getAddress(macho_file) + i * trampoline_size; | ||
| 27 | const taddr = sym.getAddress(.{}, macho_file); | ||
| 28 | const pages = try aarch64.calcNumberOfPages(@intCast(saddr), @intCast(taddr)); | ||
| 29 | try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little); | ||
| 30 | const off: u12 = @truncate(taddr); | ||
| 31 | try writer.writeInt(u32, aarch64.Instruction.add(.x16, .x16, off, false).toU32(), .little); | ||
| 32 | try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little); | ||
| 33 | } | ||
| 34 | } | ||
| 35 | |||
| 36 | pub fn calcSymtabSize(thunk: *Thunk, macho_file: *MachO) void { | ||
| 37 | thunk.output_symtab_ctx.nlocals = @as(u32, @intCast(thunk.symbols.keys().len)); | ||
| 38 | for (thunk.symbols.keys()) |ref| { | ||
| 39 | const sym = ref.getSymbol(macho_file).?; | ||
| 40 | thunk.output_symtab_ctx.strsize += @as(u32, @intCast(sym.getName(macho_file).len + "__thunk".len + 1)); | ||
| 41 | } | ||
| 42 | } | ||
| 43 | |||
| 44 | pub fn writeSymtab(thunk: Thunk, macho_file: *MachO, ctx: anytype) void { | ||
| 45 | var n_strx = thunk.output_symtab_ctx.stroff; | ||
| 46 | for (thunk.symbols.keys(), thunk.output_symtab_ctx.ilocal..) |ref, ilocal| { | ||
| 47 | const sym = ref.getSymbol(macho_file).?; | ||
| 48 | const name = sym.getName(macho_file); | ||
| 49 | const out_sym = &ctx.symtab.items[ilocal]; | ||
| 50 | out_sym.n_strx = n_strx; | ||
| 51 | @memcpy(ctx.strtab.items[n_strx..][0..name.len], name); | ||
| 52 | n_strx += @intCast(name.len); | ||
| 53 | @memcpy(ctx.strtab.items[n_strx..][0.."__thunk".len], "__thunk"); | ||
| 54 | n_strx += @intCast("__thunk".len); | ||
| 55 | ctx.strtab.items[n_strx] = 0; | ||
| 56 | n_strx += 1; | ||
| 57 | out_sym.n_type = macho.N_SECT; | ||
| 58 | out_sym.n_sect = @intCast(thunk.out_n_sect + 1); | ||
| 59 | out_sym.n_value = @intCast(thunk.getTargetAddress(ref, macho_file)); | ||
| 60 | out_sym.n_desc = 0; | ||
| 61 | } | ||
| 62 | } | ||
| 63 | |||
| 64 | pub fn format( | ||
| 65 | thunk: Thunk, | ||
| 66 | comptime unused_fmt_string: []const u8, | ||
| 67 | options: std.fmt.FormatOptions, | ||
| 68 | writer: anytype, | ||
| 69 | ) !void { | ||
| 70 | _ = thunk; | ||
| 71 | _ = unused_fmt_string; | ||
| 72 | _ = options; | ||
| 73 | _ = writer; | ||
| 74 | @compileError("do not format Thunk directly"); | ||
| 75 | } | ||
| 76 | |||
| 77 | pub fn fmt(thunk: Thunk, macho_file: *MachO) std.fmt.Formatter(format2) { | ||
| 78 | return .{ .data = .{ | ||
| 79 | .thunk = thunk, | ||
| 80 | .macho_file = macho_file, | ||
| 81 | } }; | ||
| 82 | } | ||
| 83 | |||
| 84 | const FormatContext = struct { | ||
| 85 | thunk: Thunk, | ||
| 86 | macho_file: *MachO, | ||
| 87 | }; | ||
| 88 | |||
| 89 | fn format2( | ||
| 90 | ctx: FormatContext, | ||
| 91 | comptime unused_fmt_string: []const u8, | ||
| 92 | options: std.fmt.FormatOptions, | ||
| 93 | writer: anytype, | ||
| 94 | ) !void { | ||
| 95 | _ = options; | ||
| 96 | _ = unused_fmt_string; | ||
| 97 | const thunk = ctx.thunk; | ||
| 98 | const macho_file = ctx.macho_file; | ||
| 99 | try writer.print("@{x} : size({x})\n", .{ thunk.value, thunk.size() }); | ||
| 100 | for (thunk.symbols.keys()) |ref| { | ||
| 101 | const sym = ref.getSymbol(macho_file).?; | ||
| 102 | try writer.print(" {} : {s} : @{x}\n", .{ ref, sym.getName(macho_file), sym.value }); | ||
| 103 | } | ||
| 104 | } | ||
| 105 | |||
| 106 | const trampoline_size = 3 * @sizeOf(u32); | ||
| 107 | |||
| 108 | pub const Index = u32; | ||
| 109 | |||
| 110 | const aarch64 = @import("../aarch64.zig"); | ||
| 111 | const assert = std.debug.assert; | ||
| 112 | const log = std.log.scoped(.link); | ||
| 113 | const macho = std.macho; | ||
| 114 | const math = std.math; | ||
| 115 | const mem = std.mem; | ||
| 116 | const std = @import("std"); | ||
| 117 | const trace = @import("../../tracy.zig").trace; | ||
| 118 | |||
| 119 | const Allocator = mem.Allocator; | ||
| 120 | const Atom = @import("Atom.zig"); | ||
| 121 | const MachO = @import("../MachO.zig"); | ||
| 122 | const Relocation = @import("Relocation.zig"); | ||
| 123 | const Symbol = @import("Symbol.zig"); | ||
| 124 | |||
| 125 | const Thunk = @This(); | ||
src/link/MachO/synthetic.zig+1-1| ... | @@ -204,7 +204,7 @@ pub const StubsHelperSection = struct { | ... | @@ -204,7 +204,7 @@ pub const StubsHelperSection = struct { |
| 204 | for (macho_file.stubs.symbols.items) |ref| { | 204 | for (macho_file.stubs.symbols.items) |ref| { |
| 205 | const sym = ref.getSymbol(macho_file).?; | 205 | const sym = ref.getSymbol(macho_file).?; |
| 206 | if (sym.flags.weak) continue; | 206 | if (sym.flags.weak) continue; |
| 207 | const offset = macho_file.lazy_bind.offsets.items[idx]; | 207 | const offset = macho_file.lazy_bind_section.offsets.items[idx]; |
| 208 | const source: i64 = @intCast(sect.addr + preamble_size + entry_size * idx); | 208 | const source: i64 = @intCast(sect.addr + preamble_size + entry_size * idx); |
| 209 | const target: i64 = @intCast(sect.addr); | 209 | const target: i64 = @intCast(sect.addr); |
| 210 | switch (cpu_arch) { | 210 | switch (cpu_arch) { |
src/link/MachO/thunks.zig deleted-218| ... | @@ -1,218 +0,0 @@ | ||
| 1 | pub fn createThunks(sect_id: u8, macho_file: *MachO) !void { | ||
| 2 | const tracy = trace(@src()); | ||
| 3 | defer tracy.end(); | ||
| 4 | |||
| 5 | const gpa = macho_file.base.comp.gpa; | ||
| 6 | const slice = macho_file.sections.slice(); | ||
| 7 | const header = &slice.items(.header)[sect_id]; | ||
| 8 | const thnks = &slice.items(.thunks)[sect_id]; | ||
| 9 | const atoms = slice.items(.atoms)[sect_id].items; | ||
| 10 | assert(atoms.len > 0); | ||
| 11 | |||
| 12 | for (atoms) |ref| { | ||
| 13 | ref.getAtom(macho_file).?.value = @bitCast(@as(i64, -1)); | ||
| 14 | } | ||
| 15 | |||
| 16 | var i: usize = 0; | ||
| 17 | while (i < atoms.len) { | ||
| 18 | const start = i; | ||
| 19 | const start_atom = atoms[start].getAtom(macho_file).?; | ||
| 20 | assert(start_atom.isAlive()); | ||
| 21 | start_atom.value = advance(header, start_atom.size, start_atom.alignment); | ||
| 22 | i += 1; | ||
| 23 | |||
| 24 | while (i < atoms.len and | ||
| 25 | header.size - start_atom.value < max_allowed_distance) : (i += 1) | ||
| 26 | { | ||
| 27 | const atom = atoms[i].getAtom(macho_file).?; | ||
| 28 | assert(atom.isAlive()); | ||
| 29 | atom.value = advance(header, atom.size, atom.alignment); | ||
| 30 | } | ||
| 31 | |||
| 32 | // Insert a thunk at the group end | ||
| 33 | const thunk_index = try macho_file.addThunk(); | ||
| 34 | const thunk = macho_file.getThunk(thunk_index); | ||
| 35 | thunk.out_n_sect = sect_id; | ||
| 36 | try thnks.append(gpa, thunk_index); | ||
| 37 | |||
| 38 | // Scan relocs in the group and create trampolines for any unreachable callsite | ||
| 39 | try scanRelocs(thunk_index, gpa, atoms[start..i], macho_file); | ||
| 40 | thunk.value = advance(header, thunk.size(), .@"4"); | ||
| 41 | |||
| 42 | log.debug("thunk({d}) : {}", .{ thunk_index, thunk.fmt(macho_file) }); | ||
| 43 | } | ||
| 44 | } | ||
| 45 | |||
| 46 | fn advance(sect: *macho.section_64, size: u64, alignment: Atom.Alignment) u64 { | ||
| 47 | const offset = alignment.forward(sect.size); | ||
| 48 | const padding = offset - sect.size; | ||
| 49 | sect.size += padding + size; | ||
| 50 | sect.@"align" = @max(sect.@"align", alignment.toLog2Units()); | ||
| 51 | return offset; | ||
| 52 | } | ||
| 53 | |||
| 54 | fn scanRelocs(thunk_index: Thunk.Index, gpa: Allocator, atoms: []const MachO.Ref, macho_file: *MachO) !void { | ||
| 55 | const tracy = trace(@src()); | ||
| 56 | defer tracy.end(); | ||
| 57 | |||
| 58 | const thunk = macho_file.getThunk(thunk_index); | ||
| 59 | |||
| 60 | for (atoms) |ref| { | ||
| 61 | const atom = ref.getAtom(macho_file).?; | ||
| 62 | log.debug("atom({d}) {s}", .{ atom.atom_index, atom.getName(macho_file) }); | ||
| 63 | for (atom.getRelocs(macho_file)) |rel| { | ||
| 64 | if (rel.type != .branch) continue; | ||
| 65 | if (isReachable(atom, rel, macho_file)) continue; | ||
| 66 | try thunk.symbols.put(gpa, rel.getTargetSymbolRef(atom.*, macho_file), {}); | ||
| 67 | } | ||
| 68 | atom.addExtra(.{ .thunk = thunk_index }, macho_file); | ||
| 69 | } | ||
| 70 | } | ||
| 71 | |||
| 72 | fn isReachable(atom: *const Atom, rel: Relocation, macho_file: *MachO) bool { | ||
| 73 | const target = rel.getTargetSymbol(atom.*, macho_file); | ||
| 74 | if (target.getSectionFlags().stubs or target.getSectionFlags().objc_stubs) return false; | ||
| 75 | if (atom.out_n_sect != target.getOutputSectionIndex(macho_file)) return false; | ||
| 76 | const target_atom = target.getAtom(macho_file).?; | ||
| 77 | if (target_atom.value == @as(u64, @bitCast(@as(i64, -1)))) return false; | ||
| 78 | const saddr = @as(i64, @intCast(atom.getAddress(macho_file))) + @as(i64, @intCast(rel.offset - atom.off)); | ||
| 79 | const taddr: i64 = @intCast(rel.getTargetAddress(atom.*, macho_file)); | ||
| 80 | _ = math.cast(i28, taddr + rel.addend - saddr) orelse return false; | ||
| 81 | return true; | ||
| 82 | } | ||
| 83 | |||
| 84 | pub const Thunk = struct { | ||
| 85 | value: u64 = 0, | ||
| 86 | out_n_sect: u8 = 0, | ||
| 87 | symbols: std.AutoArrayHashMapUnmanaged(MachO.Ref, void) = .{}, | ||
| 88 | output_symtab_ctx: MachO.SymtabCtx = .{}, | ||
| 89 | |||
| 90 | pub fn deinit(thunk: *Thunk, allocator: Allocator) void { | ||
| 91 | thunk.symbols.deinit(allocator); | ||
| 92 | } | ||
| 93 | |||
| 94 | pub fn size(thunk: Thunk) usize { | ||
| 95 | return thunk.symbols.keys().len * trampoline_size; | ||
| 96 | } | ||
| 97 | |||
| 98 | pub fn getAddress(thunk: Thunk, macho_file: *MachO) u64 { | ||
| 99 | const header = macho_file.sections.items(.header)[thunk.out_n_sect]; | ||
| 100 | return header.addr + thunk.value; | ||
| 101 | } | ||
| 102 | |||
| 103 | pub fn getTargetAddress(thunk: Thunk, ref: MachO.Ref, macho_file: *MachO) u64 { | ||
| 104 | return thunk.getAddress(macho_file) + thunk.symbols.getIndex(ref).? * trampoline_size; | ||
| 105 | } | ||
| 106 | |||
| 107 | pub fn write(thunk: Thunk, macho_file: *MachO, writer: anytype) !void { | ||
| 108 | for (thunk.symbols.keys(), 0..) |ref, i| { | ||
| 109 | const sym = ref.getSymbol(macho_file).?; | ||
| 110 | const saddr = thunk.getAddress(macho_file) + i * trampoline_size; | ||
| 111 | const taddr = sym.getAddress(.{}, macho_file); | ||
| 112 | const pages = try aarch64.calcNumberOfPages(@intCast(saddr), @intCast(taddr)); | ||
| 113 | try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little); | ||
| 114 | const off: u12 = @truncate(taddr); | ||
| 115 | try writer.writeInt(u32, aarch64.Instruction.add(.x16, .x16, off, false).toU32(), .little); | ||
| 116 | try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little); | ||
| 117 | } | ||
| 118 | } | ||
| 119 | |||
| 120 | pub fn calcSymtabSize(thunk: *Thunk, macho_file: *MachO) void { | ||
| 121 | thunk.output_symtab_ctx.nlocals = @as(u32, @intCast(thunk.symbols.keys().len)); | ||
| 122 | for (thunk.symbols.keys()) |ref| { | ||
| 123 | const sym = ref.getSymbol(macho_file).?; | ||
| 124 | thunk.output_symtab_ctx.strsize += @as(u32, @intCast(sym.getName(macho_file).len + "__thunk".len + 1)); | ||
| 125 | } | ||
| 126 | } | ||
| 127 | |||
| 128 | pub fn writeSymtab(thunk: Thunk, macho_file: *MachO, ctx: anytype) void { | ||
| 129 | var n_strx = thunk.output_symtab_ctx.stroff; | ||
| 130 | for (thunk.symbols.keys(), thunk.output_symtab_ctx.ilocal..) |ref, ilocal| { | ||
| 131 | const sym = ref.getSymbol(macho_file).?; | ||
| 132 | const name = sym.getName(macho_file); | ||
| 133 | const out_sym = &ctx.symtab.items[ilocal]; | ||
| 134 | out_sym.n_strx = n_strx; | ||
| 135 | @memcpy(ctx.strtab.items[n_strx..][0..name.len], name); | ||
| 136 | n_strx += @intCast(name.len); | ||
| 137 | @memcpy(ctx.strtab.items[n_strx..][0.."__thunk".len], "__thunk"); | ||
| 138 | n_strx += @intCast("__thunk".len); | ||
| 139 | ctx.strtab.items[n_strx] = 0; | ||
| 140 | n_strx += 1; | ||
| 141 | out_sym.n_type = macho.N_SECT; | ||
| 142 | out_sym.n_sect = @intCast(thunk.out_n_sect + 1); | ||
| 143 | out_sym.n_value = @intCast(thunk.getTargetAddress(ref, macho_file)); | ||
| 144 | out_sym.n_desc = 0; | ||
| 145 | } | ||
| 146 | } | ||
| 147 | |||
| 148 | pub fn format( | ||
| 149 | thunk: Thunk, | ||
| 150 | comptime unused_fmt_string: []const u8, | ||
| 151 | options: std.fmt.FormatOptions, | ||
| 152 | writer: anytype, | ||
| 153 | ) !void { | ||
| 154 | _ = thunk; | ||
| 155 | _ = unused_fmt_string; | ||
| 156 | _ = options; | ||
| 157 | _ = writer; | ||
| 158 | @compileError("do not format Thunk directly"); | ||
| 159 | } | ||
| 160 | |||
| 161 | pub fn fmt(thunk: Thunk, macho_file: *MachO) std.fmt.Formatter(format2) { | ||
| 162 | return .{ .data = .{ | ||
| 163 | .thunk = thunk, | ||
| 164 | .macho_file = macho_file, | ||
| 165 | } }; | ||
| 166 | } | ||
| 167 | |||
| 168 | const FormatContext = struct { | ||
| 169 | thunk: Thunk, | ||
| 170 | macho_file: *MachO, | ||
| 171 | }; | ||
| 172 | |||
| 173 | fn format2( | ||
| 174 | ctx: FormatContext, | ||
| 175 | comptime unused_fmt_string: []const u8, | ||
| 176 | options: std.fmt.FormatOptions, | ||
| 177 | writer: anytype, | ||
| 178 | ) !void { | ||
| 179 | _ = options; | ||
| 180 | _ = unused_fmt_string; | ||
| 181 | const thunk = ctx.thunk; | ||
| 182 | const macho_file = ctx.macho_file; | ||
| 183 | try writer.print("@{x} : size({x})\n", .{ thunk.value, thunk.size() }); | ||
| 184 | for (thunk.symbols.keys()) |ref| { | ||
| 185 | const sym = ref.getSymbol(macho_file).?; | ||
| 186 | try writer.print(" {} : {s} : @{x}\n", .{ ref, sym.getName(macho_file), sym.value }); | ||
| 187 | } | ||
| 188 | } | ||
| 189 | |||
| 190 | const trampoline_size = 3 * @sizeOf(u32); | ||
| 191 | |||
| 192 | pub const Index = u32; | ||
| 193 | }; | ||
| 194 | |||
| 195 | /// Branch instruction has 26 bits immediate but is 4 byte aligned. | ||
| 196 | const jump_bits = @bitSizeOf(i28); | ||
| 197 | const max_distance = (1 << (jump_bits - 1)); | ||
| 198 | |||
| 199 | /// A branch will need an extender if its target is larger than | ||
| 200 | /// `2^(jump_bits - 1) - margin` where margin is some arbitrary number. | ||
| 201 | /// mold uses 5MiB margin, while ld64 uses 4MiB margin. We will follow mold | ||
| 202 | /// and assume margin to be 5MiB. | ||
| 203 | const max_allowed_distance = max_distance - 0x500_000; | ||
| 204 | |||
| 205 | const aarch64 = @import("../aarch64.zig"); | ||
| 206 | const assert = std.debug.assert; | ||
| 207 | const log = std.log.scoped(.link); | ||
| 208 | const macho = std.macho; | ||
| 209 | const math = std.math; | ||
| 210 | const mem = std.mem; | ||
| 211 | const std = @import("std"); | ||
| 212 | const trace = @import("../../tracy.zig").trace; | ||
| 213 | |||
| 214 | const Allocator = mem.Allocator; | ||
| 215 | const Atom = @import("Atom.zig"); | ||
| 216 | const MachO = @import("../MachO.zig"); | ||
| 217 | const Relocation = @import("Relocation.zig"); | ||
| 218 | const Symbol = @import("Symbol.zig"); | ||
test/behavior/call.zig+4-4| ... | @@ -549,7 +549,7 @@ test "call function pointer in comptime field" { | ... | @@ -549,7 +549,7 @@ test "call function pointer in comptime field" { |
| 549 | auto: [max_len]u8 = undefined, | 549 | auto: [max_len]u8 = undefined, |
| 550 | offset: u64 = 0, | 550 | offset: u64 = 0, |
| 551 | 551 | ||
| 552 | comptime capacity: *const fn () u64 = capacity, | 552 | comptime capacityFn: *const fn () u64 = capacity, |
| 553 | 553 | ||
| 554 | const max_len: u64 = 32; | 554 | const max_len: u64 = 32; |
| 555 | 555 | ||
| ... | @@ -558,9 +558,9 @@ test "call function pointer in comptime field" { | ... | @@ -558,9 +558,9 @@ test "call function pointer in comptime field" { |
| 558 | } | 558 | } |
| 559 | }; | 559 | }; |
| 560 | 560 | ||
| 561 | const a: Auto = .{ .offset = 16, .capacity = Auto.capacity }; | 561 | const a: Auto = .{ .offset = 16, .capacityFn = Auto.capacity }; |
| 562 | try std.testing.expect(a.capacity() == 32); | 562 | try std.testing.expect(a.capacityFn() == 32); |
| 563 | try std.testing.expect((a.capacity)() == 32); | 563 | try std.testing.expect((a.capacityFn)() == 32); |
| 564 | } | 564 | } |
| 565 | 565 | ||
| 566 | test "generic function pointer can be called" { | 566 | test "generic function pointer can be called" { |
test/behavior/packed-union.zig+2-2| ... | @@ -149,12 +149,12 @@ test "packed union initialized with a runtime value" { | ... | @@ -149,12 +149,12 @@ test "packed union initialized with a runtime value" { |
| 149 | value: u63, | 149 | value: u63, |
| 150 | fields: Fields, | 150 | fields: Fields, |
| 151 | 151 | ||
| 152 | fn value() i64 { | 152 | fn getValue() i64 { |
| 153 | return 1341; | 153 | return 1341; |
| 154 | } | 154 | } |
| 155 | }; | 155 | }; |
| 156 | 156 | ||
| 157 | const timestamp: i64 = ID.value(); | 157 | const timestamp: i64 = ID.getValue(); |
| 158 | const id = ID{ .fields = Fields{ | 158 | const id = ID{ .fields = Fields{ |
| 159 | .timestamp = @as(u50, @intCast(timestamp)), | 159 | .timestamp = @as(u50, @intCast(timestamp)), |
| 160 | .random_bits = 420, | 160 | .random_bits = 420, |
test/behavior/struct.zig+3-3| ... | @@ -1529,15 +1529,15 @@ test "function pointer in struct returns the struct" { | ... | @@ -1529,15 +1529,15 @@ test "function pointer in struct returns the struct" { |
| 1529 | 1529 | ||
| 1530 | const A = struct { | 1530 | const A = struct { |
| 1531 | const A = @This(); | 1531 | const A = @This(); |
| 1532 | f: *const fn () A, | 1532 | ptr: *const fn () A, |
| 1533 | 1533 | ||
| 1534 | fn f() A { | 1534 | fn f() A { |
| 1535 | return .{ .f = f }; | 1535 | return .{ .ptr = f }; |
| 1536 | } | 1536 | } |
| 1537 | }; | 1537 | }; |
| 1538 | var a = A.f(); | 1538 | var a = A.f(); |
| 1539 | _ = &a; | 1539 | _ = &a; |
| 1540 | try expect(a.f == A.f); | 1540 | try expect(a.ptr == A.f); |
| 1541 | } | 1541 | } |
| 1542 | 1542 | ||
| 1543 | test "no dependency loop on optional field wrapped in generic function" { | 1543 | test "no dependency loop on optional field wrapped in generic function" { |
test/behavior/union.zig+4-16| ... | @@ -155,18 +155,6 @@ test "unions embedded in aggregate types" { | ... | @@ -155,18 +155,6 @@ test "unions embedded in aggregate types" { |
| 155 | } | 155 | } |
| 156 | } | 156 | } |
| 157 | 157 | ||
| 158 | test "access a member of tagged union with conflicting enum tag name" { | ||
| 159 | const Bar = union(enum) { | ||
| 160 | A: A, | ||
| 161 | B: B, | ||
| 162 | |||
| 163 | const A = u8; | ||
| 164 | const B = void; | ||
| 165 | }; | ||
| 166 | |||
| 167 | comptime assert(Bar.A == u8); | ||
| 168 | } | ||
| 169 | |||
| 170 | test "constant tagged union with payload" { | 158 | test "constant tagged union with payload" { |
| 171 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 159 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 172 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 160 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| ... | @@ -1417,10 +1405,10 @@ test "union field ptr - zero sized payload" { | ... | @@ -1417,10 +1405,10 @@ test "union field ptr - zero sized payload" { |
| 1417 | const U = union { | 1405 | const U = union { |
| 1418 | foo: void, | 1406 | foo: void, |
| 1419 | bar: void, | 1407 | bar: void, |
| 1420 | fn bar(_: *void) void {} | 1408 | fn qux(_: *void) void {} |
| 1421 | }; | 1409 | }; |
| 1422 | var u: U = .{ .foo = {} }; | 1410 | var u: U = .{ .foo = {} }; |
| 1423 | U.bar(&u.foo); | 1411 | U.qux(&u.foo); |
| 1424 | } | 1412 | } |
| 1425 | 1413 | ||
| 1426 | test "union field ptr - zero sized field" { | 1414 | test "union field ptr - zero sized field" { |
| ... | @@ -1431,10 +1419,10 @@ test "union field ptr - zero sized field" { | ... | @@ -1431,10 +1419,10 @@ test "union field ptr - zero sized field" { |
| 1431 | const U = union { | 1419 | const U = union { |
| 1432 | foo: void, | 1420 | foo: void, |
| 1433 | bar: u32, | 1421 | bar: u32, |
| 1434 | fn bar(_: *void) void {} | 1422 | fn qux(_: *void) void {} |
| 1435 | }; | 1423 | }; |
| 1436 | var u: U = .{ .foo = {} }; | 1424 | var u: U = .{ .foo = {} }; |
| 1437 | U.bar(&u.foo); | 1425 | U.qux(&u.foo); |
| 1438 | } | 1426 | } |
| 1439 | 1427 | ||
| 1440 | test "packed union in packed struct" { | 1428 | test "packed union in packed struct" { |
test/cases/compile_errors/colliding_invalid_top_level_functions.zig+3-4| ... | @@ -5,10 +5,9 @@ export fn entry() usize { | ... | @@ -5,10 +5,9 @@ export fn entry() usize { |
| 5 | } | 5 | } |
| 6 | 6 | ||
| 7 | // error | 7 | // error |
| 8 | // backend=stage2 | ||
| 9 | // target=native | ||
| 10 | // | 8 | // |
| 11 | // :2:1: error: redeclaration of 'func' | 9 | // :1:4: error: duplicate struct member name 'func' |
| 12 | // :1:1: note: other declaration here | 10 | // :2:4: note: duplicate name here |
| 11 | // :1:1: note: struct declared here | ||
| 13 | // :1:11: error: use of undeclared identifier 'bogus' | 12 | // :1:11: error: use of undeclared identifier 'bogus' |
| 14 | // :2:11: error: use of undeclared identifier 'bogus' | 13 | // :2:11: error: use of undeclared identifier 'bogus' |
test/cases/compile_errors/decl_shadows_local.zig+3-2| ... | @@ -2,6 +2,7 @@ fn foo(a: usize) void { | ... | @@ -2,6 +2,7 @@ fn foo(a: usize) void { |
| 2 | struct { | 2 | struct { |
| 3 | const a = 1; | 3 | const a = 1; |
| 4 | }; | 4 | }; |
| 5 | _ = a; | ||
| 5 | } | 6 | } |
| 6 | fn bar(a: usize) void { | 7 | fn bar(a: usize) void { |
| 7 | struct { | 8 | struct { |
| ... | @@ -18,5 +19,5 @@ fn bar(a: usize) void { | ... | @@ -18,5 +19,5 @@ fn bar(a: usize) void { |
| 18 | // | 19 | // |
| 19 | // :3:15: error: declaration 'a' shadows function parameter from outer scope | 20 | // :3:15: error: declaration 'a' shadows function parameter from outer scope |
| 20 | // :1:8: note: previous declaration here | 21 | // :1:8: note: previous declaration here |
| 21 | // :9:19: error: declaration 'a' shadows function parameter from outer scope | 22 | // :10:19: error: declaration 'a' shadows function parameter from outer scope |
| 22 | // :6:8: note: previous declaration here | 23 | // :7:8: note: previous declaration here |
test/cases/compile_errors/duplicate_enum_field.zig+2-2| ... | @@ -12,6 +12,6 @@ export fn entry() void { | ... | @@ -12,6 +12,6 @@ export fn entry() void { |
| 12 | // backend=stage2 | 12 | // backend=stage2 |
| 13 | // target=native | 13 | // target=native |
| 14 | // | 14 | // |
| 15 | // :2:5: error: duplicate enum field name | 15 | // :2:5: error: duplicate enum member name 'Bar' |
| 16 | // :3:5: note: duplicate field here | 16 | // :3:5: note: duplicate name here |
| 17 | // :1:13: note: enum declared here | 17 | // :1:13: note: enum declared here |
test/cases/compile_errors/duplicate_struct_field.zig+5-5| ... | @@ -24,10 +24,10 @@ export fn b() void { | ... | @@ -24,10 +24,10 @@ export fn b() void { |
| 24 | // backend=stage2 | 24 | // backend=stage2 |
| 25 | // target=native | 25 | // target=native |
| 26 | // | 26 | // |
| 27 | // :2:5: error: duplicate struct field name | 27 | // :2:5: error: duplicate struct member name 'Bar' |
| 28 | // :3:5: note: duplicate field here | 28 | // :3:5: note: duplicate name here |
| 29 | // :1:13: note: struct declared here | 29 | // :1:13: note: struct declared here |
| 30 | // :7:5: error: duplicate struct field name | 30 | // :7:5: error: duplicate struct member name 'a' |
| 31 | // :9:5: note: duplicate field here | 31 | // :9:5: note: duplicate name here |
| 32 | // :10:5: note: duplicate field here | 32 | // :10:5: note: duplicate name here |
| 33 | // :6:11: note: struct declared here | 33 | // :6:11: note: struct declared here |
test/cases/compile_errors/duplicate_union_field.zig+2-4| ... | @@ -8,9 +8,7 @@ export fn entry() void { | ... | @@ -8,9 +8,7 @@ export fn entry() void { |
| 8 | } | 8 | } |
| 9 | 9 | ||
| 10 | // error | 10 | // error |
| 11 | // backend=stage2 | ||
| 12 | // target=native | ||
| 13 | // | 11 | // |
| 14 | // :2:5: error: duplicate union field name | 12 | // :2:5: error: duplicate union member name 'Bar' |
| 15 | // :3:5: note: duplicate field here | 13 | // :3:5: note: duplicate name here |
| 16 | // :1:13: note: union declared here | 14 | // :1:13: note: union declared here |
test/cases/compile_errors/error_in_struct_initializer_doesnt_crash_the_compiler.zig+2-4| ... | @@ -8,9 +8,7 @@ pub export fn entry() void { | ... | @@ -8,9 +8,7 @@ pub export fn entry() void { |
| 8 | } | 8 | } |
| 9 | 9 | ||
| 10 | // error | 10 | // error |
| 11 | // backend=stage2 | ||
| 12 | // target=native | ||
| 13 | // | 11 | // |
| 14 | // :3:9: error: duplicate struct field name | 12 | // :3:9: error: duplicate struct member name 'e' |
| 15 | // :4:9: note: duplicate field here | 13 | // :4:9: note: duplicate name here |
| 16 | // :2:22: note: struct declared here | 14 | // :2:22: note: struct declared here |
test/cases/compile_errors/field_decl_name_conflict.zig created+18| ... | @@ -0,0 +1,18 @@ | ||
| 1 | foo: u32, | ||
| 2 | bar: u32, | ||
| 3 | qux: u32, | ||
| 4 | |||
| 5 | const foo = 123; | ||
| 6 | |||
| 7 | var bar: u8 = undefined; | ||
| 8 | fn bar() void {} | ||
| 9 | |||
| 10 | // error | ||
| 11 | // | ||
| 12 | // :1:1: error: duplicate struct member name 'foo' | ||
| 13 | // :5:7: note: duplicate name here | ||
| 14 | // :1:1: note: struct declared here | ||
| 15 | // :2:1: error: duplicate struct member name 'bar' | ||
| 16 | // :7:5: note: duplicate name here | ||
| 17 | // :8:4: note: duplicate name here | ||
| 18 | // :1:1: note: struct declared here | ||
test/cases/compile_errors/invalid_duplicate_test_decl_name.zig+3-2| ... | @@ -6,5 +6,6 @@ test "thingy" {} | ... | @@ -6,5 +6,6 @@ test "thingy" {} |
| 6 | // target=native | 6 | // target=native |
| 7 | // is_test=true | 7 | // is_test=true |
| 8 | // | 8 | // |
| 9 | // :2:1: error: duplicate test name 'thingy' | 9 | // :1:6: error: duplicate test name 'thingy' |
| 10 | // :1:1: note: other test here | 10 | // :2:6: note: duplicate test here |
| 11 | // :1:1: note: struct declared here |
test/cases/compile_errors/invalid_store_to_comptime_field.zig+4-4| ... | @@ -25,21 +25,21 @@ pub export fn entry3() void { | ... | @@ -25,21 +25,21 @@ pub export fn entry3() void { |
| 25 | const U = struct { | 25 | const U = struct { |
| 26 | comptime foo: u32 = 1, | 26 | comptime foo: u32 = 1, |
| 27 | bar: u32, | 27 | bar: u32, |
| 28 | fn foo(x: @This()) void { | 28 | fn qux(x: @This()) void { |
| 29 | _ = x; | 29 | _ = x; |
| 30 | } | 30 | } |
| 31 | }; | 31 | }; |
| 32 | _ = U.foo(U{ .foo = 2, .bar = 2 }); | 32 | _ = U.qux(U{ .foo = 2, .bar = 2 }); |
| 33 | } | 33 | } |
| 34 | pub export fn entry4() void { | 34 | pub export fn entry4() void { |
| 35 | const U = struct { | 35 | const U = struct { |
| 36 | comptime foo: u32 = 1, | 36 | comptime foo: u32 = 1, |
| 37 | bar: u32, | 37 | bar: u32, |
| 38 | fn foo(x: @This()) void { | 38 | fn qux(x: @This()) void { |
| 39 | _ = x; | 39 | _ = x; |
| 40 | } | 40 | } |
| 41 | }; | 41 | }; |
| 42 | _ = U.foo(.{ .foo = 2, .bar = 2 }); | 42 | _ = U.qux(.{ .foo = 2, .bar = 2 }); |
| 43 | } | 43 | } |
| 44 | pub export fn entry5() void { | 44 | pub export fn entry5() void { |
| 45 | comptime var y = .{ 1, 2 }; | 45 | comptime var y = .{ 1, 2 }; |
test/cases/compile_errors/multiple_function_definitions.zig+3-4| ... | @@ -5,8 +5,7 @@ export fn entry() void { | ... | @@ -5,8 +5,7 @@ export fn entry() void { |
| 5 | } | 5 | } |
| 6 | 6 | ||
| 7 | // error | 7 | // error |
| 8 | // backend=stage2 | ||
| 9 | // target=native | ||
| 10 | // | 8 | // |
| 11 | // :2:1: error: redeclaration of 'a' | 9 | // :1:4: error: duplicate struct member name 'a' |
| 12 | // :1:1: note: other declaration here | 10 | // :2:4: note: duplicate name here |
| 11 | // :1:1: note: struct declared here |
test/cases/compile_errors/redefinition_of_enums.zig+3-2| ... | @@ -5,5 +5,6 @@ const A = enum { x }; | ... | @@ -5,5 +5,6 @@ const A = enum { x }; |
| 5 | // backend=stage2 | 5 | // backend=stage2 |
| 6 | // target=native | 6 | // target=native |
| 7 | // | 7 | // |
| 8 | // :2:1: error: redeclaration of 'A' | 8 | // :1:7: error: duplicate struct member name 'A' |
| 9 | // :1:1: note: other declaration here | 9 | // :2:7: note: duplicate name here |
| 10 | // :1:1: note: struct declared here |
test/cases/compile_errors/redefinition_of_global_variables.zig+3-2| ... | @@ -5,5 +5,6 @@ var a: i32 = 2; | ... | @@ -5,5 +5,6 @@ var a: i32 = 2; |
| 5 | // backend=stage2 | 5 | // backend=stage2 |
| 6 | // target=native | 6 | // target=native |
| 7 | // | 7 | // |
| 8 | // :2:1: error: redeclaration of 'a' | 8 | // :1:5: error: duplicate struct member name 'a' |
| 9 | // :1:1: note: other declaration here | 9 | // :2:5: note: duplicate name here |
| 10 | // :1:1: note: struct declared here |
test/cases/compile_errors/redefinition_of_struct.zig+3-2| ... | @@ -5,5 +5,6 @@ const A = struct { y: i32 }; | ... | @@ -5,5 +5,6 @@ const A = struct { y: i32 }; |
| 5 | // backend=stage2 | 5 | // backend=stage2 |
| 6 | // target=native | 6 | // target=native |
| 7 | // | 7 | // |
| 8 | // :2:1: error: redeclaration of 'A' | 8 | // :1:7: error: duplicate struct member name 'A' |
| 9 | // :1:1: note: other declaration here | 9 | // :2:7: note: duplicate name here |
| 10 | // :1:1: note: struct declared here |
test/cases/compile_errors/struct_duplicate_field_name.zig+2-2| ... | @@ -11,6 +11,6 @@ export fn entry() void { | ... | @@ -11,6 +11,6 @@ export fn entry() void { |
| 11 | // error | 11 | // error |
| 12 | // target=native | 12 | // target=native |
| 13 | // | 13 | // |
| 14 | // :2:5: error: duplicate struct field name | 14 | // :2:5: error: duplicate struct member name 'foo' |
| 15 | // :3:5: note: duplicate field here | 15 | // :3:5: note: duplicate name here |
| 16 | // :1:11: note: struct declared here | 16 | // :1:11: note: struct declared here |
test/cases/compile_errors/union_duplicate_enum_field.zig+2-2| ... | @@ -12,6 +12,6 @@ export fn foo() void { | ... | @@ -12,6 +12,6 @@ export fn foo() void { |
| 12 | // error | 12 | // error |
| 13 | // target=native | 13 | // target=native |
| 14 | // | 14 | // |
| 15 | // :3:5: error: duplicate union field name | 15 | // :3:5: error: duplicate union member name 'a' |
| 16 | // :4:5: note: duplicate field here | 16 | // :4:5: note: duplicate name here |
| 17 | // :2:11: note: union declared here | 17 | // :2:11: note: union declared here |
test/cases/compile_errors/union_duplicate_field_definition.zig+2-2| ... | @@ -11,6 +11,6 @@ export fn entry() void { | ... | @@ -11,6 +11,6 @@ export fn entry() void { |
| 11 | // error | 11 | // error |
| 12 | // target=native | 12 | // target=native |
| 13 | // | 13 | // |
| 14 | // :2:5: error: duplicate union field name | 14 | // :2:5: error: duplicate union member name 'foo' |
| 15 | // :3:5: note: duplicate field here | 15 | // :3:5: note: duplicate name here |
| 16 | // :1:11: note: union declared here | 16 | // :1:11: note: union declared here |
test/cases/function_redeclaration.zig+3-2| ... | @@ -8,7 +8,8 @@ fn foo() void { | ... | @@ -8,7 +8,8 @@ fn foo() void { |
| 8 | 8 | ||
| 9 | // error | 9 | // error |
| 10 | // | 10 | // |
| 11 | // :3:1: error: redeclaration of 'entry' | 11 | // :2:4: error: duplicate struct member name 'entry' |
| 12 | // :2:1: note: other declaration here | 12 | // :3:4: note: duplicate name here |
| 13 | // :2:1: note: struct declared here | ||
| 13 | // :6:9: error: local variable shadows declaration of 'foo' | 14 | // :6:9: error: local variable shadows declaration of 'foo' |
| 14 | // :5:1: note: declared here | 15 | // :5:1: note: declared here |
test/cases/global_variable_redeclaration.zig+3-2| ... | @@ -4,5 +4,6 @@ var foo = true; | ... | @@ -4,5 +4,6 @@ var foo = true; |
| 4 | 4 | ||
| 5 | // error | 5 | // error |
| 6 | // | 6 | // |
| 7 | // :3:1: error: redeclaration of 'foo' | 7 | // :2:5: error: duplicate struct member name 'foo' |
| 8 | // :2:1: note: other declaration here | 8 | // :3:5: note: duplicate name here |
| 9 | // :2:1: note: struct declared here |
test/compile_errors.zig+2-2| ... | @@ -92,7 +92,7 @@ pub fn addCases(ctx: *Cases, b: *std.Build) !void { | ... | @@ -92,7 +92,7 @@ pub fn addCases(ctx: *Cases, b: *std.Build) !void { |
| 92 | \\const a = @import("a.zig"); | 92 | \\const a = @import("a.zig"); |
| 93 | \\ | 93 | \\ |
| 94 | \\export fn entry() void { | 94 | \\export fn entry() void { |
| 95 | \\ _ = a.S.foo(a.S{ .foo = 2, .bar = 2 }); | 95 | \\ _ = a.S.qux(a.S{ .foo = 2, .bar = 2 }); |
| 96 | \\} | 96 | \\} |
| 97 | , &[_][]const u8{ | 97 | , &[_][]const u8{ |
| 98 | ":4:23: error: value stored in comptime field does not match the default value of the field", | 98 | ":4:23: error: value stored in comptime field does not match the default value of the field", |
| ... | @@ -102,7 +102,7 @@ pub fn addCases(ctx: *Cases, b: *std.Build) !void { | ... | @@ -102,7 +102,7 @@ pub fn addCases(ctx: *Cases, b: *std.Build) !void { |
| 102 | \\pub const S = struct { | 102 | \\pub const S = struct { |
| 103 | \\ comptime foo: u32 = 1, | 103 | \\ comptime foo: u32 = 1, |
| 104 | \\ bar: u32, | 104 | \\ bar: u32, |
| 105 | \\ pub fn foo(x: @This()) void { | 105 | \\ pub fn qux(x: @This()) void { |
| 106 | \\ _ = x; | 106 | \\ _ = x; |
| 107 | \\ } | 107 | \\ } |
| 108 | \\}; | 108 | \\}; |