| 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 | 613 | src/link/Elf/relocatable.zig |
| 614 | 614 | src/link/Elf/relocation.zig |
| 615 | 615 | src/link/Elf/synthetic_sections.zig |
| 616 | src/link/Elf/thunks.zig | |
| 616 | src/link/Elf/Thunk.zig | |
| 617 | 617 | src/link/MachO.zig |
| 618 | 618 | src/link/MachO/Archive.zig |
| 619 | 619 | src/link/MachO/Atom.zig |
| ... | ... | @@ -638,7 +638,7 @@ set(ZIG_STAGE2_SOURCES |
| 638 | 638 | src/link/MachO/load_commands.zig |
| 639 | 639 | src/link/MachO/relocatable.zig |
| 640 | 640 | src/link/MachO/synthetic.zig |
| 641 | src/link/MachO/thunks.zig | |
| 641 | src/link/MachO/Thunk.zig | |
| 642 | 642 | src/link/MachO/uuid.zig |
| 643 | 643 | src/link/NvPtx.zig |
| 644 | 644 | src/link/Plan9.zig |
lib/std/crypto/poly1305.zig+5-5| ... | ... | @@ -12,7 +12,7 @@ pub const Poly1305 = struct { |
| 12 | 12 | // accumulated hash |
| 13 | 13 | h: [3]u64 = [_]u64{ 0, 0, 0 }, |
| 14 | 14 | // random number added at the end (from the secret key) |
| 15 | pad: [2]u64, | |
| 15 | end_pad: [2]u64, | |
| 16 | 16 | // how many bytes are waiting to be processed in a partial block |
| 17 | 17 | leftover: usize = 0, |
| 18 | 18 | // partial block buffer |
| ... | ... | @@ -24,7 +24,7 @@ pub const Poly1305 = struct { |
| 24 | 24 | mem.readInt(u64, key[0..8], .little) & 0x0ffffffc0fffffff, |
| 25 | 25 | mem.readInt(u64, key[8..16], .little) & 0x0ffffffc0ffffffc, |
| 26 | 26 | }, |
| 27 | .pad = [_]u64{ | |
| 27 | .end_pad = [_]u64{ | |
| 28 | 28 | mem.readInt(u64, key[16..24], .little), |
| 29 | 29 | mem.readInt(u64, key[24..32], .little), |
| 30 | 30 | }, |
| ... | ... | @@ -177,9 +177,9 @@ pub const Poly1305 = struct { |
| 177 | 177 | h1 ^= mask & (h1 ^ h_p1); |
| 178 | 178 | |
| 179 | 179 | // Add the first half of the key, we intentionally don't use @addWithOverflow() here. |
| 180 | st.h[0] = h0 +% st.pad[0]; | |
| 181 | const c = ((h0 & st.pad[0]) | ((h0 | st.pad[0]) & ~st.h[0])) >> 63; | |
| 182 | st.h[1] = h1 +% st.pad[1] +% c; | |
| 180 | st.h[0] = h0 +% st.end_pad[0]; | |
| 181 | const c = ((h0 & st.end_pad[0]) | ((h0 | st.end_pad[0]) & ~st.h[0])) >> 63; | |
| 182 | st.h[1] = h1 +% st.end_pad[1] +% c; | |
| 183 | 183 | |
| 184 | 184 | mem.writeInt(u64, out[0..8], st.h[0], .little); |
| 185 | 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 | 63 | } |
| 64 | 64 | |
| 65 | 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 | 67 | return error.InvalidDebugInfo; |
| 68 | 68 | const reader = stream.reader(); |
| 69 | 69 | |
| 70 | 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 | 72 | return error.UnknownPDBVersion; |
| 73 | 73 | // if (header.Age != age) |
| 74 | 74 | // return error.UnmatchingPDB; |
| 75 | 75 | |
| 76 | const mod_info_size = header.ModInfoSize; | |
| 77 | const section_contrib_size = header.SectionContributionSize; | |
| 76 | const mod_info_size = header.mod_info_size; | |
| 77 | const section_contrib_size = header.section_contribution_size; | |
| 78 | 78 | |
| 79 | 79 | var modules = std.ArrayList(Module).init(self.allocator); |
| 80 | 80 | errdefer modules.deinit(); |
| ... | ... | @@ -143,7 +143,7 @@ pub fn parseDbiStream(self: *Pdb) !void { |
| 143 | 143 | } |
| 144 | 144 | |
| 145 | 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 | 147 | return error.InvalidDebugInfo; |
| 148 | 148 | const reader = stream.reader(); |
| 149 | 149 | |
| ... | ... | @@ -168,23 +168,23 @@ pub fn parseInfoStream(self: *Pdb) !void { |
| 168 | 168 | try reader.readNoEof(name_bytes); |
| 169 | 169 | |
| 170 | 170 | const HashTableHeader = extern struct { |
| 171 | Size: u32, | |
| 172 | Capacity: u32, | |
| 171 | size: u32, | |
| 172 | capacity: u32, | |
| 173 | 173 | |
| 174 | 174 | fn maxLoad(cap: u32) u32 { |
| 175 | 175 | return cap * 2 / 3 + 1; |
| 176 | 176 | } |
| 177 | 177 | }; |
| 178 | 178 | const hash_tbl_hdr = try reader.readStruct(HashTableHeader); |
| 179 | if (hash_tbl_hdr.Capacity == 0) | |
| 179 | if (hash_tbl_hdr.capacity == 0) | |
| 180 | 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 | 183 | return error.InvalidDebugInfo; |
| 184 | 184 | |
| 185 | 185 | const present = try readSparseBitVector(&reader, self.allocator); |
| 186 | 186 | defer self.allocator.free(present); |
| 187 | if (present.len != hash_tbl_hdr.Size) | |
| 187 | if (present.len != hash_tbl_hdr.size) | |
| 188 | 188 | return error.InvalidDebugInfo; |
| 189 | 189 | const deleted = try readSparseBitVector(&reader, self.allocator); |
| 190 | 190 | defer self.allocator.free(deleted); |
| ... | ... | @@ -212,19 +212,19 @@ pub fn getSymbolName(self: *Pdb, module: *Module, address: u64) ?[]const u8 { |
| 212 | 212 | |
| 213 | 213 | var symbol_i: usize = 0; |
| 214 | 214 | while (symbol_i != module.symbols.len) { |
| 215 | const prefix = @as(*align(1) pdb.RecordPrefix, @ptrCast(&module.symbols[symbol_i])); | |
| 216 | if (prefix.RecordLen < 2) | |
| 215 | const prefix: *align(1) pdb.RecordPrefix = @ptrCast(&module.symbols[symbol_i]); | |
| 216 | if (prefix.record_len < 2) | |
| 217 | 217 | return null; |
| 218 | switch (prefix.RecordKind) { | |
| 219 | .S_LPROC32, .S_GPROC32 => { | |
| 220 | const proc_sym = @as(*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) { | |
| 222 | return std.mem.sliceTo(@as([*:0]u8, @ptrCast(&proc_sym.Name[0])), 0); | |
| 218 | switch (prefix.record_kind) { | |
| 219 | .lproc32, .gproc32 => { | |
| 220 | const proc_sym: *align(1) pdb.ProcSym = @ptrCast(&module.symbols[symbol_i + @sizeOf(pdb.RecordPrefix)]); | |
| 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); | |
| 223 | 223 | } |
| 224 | 224 | }, |
| 225 | 225 | else => {}, |
| 226 | 226 | } |
| 227 | symbol_i += prefix.RecordLen + @sizeOf(u16); | |
| 227 | symbol_i += prefix.record_len + @sizeOf(u16); | |
| 228 | 228 | } |
| 229 | 229 | |
| 230 | 230 | return null; |
| ... | ... | @@ -238,44 +238,44 @@ pub fn getLineNumberInfo(self: *Pdb, module: *Module, address: u64) !std.debug.S |
| 238 | 238 | var skip_len: usize = undefined; |
| 239 | 239 | const checksum_offset = module.checksum_offset orelse return error.MissingDebugInfo; |
| 240 | 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])); | |
| 242 | skip_len = subsect_hdr.Length; | |
| 241 | const subsect_hdr: *align(1) pdb.DebugSubsectionHeader = @ptrCast(&subsect_info[sect_offset]); | |
| 242 | skip_len = subsect_hdr.length; | |
| 243 | 243 | sect_offset += @sizeOf(pdb.DebugSubsectionHeader); |
| 244 | 244 | |
| 245 | switch (subsect_hdr.Kind) { | |
| 246 | .Lines => { | |
| 245 | switch (subsect_hdr.kind) { | |
| 246 | .lines => { | |
| 247 | 247 | var line_index = sect_offset; |
| 248 | 248 | |
| 249 | const line_hdr = @as(*align(1) pdb.LineFragmentHeader, @ptrCast(&subsect_info[line_index])); | |
| 250 | if (line_hdr.RelocSegment == 0) | |
| 249 | const line_hdr: *align(1) pdb.LineFragmentHeader = @ptrCast(&subsect_info[line_index]); | |
| 250 | if (line_hdr.reloc_segment == 0) | |
| 251 | 251 | return error.MissingDebugInfo; |
| 252 | 252 | line_index += @sizeOf(pdb.LineFragmentHeader); |
| 253 | const frag_vaddr_start = line_hdr.RelocOffset; | |
| 254 | const frag_vaddr_end = frag_vaddr_start + line_hdr.CodeSize; | |
| 253 | const frag_vaddr_start = line_hdr.reloc_offset; | |
| 254 | const frag_vaddr_end = frag_vaddr_start + line_hdr.code_size; | |
| 255 | 255 | |
| 256 | 256 | if (address >= frag_vaddr_start and address < frag_vaddr_end) { |
| 257 | 257 | // There is an unknown number of LineBlockFragmentHeaders (and their accompanying line and column records) |
| 258 | 258 | // from now on. We will iterate through them, and eventually find a SourceLocation that we're interested in, |
| 259 | 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 | 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 | 264 | line_index += @sizeOf(pdb.LineBlockFragmentHeader); |
| 265 | 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 | 269 | // All line entries are stored inside their line block by ascending start address. |
| 270 | 270 | // Heuristic: we want to find the last line entry |
| 271 | 271 | // that has a vaddr_start <= address. |
| 272 | 272 | // This is done with a simple linear search. |
| 273 | 273 | var line_i: u32 = 0; |
| 274 | while (line_i < block_hdr.NumLines) : (line_i += 1) { | |
| 275 | const line_num_entry = @as(*align(1) pdb.LineNumberEntry, @ptrCast(&subsect_info[line_index])); | |
| 274 | while (line_i < block_hdr.num_lines) : (line_i += 1) { | |
| 275 | const line_num_entry: *align(1) pdb.LineNumberEntry = @ptrCast(&subsect_info[line_index]); | |
| 276 | 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 | 279 | if (address < vaddr_start) { |
| 280 | 280 | break; |
| 281 | 281 | } |
| ... | ... | @@ -283,28 +283,27 @@ pub fn getLineNumberInfo(self: *Pdb, module: *Module, address: u64) !std.debug.S |
| 283 | 283 | |
| 284 | 284 | // line_i == 0 would mean that no matching pdb.LineNumberEntry was found. |
| 285 | 285 | if (line_i > 0) { |
| 286 | const subsect_index = checksum_offset + block_hdr.NameIndex; | |
| 287 | const chksum_hdr = @as(*align(1) pdb.FileChecksumEntryHeader, @ptrCast(&module.subsect_info[subsect_index])); | |
| 288 | const strtab_offset = @sizeOf(pdb.StringTableHeader) + chksum_hdr.FileNameOffset; | |
| 286 | const subsect_index = checksum_offset + block_hdr.name_index; | |
| 287 | const chksum_hdr: *align(1) pdb.FileChecksumEntryHeader = @ptrCast(&module.subsect_info[subsect_index]); | |
| 288 | const strtab_offset = @sizeOf(pdb.StringTableHeader) + chksum_hdr.file_name_offset; | |
| 289 | 289 | try self.string_table.?.seekTo(strtab_offset); |
| 290 | 290 | const source_file_name = try self.string_table.?.reader().readUntilDelimiterAlloc(self.allocator, 0, 1024); |
| 291 | 291 | |
| 292 | 292 | const line_entry_idx = line_i - 1; |
| 293 | 293 | |
| 294 | 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 | 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])); | |
| 298 | break :blk col_num_entry.StartColumn; | |
| 297 | const col_num_entry: *align(1) pdb.ColumnNumberEntry = @ptrCast(&subsect_info[col_index]); | |
| 298 | break :blk col_num_entry.start_column; | |
| 299 | 299 | } else 0; |
| 300 | 300 | |
| 301 | 301 | const found_line_index = start_line_index + line_entry_idx * @sizeOf(pdb.LineNumberEntry); |
| 302 | 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 | 304 | return .{ |
| 306 | 305 | .file_name = source_file_name, |
| 307 | .line = flags.Start, | |
| 306 | .line = line_num_entry.flags.start, | |
| 308 | 307 | .column = column, |
| 309 | 308 | }; |
| 310 | 309 | } |
| ... | ... | @@ -335,12 +334,12 @@ pub fn getModule(self: *Pdb, index: usize) !?*Module { |
| 335 | 334 | return mod; |
| 336 | 335 | |
| 337 | 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 | 338 | return error.InvalidDebugInfo; |
| 340 | if (mod.mod_info.C13ByteSize == 0) | |
| 339 | if (mod.mod_info.c13_byte_size == 0) | |
| 341 | 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 | 343 | return error.MissingDebugInfo; |
| 345 | 344 | const reader = stream.reader(); |
| 346 | 345 | |
| ... | ... | @@ -348,23 +347,23 @@ pub fn getModule(self: *Pdb, index: usize) !?*Module { |
| 348 | 347 | if (signature != 4) |
| 349 | 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 | 351 | errdefer self.allocator.free(mod.symbols); |
| 353 | 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 | 355 | errdefer self.allocator.free(mod.subsect_info); |
| 357 | 356 | try reader.readNoEof(mod.subsect_info); |
| 358 | 357 | |
| 359 | 358 | var sect_offset: usize = 0; |
| 360 | 359 | var skip_len: usize = undefined; |
| 361 | 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])); | |
| 363 | skip_len = subsect_hdr.Length; | |
| 361 | const subsect_hdr: *align(1) pdb.DebugSubsectionHeader = @ptrCast(&mod.subsect_info[sect_offset]); | |
| 362 | skip_len = subsect_hdr.length; | |
| 364 | 363 | sect_offset += @sizeOf(pdb.DebugSubsectionHeader); |
| 365 | 364 | |
| 366 | switch (subsect_hdr.Kind) { | |
| 367 | .FileChecksums => { | |
| 365 | switch (subsect_hdr.kind) { | |
| 366 | .file_checksums => { | |
| 368 | 367 | mod.checksum_offset = sect_offset; |
| 369 | 368 | break; |
| 370 | 369 | }, |
| ... | ... | @@ -401,30 +400,30 @@ const Msf = struct { |
| 401 | 400 | const superblock = try in.readStruct(pdb.SuperBlock); |
| 402 | 401 | |
| 403 | 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 | 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 | 406 | return error.InvalidDebugInfo; |
| 408 | 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 | 409 | return error.InvalidDebugInfo; |
| 411 | switch (superblock.BlockSize) { | |
| 410 | switch (superblock.block_size) { | |
| 412 | 411 | // llvm only supports 4096 but we can handle any of these values |
| 413 | 412 | 512, 1024, 2048, 4096 => {}, |
| 414 | 413 | else => return error.InvalidDebugInfo, |
| 415 | 414 | } |
| 416 | 415 | |
| 417 | const dir_block_count = blockCountFromSize(superblock.NumDirectoryBytes, superblock.BlockSize); | |
| 418 | if (dir_block_count > superblock.BlockSize / @sizeOf(u32)) | |
| 416 | const dir_block_count = blockCountFromSize(superblock.num_directory_bytes, superblock.block_size); | |
| 417 | if (dir_block_count > superblock.block_size / @sizeOf(u32)) | |
| 419 | 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 | 421 | const dir_blocks = try allocator.alloc(u32, dir_block_count); |
| 423 | 422 | for (dir_blocks) |*b| { |
| 424 | 423 | b.* = try in.readInt(u32, .little); |
| 425 | 424 | } |
| 426 | 425 | var directory = MsfStream.init( |
| 427 | superblock.BlockSize, | |
| 426 | superblock.block_size, | |
| 428 | 427 | file, |
| 429 | 428 | dir_blocks, |
| 430 | 429 | ); |
| ... | ... | @@ -440,7 +439,7 @@ const Msf = struct { |
| 440 | 439 | const Nil = 0xFFFFFFFF; |
| 441 | 440 | for (stream_sizes) |*s| { |
| 442 | 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 | 445 | const streams = try allocator.alloc(MsfStream, stream_count); |
| ... | ... | @@ -455,15 +454,15 @@ const Msf = struct { |
| 455 | 454 | var j: u32 = 0; |
| 456 | 455 | while (j < size) : (j += 1) { |
| 457 | 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 | 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 | 460 | return error.InvalidBlockIndex; |
| 462 | 461 | blocks[j] = block_id; |
| 463 | 462 | } |
| 464 | 463 | |
| 465 | 464 | stream.* = MsfStream.init( |
| 466 | superblock.BlockSize, | |
| 465 | superblock.block_size, | |
| 467 | 466 | file, |
| 468 | 467 | blocks, |
| 469 | 468 | ); |
| ... | ... | @@ -471,7 +470,7 @@ const Msf = struct { |
| 471 | 470 | } |
| 472 | 471 | |
| 473 | 472 | const end = directory.pos; |
| 474 | if (end - begin != superblock.NumDirectoryBytes) | |
| 473 | if (end - begin != superblock.num_directory_bytes) | |
| 475 | 474 | return error.InvalidStreamDirectory; |
| 476 | 475 | |
| 477 | 476 | return Msf{ |
lib/std/debug/SelfInfo.zig+5-5| ... | ... | @@ -732,14 +732,14 @@ pub const Module = switch (native_os) { |
| 732 | 732 | fn getSymbolFromPdb(self: *@This(), relocated_address: usize) !?std.debug.Symbol { |
| 733 | 733 | var coff_section: *align(1) const coff.SectionHeader = undefined; |
| 734 | 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 | 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; | |
| 740 | const vaddr_end = vaddr_start + sect_contrib.Size; | |
| 739 | const vaddr_start = coff_section.virtual_address + sect_contrib.offset; | |
| 740 | const vaddr_end = vaddr_start + sect_contrib.size; | |
| 741 | 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 | 744 | } else { |
| 745 | 745 | // we have no information to add to the address |
lib/std/enums.zig+1-1| ... | ... | @@ -1501,7 +1501,7 @@ test values { |
| 1501 | 1501 | X, |
| 1502 | 1502 | Y, |
| 1503 | 1503 | Z, |
| 1504 | pub const X = 1; | |
| 1504 | const A = 1; | |
| 1505 | 1505 | }; |
| 1506 | 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 | |
| 8 | 8 | pub fn SbrkAllocator(comptime sbrk: *const fn (n: usize) usize) type { |
| 9 | 9 | return struct { |
| 10 | pub const vtable = Allocator.VTable{ | |
| 10 | pub const vtable: Allocator.VTable = .{ | |
| 11 | 11 | .alloc = alloc, |
| 12 | 12 | .resize = resize, |
| 13 | 13 | .free = free, |
| ... | ... | @@ -15,8 +15,6 @@ pub fn SbrkAllocator(comptime sbrk: *const fn (n: usize) usize) type { |
| 15 | 15 | |
| 16 | 16 | pub const Error = Allocator.Error; |
| 17 | 17 | |
| 18 | lock: std.Thread.Mutex = .{}, | |
| 19 | ||
| 20 | 18 | const max_usize = math.maxInt(usize); |
| 21 | 19 | const ushift = math.Log2Int(usize); |
| 22 | 20 | const bigpage_size = 64 * 1024; |
lib/std/meta.zig+2-2| ... | ... | @@ -294,7 +294,7 @@ test declarations { |
| 294 | 294 | pub fn a() void {} |
| 295 | 295 | }; |
| 296 | 296 | const U1 = union { |
| 297 | a: u8, | |
| 297 | b: u8, | |
| 298 | 298 | |
| 299 | 299 | pub fn a() void {} |
| 300 | 300 | }; |
| ... | ... | @@ -334,7 +334,7 @@ test declarationInfo { |
| 334 | 334 | pub fn a() void {} |
| 335 | 335 | }; |
| 336 | 336 | const U1 = union { |
| 337 | a: u8, | |
| 337 | b: u8, | |
| 338 | 338 | |
| 339 | 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 | 4 | const Guid = uefi.Guid; |
| 5 | 5 | |
| 6 | 6 | pub const DevicePath = union(Type) { |
| 7 | Hardware: Hardware, | |
| 8 | Acpi: Acpi, | |
| 9 | Messaging: Messaging, | |
| 10 | Media: Media, | |
| 11 | BiosBootSpecification: BiosBootSpecification, | |
| 12 | End: End, | |
| 7 | hardware: Hardware, | |
| 8 | acpi: Acpi, | |
| 9 | messaging: Messaging, | |
| 10 | media: Media, | |
| 11 | bios_boot_specification: BiosBootSpecification, | |
| 12 | end: End, | |
| 13 | 13 | |
| 14 | 14 | pub const Type = enum(u8) { |
| 15 | Hardware = 0x01, | |
| 16 | Acpi = 0x02, | |
| 17 | Messaging = 0x03, | |
| 18 | Media = 0x04, | |
| 19 | BiosBootSpecification = 0x05, | |
| 20 | End = 0x7f, | |
| 15 | hardware = 0x01, | |
| 16 | acpi = 0x02, | |
| 17 | messaging = 0x03, | |
| 18 | media = 0x04, | |
| 19 | bios_boot_specification = 0x05, | |
| 20 | end = 0x7f, | |
| 21 | 21 | _, |
| 22 | 22 | }; |
| 23 | 23 | |
| 24 | 24 | pub const Hardware = union(Subtype) { |
| 25 | Pci: *const PciDevicePath, | |
| 26 | PcCard: *const PcCardDevicePath, | |
| 27 | MemoryMapped: *const MemoryMappedDevicePath, | |
| 28 | Vendor: *const VendorDevicePath, | |
| 29 | Controller: *const ControllerDevicePath, | |
| 30 | Bmc: *const BmcDevicePath, | |
| 25 | pci: *const PciDevicePath, | |
| 26 | pc_card: *const PcCardDevicePath, | |
| 27 | memory_mapped: *const MemoryMappedDevicePath, | |
| 28 | vendor: *const VendorDevicePath, | |
| 29 | controller: *const ControllerDevicePath, | |
| 30 | bmc: *const BmcDevicePath, | |
| 31 | 31 | |
| 32 | 32 | pub const Subtype = enum(u8) { |
| 33 | Pci = 1, | |
| 34 | PcCard = 2, | |
| 35 | MemoryMapped = 3, | |
| 36 | Vendor = 4, | |
| 37 | Controller = 5, | |
| 38 | Bmc = 6, | |
| 33 | pci = 1, | |
| 34 | pc_card = 2, | |
| 35 | memory_mapped = 3, | |
| 36 | vendor = 4, | |
| 37 | controller = 5, | |
| 38 | bmc = 6, | |
| 39 | 39 | _, |
| 40 | 40 | }; |
| 41 | 41 | |
| ... | ... | @@ -151,14 +151,14 @@ pub const DevicePath = union(Type) { |
| 151 | 151 | }; |
| 152 | 152 | |
| 153 | 153 | pub const Acpi = union(Subtype) { |
| 154 | Acpi: *const BaseAcpiDevicePath, | |
| 155 | ExpandedAcpi: *const ExpandedAcpiDevicePath, | |
| 156 | Adr: *const AdrDevicePath, | |
| 154 | acpi: *const BaseAcpiDevicePath, | |
| 155 | expanded_acpi: *const ExpandedAcpiDevicePath, | |
| 156 | adr: *const AdrDevicePath, | |
| 157 | 157 | |
| 158 | 158 | pub const Subtype = enum(u8) { |
| 159 | Acpi = 1, | |
| 160 | ExpandedAcpi = 2, | |
| 161 | Adr = 3, | |
| 159 | acpi = 1, | |
| 160 | expanded_acpi = 2, | |
| 161 | adr = 3, | |
| 162 | 162 | _, |
| 163 | 163 | }; |
| 164 | 164 |
lib/std/pdb.zig+321-322| ... | ... | @@ -20,297 +20,297 @@ const ArrayList = std.ArrayList; |
| 20 | 20 | |
| 21 | 21 | /// https://llvm.org/docs/PDB/DbiStream.html#stream-header |
| 22 | 22 | pub const DbiStreamHeader = extern struct { |
| 23 | VersionSignature: i32, | |
| 24 | VersionHeader: u32, | |
| 25 | Age: u32, | |
| 26 | GlobalStreamIndex: u16, | |
| 27 | BuildNumber: u16, | |
| 28 | PublicStreamIndex: u16, | |
| 29 | PdbDllVersion: u16, | |
| 30 | SymRecordStream: u16, | |
| 31 | PdbDllRbld: u16, | |
| 32 | ModInfoSize: u32, | |
| 33 | SectionContributionSize: u32, | |
| 34 | SectionMapSize: u32, | |
| 35 | SourceInfoSize: i32, | |
| 36 | TypeServerSize: i32, | |
| 37 | MFCTypeServerIndex: u32, | |
| 38 | OptionalDbgHeaderSize: i32, | |
| 39 | ECSubstreamSize: i32, | |
| 40 | Flags: u16, | |
| 41 | Machine: u16, | |
| 42 | Padding: u32, | |
| 23 | version_signature: i32, | |
| 24 | version_header: u32, | |
| 25 | age: u32, | |
| 26 | global_stream_index: u16, | |
| 27 | build_number: u16, | |
| 28 | public_stream_index: u16, | |
| 29 | pdb_dll_version: u16, | |
| 30 | sym_record_stream: u16, | |
| 31 | pdb_dll_rbld: u16, | |
| 32 | mod_info_size: u32, | |
| 33 | section_contribution_size: u32, | |
| 34 | section_map_size: u32, | |
| 35 | source_info_size: i32, | |
| 36 | type_server_size: i32, | |
| 37 | mfc_type_server_index: u32, | |
| 38 | optional_dbg_header_size: i32, | |
| 39 | ec_substream_size: i32, | |
| 40 | flags: u16, | |
| 41 | machine: u16, | |
| 42 | padding: u32, | |
| 43 | 43 | }; |
| 44 | 44 | |
| 45 | 45 | pub const SectionContribEntry = extern struct { |
| 46 | 46 | /// COFF Section index, 1-based |
| 47 | Section: u16, | |
| 48 | Padding1: [2]u8, | |
| 49 | Offset: u32, | |
| 50 | Size: u32, | |
| 51 | Characteristics: u32, | |
| 52 | ModuleIndex: u16, | |
| 53 | Padding2: [2]u8, | |
| 54 | DataCrc: u32, | |
| 55 | RelocCrc: u32, | |
| 47 | section: u16, | |
| 48 | padding1: [2]u8, | |
| 49 | offset: u32, | |
| 50 | size: u32, | |
| 51 | characteristics: u32, | |
| 52 | module_index: u16, | |
| 53 | padding2: [2]u8, | |
| 54 | data_crc: u32, | |
| 55 | reloc_crc: u32, | |
| 56 | 56 | }; |
| 57 | 57 | |
| 58 | 58 | pub const ModInfo = extern struct { |
| 59 | Unused1: u32, | |
| 60 | SectionContr: SectionContribEntry, | |
| 61 | Flags: u16, | |
| 62 | ModuleSymStream: u16, | |
| 63 | SymByteSize: u32, | |
| 64 | C11ByteSize: u32, | |
| 65 | C13ByteSize: u32, | |
| 66 | SourceFileCount: u16, | |
| 67 | Padding: [2]u8, | |
| 68 | Unused2: u32, | |
| 69 | SourceFileNameIndex: u32, | |
| 70 | PdbFilePathNameIndex: u32, | |
| 59 | unused1: u32, | |
| 60 | section_contr: SectionContribEntry, | |
| 61 | flags: u16, | |
| 62 | module_sym_stream: u16, | |
| 63 | sym_byte_size: u32, | |
| 64 | c11_byte_size: u32, | |
| 65 | c13_byte_size: u32, | |
| 66 | source_file_count: u16, | |
| 67 | padding: [2]u8, | |
| 68 | unused2: u32, | |
| 69 | source_file_name_index: u32, | |
| 70 | pdb_file_path_name_index: u32, | |
| 71 | 71 | // These fields are variable length |
| 72 | //ModuleName: char[], | |
| 73 | //ObjFileName: char[], | |
| 72 | //module_name: char[], | |
| 73 | //obj_file_name: char[], | |
| 74 | 74 | }; |
| 75 | 75 | |
| 76 | 76 | pub const SectionMapHeader = extern struct { |
| 77 | 77 | /// Number of segment descriptors |
| 78 | Count: u16, | |
| 78 | count: u16, | |
| 79 | 79 | |
| 80 | 80 | /// Number of logical segment descriptors |
| 81 | LogCount: u16, | |
| 81 | log_count: u16, | |
| 82 | 82 | }; |
| 83 | 83 | |
| 84 | 84 | pub const SectionMapEntry = extern struct { |
| 85 | 85 | /// See the SectionMapEntryFlags enum below. |
| 86 | Flags: u16, | |
| 86 | flags: u16, | |
| 87 | 87 | |
| 88 | 88 | /// Logical overlay number |
| 89 | Ovl: u16, | |
| 89 | ovl: u16, | |
| 90 | 90 | |
| 91 | 91 | /// Group index into descriptor array. |
| 92 | Group: u16, | |
| 93 | Frame: u16, | |
| 92 | group: u16, | |
| 93 | frame: u16, | |
| 94 | 94 | |
| 95 | 95 | /// Byte index of segment / group name in string table, or 0xFFFF. |
| 96 | SectionName: u16, | |
| 96 | section_name: u16, | |
| 97 | 97 | |
| 98 | 98 | /// Byte index of class in string table, or 0xFFFF. |
| 99 | ClassName: u16, | |
| 99 | class_name: u16, | |
| 100 | 100 | |
| 101 | 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 | 104 | /// Byte count of the segment or group. |
| 105 | SectionLength: u32, | |
| 105 | section_length: u32, | |
| 106 | 106 | }; |
| 107 | 107 | |
| 108 | 108 | pub const StreamType = enum(u16) { |
| 109 | Pdb = 1, | |
| 110 | Tpi = 2, | |
| 111 | Dbi = 3, | |
| 112 | Ipi = 4, | |
| 109 | pdb = 1, | |
| 110 | tpi = 2, | |
| 111 | dbi = 3, | |
| 112 | ipi = 4, | |
| 113 | 113 | }; |
| 114 | 114 | |
| 115 | 115 | /// Duplicate copy of SymbolRecordKind, but using the official CV names. Useful |
| 116 | 116 | /// for reference purposes and when dealing with unknown record types. |
| 117 | 117 | pub const SymbolKind = enum(u16) { |
| 118 | S_COMPILE = 1, | |
| 119 | S_REGISTER_16t = 2, | |
| 120 | S_CONSTANT_16t = 3, | |
| 121 | S_UDT_16t = 4, | |
| 122 | S_SSEARCH = 5, | |
| 123 | S_SKIP = 7, | |
| 124 | S_CVRESERVE = 8, | |
| 125 | S_OBJNAME_ST = 9, | |
| 126 | S_ENDARG = 10, | |
| 127 | S_COBOLUDT_16t = 11, | |
| 128 | S_MANYREG_16t = 12, | |
| 129 | S_RETURN = 13, | |
| 130 | S_ENTRYTHIS = 14, | |
| 131 | S_BPREL16 = 256, | |
| 132 | S_LDATA16 = 257, | |
| 133 | S_GDATA16 = 258, | |
| 134 | S_PUB16 = 259, | |
| 135 | S_LPROC16 = 260, | |
| 136 | S_GPROC16 = 261, | |
| 137 | S_THUNK16 = 262, | |
| 138 | S_BLOCK16 = 263, | |
| 139 | S_WITH16 = 264, | |
| 140 | S_LABEL16 = 265, | |
| 141 | S_CEXMODEL16 = 266, | |
| 142 | S_VFTABLE16 = 267, | |
| 143 | S_REGREL16 = 268, | |
| 144 | S_BPREL32_16t = 512, | |
| 145 | S_LDATA32_16t = 513, | |
| 146 | S_GDATA32_16t = 514, | |
| 147 | S_PUB32_16t = 515, | |
| 148 | S_LPROC32_16t = 516, | |
| 149 | S_GPROC32_16t = 517, | |
| 150 | S_THUNK32_ST = 518, | |
| 151 | S_BLOCK32_ST = 519, | |
| 152 | S_WITH32_ST = 520, | |
| 153 | S_LABEL32_ST = 521, | |
| 154 | S_CEXMODEL32 = 522, | |
| 155 | S_VFTABLE32_16t = 523, | |
| 156 | S_REGREL32_16t = 524, | |
| 157 | S_LTHREAD32_16t = 525, | |
| 158 | S_GTHREAD32_16t = 526, | |
| 159 | S_SLINK32 = 527, | |
| 160 | S_LPROCMIPS_16t = 768, | |
| 161 | S_GPROCMIPS_16t = 769, | |
| 162 | S_PROCREF_ST = 1024, | |
| 163 | S_DATAREF_ST = 1025, | |
| 164 | S_ALIGN = 1026, | |
| 165 | S_LPROCREF_ST = 1027, | |
| 166 | S_OEM = 1028, | |
| 167 | S_TI16_MAX = 4096, | |
| 168 | S_REGISTER_ST = 4097, | |
| 169 | S_CONSTANT_ST = 4098, | |
| 170 | S_UDT_ST = 4099, | |
| 171 | S_COBOLUDT_ST = 4100, | |
| 172 | S_MANYREG_ST = 4101, | |
| 173 | S_BPREL32_ST = 4102, | |
| 174 | S_LDATA32_ST = 4103, | |
| 175 | S_GDATA32_ST = 4104, | |
| 176 | S_PUB32_ST = 4105, | |
| 177 | S_LPROC32_ST = 4106, | |
| 178 | S_GPROC32_ST = 4107, | |
| 179 | S_VFTABLE32 = 4108, | |
| 180 | S_REGREL32_ST = 4109, | |
| 181 | S_LTHREAD32_ST = 4110, | |
| 182 | S_GTHREAD32_ST = 4111, | |
| 183 | S_LPROCMIPS_ST = 4112, | |
| 184 | S_GPROCMIPS_ST = 4113, | |
| 185 | S_COMPILE2_ST = 4115, | |
| 186 | S_MANYREG2_ST = 4116, | |
| 187 | S_LPROCIA64_ST = 4117, | |
| 188 | S_GPROCIA64_ST = 4118, | |
| 189 | S_LOCALSLOT_ST = 4119, | |
| 190 | S_PARAMSLOT_ST = 4120, | |
| 191 | S_ANNOTATION = 4121, | |
| 192 | S_GMANPROC_ST = 4122, | |
| 193 | S_LMANPROC_ST = 4123, | |
| 194 | S_RESERVED1 = 4124, | |
| 195 | S_RESERVED2 = 4125, | |
| 196 | S_RESERVED3 = 4126, | |
| 197 | S_RESERVED4 = 4127, | |
| 198 | S_LMANDATA_ST = 4128, | |
| 199 | S_GMANDATA_ST = 4129, | |
| 200 | S_MANFRAMEREL_ST = 4130, | |
| 201 | S_MANREGISTER_ST = 4131, | |
| 202 | S_MANSLOT_ST = 4132, | |
| 203 | S_MANMANYREG_ST = 4133, | |
| 204 | S_MANREGREL_ST = 4134, | |
| 205 | S_MANMANYREG2_ST = 4135, | |
| 206 | S_MANTYPREF = 4136, | |
| 207 | S_UNAMESPACE_ST = 4137, | |
| 208 | S_ST_MAX = 4352, | |
| 209 | S_WITH32 = 4356, | |
| 210 | S_MANYREG = 4362, | |
| 211 | S_LPROCMIPS = 4372, | |
| 212 | S_GPROCMIPS = 4373, | |
| 213 | S_MANYREG2 = 4375, | |
| 214 | S_LPROCIA64 = 4376, | |
| 215 | S_GPROCIA64 = 4377, | |
| 216 | S_LOCALSLOT = 4378, | |
| 217 | S_PARAMSLOT = 4379, | |
| 218 | S_MANFRAMEREL = 4382, | |
| 219 | S_MANREGISTER = 4383, | |
| 220 | S_MANSLOT = 4384, | |
| 221 | S_MANMANYREG = 4385, | |
| 222 | S_MANREGREL = 4386, | |
| 223 | S_MANMANYREG2 = 4387, | |
| 224 | S_UNAMESPACE = 4388, | |
| 225 | S_DATAREF = 4390, | |
| 226 | S_ANNOTATIONREF = 4392, | |
| 227 | S_TOKENREF = 4393, | |
| 228 | S_GMANPROC = 4394, | |
| 229 | S_LMANPROC = 4395, | |
| 230 | S_ATTR_FRAMEREL = 4398, | |
| 231 | S_ATTR_REGISTER = 4399, | |
| 232 | S_ATTR_REGREL = 4400, | |
| 233 | S_ATTR_MANYREG = 4401, | |
| 234 | S_SEPCODE = 4402, | |
| 235 | S_LOCAL_2005 = 4403, | |
| 236 | S_DEFRANGE_2005 = 4404, | |
| 237 | S_DEFRANGE2_2005 = 4405, | |
| 238 | S_DISCARDED = 4411, | |
| 239 | S_LPROCMIPS_ID = 4424, | |
| 240 | S_GPROCMIPS_ID = 4425, | |
| 241 | S_LPROCIA64_ID = 4426, | |
| 242 | S_GPROCIA64_ID = 4427, | |
| 243 | S_DEFRANGE_HLSL = 4432, | |
| 244 | S_GDATA_HLSL = 4433, | |
| 245 | S_LDATA_HLSL = 4434, | |
| 246 | S_LOCAL_DPC_GROUPSHARED = 4436, | |
| 247 | S_DEFRANGE_DPC_PTR_TAG = 4439, | |
| 248 | S_DPC_SYM_TAG_MAP = 4440, | |
| 249 | S_ARMSWITCHTABLE = 4441, | |
| 250 | S_POGODATA = 4444, | |
| 251 | S_INLINESITE2 = 4445, | |
| 252 | S_MOD_TYPEREF = 4447, | |
| 253 | S_REF_MINIPDB = 4448, | |
| 254 | S_PDBMAP = 4449, | |
| 255 | S_GDATA_HLSL32 = 4450, | |
| 256 | S_LDATA_HLSL32 = 4451, | |
| 257 | S_GDATA_HLSL32_EX = 4452, | |
| 258 | S_LDATA_HLSL32_EX = 4453, | |
| 259 | S_FASTLINK = 4455, | |
| 260 | S_INLINEES = 4456, | |
| 261 | S_END = 6, | |
| 262 | S_INLINESITE_END = 4430, | |
| 263 | S_PROC_ID_END = 4431, | |
| 264 | S_THUNK32 = 4354, | |
| 265 | S_TRAMPOLINE = 4396, | |
| 266 | S_SECTION = 4406, | |
| 267 | S_COFFGROUP = 4407, | |
| 268 | S_EXPORT = 4408, | |
| 269 | S_LPROC32 = 4367, | |
| 270 | S_GPROC32 = 4368, | |
| 271 | S_LPROC32_ID = 4422, | |
| 272 | S_GPROC32_ID = 4423, | |
| 273 | S_LPROC32_DPC = 4437, | |
| 274 | S_LPROC32_DPC_ID = 4438, | |
| 275 | S_REGISTER = 4358, | |
| 276 | S_PUB32 = 4366, | |
| 277 | S_PROCREF = 4389, | |
| 278 | S_LPROCREF = 4391, | |
| 279 | S_ENVBLOCK = 4413, | |
| 280 | S_INLINESITE = 4429, | |
| 281 | S_LOCAL = 4414, | |
| 282 | S_DEFRANGE = 4415, | |
| 283 | S_DEFRANGE_SUBFIELD = 4416, | |
| 284 | S_DEFRANGE_REGISTER = 4417, | |
| 285 | S_DEFRANGE_FRAMEPOINTER_REL = 4418, | |
| 286 | S_DEFRANGE_SUBFIELD_REGISTER = 4419, | |
| 287 | S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE = 4420, | |
| 288 | S_DEFRANGE_REGISTER_REL = 4421, | |
| 289 | S_BLOCK32 = 4355, | |
| 290 | S_LABEL32 = 4357, | |
| 291 | S_OBJNAME = 4353, | |
| 292 | S_COMPILE2 = 4374, | |
| 293 | S_COMPILE3 = 4412, | |
| 294 | S_FRAMEPROC = 4114, | |
| 295 | S_CALLSITEINFO = 4409, | |
| 296 | S_FILESTATIC = 4435, | |
| 297 | S_HEAPALLOCSITE = 4446, | |
| 298 | S_FRAMECOOKIE = 4410, | |
| 299 | S_CALLEES = 4442, | |
| 300 | S_CALLERS = 4443, | |
| 301 | S_UDT = 4360, | |
| 302 | S_COBOLUDT = 4361, | |
| 303 | S_BUILDINFO = 4428, | |
| 304 | S_BPREL32 = 4363, | |
| 305 | S_REGREL32 = 4369, | |
| 306 | S_CONSTANT = 4359, | |
| 307 | S_MANCONSTANT = 4397, | |
| 308 | S_LDATA32 = 4364, | |
| 309 | S_GDATA32 = 4365, | |
| 310 | S_LMANDATA = 4380, | |
| 311 | S_GMANDATA = 4381, | |
| 312 | S_LTHREAD32 = 4370, | |
| 313 | S_GTHREAD32 = 4371, | |
| 118 | compile = 1, | |
| 119 | register_16t = 2, | |
| 120 | constant_16t = 3, | |
| 121 | udt_16t = 4, | |
| 122 | ssearch = 5, | |
| 123 | skip = 7, | |
| 124 | cvreserve = 8, | |
| 125 | objname_st = 9, | |
| 126 | endarg = 10, | |
| 127 | coboludt_16t = 11, | |
| 128 | manyreg_16t = 12, | |
| 129 | @"return" = 13, | |
| 130 | entrythis = 14, | |
| 131 | bprel16 = 256, | |
| 132 | ldata16 = 257, | |
| 133 | gdata16 = 258, | |
| 134 | pub16 = 259, | |
| 135 | lproc16 = 260, | |
| 136 | gproc16 = 261, | |
| 137 | thunk16 = 262, | |
| 138 | block16 = 263, | |
| 139 | with16 = 264, | |
| 140 | label16 = 265, | |
| 141 | cexmodel16 = 266, | |
| 142 | vftable16 = 267, | |
| 143 | regrel16 = 268, | |
| 144 | bprel32_16t = 512, | |
| 145 | ldata32_16t = 513, | |
| 146 | gdata32_16t = 514, | |
| 147 | pub32_16t = 515, | |
| 148 | lproc32_16t = 516, | |
| 149 | gproc32_16t = 517, | |
| 150 | thunk32_st = 518, | |
| 151 | block32_st = 519, | |
| 152 | with32_st = 520, | |
| 153 | label32_st = 521, | |
| 154 | cexmodel32 = 522, | |
| 155 | vftable32_16t = 523, | |
| 156 | regrel32_16t = 524, | |
| 157 | lthread32_16t = 525, | |
| 158 | gthread32_16t = 526, | |
| 159 | slink32 = 527, | |
| 160 | lprocmips_16t = 768, | |
| 161 | gprocmips_16t = 769, | |
| 162 | procref_st = 1024, | |
| 163 | dataref_st = 1025, | |
| 164 | @"align" = 1026, | |
| 165 | lprocref_st = 1027, | |
| 166 | oem = 1028, | |
| 167 | ti16_max = 4096, | |
| 168 | register_st = 4097, | |
| 169 | constant_st = 4098, | |
| 170 | udt_st = 4099, | |
| 171 | coboludt_st = 4100, | |
| 172 | manyreg_st = 4101, | |
| 173 | bprel32_st = 4102, | |
| 174 | ldata32_st = 4103, | |
| 175 | gdata32_st = 4104, | |
| 176 | pub32_st = 4105, | |
| 177 | lproc32_st = 4106, | |
| 178 | gproc32_st = 4107, | |
| 179 | vftable32 = 4108, | |
| 180 | regrel32_st = 4109, | |
| 181 | lthread32_st = 4110, | |
| 182 | gthread32_st = 4111, | |
| 183 | lprocmips_st = 4112, | |
| 184 | gprocmips_st = 4113, | |
| 185 | compile2_st = 4115, | |
| 186 | manyreg2_st = 4116, | |
| 187 | lprocia64_st = 4117, | |
| 188 | gprocia64_st = 4118, | |
| 189 | localslot_st = 4119, | |
| 190 | paramslot_st = 4120, | |
| 191 | annotation = 4121, | |
| 192 | gmanproc_st = 4122, | |
| 193 | lmanproc_st = 4123, | |
| 194 | reserved1 = 4124, | |
| 195 | reserved2 = 4125, | |
| 196 | reserved3 = 4126, | |
| 197 | reserved4 = 4127, | |
| 198 | lmandata_st = 4128, | |
| 199 | gmandata_st = 4129, | |
| 200 | manframerel_st = 4130, | |
| 201 | manregister_st = 4131, | |
| 202 | manslot_st = 4132, | |
| 203 | manmanyreg_st = 4133, | |
| 204 | manregrel_st = 4134, | |
| 205 | manmanyreg2_st = 4135, | |
| 206 | mantypref = 4136, | |
| 207 | unamespace_st = 4137, | |
| 208 | st_max = 4352, | |
| 209 | with32 = 4356, | |
| 210 | manyreg = 4362, | |
| 211 | lprocmips = 4372, | |
| 212 | gprocmips = 4373, | |
| 213 | manyreg2 = 4375, | |
| 214 | lprocia64 = 4376, | |
| 215 | gprocia64 = 4377, | |
| 216 | localslot = 4378, | |
| 217 | paramslot = 4379, | |
| 218 | manframerel = 4382, | |
| 219 | manregister = 4383, | |
| 220 | manslot = 4384, | |
| 221 | manmanyreg = 4385, | |
| 222 | manregrel = 4386, | |
| 223 | manmanyreg2 = 4387, | |
| 224 | unamespace = 4388, | |
| 225 | dataref = 4390, | |
| 226 | annotationref = 4392, | |
| 227 | tokenref = 4393, | |
| 228 | gmanproc = 4394, | |
| 229 | lmanproc = 4395, | |
| 230 | attr_framerel = 4398, | |
| 231 | attr_register = 4399, | |
| 232 | attr_regrel = 4400, | |
| 233 | attr_manyreg = 4401, | |
| 234 | sepcode = 4402, | |
| 235 | local_2005 = 4403, | |
| 236 | defrange_2005 = 4404, | |
| 237 | defrange2_2005 = 4405, | |
| 238 | discarded = 4411, | |
| 239 | lprocmips_id = 4424, | |
| 240 | gprocmips_id = 4425, | |
| 241 | lprocia64_id = 4426, | |
| 242 | gprocia64_id = 4427, | |
| 243 | defrange_hlsl = 4432, | |
| 244 | gdata_hlsl = 4433, | |
| 245 | ldata_hlsl = 4434, | |
| 246 | local_dpc_groupshared = 4436, | |
| 247 | defrange_dpc_ptr_tag = 4439, | |
| 248 | dpc_sym_tag_map = 4440, | |
| 249 | armswitchtable = 4441, | |
| 250 | pogodata = 4444, | |
| 251 | inlinesite2 = 4445, | |
| 252 | mod_typeref = 4447, | |
| 253 | ref_minipdb = 4448, | |
| 254 | pdbmap = 4449, | |
| 255 | gdata_hlsl32 = 4450, | |
| 256 | ldata_hlsl32 = 4451, | |
| 257 | gdata_hlsl32_ex = 4452, | |
| 258 | ldata_hlsl32_ex = 4453, | |
| 259 | fastlink = 4455, | |
| 260 | inlinees = 4456, | |
| 261 | end = 6, | |
| 262 | inlinesite_end = 4430, | |
| 263 | proc_id_end = 4431, | |
| 264 | thunk32 = 4354, | |
| 265 | trampoline = 4396, | |
| 266 | section = 4406, | |
| 267 | coffgroup = 4407, | |
| 268 | @"export" = 4408, | |
| 269 | lproc32 = 4367, | |
| 270 | gproc32 = 4368, | |
| 271 | lproc32_id = 4422, | |
| 272 | gproc32_id = 4423, | |
| 273 | lproc32_dpc = 4437, | |
| 274 | lproc32_dpc_id = 4438, | |
| 275 | register = 4358, | |
| 276 | pub32 = 4366, | |
| 277 | procref = 4389, | |
| 278 | lprocref = 4391, | |
| 279 | envblock = 4413, | |
| 280 | inlinesite = 4429, | |
| 281 | local = 4414, | |
| 282 | defrange = 4415, | |
| 283 | defrange_subfield = 4416, | |
| 284 | defrange_register = 4417, | |
| 285 | defrange_framepointer_rel = 4418, | |
| 286 | defrange_subfield_register = 4419, | |
| 287 | defrange_framepointer_rel_full_scope = 4420, | |
| 288 | defrange_register_rel = 4421, | |
| 289 | block32 = 4355, | |
| 290 | label32 = 4357, | |
| 291 | objname = 4353, | |
| 292 | compile2 = 4374, | |
| 293 | compile3 = 4412, | |
| 294 | frameproc = 4114, | |
| 295 | callsiteinfo = 4409, | |
| 296 | filestatic = 4435, | |
| 297 | heapallocsite = 4446, | |
| 298 | framecookie = 4410, | |
| 299 | callees = 4442, | |
| 300 | callers = 4443, | |
| 301 | udt = 4360, | |
| 302 | coboludt = 4361, | |
| 303 | buildinfo = 4428, | |
| 304 | bprel32 = 4363, | |
| 305 | regrel32 = 4369, | |
| 306 | constant = 4359, | |
| 307 | manconstant = 4397, | |
| 308 | ldata32 = 4364, | |
| 309 | gdata32 = 4365, | |
| 310 | lmandata = 4380, | |
| 311 | gmandata = 4381, | |
| 312 | lthread32 = 4370, | |
| 313 | gthread32 = 4371, | |
| 314 | 314 | }; |
| 315 | 315 | |
| 316 | 316 | pub const TypeIndex = u32; |
| ... | ... | @@ -320,28 +320,28 @@ pub const TypeIndex = u32; |
| 320 | 320 | // we should define RecordPrefix as part of the ProcSym structure. |
| 321 | 321 | // This might be important when we start generating PDB in self-hosted with our own PE linker. |
| 322 | 322 | pub const ProcSym = extern struct { |
| 323 | Parent: u32, | |
| 324 | End: u32, | |
| 325 | Next: u32, | |
| 326 | CodeSize: u32, | |
| 327 | DbgStart: u32, | |
| 328 | DbgEnd: u32, | |
| 329 | FunctionType: TypeIndex, | |
| 330 | CodeOffset: u32, | |
| 331 | Segment: u16, | |
| 332 | Flags: ProcSymFlags, | |
| 333 | Name: [1]u8, // null-terminated | |
| 323 | parent: u32, | |
| 324 | end: u32, | |
| 325 | next: u32, | |
| 326 | code_size: u32, | |
| 327 | dbg_start: u32, | |
| 328 | dbg_end: u32, | |
| 329 | function_type: TypeIndex, | |
| 330 | code_offset: u32, | |
| 331 | segment: u16, | |
| 332 | flags: ProcSymFlags, | |
| 333 | name: [1]u8, // null-terminated | |
| 334 | 334 | }; |
| 335 | 335 | |
| 336 | 336 | pub const ProcSymFlags = packed struct { |
| 337 | HasFP: bool, | |
| 338 | HasIRET: bool, | |
| 339 | HasFRET: bool, | |
| 340 | IsNoReturn: bool, | |
| 341 | IsUnreachable: bool, | |
| 342 | HasCustomCallingConv: bool, | |
| 343 | IsNoInline: bool, | |
| 344 | HasOptimizedDebugInfo: bool, | |
| 337 | has_fp: bool, | |
| 338 | has_iret: bool, | |
| 339 | has_fret: bool, | |
| 340 | is_no_return: bool, | |
| 341 | is_unreachable: bool, | |
| 342 | has_custom_calling_conv: bool, | |
| 343 | is_no_inline: bool, | |
| 344 | has_optimized_debug_info: bool, | |
| 345 | 345 | }; |
| 346 | 346 | |
| 347 | 347 | pub const SectionContrSubstreamVersion = enum(u32) { |
| ... | ... | @@ -351,11 +351,11 @@ pub const SectionContrSubstreamVersion = enum(u32) { |
| 351 | 351 | }; |
| 352 | 352 | |
| 353 | 353 | pub const RecordPrefix = extern struct { |
| 354 | /// Record length, starting from &RecordKind. | |
| 355 | RecordLen: u16, | |
| 354 | /// Record length, starting from &record_kind. | |
| 355 | record_len: u16, | |
| 356 | 356 | |
| 357 | 357 | /// Record kind enum (SymRecordKind or TypeRecordKind) |
| 358 | RecordKind: SymbolKind, | |
| 358 | record_kind: SymbolKind, | |
| 359 | 359 | }; |
| 360 | 360 | |
| 361 | 361 | /// The following variable length array appears immediately after the header. |
| ... | ... | @@ -364,19 +364,19 @@ pub const RecordPrefix = extern struct { |
| 364 | 364 | /// Each `LineBlockFragmentHeader` as specified below. |
| 365 | 365 | pub const LineFragmentHeader = extern struct { |
| 366 | 366 | /// Code offset of line contribution. |
| 367 | RelocOffset: u32, | |
| 367 | reloc_offset: u32, | |
| 368 | 368 | |
| 369 | 369 | /// Code segment of line contribution. |
| 370 | RelocSegment: u16, | |
| 371 | Flags: LineFlags, | |
| 370 | reloc_segment: u16, | |
| 371 | flags: LineFlags, | |
| 372 | 372 | |
| 373 | 373 | /// Code size of this line contribution. |
| 374 | CodeSize: u32, | |
| 374 | code_size: u32, | |
| 375 | 375 | }; |
| 376 | 376 | |
| 377 | 377 | pub const LineFlags = packed struct { |
| 378 | 378 | /// CV_LINES_HAVE_COLUMNS |
| 379 | LF_HaveColumns: bool, | |
| 379 | have_columns: bool, | |
| 380 | 380 | unused: u15, |
| 381 | 381 | }; |
| 382 | 382 | |
| ... | ... | @@ -389,110 +389,109 @@ pub const LineBlockFragmentHeader = extern struct { |
| 389 | 389 | /// checksums buffer. The checksum entry then |
| 390 | 390 | /// contains another offset into the string |
| 391 | 391 | /// table of the actual name. |
| 392 | NameIndex: u32, | |
| 393 | NumLines: u32, | |
| 392 | name_index: u32, | |
| 393 | num_lines: u32, | |
| 394 | 394 | |
| 395 | 395 | /// code size of block, in bytes |
| 396 | BlockSize: u32, | |
| 396 | block_size: u32, | |
| 397 | 397 | }; |
| 398 | 398 | |
| 399 | 399 | pub const LineNumberEntry = extern struct { |
| 400 | 400 | /// Offset to start of code bytes for line number |
| 401 | Offset: u32, | |
| 402 | Flags: u32, | |
| 401 | offset: u32, | |
| 402 | flags: Flags, | |
| 403 | 403 | |
| 404 | /// TODO runtime crash when I make the actual type of Flags this | |
| 405 | pub const Flags = packed struct { | |
| 404 | pub const Flags = packed struct(u32) { | |
| 406 | 405 | /// Start line number |
| 407 | Start: u24, | |
| 406 | start: u24, | |
| 408 | 407 | /// Delta of lines to the end of the expression. Still unclear. |
| 409 | 408 | // TODO figure out the point of this field. |
| 410 | End: u7, | |
| 411 | IsStatement: bool, | |
| 409 | end: u7, | |
| 410 | is_statement: bool, | |
| 412 | 411 | }; |
| 413 | 412 | }; |
| 414 | 413 | |
| 415 | 414 | pub const ColumnNumberEntry = extern struct { |
| 416 | StartColumn: u16, | |
| 417 | EndColumn: u16, | |
| 415 | start_column: u16, | |
| 416 | end_column: u16, | |
| 418 | 417 | }; |
| 419 | 418 | |
| 420 | 419 | /// Checksum bytes follow. |
| 421 | 420 | pub const FileChecksumEntryHeader = extern struct { |
| 422 | 421 | /// Byte offset of filename in global string table. |
| 423 | FileNameOffset: u32, | |
| 422 | file_name_offset: u32, | |
| 424 | 423 | /// Number of bytes of checksum. |
| 425 | ChecksumSize: u8, | |
| 424 | checksum_size: u8, | |
| 426 | 425 | /// FileChecksumKind |
| 427 | ChecksumKind: u8, | |
| 426 | checksum_kind: u8, | |
| 428 | 427 | }; |
| 429 | 428 | |
| 430 | 429 | pub const DebugSubsectionKind = enum(u32) { |
| 431 | None = 0, | |
| 432 | Symbols = 0xf1, | |
| 433 | Lines = 0xf2, | |
| 434 | StringTable = 0xf3, | |
| 435 | FileChecksums = 0xf4, | |
| 436 | FrameData = 0xf5, | |
| 437 | InlineeLines = 0xf6, | |
| 438 | CrossScopeImports = 0xf7, | |
| 439 | CrossScopeExports = 0xf8, | |
| 430 | none = 0, | |
| 431 | symbols = 0xf1, | |
| 432 | lines = 0xf2, | |
| 433 | string_table = 0xf3, | |
| 434 | file_checksums = 0xf4, | |
| 435 | frame_data = 0xf5, | |
| 436 | inlinee_lines = 0xf6, | |
| 437 | cross_scope_imports = 0xf7, | |
| 438 | cross_scope_exports = 0xf8, | |
| 440 | 439 | |
| 441 | 440 | // These appear to relate to .Net assembly info. |
| 442 | ILLines = 0xf9, | |
| 443 | FuncMDTokenMap = 0xfa, | |
| 444 | TypeMDTokenMap = 0xfb, | |
| 445 | MergedAssemblyInput = 0xfc, | |
| 441 | il_lines = 0xf9, | |
| 442 | func_md_token_map = 0xfa, | |
| 443 | type_md_token_map = 0xfb, | |
| 444 | merged_assembly_input = 0xfc, | |
| 446 | 445 | |
| 447 | CoffSymbolRVA = 0xfd, | |
| 446 | coff_symbol_rva = 0xfd, | |
| 448 | 447 | }; |
| 449 | 448 | |
| 450 | 449 | pub const DebugSubsectionHeader = extern struct { |
| 451 | 450 | /// codeview::DebugSubsectionKind enum |
| 452 | Kind: DebugSubsectionKind, | |
| 451 | kind: DebugSubsectionKind, | |
| 453 | 452 | |
| 454 | 453 | /// number of bytes occupied by this record. |
| 455 | Length: u32, | |
| 454 | length: u32, | |
| 456 | 455 | }; |
| 457 | 456 | |
| 458 | 457 | pub const StringTableHeader = extern struct { |
| 459 | 458 | /// PDBStringTableSignature |
| 460 | Signature: u32, | |
| 459 | signature: u32, | |
| 461 | 460 | /// 1 or 2 |
| 462 | HashVersion: u32, | |
| 461 | hash_version: u32, | |
| 463 | 462 | /// Number of bytes of names buffer. |
| 464 | ByteSize: u32, | |
| 463 | byte_size: u32, | |
| 465 | 464 | }; |
| 466 | 465 | |
| 467 | 466 | // https://llvm.org/docs/PDB/MsfFile.html#the-superblock |
| 468 | 467 | pub const SuperBlock = extern struct { |
| 469 | 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 | 473 | /// The block size of the internal file system. Valid values are 512, 1024, |
| 475 | 474 | /// 2048, and 4096 bytes. Certain aspects of the MSF file layout vary depending |
| 476 | 475 | /// on the block sizes. For the purposes of LLVM, we handle only block sizes of |
| 477 | 476 | /// 4KiB, and all further discussion assumes a block size of 4KiB. |
| 478 | BlockSize: u32, | |
| 477 | block_size: u32, | |
| 479 | 478 | |
| 480 | 479 | /// The index of a block within the file, at which begins a bitfield representing |
| 481 | 480 | /// the set of all blocks within the file which are “free” (i.e. the data within |
| 482 | 481 | /// that block is not used). See The Free Block Map for more information. Important: |
| 483 | 482 | /// FreeBlockMapBlock can only be 1 or 2! |
| 484 | FreeBlockMapBlock: u32, | |
| 483 | free_block_map_block: u32, | |
| 485 | 484 | |
| 486 | 485 | /// The total number of blocks in the file. NumBlocks * BlockSize should equal the |
| 487 | 486 | /// size of the file on disk. |
| 488 | NumBlocks: u32, | |
| 487 | num_blocks: u32, | |
| 489 | 488 | |
| 490 | 489 | /// The size of the stream directory, in bytes. The stream directory contains |
| 491 | 490 | /// information about each stream’s size and the set of blocks that it occupies. |
| 492 | 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 | 495 | /// The index of a block within the MSF file. At this block is an array of |
| 497 | 496 | /// ulittle32_t’s listing the blocks that the stream directory resides on. |
| 498 | 497 | /// For large MSF files, the stream directory (which describes the block |
| ... | ... | @@ -508,5 +507,5 @@ pub const SuperBlock = extern struct { |
| 508 | 507 | // This would mean the Stream Directory is bigger than BlockSize / sizeof(u32) |
| 509 | 508 | // blocks. We're not even close to this with a 1GB pdb file, and LLVM didn't |
| 510 | 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 | 4053 | // The source slice is added towards the *end* of this function. |
| 4054 | 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 | 4057 | const fn_name_token = fn_proto.name_token orelse return error.AnalysisFail; |
| 4058 | 4058 | |
| 4059 | 4059 | // We insert this at the beginning so that its instruction index marks the |
| ... | ... | @@ -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 | 5023 | const field_count: u32 = @intCast(container_decl.ast.members.len - decl_count); |
| 5024 | 5024 | |
| 5025 | 5025 | const bits_per_field = 4; |
| ... | ... | @@ -5088,15 +5088,6 @@ fn structDeclInner( |
| 5088 | 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 | 5091 | var known_non_opv = false; |
| 5101 | 5092 | var known_comptime_only = false; |
| 5102 | 5093 | var any_comptime_fields = false; |
| ... | ... | @@ -5117,16 +5108,6 @@ fn structDeclInner( |
| 5117 | 5108 | assert(!member.ast.tuple_like); |
| 5118 | 5109 | |
| 5119 | 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 | 5111 | } else if (!member.ast.tuple_like) { |
| 5131 | 5112 | return astgen.failTok(member.ast.main_token, "tuple field has a name", .{}); |
| 5132 | 5113 | } |
| ... | ... | @@ -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 | 5195 | var fields_hash: std.zig.SrcHash = undefined; |
| 5241 | 5196 | astgen.src_hasher.final(&fields_hash); |
| 5242 | 5197 | |
| ... | ... | @@ -5317,7 +5272,7 @@ fn unionDeclInner( |
| 5317 | 5272 | }; |
| 5318 | 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 | 5276 | const field_count: u32 = @intCast(members.len - decl_count); |
| 5322 | 5277 | |
| 5323 | 5278 | if (layout != .auto and (auto_enum_tok != null or arg_node != 0)) { |
| ... | ... | @@ -5348,15 +5303,6 @@ fn unionDeclInner( |
| 5348 | 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 | 5306 | for (members) |member_node| { |
| 5361 | 5307 | var member = switch (try containerMember(&block_scope, &namespace.base, &wip_members, member_node)) { |
| 5362 | 5308 | .decl => continue, |
| ... | ... | @@ -5374,16 +5320,6 @@ fn unionDeclInner( |
| 5374 | 5320 | const field_name = try astgen.identAsString(member.ast.main_token); |
| 5375 | 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 | 5323 | const doc_comment_index = try astgen.docCommentAsString(member.firstToken()); |
| 5388 | 5324 | wip_members.appendToField(@intFromEnum(doc_comment_index)); |
| 5389 | 5325 | |
| ... | ... | @@ -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 | 5377 | var fields_hash: std.zig.SrcHash = undefined; |
| 5468 | 5378 | astgen.src_hasher.final(&fields_hash); |
| 5469 | 5379 | |
| ... | ... | @@ -5666,7 +5576,7 @@ fn containerDecl( |
| 5666 | 5576 | }; |
| 5667 | 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 | 5580 | namespace.base.tag = .namespace; |
| 5671 | 5581 | |
| 5672 | 5582 | const arg_inst: Zir.Inst.Ref = if (container_decl.ast.arg != 0) |
| ... | ... | @@ -5687,15 +5597,6 @@ fn containerDecl( |
| 5687 | 5597 | } |
| 5688 | 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 | 5600 | for (container_decl.ast.members) |member_node| { |
| 5700 | 5601 | if (member_node == counts.nonexhaustive_node) |
| 5701 | 5602 | continue; |
| ... | ... | @@ -5712,16 +5613,6 @@ fn containerDecl( |
| 5712 | 5613 | const field_name = try astgen.identAsString(member.ast.main_token); |
| 5713 | 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 | 5616 | const doc_comment_index = try astgen.docCommentAsString(member.firstToken()); |
| 5726 | 5617 | wip_members.appendToField(@intFromEnum(doc_comment_index)); |
| 5727 | 5618 | |
| ... | ... | @@ -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 | 5642 | if (!block_scope.isEmpty()) { |
| 5778 | 5643 | _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value); |
| 5779 | 5644 | } |
| ... | ... | @@ -5833,7 +5698,7 @@ fn containerDecl( |
| 5833 | 5698 | }; |
| 5834 | 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 | 5703 | var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, 0, 0, 0); |
| 5839 | 5704 | defer wip_members.deinit(); |
| ... | ... | @@ -13594,31 +13459,67 @@ fn advanceSourceCursor(astgen: *AstGen, end: usize) void { |
| 13594 | 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 | 13470 | const gpa = astgen.gpa; |
| 13599 | 13471 | const tree = astgen.tree; |
| 13600 | 13472 | const node_tags = tree.nodes.items(.tag); |
| 13601 | 13473 | const main_tokens = tree.nodes.items(.main_token); |
| 13602 | 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. | |
| 13605 | var named_tests: std.AutoHashMapUnmanaged(Zir.NullTerminatedString, Ast.Node.Index) = .{}; | |
| 13606 | var decltests: std.AutoHashMapUnmanaged(Zir.NullTerminatedString, Ast.Node.Index) = .{}; | |
| 13476 | // This type forms a linked list of source tokens declaring the same name. | |
| 13477 | const NameEntry = struct { | |
| 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 | 13492 | defer { |
| 13608 | named_tests.deinit(gpa); | |
| 13609 | decltests.deinit(gpa); | |
| 13493 | names.deinit(sfba); | |
| 13494 | test_names.deinit(sfba); | |
| 13495 | decltest_names.deinit(sfba); | |
| 13610 | 13496 | } |
| 13611 | 13497 | |
| 13498 | var any_duplicates = false; | |
| 13612 | 13499 | var decl_count: u32 = 0; |
| 13613 | 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 | 13516 | .global_var_decl, |
| 13616 | 13517 | .local_var_decl, |
| 13617 | 13518 | .simple_var_decl, |
| 13618 | 13519 | .aligned_var_decl, |
| 13619 | 13520 | => blk: { |
| 13620 | 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 | 13525 | .fn_proto_simple, |
| ... | ... | @@ -13630,12 +13531,10 @@ fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const Ast. |
| 13630 | 13531 | decl_count += 1; |
| 13631 | 13532 | const ident = main_tokens[member_node] + 1; |
| 13632 | 13533 | if (token_tags[ident] != .identifier) { |
| 13633 | switch (astgen.failNode(member_node, "missing function name", .{})) { | |
| 13634 | error.AnalysisFail => continue, | |
| 13635 | error.OutOfMemory => return error.OutOfMemory, | |
| 13636 | } | |
| 13534 | try astgen.appendErrorNode(member_node, "missing function name", .{}); | |
| 13535 | continue; | |
| 13637 | 13536 | } |
| 13638 | break :blk ident; | |
| 13537 | break :blk .{ .decl, ident }; | |
| 13639 | 13538 | }, |
| 13640 | 13539 | |
| 13641 | 13540 | .@"comptime", .@"usingnamespace" => { |
| ... | ... | @@ -13648,70 +13547,87 @@ fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const Ast. |
| 13648 | 13547 | // We don't want shadowing detection here, and test names work a bit differently, so |
| 13649 | 13548 | // we must do the redeclaration detection ourselves. |
| 13650 | 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 | 13554 | switch (token_tags[test_name_token]) { |
| 13652 | 13555 | else => {}, // unnamed test |
| 13653 | 13556 | .string_literal => { |
| 13654 | 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 | 13559 | if (gop.found_existing) { |
| 13657 | const name_slice = astgen.string_bytes.items[@intFromEnum(name.index)..][0..name.len]; | |
| 13658 | const name_duped = try gpa.dupe(u8, name_slice); | |
| 13659 | defer gpa.free(name_duped); | |
| 13660 | try astgen.appendErrorNodeNotes(member_node, "duplicate test name '{s}'", .{name_duped}, &.{ | |
| 13661 | try astgen.errNoteNode(gop.value_ptr.*, "other test here", .{}), | |
| 13662 | }); | |
| 13560 | var e = gop.value_ptr; | |
| 13561 | while (e.next) |n| e = n; | |
| 13562 | e.next = try astgen.arena.create(NameEntry); | |
| 13563 | e.next.?.* = new_ent; | |
| 13564 | any_duplicates = true; | |
| 13663 | 13565 | } else { |
| 13664 | gop.value_ptr.* = member_node; | |
| 13566 | gop.value_ptr.* = new_ent; | |
| 13665 | 13567 | } |
| 13666 | 13568 | }, |
| 13667 | 13569 | .identifier => { |
| 13668 | 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 | 13572 | if (gop.found_existing) { |
| 13671 | const name_slice = mem.span(astgen.nullTerminatedString(name)); | |
| 13672 | const name_duped = try gpa.dupe(u8, name_slice); | |
| 13673 | defer gpa.free(name_duped); | |
| 13674 | try astgen.appendErrorNodeNotes(member_node, "duplicate decltest '{s}'", .{name_duped}, &.{ | |
| 13675 | try astgen.errNoteNode(gop.value_ptr.*, "other decltest here", .{}), | |
| 13676 | }); | |
| 13573 | var e = gop.value_ptr; | |
| 13574 | while (e.next) |n| e = n; | |
| 13575 | e.next = try astgen.arena.create(NameEntry); | |
| 13576 | e.next.?.* = new_ent; | |
| 13577 | any_duplicates = true; | |
| 13677 | 13578 | } else { |
| 13678 | gop.value_ptr.* = member_node; | |
| 13579 | gop.value_ptr.* = new_ent; | |
| 13679 | 13580 | } |
| 13680 | 13581 | }, |
| 13681 | 13582 | } |
| 13682 | 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 | 13621 | const token_bytes = astgen.tree.tokenSlice(name_token); |
| 13689 | 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 | 13624 | token_bytes, |
| 13692 | }, &[_]u32{ | |
| 13625 | }, &.{ | |
| 13693 | 13626 | try astgen.errNoteTok(name_token, "consider using @\"{s}\" to disambiguate", .{ |
| 13694 | 13627 | token_bytes, |
| 13695 | 13628 | }), |
| 13696 | })) { | |
| 13697 | error.AnalysisFail => 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 | } | |
| 13629 | }); | |
| 13630 | continue; | |
| 13715 | 13631 | } |
| 13716 | 13632 | |
| 13717 | 13633 | var s = namespace.parent; |
| ... | ... | @@ -13719,30 +13635,32 @@ fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const Ast. |
| 13719 | 13635 | .local_val => { |
| 13720 | 13636 | const local_val = s.cast(Scope.LocalVal).?; |
| 13721 | 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 | 13639 | token_bytes, @tagName(local_val.id_cat), |
| 13724 | }, &[_]u32{ | |
| 13640 | }, &.{ | |
| 13725 | 13641 | try astgen.errNoteTok( |
| 13726 | 13642 | local_val.token_src, |
| 13727 | 13643 | "previous declaration here", |
| 13728 | 13644 | .{}, |
| 13729 | 13645 | ), |
| 13730 | 13646 | }); |
| 13647 | break; | |
| 13731 | 13648 | } |
| 13732 | 13649 | s = local_val.parent; |
| 13733 | 13650 | }, |
| 13734 | 13651 | .local_ptr => { |
| 13735 | 13652 | const local_ptr = s.cast(Scope.LocalPtr).?; |
| 13736 | 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 | 13655 | token_bytes, @tagName(local_ptr.id_cat), |
| 13739 | }, &[_]u32{ | |
| 13656 | }, &.{ | |
| 13740 | 13657 | try astgen.errNoteTok( |
| 13741 | 13658 | local_ptr.token_src, |
| 13742 | 13659 | "previous declaration here", |
| 13743 | 13660 | .{}, |
| 13744 | 13661 | ), |
| 13745 | 13662 | }); |
| 13663 | break; | |
| 13746 | 13664 | } |
| 13747 | 13665 | s = local_ptr.parent; |
| 13748 | 13666 | }, |
| ... | ... | @@ -13751,8 +13669,46 @@ fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const Ast. |
| 13751 | 13669 | .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent, |
| 13752 | 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 | 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 | 1069 | }; |
| 1070 | 1070 | } |
| 1071 | 1071 | |
| 1072 | fn bitfield( | |
| 1072 | fn initBitfield( | |
| 1073 | 1073 | opc: u2, |
| 1074 | 1074 | n: u1, |
| 1075 | 1075 | rd: Register, |
| ... | ... | @@ -1579,7 +1579,7 @@ pub const Instruction = union(enum) { |
| 1579 | 1579 | 64 => 0b1, |
| 1580 | 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 | 1585 | pub fn bfm(rd: Register, rn: Register, immr: u6, imms: u6) Instruction { |
| ... | ... | @@ -1588,7 +1588,7 @@ pub const Instruction = union(enum) { |
| 1588 | 1588 | 64 => 0b1, |
| 1589 | 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 | 1594 | pub fn ubfm(rd: Register, rn: Register, immr: u6, imms: u6) Instruction { |
| ... | ... | @@ -1597,7 +1597,7 @@ pub const Instruction = union(enum) { |
| 1597 | 1597 | 64 => 0b1, |
| 1598 | 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 | 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 | 662 | }; |
| 663 | 663 | } |
| 664 | 664 | |
| 665 | fn multiply( | |
| 665 | fn initMultiply( | |
| 666 | 666 | cond: Condition, |
| 667 | 667 | set_cond: u1, |
| 668 | 668 | rd: Register, |
| ... | ... | @@ -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 | 868 | return Instruction{ |
| 869 | 869 | .branch = .{ |
| 870 | 870 | .cond = @intFromEnum(cond), |
| ... | ... | @@ -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 | 904 | return Instruction{ |
| 905 | 905 | .breakpoint = .{ |
| 906 | 906 | .imm12 = @as(u12, @truncate(imm >> 4)), |
| ... | ... | @@ -1087,19 +1087,19 @@ pub const Instruction = union(enum) { |
| 1087 | 1087 | // Multiply |
| 1088 | 1088 | |
| 1089 | 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 | 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 | 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 | 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 | 1105 | // Multiply long |
| ... | ... | @@ -1261,11 +1261,11 @@ pub const Instruction = union(enum) { |
| 1261 | 1261 | // Branch |
| 1262 | 1262 | |
| 1263 | 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 | 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 | 1271 | // Branch and exchange |
| ... | ... | @@ -1289,7 +1289,7 @@ pub const Instruction = union(enum) { |
| 1289 | 1289 | // Breakpoint |
| 1290 | 1290 | |
| 1291 | 1291 | pub fn bkpt(imm: u16) Instruction { |
| 1292 | return breakpoint(imm); | |
| 1292 | return initBreakpoint(imm); | |
| 1293 | 1293 | } |
| 1294 | 1294 | |
| 1295 | 1295 | // Aliases |
src/arch/x86_64/CodeGen.zig+1-1| ... | ... | @@ -15563,7 +15563,7 @@ fn genLazySymbolRef( |
| 15563 | 15563 | .mov => try self.asmRegisterMemory( |
| 15564 | 15564 | .{ ._, tag }, |
| 15565 | 15565 | reg.to64(), |
| 15566 | Memory.sib(.qword, .{ .base = .{ .reg = reg.to64() } }), | |
| 15566 | Memory.initSib(.qword, .{ .base = .{ .reg = reg.to64() } }), | |
| 15567 | 15567 | ), |
| 15568 | 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 | 95 | |
| 96 | 96 | if (modrm.rip()) { |
| 97 | 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 | 99 | .op2 = op2, |
| 100 | 100 | }); |
| 101 | 101 | } |
| ... | ... | @@ -106,7 +106,7 @@ pub fn next(dis: *Disassembler) Error!?Instruction { |
| 106 | 106 | else |
| 107 | 107 | parseGpRegister(modrm.op2, prefixes.rex.b, prefixes.rex, 64); |
| 108 | 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 | 110 | .base = if (base) |base_reg| .{ .reg = base_reg } else .none, |
| 111 | 111 | .scale_index = scale_index, |
| 112 | 112 | .disp = disp, |
| ... | ... | @@ -119,14 +119,14 @@ pub fn next(dis: *Disassembler) Error!?Instruction { |
| 119 | 119 | const offset = try dis.parseOffset(); |
| 120 | 120 | return inst(enc, .{ |
| 121 | 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 | 125 | .td => { |
| 126 | 126 | const seg = segmentRegister(prefixes.legacy); |
| 127 | 127 | const offset = try dis.parseOffset(); |
| 128 | 128 | return inst(enc, .{ |
| 129 | .op1 = .{ .mem = Memory.moffs(seg, offset) }, | |
| 129 | .op1 = .{ .mem = Memory.initMoffs(seg, offset) }, | |
| 130 | 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 | 153 | |
| 154 | 154 | if (modrm.rip()) { |
| 155 | 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 | 157 | .op2 = .{ .reg = parseGpRegister(modrm.op1, prefixes.rex.r, prefixes.rex, src_bit_size) }, |
| 158 | 158 | .op3 = op3, |
| 159 | 159 | }); |
| ... | ... | @@ -165,7 +165,7 @@ pub fn next(dis: *Disassembler) Error!?Instruction { |
| 165 | 165 | else |
| 166 | 166 | parseGpRegister(modrm.op2, prefixes.rex.b, prefixes.rex, 64); |
| 167 | 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 | 169 | .base = if (base) |base_reg| .{ .reg = base_reg } else .none, |
| 170 | 170 | .scale_index = scale_index, |
| 171 | 171 | .disp = disp, |
| ... | ... | @@ -203,7 +203,7 @@ pub fn next(dis: *Disassembler) Error!?Instruction { |
| 203 | 203 | if (modrm.rip()) { |
| 204 | 204 | return inst(enc, .{ |
| 205 | 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 | 207 | .op3 = op3, |
| 208 | 208 | }); |
| 209 | 209 | } |
| ... | ... | @@ -215,7 +215,7 @@ pub fn next(dis: *Disassembler) Error!?Instruction { |
| 215 | 215 | parseGpRegister(modrm.op2, prefixes.rex.b, prefixes.rex, 64); |
| 216 | 216 | return inst(enc, .{ |
| 217 | 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 | 219 | .base = if (base) |base_reg| .{ .reg = base_reg } else .none, |
| 220 | 220 | .scale_index = scale_index, |
| 221 | 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 | 200 | }); |
| 201 | 201 | try lower.emit(.none, .lea, &.{ |
| 202 | 202 | .{ .reg = inst.data.ri.r1 }, |
| 203 | .{ .mem = Memory.sib(.qword, .{ | |
| 203 | .{ .mem = Memory.initSib(.qword, .{ | |
| 204 | 204 | .base = .{ .reg = inst.data.ri.r1 }, |
| 205 | 205 | .disp = -page_size, |
| 206 | 206 | }) }, |
| 207 | 207 | }); |
| 208 | 208 | try lower.emit(.none, .@"test", &.{ |
| 209 | .{ .mem = Memory.sib(.dword, .{ | |
| 209 | .{ .mem = Memory.initSib(.dword, .{ | |
| 210 | 210 | .base = .{ .reg = inst.data.ri.r1 }, |
| 211 | 211 | }) }, |
| 212 | 212 | .{ .reg = inst.data.ri.r1.to32() }, |
| ... | ... | @@ -220,7 +220,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { |
| 220 | 220 | var offset = page_size; |
| 221 | 221 | while (offset < @as(i32, @bitCast(inst.data.ri.i))) : (offset += page_size) { |
| 222 | 222 | try lower.emit(.none, .@"test", &.{ |
| 223 | .{ .mem = Memory.sib(.dword, .{ | |
| 223 | .{ .mem = Memory.initSib(.dword, .{ | |
| 224 | 224 | .base = .{ .reg = inst.data.ri.r1 }, |
| 225 | 225 | .disp = -offset, |
| 226 | 226 | }) }, |
| ... | ... | @@ -246,7 +246,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { |
| 246 | 246 | }, |
| 247 | 247 | .pseudo_probe_adjust_loop_rr => { |
| 248 | 248 | try lower.emit(.none, .@"test", &.{ |
| 249 | .{ .mem = Memory.sib(.dword, .{ | |
| 249 | .{ .mem = Memory.initSib(.dword, .{ | |
| 250 | 250 | .base = .{ .reg = inst.data.rr.r1 }, |
| 251 | 251 | .scale_index = .{ .scale = 1, .index = inst.data.rr.r2 }, |
| 252 | 252 | .disp = -page_size, |
| ... | ... | @@ -417,7 +417,7 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) |
| 417 | 417 | lower.result_insts[lower.result_insts_len] = |
| 418 | 418 | try Instruction.new(.none, .lea, &[_]Operand{ |
| 419 | 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 | 422 | lower.result_insts_len += 1; |
| 423 | 423 | _ = lower.reloc(.{ |
| ... | ... | @@ -430,7 +430,7 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) |
| 430 | 430 | lower.result_insts_len += 1; |
| 431 | 431 | _ = lower.reloc(.{ .linker_dtpoff = sym_index }, 0); |
| 432 | 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 | 434 | .base = .{ .reg = .rax }, |
| 435 | 435 | .disp = std.math.minInt(i32), |
| 436 | 436 | }) }; |
| ... | ... | @@ -439,12 +439,12 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) |
| 439 | 439 | lower.result_insts[lower.result_insts_len] = |
| 440 | 440 | try Instruction.new(.none, .mov, &[_]Operand{ |
| 441 | 441 | .{ .reg = .rax }, |
| 442 | .{ .mem = Memory.sib(.qword, .{ .base = .{ .reg = .fs } }) }, | |
| 442 | .{ .mem = Memory.initSib(.qword, .{ .base = .{ .reg = .fs } }) }, | |
| 443 | 443 | }); |
| 444 | 444 | lower.result_insts_len += 1; |
| 445 | 445 | _ = lower.reloc(.{ .linker_reloc = sym_index }, 0); |
| 446 | 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 | 448 | .base = .{ .reg = .rax }, |
| 449 | 449 | .disp = std.math.minInt(i32), |
| 450 | 450 | }) }; |
| ... | ... | @@ -455,7 +455,7 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) |
| 455 | 455 | if (lower.pic) switch (mnemonic) { |
| 456 | 456 | .lea => { |
| 457 | 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 | 460 | .mov => { |
| 461 | 461 | if (elf_sym.flags.is_extern_ptr) { |
| ... | ... | @@ -463,25 +463,25 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) |
| 463 | 463 | lower.result_insts[lower.result_insts_len] = |
| 464 | 464 | try Instruction.new(.none, .mov, &[_]Operand{ |
| 465 | 465 | .{ .reg = reg.to64() }, |
| 466 | .{ .mem = Memory.rip(.qword, 0) }, | |
| 466 | .{ .mem = Memory.initRip(.qword, 0) }, | |
| 467 | 467 | }); |
| 468 | 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 | 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 | 475 | else => unreachable, |
| 476 | 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 | 478 | .base = .{ .reg = .ds }, |
| 479 | 479 | }) }, |
| 480 | 480 | .lea => { |
| 481 | 481 | emit_mnemonic = .mov; |
| 482 | 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 | 485 | .base = .{ .reg = .ds }, |
| 486 | 486 | }) }, |
| 487 | 487 | else => unreachable, |
| ... | ... | @@ -495,12 +495,12 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) |
| 495 | 495 | lower.result_insts[lower.result_insts_len] = |
| 496 | 496 | try Instruction.new(.none, .mov, &[_]Operand{ |
| 497 | 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 | 500 | lower.result_insts_len += 1; |
| 501 | 501 | lower.result_insts[lower.result_insts_len] = |
| 502 | 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 | 505 | lower.result_insts_len += 1; |
| 506 | 506 | emit_mnemonic = .mov; |
| ... | ... | @@ -511,7 +511,7 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) |
| 511 | 511 | break :op switch (mnemonic) { |
| 512 | 512 | .lea => { |
| 513 | 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 | 516 | .mov => { |
| 517 | 517 | if (macho_sym.flags.is_extern_ptr) { |
| ... | ... | @@ -519,14 +519,14 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) |
| 519 | 519 | lower.result_insts[lower.result_insts_len] = |
| 520 | 520 | try Instruction.new(.none, .mov, &[_]Operand{ |
| 521 | 521 | .{ .reg = reg.to64() }, |
| 522 | .{ .mem = Memory.rip(.qword, 0) }, | |
| 522 | .{ .mem = Memory.initRip(.qword, 0) }, | |
| 523 | 523 | }); |
| 524 | 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 | 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 | 531 | else => unreachable, |
| 532 | 532 | }; |
| ... | ... | @@ -701,7 +701,7 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void { |
| 701 | 701 | }, extra.off); |
| 702 | 702 | break :ops &.{ |
| 703 | 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 | 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 | 1234 | .rm => { |
| 1235 | 1235 | if (mem.info.base == .reg and @as(Register, @enumFromInt(mem.base)) == .rip) { |
| 1236 | 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 | 1240 | .disp = @bitCast(mem.off), |
| 1241 | 1241 | .base = switch (mem.info.base) { |
| 1242 | 1242 | .none => .none, |
| ... | ... | @@ -1258,7 +1258,7 @@ pub const Memory = struct { |
| 1258 | 1258 | }, |
| 1259 | 1259 | .off => { |
| 1260 | 1260 | assert(mem.info.base == .reg); |
| 1261 | return encoder.Instruction.Memory.moffs( | |
| 1261 | return encoder.Instruction.Memory.initMoffs( | |
| 1262 | 1262 | @enumFromInt(mem.base), |
| 1263 | 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 | 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 | 114 | assert(reg.class() == .segment); |
| 115 | 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 | 119 | disp: i32 = 0, |
| 120 | 120 | base: Base = .none, |
| 121 | 121 | scale_index: ?ScaleIndex = null, |
| ... | ... | @@ -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 | 133 | return .{ .rip = .{ .ptr_size = ptr_size, .disp = displacement } }; |
| 134 | 134 | } |
| 135 | 135 | |
| ... | ... | @@ -1266,7 +1266,7 @@ test "lower MI encoding" { |
| 1266 | 1266 | try expectEqualHexStrings("\x49\xC7\xC4\x00\x10\x00\x00", enc.code(), "mov r12, 0x1000"); |
| 1267 | 1267 | |
| 1268 | 1268 | try enc.encode(.mov, &.{ |
| 1269 | .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .r12 } }) }, | |
| 1269 | .{ .mem = Instruction.Memory.initSib(.byte, .{ .base = .{ .reg = .r12 } }) }, | |
| 1270 | 1270 | .{ .imm = Instruction.Immediate.u(0x10) }, |
| 1271 | 1271 | }); |
| 1272 | 1272 | try expectEqualHexStrings("\x41\xC6\x04\x24\x10", enc.code(), "mov BYTE PTR [r12], 0x10"); |
| ... | ... | @@ -1290,13 +1290,13 @@ test "lower MI encoding" { |
| 1290 | 1290 | try expectEqualHexStrings("\x48\xc7\xc0\x10\x00\x00\x00", enc.code(), "mov rax, 0x10"); |
| 1291 | 1291 | |
| 1292 | 1292 | try enc.encode(.mov, &.{ |
| 1293 | .{ .mem = Instruction.Memory.sib(.dword, .{ .base = .{ .reg = .r11 } }) }, | |
| 1293 | .{ .mem = Instruction.Memory.initSib(.dword, .{ .base = .{ .reg = .r11 } }) }, | |
| 1294 | 1294 | .{ .imm = Instruction.Immediate.u(0x10) }, |
| 1295 | 1295 | }); |
| 1296 | 1296 | try expectEqualHexStrings("\x41\xc7\x03\x10\x00\x00\x00", enc.code(), "mov DWORD PTR [r11], 0x10"); |
| 1297 | 1297 | |
| 1298 | 1298 | try enc.encode(.mov, &.{ |
| 1299 | .{ .mem = Instruction.Memory.rip(.qword, 0x10) }, | |
| 1299 | .{ .mem = Instruction.Memory.initRip(.qword, 0x10) }, | |
| 1300 | 1300 | .{ .imm = Instruction.Immediate.u(0x10) }, |
| 1301 | 1301 | }); |
| 1302 | 1302 | try expectEqualHexStrings( |
| ... | ... | @@ -1306,25 +1306,25 @@ test "lower MI encoding" { |
| 1306 | 1306 | ); |
| 1307 | 1307 | |
| 1308 | 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 | 1310 | .{ .imm = Instruction.Immediate.u(0x10) }, |
| 1311 | 1311 | }); |
| 1312 | 1312 | try expectEqualHexStrings("\x48\xc7\x45\xf8\x10\x00\x00\x00", enc.code(), "mov QWORD PTR [rbp - 8], 0x10"); |
| 1313 | 1313 | |
| 1314 | 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 | 1316 | .{ .imm = Instruction.Immediate.s(-16) }, |
| 1317 | 1317 | }); |
| 1318 | 1318 | try expectEqualHexStrings("\x66\xC7\x45\xFE\xF0\xFF", enc.code(), "mov WORD PTR [rbp - 2], -16"); |
| 1319 | 1319 | |
| 1320 | 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 | 1322 | .{ .imm = Instruction.Immediate.u(0x10) }, |
| 1323 | 1323 | }); |
| 1324 | 1324 | try expectEqualHexStrings("\xC6\x45\xFF\x10", enc.code(), "mov BYTE PTR [rbp - 1], 0x10"); |
| 1325 | 1325 | |
| 1326 | 1326 | try enc.encode(.mov, &.{ |
| 1327 | .{ .mem = Instruction.Memory.sib(.qword, .{ | |
| 1327 | .{ .mem = Instruction.Memory.initSib(.qword, .{ | |
| 1328 | 1328 | .base = .{ .reg = .ds }, |
| 1329 | 1329 | .disp = 0x10000000, |
| 1330 | 1330 | .scale_index = .{ .scale = 2, .index = .rcx }, |
| ... | ... | @@ -1338,13 +1338,13 @@ test "lower MI encoding" { |
| 1338 | 1338 | ); |
| 1339 | 1339 | |
| 1340 | 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 | 1342 | .{ .imm = Instruction.Immediate.u(0x10) }, |
| 1343 | 1343 | }); |
| 1344 | 1344 | try expectEqualHexStrings("\x80\x55\xF0\x10", enc.code(), "adc BYTE PTR [rbp - 0x10], 0x10"); |
| 1345 | 1345 | |
| 1346 | 1346 | try enc.encode(.adc, &.{ |
| 1347 | .{ .mem = Instruction.Memory.rip(.qword, 0) }, | |
| 1347 | .{ .mem = Instruction.Memory.initRip(.qword, 0) }, | |
| 1348 | 1348 | .{ .imm = Instruction.Immediate.u(0x10) }, |
| 1349 | 1349 | }); |
| 1350 | 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 | 1356 | try expectEqualHexStrings("\x48\x83\xD0\x10", enc.code(), "adc rax, 0x10"); |
| 1357 | 1357 | |
| 1358 | 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 | 1360 | .{ .imm = Instruction.Immediate.u(0x10) }, |
| 1361 | 1361 | }); |
| 1362 | 1362 | try expectEqualHexStrings("\x83\x42\xF8\x10", enc.code(), "add DWORD PTR [rdx - 8], 0x10"); |
| ... | ... | @@ -1368,13 +1368,13 @@ test "lower MI encoding" { |
| 1368 | 1368 | try expectEqualHexStrings("\x48\x83\xC0\x10", enc.code(), "add rax, 0x10"); |
| 1369 | 1369 | |
| 1370 | 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 | 1372 | .{ .imm = Instruction.Immediate.s(-0x10) }, |
| 1373 | 1373 | }); |
| 1374 | 1374 | try expectEqualHexStrings("\x48\x83\x45\xF0\xF0", enc.code(), "add QWORD PTR [rbp - 0x10], -0x10"); |
| 1375 | 1375 | |
| 1376 | 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 | 1378 | .{ .imm = Instruction.Immediate.u(0x10) }, |
| 1379 | 1379 | }); |
| 1380 | 1380 | try expectEqualHexStrings( |
| ... | ... | @@ -1384,7 +1384,7 @@ test "lower MI encoding" { |
| 1384 | 1384 | ); |
| 1385 | 1385 | |
| 1386 | 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 | 1388 | .{ .imm = Instruction.Immediate.u(0x10) }, |
| 1389 | 1389 | }); |
| 1390 | 1390 | try expectEqualHexStrings( |
| ... | ... | @@ -1394,7 +1394,7 @@ test "lower MI encoding" { |
| 1394 | 1394 | ); |
| 1395 | 1395 | |
| 1396 | 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 | 1398 | .{ .imm = Instruction.Immediate.u(0x10) }, |
| 1399 | 1399 | }); |
| 1400 | 1400 | try expectEqualHexStrings( |
| ... | ... | @@ -1404,7 +1404,7 @@ test "lower MI encoding" { |
| 1404 | 1404 | ); |
| 1405 | 1405 | |
| 1406 | 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 | 1408 | .{ .imm = Instruction.Immediate.u(0x10) }, |
| 1409 | 1409 | }); |
| 1410 | 1410 | try expectEqualHexStrings( |
| ... | ... | @@ -1419,25 +1419,25 @@ test "lower RM encoding" { |
| 1419 | 1419 | |
| 1420 | 1420 | try enc.encode(.mov, &.{ |
| 1421 | 1421 | .{ .reg = .rax }, |
| 1422 | .{ .mem = Instruction.Memory.sib(.qword, .{ .base = .{ .reg = .r11 } }) }, | |
| 1422 | .{ .mem = Instruction.Memory.initSib(.qword, .{ .base = .{ .reg = .r11 } }) }, | |
| 1423 | 1423 | }); |
| 1424 | 1424 | try expectEqualHexStrings("\x49\x8b\x03", enc.code(), "mov rax, QWORD PTR [r11]"); |
| 1425 | 1425 | |
| 1426 | 1426 | try enc.encode(.mov, &.{ |
| 1427 | 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 | 1430 | try expectEqualHexStrings("\x48\x8B\x1C\x25\x10\x00\x00\x00", enc.code(), "mov rbx, QWORD PTR ds:0x10"); |
| 1431 | 1431 | |
| 1432 | 1432 | try enc.encode(.mov, &.{ |
| 1433 | 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 | 1436 | try expectEqualHexStrings("\x48\x8B\x45\xFC", enc.code(), "mov rax, QWORD PTR [rbp - 4]"); |
| 1437 | 1437 | |
| 1438 | 1438 | try enc.encode(.mov, &.{ |
| 1439 | 1439 | .{ .reg = .rax }, |
| 1440 | .{ .mem = Instruction.Memory.sib(.qword, .{ | |
| 1440 | .{ .mem = Instruction.Memory.initSib(.qword, .{ | |
| 1441 | 1441 | .base = .{ .reg = .rbp }, |
| 1442 | 1442 | .scale_index = .{ .scale = 1, .index = .rcx }, |
| 1443 | 1443 | .disp = -8, |
| ... | ... | @@ -1447,7 +1447,7 @@ test "lower RM encoding" { |
| 1447 | 1447 | |
| 1448 | 1448 | try enc.encode(.mov, &.{ |
| 1449 | 1449 | .{ .reg = .eax }, |
| 1450 | .{ .mem = Instruction.Memory.sib(.dword, .{ | |
| 1450 | .{ .mem = Instruction.Memory.initSib(.dword, .{ | |
| 1451 | 1451 | .base = .{ .reg = .rbp }, |
| 1452 | 1452 | .scale_index = .{ .scale = 4, .index = .rdx }, |
| 1453 | 1453 | .disp = -4, |
| ... | ... | @@ -1457,7 +1457,7 @@ test "lower RM encoding" { |
| 1457 | 1457 | |
| 1458 | 1458 | try enc.encode(.mov, &.{ |
| 1459 | 1459 | .{ .reg = .rax }, |
| 1460 | .{ .mem = Instruction.Memory.sib(.qword, .{ | |
| 1460 | .{ .mem = Instruction.Memory.initSib(.qword, .{ | |
| 1461 | 1461 | .base = .{ .reg = .rbp }, |
| 1462 | 1462 | .scale_index = .{ .scale = 8, .index = .rcx }, |
| 1463 | 1463 | .disp = -8, |
| ... | ... | @@ -1467,7 +1467,7 @@ test "lower RM encoding" { |
| 1467 | 1467 | |
| 1468 | 1468 | try enc.encode(.mov, &.{ |
| 1469 | 1469 | .{ .reg = .r8b }, |
| 1470 | .{ .mem = Instruction.Memory.sib(.byte, .{ | |
| 1470 | .{ .mem = Instruction.Memory.initSib(.byte, .{ | |
| 1471 | 1471 | .base = .{ .reg = .rsi }, |
| 1472 | 1472 | .scale_index = .{ .scale = 1, .index = .rcx }, |
| 1473 | 1473 | .disp = -24, |
| ... | ... | @@ -1483,7 +1483,7 @@ test "lower RM encoding" { |
| 1483 | 1483 | try expectEqualHexStrings("\x48\x8C\xC8", enc.code(), "mov rax, cs"); |
| 1484 | 1484 | |
| 1485 | 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 | 1487 | .{ .reg = .fs }, |
| 1488 | 1488 | }); |
| 1489 | 1489 | try expectEqualHexStrings("\x8C\x65\xF0", enc.code(), "mov WORD PTR [rbp - 16], fs"); |
| ... | ... | @@ -1514,19 +1514,19 @@ test "lower RM encoding" { |
| 1514 | 1514 | |
| 1515 | 1515 | try enc.encode(.movsx, &.{ |
| 1516 | 1516 | .{ .reg = .eax }, |
| 1517 | .{ .mem = Instruction.Memory.sib(.word, .{ .base = .{ .reg = .rbp } }) }, | |
| 1517 | .{ .mem = Instruction.Memory.initSib(.word, .{ .base = .{ .reg = .rbp } }) }, | |
| 1518 | 1518 | }); |
| 1519 | 1519 | try expectEqualHexStrings("\x0F\xBF\x45\x00", enc.code(), "movsx eax, BYTE PTR [rbp]"); |
| 1520 | 1520 | |
| 1521 | 1521 | try enc.encode(.movsx, &.{ |
| 1522 | 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 | 1525 | try expectEqualHexStrings("\x0F\xBE\x04\x45\x00\x00\x00\x00", enc.code(), "movsx eax, BYTE PTR [rax * 2]"); |
| 1526 | 1526 | |
| 1527 | 1527 | try enc.encode(.movsx, &.{ |
| 1528 | 1528 | .{ .reg = .ax }, |
| 1529 | .{ .mem = Instruction.Memory.rip(.byte, 0x10) }, | |
| 1529 | .{ .mem = Instruction.Memory.initRip(.byte, 0x10) }, | |
| 1530 | 1530 | }); |
| 1531 | 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 | 1544 | |
| 1545 | 1545 | try enc.encode(.lea, &.{ |
| 1546 | 1546 | .{ .reg = .rax }, |
| 1547 | .{ .mem = Instruction.Memory.rip(.qword, 0x10) }, | |
| 1547 | .{ .mem = Instruction.Memory.initRip(.qword, 0x10) }, | |
| 1548 | 1548 | }); |
| 1549 | 1549 | try expectEqualHexStrings("\x48\x8D\x05\x10\x00\x00\x00", enc.code(), "lea rax, QWORD PTR [rip + 0x10]"); |
| 1550 | 1550 | |
| 1551 | 1551 | try enc.encode(.lea, &.{ |
| 1552 | 1552 | .{ .reg = .rax }, |
| 1553 | .{ .mem = Instruction.Memory.rip(.dword, 0x10) }, | |
| 1553 | .{ .mem = Instruction.Memory.initRip(.dword, 0x10) }, | |
| 1554 | 1554 | }); |
| 1555 | 1555 | try expectEqualHexStrings("\x48\x8D\x05\x10\x00\x00\x00", enc.code(), "lea rax, DWORD PTR [rip + 0x10]"); |
| 1556 | 1556 | |
| 1557 | 1557 | try enc.encode(.lea, &.{ |
| 1558 | 1558 | .{ .reg = .eax }, |
| 1559 | .{ .mem = Instruction.Memory.rip(.dword, 0x10) }, | |
| 1559 | .{ .mem = Instruction.Memory.initRip(.dword, 0x10) }, | |
| 1560 | 1560 | }); |
| 1561 | 1561 | try expectEqualHexStrings("\x8D\x05\x10\x00\x00\x00", enc.code(), "lea eax, DWORD PTR [rip + 0x10]"); |
| 1562 | 1562 | |
| 1563 | 1563 | try enc.encode(.lea, &.{ |
| 1564 | 1564 | .{ .reg = .eax }, |
| 1565 | .{ .mem = Instruction.Memory.rip(.word, 0x10) }, | |
| 1565 | .{ .mem = Instruction.Memory.initRip(.word, 0x10) }, | |
| 1566 | 1566 | }); |
| 1567 | 1567 | try expectEqualHexStrings("\x8D\x05\x10\x00\x00\x00", enc.code(), "lea eax, WORD PTR [rip + 0x10]"); |
| 1568 | 1568 | |
| 1569 | 1569 | try enc.encode(.lea, &.{ |
| 1570 | 1570 | .{ .reg = .ax }, |
| 1571 | .{ .mem = Instruction.Memory.rip(.byte, 0x10) }, | |
| 1571 | .{ .mem = Instruction.Memory.initRip(.byte, 0x10) }, | |
| 1572 | 1572 | }); |
| 1573 | 1573 | try expectEqualHexStrings("\x66\x8D\x05\x10\x00\x00\x00", enc.code(), "lea ax, BYTE PTR [rip + 0x10]"); |
| 1574 | 1574 | |
| 1575 | 1575 | try enc.encode(.lea, &.{ |
| 1576 | 1576 | .{ .reg = .rsi }, |
| 1577 | .{ .mem = Instruction.Memory.sib(.qword, .{ | |
| 1577 | .{ .mem = Instruction.Memory.initSib(.qword, .{ | |
| 1578 | 1578 | .base = .{ .reg = .rbp }, |
| 1579 | 1579 | .scale_index = .{ .scale = 1, .index = .rcx }, |
| 1580 | 1580 | }) }, |
| ... | ... | @@ -1583,31 +1583,31 @@ test "lower RM encoding" { |
| 1583 | 1583 | |
| 1584 | 1584 | try enc.encode(.add, &.{ |
| 1585 | 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 | 1588 | try expectEqualHexStrings("\x4C\x03\x1C\x25\x00\x00\x00\x10", enc.code(), "add r11, QWORD PTR ds:0x10000000"); |
| 1589 | 1589 | |
| 1590 | 1590 | try enc.encode(.add, &.{ |
| 1591 | 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 | 1594 | try expectEqualHexStrings("\x44\x02\x24\x25\x00\x00\x00\x10", enc.code(), "add r11b, BYTE PTR ds:0x10000000"); |
| 1595 | 1595 | |
| 1596 | 1596 | try enc.encode(.add, &.{ |
| 1597 | 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 | 1600 | try expectEqualHexStrings("\x64\x44\x02\x24\x25\x00\x00\x00\x10", enc.code(), "add r11b, BYTE PTR fs:0x10000000"); |
| 1601 | 1601 | |
| 1602 | 1602 | try enc.encode(.sub, &.{ |
| 1603 | 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 | 1606 | try expectEqualHexStrings("\x4D\x2B\x9D\x00\x00\x00\x10", enc.code(), "sub r11, QWORD PTR [r13 + 0x10000000]"); |
| 1607 | 1607 | |
| 1608 | 1608 | try enc.encode(.sub, &.{ |
| 1609 | 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 | 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 | 1630 | |
| 1631 | 1631 | try enc.encode(.imul, &.{ |
| 1632 | 1632 | .{ .reg = .r11 }, |
| 1633 | .{ .mem = Instruction.Memory.rip(.qword, -16) }, | |
| 1633 | .{ .mem = Instruction.Memory.initRip(.qword, -16) }, | |
| 1634 | 1634 | .{ .imm = Instruction.Immediate.s(-1024) }, |
| 1635 | 1635 | }); |
| 1636 | 1636 | try expectEqualHexStrings( |
| ... | ... | @@ -1641,7 +1641,7 @@ test "lower RMI encoding" { |
| 1641 | 1641 | |
| 1642 | 1642 | try enc.encode(.imul, &.{ |
| 1643 | 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 | 1645 | .{ .imm = Instruction.Immediate.s(-1024) }, |
| 1646 | 1646 | }); |
| 1647 | 1647 | try expectEqualHexStrings( |
| ... | ... | @@ -1652,7 +1652,7 @@ test "lower RMI encoding" { |
| 1652 | 1652 | |
| 1653 | 1653 | try enc.encode(.imul, &.{ |
| 1654 | 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 | 1656 | .{ .imm = Instruction.Immediate.u(1024) }, |
| 1657 | 1657 | }); |
| 1658 | 1658 | try expectEqualHexStrings( |
| ... | ... | @@ -1672,19 +1672,19 @@ test "lower MR encoding" { |
| 1672 | 1672 | try expectEqualHexStrings("\x48\x89\xD8", enc.code(), "mov rax, rbx"); |
| 1673 | 1673 | |
| 1674 | 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 | 1676 | .{ .reg = .r11 }, |
| 1677 | 1677 | }); |
| 1678 | 1678 | try expectEqualHexStrings("\x4c\x89\x5d\xfc", enc.code(), "mov QWORD PTR [rbp - 4], r11"); |
| 1679 | 1679 | |
| 1680 | 1680 | try enc.encode(.mov, &.{ |
| 1681 | .{ .mem = Instruction.Memory.rip(.qword, 0x10) }, | |
| 1681 | .{ .mem = Instruction.Memory.initRip(.qword, 0x10) }, | |
| 1682 | 1682 | .{ .reg = .r12 }, |
| 1683 | 1683 | }); |
| 1684 | 1684 | try expectEqualHexStrings("\x4C\x89\x25\x10\x00\x00\x00", enc.code(), "mov QWORD PTR [rip + 0x10], r12"); |
| 1685 | 1685 | |
| 1686 | 1686 | try enc.encode(.mov, &.{ |
| 1687 | .{ .mem = Instruction.Memory.sib(.qword, .{ | |
| 1687 | .{ .mem = Instruction.Memory.initSib(.qword, .{ | |
| 1688 | 1688 | .base = .{ .reg = .r11 }, |
| 1689 | 1689 | .scale_index = .{ .scale = 2, .index = .r12 }, |
| 1690 | 1690 | .disp = 0x10, |
| ... | ... | @@ -1694,13 +1694,13 @@ test "lower MR encoding" { |
| 1694 | 1694 | try expectEqualHexStrings("\x4F\x89\x6C\x63\x10", enc.code(), "mov QWORD PTR [r11 + 2 * r12 + 0x10], r13"); |
| 1695 | 1695 | |
| 1696 | 1696 | try enc.encode(.mov, &.{ |
| 1697 | .{ .mem = Instruction.Memory.rip(.word, -0x10) }, | |
| 1697 | .{ .mem = Instruction.Memory.initRip(.word, -0x10) }, | |
| 1698 | 1698 | .{ .reg = .r12w }, |
| 1699 | 1699 | }); |
| 1700 | 1700 | try expectEqualHexStrings("\x66\x44\x89\x25\xF0\xFF\xFF\xFF", enc.code(), "mov WORD PTR [rip - 0x10], r12w"); |
| 1701 | 1701 | |
| 1702 | 1702 | try enc.encode(.mov, &.{ |
| 1703 | .{ .mem = Instruction.Memory.sib(.byte, .{ | |
| 1703 | .{ .mem = Instruction.Memory.initSib(.byte, .{ | |
| 1704 | 1704 | .base = .{ .reg = .r11 }, |
| 1705 | 1705 | .scale_index = .{ .scale = 2, .index = .r12 }, |
| 1706 | 1706 | .disp = 0x10, |
| ... | ... | @@ -1710,25 +1710,25 @@ test "lower MR encoding" { |
| 1710 | 1710 | try expectEqualHexStrings("\x47\x88\x6C\x63\x10", enc.code(), "mov BYTE PTR [r11 + 2 * r12 + 0x10], r13b"); |
| 1711 | 1711 | |
| 1712 | 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 | 1714 | .{ .reg = .r12b }, |
| 1715 | 1715 | }); |
| 1716 | 1716 | try expectEqualHexStrings("\x44\x00\x24\x25\x00\x00\x00\x10", enc.code(), "add BYTE PTR ds:0x10000000, r12b"); |
| 1717 | 1717 | |
| 1718 | 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 | 1720 | .{ .reg = .r12d }, |
| 1721 | 1721 | }); |
| 1722 | 1722 | try expectEqualHexStrings("\x44\x01\x24\x25\x00\x00\x00\x10", enc.code(), "add DWORD PTR [ds:0x10000000], r12d"); |
| 1723 | 1723 | |
| 1724 | 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 | 1726 | .{ .reg = .r12d }, |
| 1727 | 1727 | }); |
| 1728 | 1728 | try expectEqualHexStrings("\x65\x44\x01\x24\x25\x00\x00\x00\x10", enc.code(), "add DWORD PTR [gs:0x10000000], r12d"); |
| 1729 | 1729 | |
| 1730 | 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 | 1732 | .{ .reg = .r12 }, |
| 1733 | 1733 | }); |
| 1734 | 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 | 1743 | try expectEqualHexStrings("\x41\xFF\xD4", enc.code(), "call r12"); |
| 1744 | 1744 | |
| 1745 | 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 | 1748 | try expectEqualHexStrings("\x41\xFF\x14\x24", enc.code(), "call QWORD PTR [r12]"); |
| 1749 | 1749 | |
| 1750 | 1750 | try enc.encode(.call, &.{ |
| 1751 | .{ .mem = Instruction.Memory.sib(.qword, .{ | |
| 1751 | .{ .mem = Instruction.Memory.initSib(.qword, .{ | |
| 1752 | 1752 | .base = .none, |
| 1753 | 1753 | .scale_index = .{ .index = .r11, .scale = 2 }, |
| 1754 | 1754 | }) }, |
| ... | ... | @@ -1756,7 +1756,7 @@ test "lower M encoding" { |
| 1756 | 1756 | try expectEqualHexStrings("\x42\xFF\x14\x5D\x00\x00\x00\x00", enc.code(), "call QWORD PTR [r11 * 2]"); |
| 1757 | 1757 | |
| 1758 | 1758 | try enc.encode(.call, &.{ |
| 1759 | .{ .mem = Instruction.Memory.sib(.qword, .{ | |
| 1759 | .{ .mem = Instruction.Memory.initSib(.qword, .{ | |
| 1760 | 1760 | .base = .none, |
| 1761 | 1761 | .scale_index = .{ .index = .r12, .scale = 2 }, |
| 1762 | 1762 | }) }, |
| ... | ... | @@ -1764,7 +1764,7 @@ test "lower M encoding" { |
| 1764 | 1764 | try expectEqualHexStrings("\x42\xFF\x14\x65\x00\x00\x00\x00", enc.code(), "call QWORD PTR [r12 * 2]"); |
| 1765 | 1765 | |
| 1766 | 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 | 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 | 1774 | try expectEqualHexStrings("\xE8\x00\x00\x00\x00", enc.code(), "call 0x0"); |
| 1775 | 1775 | |
| 1776 | 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 | 1779 | try expectEqualHexStrings("\xFF\x75\x00", enc.code(), "push QWORD PTR [rbp]"); |
| 1780 | 1780 | |
| 1781 | 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 | 1784 | try expectEqualHexStrings("\x66\xFF\x75\x00", enc.code(), "push QWORD PTR [rbp]"); |
| 1785 | 1785 | |
| 1786 | 1786 | try enc.encode(.pop, &.{ |
| 1787 | .{ .mem = Instruction.Memory.rip(.qword, 0) }, | |
| 1787 | .{ .mem = Instruction.Memory.initRip(.qword, 0) }, | |
| 1788 | 1788 | }); |
| 1789 | 1789 | try expectEqualHexStrings("\x8F\x05\x00\x00\x00\x00", enc.code(), "pop QWORD PTR [rip]"); |
| 1790 | 1790 | |
| 1791 | 1791 | try enc.encode(.pop, &.{ |
| 1792 | .{ .mem = Instruction.Memory.rip(.word, 0) }, | |
| 1792 | .{ .mem = Instruction.Memory.initRip(.word, 0) }, | |
| 1793 | 1793 | }); |
| 1794 | 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 | 1870 | |
| 1871 | 1871 | try enc.encode(.mov, &.{ |
| 1872 | 1872 | .{ .reg = .rax }, |
| 1873 | .{ .mem = Instruction.Memory.moffs(.cs, 0x10) }, | |
| 1873 | .{ .mem = Instruction.Memory.initMoffs(.cs, 0x10) }, | |
| 1874 | 1874 | }); |
| 1875 | 1875 | try expectEqualHexStrings("\x2E\x48\xA1\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs rax, cs:0x10"); |
| 1876 | 1876 | |
| 1877 | 1877 | try enc.encode(.mov, &.{ |
| 1878 | 1878 | .{ .reg = .eax }, |
| 1879 | .{ .mem = Instruction.Memory.moffs(.fs, 0x10) }, | |
| 1879 | .{ .mem = Instruction.Memory.initMoffs(.fs, 0x10) }, | |
| 1880 | 1880 | }); |
| 1881 | 1881 | try expectEqualHexStrings("\x64\xA1\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs eax, fs:0x10"); |
| 1882 | 1882 | |
| 1883 | 1883 | try enc.encode(.mov, &.{ |
| 1884 | 1884 | .{ .reg = .ax }, |
| 1885 | .{ .mem = Instruction.Memory.moffs(.gs, 0x10) }, | |
| 1885 | .{ .mem = Instruction.Memory.initMoffs(.gs, 0x10) }, | |
| 1886 | 1886 | }); |
| 1887 | 1887 | try expectEqualHexStrings("\x65\x66\xA1\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs ax, gs:0x10"); |
| 1888 | 1888 | |
| 1889 | 1889 | try enc.encode(.mov, &.{ |
| 1890 | 1890 | .{ .reg = .al }, |
| 1891 | .{ .mem = Instruction.Memory.moffs(.ds, 0x10) }, | |
| 1891 | .{ .mem = Instruction.Memory.initMoffs(.ds, 0x10) }, | |
| 1892 | 1892 | }); |
| 1893 | 1893 | try expectEqualHexStrings("\xA0\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs al, ds:0x10"); |
| 1894 | 1894 | |
| 1895 | 1895 | try enc.encode(.mov, &.{ |
| 1896 | .{ .mem = Instruction.Memory.moffs(.cs, 0x10) }, | |
| 1896 | .{ .mem = Instruction.Memory.initMoffs(.cs, 0x10) }, | |
| 1897 | 1897 | .{ .reg = .rax }, |
| 1898 | 1898 | }); |
| 1899 | 1899 | try expectEqualHexStrings("\x2E\x48\xA3\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs cs:0x10, rax"); |
| 1900 | 1900 | |
| 1901 | 1901 | try enc.encode(.mov, &.{ |
| 1902 | .{ .mem = Instruction.Memory.moffs(.fs, 0x10) }, | |
| 1902 | .{ .mem = Instruction.Memory.initMoffs(.fs, 0x10) }, | |
| 1903 | 1903 | .{ .reg = .eax }, |
| 1904 | 1904 | }); |
| 1905 | 1905 | try expectEqualHexStrings("\x64\xA3\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs fs:0x10, eax"); |
| 1906 | 1906 | |
| 1907 | 1907 | try enc.encode(.mov, &.{ |
| 1908 | .{ .mem = Instruction.Memory.moffs(.gs, 0x10) }, | |
| 1908 | .{ .mem = Instruction.Memory.initMoffs(.gs, 0x10) }, | |
| 1909 | 1909 | .{ .reg = .ax }, |
| 1910 | 1910 | }); |
| 1911 | 1911 | try expectEqualHexStrings("\x65\x66\xA3\x10\x00\x00\x00\x00\x00\x00\x00", enc.code(), "movabs gs:0x10, ax"); |
| 1912 | 1912 | |
| 1913 | 1913 | try enc.encode(.mov, &.{ |
| 1914 | .{ .mem = Instruction.Memory.moffs(.ds, 0x10) }, | |
| 1914 | .{ .mem = Instruction.Memory.initMoffs(.ds, 0x10) }, | |
| 1915 | 1915 | .{ .reg = .al }, |
| 1916 | 1916 | }); |
| 1917 | 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 | 1949 | .{ .reg = .al }, |
| 1950 | 1950 | }); |
| 1951 | 1951 | try invalidInstruction(.call, &.{ |
| 1952 | .{ .mem = Instruction.Memory.rip(.dword, 0) }, | |
| 1952 | .{ .mem = Instruction.Memory.initRip(.dword, 0) }, | |
| 1953 | 1953 | }); |
| 1954 | 1954 | try invalidInstruction(.call, &.{ |
| 1955 | .{ .mem = Instruction.Memory.rip(.word, 0) }, | |
| 1955 | .{ .mem = Instruction.Memory.initRip(.word, 0) }, | |
| 1956 | 1956 | }); |
| 1957 | 1957 | try invalidInstruction(.call, &.{ |
| 1958 | .{ .mem = Instruction.Memory.rip(.byte, 0) }, | |
| 1958 | .{ .mem = Instruction.Memory.initRip(.byte, 0) }, | |
| 1959 | 1959 | }); |
| 1960 | 1960 | try invalidInstruction(.mov, &.{ |
| 1961 | .{ .mem = Instruction.Memory.rip(.word, 0x10) }, | |
| 1961 | .{ .mem = Instruction.Memory.initRip(.word, 0x10) }, | |
| 1962 | 1962 | .{ .reg = .r12 }, |
| 1963 | 1963 | }); |
| 1964 | 1964 | try invalidInstruction(.lea, &.{ |
| ... | ... | @@ -1967,7 +1967,7 @@ test "invalid instruction" { |
| 1967 | 1967 | }); |
| 1968 | 1968 | try invalidInstruction(.lea, &.{ |
| 1969 | 1969 | .{ .reg = .al }, |
| 1970 | .{ .mem = Instruction.Memory.rip(.byte, 0) }, | |
| 1970 | .{ .mem = Instruction.Memory.initRip(.byte, 0) }, | |
| 1971 | 1971 | }); |
| 1972 | 1972 | try invalidInstruction(.pop, &.{ |
| 1973 | 1973 | .{ .reg = .r12b }, |
| ... | ... | @@ -1992,7 +1992,7 @@ fn cannotEncode(mnemonic: Instruction.Mnemonic, ops: []const Instruction.Operand |
| 1992 | 1992 | |
| 1993 | 1993 | test "cannot encode" { |
| 1994 | 1994 | try cannotEncode(.@"test", &.{ |
| 1995 | .{ .mem = Instruction.Memory.sib(.byte, .{ .base = .{ .reg = .r12 } }) }, | |
| 1995 | .{ .mem = Instruction.Memory.initSib(.byte, .{ .base = .{ .reg = .r12 } }) }, | |
| 1996 | 1996 | .{ .reg = .ah }, |
| 1997 | 1997 | }); |
| 1998 | 1998 | try cannotEncode(.@"test", &.{ |
| ... | ... | @@ -2369,7 +2369,7 @@ const Assembler = struct { |
| 2369 | 2369 | if (res.rip) { |
| 2370 | 2370 | if (res.base != null or res.scale_index != null or res.offset != null) |
| 2371 | 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 | 2374 | if (res.base) |base| { |
| 2375 | 2375 | if (res.rip) |
| ... | ... | @@ -2377,9 +2377,9 @@ const Assembler = struct { |
| 2377 | 2377 | if (res.offset) |offset| { |
| 2378 | 2378 | if (res.scale_index != null or res.disp != null) |
| 2379 | 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 | 2383 | .base = .{ .reg = base }, |
| 2384 | 2384 | .scale_index = res.scale_index, |
| 2385 | 2385 | .disp = res.disp orelse 0, |
src/codegen.zig+2-11| ... | ... | @@ -836,16 +836,6 @@ pub const GenResult = union(enum) { |
| 836 | 836 | /// Traditionally, this corresponds to emitting a relocation in a relocatable object file. |
| 837 | 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 | 841 | fn genNavRef( |
| ... | ... | @@ -935,7 +925,8 @@ fn genNavRef( |
| 935 | 925 | const atom = p9.getAtom(atom_index); |
| 936 | 926 | return .{ .mcv = .{ .memory = atom.getOffsetTableAddress(p9) } }; |
| 937 | 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 | 33 | .abbrevs = .{ .abbrevs = .{} }, |
| 34 | 34 | }; |
| 35 | 35 | |
| 36 | const set_bid: u32 = 1; | |
| 37 | const block_name: u32 = 2; | |
| 38 | const set_record_name: u32 = 3; | |
| 36 | const set_bid_id: u32 = 1; | |
| 37 | const block_name_id: u32 = 2; | |
| 38 | const set_record_name_id: u32 = 3; | |
| 39 | 39 | |
| 40 | 40 | fn deinit(info: *Info, allocator: std.mem.Allocator) void { |
| 41 | 41 | allocator.free(info.block_name); |
| ... | ... | @@ -61,7 +61,7 @@ pub const Record = struct { |
| 61 | 61 | assert(record.id == Abbrev.Builtin.define_abbrev.toRecordId()); |
| 62 | 62 | var i: usize = 0; |
| 63 | 63 | while (i < record.operands.len) switch (record.operands[i]) { |
| 64 | Abbrev.Operand.literal => { | |
| 64 | Abbrev.Operand.literal_id => { | |
| 65 | 65 | try operands.append(.{ .literal = record.operands[i + 1] }); |
| 66 | 66 | i += 2; |
| 67 | 67 | }, |
| ... | ... | @@ -211,7 +211,7 @@ fn nextRecord(bc: *BitcodeReader) !?Record { |
| 211 | 211 | .align_32_bits, .block_len => return error.UnsupportedArrayElement, |
| 212 | 212 | .abbrev_op => switch (try bc.readFixed(u1, 1)) { |
| 213 | 213 | 1 => try operands.appendSlice(&.{ |
| 214 | Abbrev.Operand.literal, | |
| 214 | Abbrev.Operand.literal_id, | |
| 215 | 215 | try bc.readVbr(u64, 8), |
| 216 | 216 | }), |
| 217 | 217 | 0 => { |
| ... | ... | @@ -334,9 +334,9 @@ fn parseBlockInfoBlock(bc: *BitcodeReader) !void { |
| 334 | 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 | 338 | return error.Overflow, |
| 339 | Block.Info.block_name => if (bc.keep_names) { | |
| 339 | Block.Info.block_name_id => if (bc.keep_names) { | |
| 340 | 340 | const gop = try bc.block_info.getOrPut(bc.allocator, block_id orelse |
| 341 | 341 | return error.UnspecifiedBlockId); |
| 342 | 342 | if (!gop.found_existing) gop.value_ptr.* = Block.Info.default; |
| ... | ... | @@ -346,7 +346,7 @@ fn parseBlockInfoBlock(bc: *BitcodeReader) !void { |
| 346 | 346 | byte.* = std.math.cast(u8, operand) orelse return error.InvalidName; |
| 347 | 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 | 350 | const gop = try bc.block_info.getOrPut(bc.allocator, block_id orelse |
| 351 | 351 | return error.UnspecifiedBlockId); |
| 352 | 352 | if (!gop.found_existing) gop.value_ptr.* = Block.Info.default; |
| ... | ... | @@ -467,7 +467,7 @@ const Abbrev = struct { |
| 467 | 467 | block_len, |
| 468 | 468 | abbrev_op, |
| 469 | 469 | |
| 470 | const literal = std.math.maxInt(u64); | |
| 470 | const literal_id = std.math.maxInt(u64); | |
| 471 | 471 | const Encoding = enum(u3) { |
| 472 | 472 | fixed = 1, |
| 473 | 473 | vbr = 2, |
src/link/Elf.zig+84-3| ... | ... | @@ -3467,7 +3467,7 @@ fn updateSectionSizes(self: *Elf) !void { |
| 3467 | 3467 | if (atom_list.items.len == 0) continue; |
| 3468 | 3468 | |
| 3469 | 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 | 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 | 5661 | const std = @import("std"); |
| 5580 | 5662 | const build_options = @import("build_options"); |
| 5581 | 5663 | const builtin = @import("builtin"); |
| ... | ... | @@ -5598,7 +5680,6 @@ const musl = @import("../musl.zig"); |
| 5598 | 5680 | const relocatable = @import("Elf/relocatable.zig"); |
| 5599 | 5681 | const relocation = @import("Elf/relocation.zig"); |
| 5600 | 5682 | const target_util = @import("../target.zig"); |
| 5601 | const thunks = @import("Elf/thunks.zig"); | |
| 5602 | 5683 | const trace = @import("../tracy.zig").trace; |
| 5603 | 5684 | const synthetic_sections = @import("Elf/synthetic_sections.zig"); |
| 5604 | 5685 | |
| ... | ... | @@ -5636,7 +5717,7 @@ const PltGotSection = synthetic_sections.PltGotSection; |
| 5636 | 5717 | const SharedObject = @import("Elf/SharedObject.zig"); |
| 5637 | 5718 | const Symbol = @import("Elf/Symbol.zig"); |
| 5638 | 5719 | const StringTable = @import("StringTable.zig"); |
| 5639 | const Thunk = thunks.Thunk; | |
| 5720 | const Thunk = @import("Elf/Thunk.zig"); | |
| 5640 | 5721 | const Value = @import("../Value.zig"); |
| 5641 | 5722 | const VerneedSection = synthetic_sections.VerneedSection; |
| 5642 | 5723 | const ZigObject = @import("Elf/ZigObject.zig"); |
src/link/Elf/Atom.zig+1-1| ... | ... | @@ -2251,6 +2251,6 @@ const Fde = eh_frame.Fde; |
| 2251 | 2251 | const File = @import("file.zig").File; |
| 2252 | 2252 | const Object = @import("Object.zig"); |
| 2253 | 2253 | const Symbol = @import("Symbol.zig"); |
| 2254 | const Thunk = @import("thunks.zig").Thunk; | |
| 2254 | const Thunk = @import("Thunk.zig"); | |
| 2255 | 2255 | const ZigObject = @import("ZigObject.zig"); |
| 2256 | 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 | 64 | objc_stubs: ObjcStubsSection = .{}, |
| 65 | 65 | la_symbol_ptr: LaSymbolPtrSection = .{}, |
| 66 | 66 | tlv_ptr: TlvPtrSection = .{}, |
| 67 | rebase: Rebase = .{}, | |
| 68 | bind: Bind = .{}, | |
| 69 | weak_bind: WeakBind = .{}, | |
| 70 | lazy_bind: LazyBind = .{}, | |
| 67 | rebase_section: Rebase = .{}, | |
| 68 | bind_section: Bind = .{}, | |
| 69 | weak_bind_section: WeakBind = .{}, | |
| 70 | lazy_bind_section: LazyBind = .{}, | |
| 71 | 71 | export_trie: ExportTrie = .{}, |
| 72 | 72 | unwind_info: UnwindInfo = .{}, |
| 73 | 73 | data_in_code: DataInCode = .{}, |
| ... | ... | @@ -324,10 +324,10 @@ pub fn deinit(self: *MachO) void { |
| 324 | 324 | self.stubs.deinit(gpa); |
| 325 | 325 | self.objc_stubs.deinit(gpa); |
| 326 | 326 | self.tlv_ptr.deinit(gpa); |
| 327 | self.rebase.deinit(gpa); | |
| 328 | self.bind.deinit(gpa); | |
| 329 | self.weak_bind.deinit(gpa); | |
| 330 | self.lazy_bind.deinit(gpa); | |
| 327 | self.rebase_section.deinit(gpa); | |
| 328 | self.bind_section.deinit(gpa); | |
| 329 | self.weak_bind_section.deinit(gpa); | |
| 330 | self.lazy_bind_section.deinit(gpa); | |
| 331 | 331 | self.export_trie.deinit(gpa); |
| 332 | 332 | self.unwind_info.deinit(gpa); |
| 333 | 333 | self.data_in_code.deinit(gpa); |
| ... | ... | @@ -2005,7 +2005,7 @@ fn calcSectionSizeWorker(self: *MachO, sect_id: u8) void { |
| 2005 | 2005 | fn createThunksWorker(self: *MachO, sect_id: u8) void { |
| 2006 | 2006 | const tracy = trace(@src()); |
| 2007 | 2007 | defer tracy.end(); |
| 2008 | thunks.createThunks(sect_id, self) catch |err| { | |
| 2008 | self.createThunks(sect_id) catch |err| { | |
| 2009 | 2009 | const header = self.sections.items(.header)[sect_id]; |
| 2010 | 2010 | self.reportUnexpectedError("failed to create thunks and calculate size of section '{s},{s}': {s}", .{ |
| 2011 | 2011 | header.segName(), |
| ... | ... | @@ -2562,7 +2562,7 @@ fn updateLazyBindSizeWorker(self: *MachO) void { |
| 2562 | 2562 | defer tracy.end(); |
| 2563 | 2563 | const doWork = struct { |
| 2564 | 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 | 2566 | const sect_id = macho_file.stubs_helper_sect_index.?; |
| 2567 | 2567 | const out = &macho_file.sections.items(.out)[sect_id]; |
| 2568 | 2568 | var stream = std.io.fixedBufferStream(out.items); |
| ... | ... | @@ -2585,9 +2585,9 @@ pub fn updateLinkeditSizeWorker(self: *MachO, tag: enum { |
| 2585 | 2585 | data_in_code, |
| 2586 | 2586 | }) void { |
| 2587 | 2587 | const res = switch (tag) { |
| 2588 | .rebase => self.rebase.updateSize(self), | |
| 2589 | .bind => self.bind.updateSize(self), | |
| 2590 | .weak_bind => self.weak_bind.updateSize(self), | |
| 2588 | .rebase => self.rebase_section.updateSize(self), | |
| 2589 | .bind => self.bind_section.updateSize(self), | |
| 2590 | .weak_bind => self.weak_bind_section.updateSize(self), | |
| 2591 | 2591 | .export_trie => self.export_trie.updateSize(self), |
| 2592 | 2592 | .data_in_code => self.data_in_code.updateSize(self), |
| 2593 | 2593 | }; |
| ... | ... | @@ -2640,13 +2640,13 @@ fn writeDyldInfo(self: *MachO) !void { |
| 2640 | 2640 | var stream = std.io.fixedBufferStream(buffer); |
| 2641 | 2641 | const writer = stream.writer(); |
| 2642 | 2642 | |
| 2643 | try self.rebase.write(writer); | |
| 2643 | try self.rebase_section.write(writer); | |
| 2644 | 2644 | try stream.seekTo(cmd.bind_off - base_off); |
| 2645 | try self.bind.write(writer); | |
| 2645 | try self.bind_section.write(writer); | |
| 2646 | 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 | 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 | 2650 | try stream.seekTo(cmd.export_off - base_off); |
| 2651 | 2651 | try self.export_trie.write(writer); |
| 2652 | 2652 | try self.base.file.?.pwriteAll(buffer, cmd.rebase_off); |
| ... | ... | @@ -4602,7 +4602,6 @@ const load_commands = @import("MachO/load_commands.zig"); |
| 4602 | 4602 | const relocatable = @import("MachO/relocatable.zig"); |
| 4603 | 4603 | const tapi = @import("tapi.zig"); |
| 4604 | 4604 | const target_util = @import("../target.zig"); |
| 4605 | const thunks = @import("MachO/thunks.zig"); | |
| 4606 | 4605 | const trace = @import("../tracy.zig").trace; |
| 4607 | 4606 | const synthetic = @import("MachO/synthetic.zig"); |
| 4608 | 4607 | |
| ... | ... | @@ -4641,7 +4640,7 @@ const StringTable = @import("StringTable.zig"); |
| 4641 | 4640 | const StubsSection = synthetic.StubsSection; |
| 4642 | 4641 | const StubsHelperSection = synthetic.StubsHelperSection; |
| 4643 | 4642 | const Symbol = @import("MachO/Symbol.zig"); |
| 4644 | const Thunk = thunks.Thunk; | |
| 4643 | const Thunk = @import("MachO/Thunk.zig"); | |
| 4645 | 4644 | const TlvPtrSection = synthetic.TlvPtrSection; |
| 4646 | 4645 | const Value = @import("../Value.zig"); |
| 4647 | 4646 | const UnwindInfo = @import("MachO/UnwindInfo.zig"); |
| ... | ... | @@ -5292,3 +5291,96 @@ pub const KernE = enum(u32) { |
| 5292 | 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 | 1220 | const Object = @import("Object.zig"); |
| 1221 | 1221 | const Relocation = @import("Relocation.zig"); |
| 1222 | 1222 | const Symbol = @import("Symbol.zig"); |
| 1223 | const Thunk = @import("thunks.zig").Thunk; | |
| 1223 | const Thunk = @import("Thunk.zig"); | |
| 1224 | 1224 | const UnwindInfo = @import("UnwindInfo.zig"); |
| 1225 | 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 | 204 | for (macho_file.stubs.symbols.items) |ref| { |
| 205 | 205 | const sym = ref.getSymbol(macho_file).?; |
| 206 | 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 | 208 | const source: i64 = @intCast(sect.addr + preamble_size + entry_size * idx); |
| 209 | 209 | const target: i64 = @intCast(sect.addr); |
| 210 | 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 | 549 | auto: [max_len]u8 = undefined, |
| 550 | 550 | offset: u64 = 0, |
| 551 | 551 | |
| 552 | comptime capacity: *const fn () u64 = capacity, | |
| 552 | comptime capacityFn: *const fn () u64 = capacity, | |
| 553 | 553 | |
| 554 | 554 | const max_len: u64 = 32; |
| 555 | 555 | |
| ... | ... | @@ -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 }; | |
| 562 | try std.testing.expect(a.capacity() == 32); | |
| 563 | try std.testing.expect((a.capacity)() == 32); | |
| 561 | const a: Auto = .{ .offset = 16, .capacityFn = Auto.capacity }; | |
| 562 | try std.testing.expect(a.capacityFn() == 32); | |
| 563 | try std.testing.expect((a.capacityFn)() == 32); | |
| 564 | 564 | } |
| 565 | 565 | |
| 566 | 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 | 149 | value: u63, |
| 150 | 150 | fields: Fields, |
| 151 | 151 | |
| 152 | fn value() i64 { | |
| 152 | fn getValue() i64 { | |
| 153 | 153 | return 1341; |
| 154 | 154 | } |
| 155 | 155 | }; |
| 156 | 156 | |
| 157 | const timestamp: i64 = ID.value(); | |
| 157 | const timestamp: i64 = ID.getValue(); | |
| 158 | 158 | const id = ID{ .fields = Fields{ |
| 159 | 159 | .timestamp = @as(u50, @intCast(timestamp)), |
| 160 | 160 | .random_bits = 420, |
test/behavior/struct.zig+3-3| ... | ... | @@ -1529,15 +1529,15 @@ test "function pointer in struct returns the struct" { |
| 1529 | 1529 | |
| 1530 | 1530 | const A = struct { |
| 1531 | 1531 | const A = @This(); |
| 1532 | f: *const fn () A, | |
| 1532 | ptr: *const fn () A, | |
| 1533 | 1533 | |
| 1534 | 1534 | fn f() A { |
| 1535 | return .{ .f = f }; | |
| 1535 | return .{ .ptr = f }; | |
| 1536 | 1536 | } |
| 1537 | 1537 | }; |
| 1538 | 1538 | var a = A.f(); |
| 1539 | 1539 | _ = &a; |
| 1540 | try expect(a.f == A.f); | |
| 1540 | try expect(a.ptr == A.f); | |
| 1541 | 1541 | } |
| 1542 | 1542 | |
| 1543 | 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 | 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 | 158 | test "constant tagged union with payload" { |
| 171 | 159 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 172 | 160 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| ... | ... | @@ -1417,10 +1405,10 @@ test "union field ptr - zero sized payload" { |
| 1417 | 1405 | const U = union { |
| 1418 | 1406 | foo: void, |
| 1419 | 1407 | bar: void, |
| 1420 | fn bar(_: *void) void {} | |
| 1408 | fn qux(_: *void) void {} | |
| 1421 | 1409 | }; |
| 1422 | 1410 | var u: U = .{ .foo = {} }; |
| 1423 | U.bar(&u.foo); | |
| 1411 | U.qux(&u.foo); | |
| 1424 | 1412 | } |
| 1425 | 1413 | |
| 1426 | 1414 | test "union field ptr - zero sized field" { |
| ... | ... | @@ -1431,10 +1419,10 @@ test "union field ptr - zero sized field" { |
| 1431 | 1419 | const U = union { |
| 1432 | 1420 | foo: void, |
| 1433 | 1421 | bar: u32, |
| 1434 | fn bar(_: *void) void {} | |
| 1422 | fn qux(_: *void) void {} | |
| 1435 | 1423 | }; |
| 1436 | 1424 | var u: U = .{ .foo = {} }; |
| 1437 | U.bar(&u.foo); | |
| 1425 | U.qux(&u.foo); | |
| 1438 | 1426 | } |
| 1439 | 1427 | |
| 1440 | 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 | 5 | } |
| 6 | 6 | |
| 7 | 7 | // error |
| 8 | // backend=stage2 | |
| 9 | // target=native | |
| 10 | 8 | // |
| 11 | // :2:1: error: redeclaration of 'func' | |
| 12 | // :1:1: note: other declaration here | |
| 9 | // :1:4: error: duplicate struct member name 'func' | |
| 10 | // :2:4: note: duplicate name here | |
| 11 | // :1:1: note: struct declared here | |
| 13 | 12 | // :1:11: error: use of undeclared identifier 'bogus' |
| 14 | 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 | 2 | struct { |
| 3 | 3 | const a = 1; |
| 4 | 4 | }; |
| 5 | _ = a; | |
| 5 | 6 | } |
| 6 | 7 | fn bar(a: usize) void { |
| 7 | 8 | struct { |
| ... | ... | @@ -18,5 +19,5 @@ fn bar(a: usize) void { |
| 18 | 19 | // |
| 19 | 20 | // :3:15: error: declaration 'a' shadows function parameter from outer scope |
| 20 | 21 | // :1:8: note: previous declaration here |
| 21 | // :9:19: error: declaration 'a' shadows function parameter from outer scope | |
| 22 | // :6:8: note: previous declaration here | |
| 22 | // :10:19: error: declaration 'a' shadows function parameter from outer scope | |
| 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 | 12 | // backend=stage2 |
| 13 | 13 | // target=native |
| 14 | 14 | // |
| 15 | // :2:5: error: duplicate enum field name | |
| 16 | // :3:5: note: duplicate field here | |
| 15 | // :2:5: error: duplicate enum member name 'Bar' | |
| 16 | // :3:5: note: duplicate name here | |
| 17 | 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 | 24 | // backend=stage2 |
| 25 | 25 | // target=native |
| 26 | 26 | // |
| 27 | // :2:5: error: duplicate struct field name | |
| 28 | // :3:5: note: duplicate field here | |
| 27 | // :2:5: error: duplicate struct member name 'Bar' | |
| 28 | // :3:5: note: duplicate name here | |
| 29 | 29 | // :1:13: note: struct declared here |
| 30 | // :7:5: error: duplicate struct field name | |
| 31 | // :9:5: note: duplicate field here | |
| 32 | // :10:5: note: duplicate field here | |
| 30 | // :7:5: error: duplicate struct member name 'a' | |
| 31 | // :9:5: note: duplicate name here | |
| 32 | // :10:5: note: duplicate name here | |
| 33 | 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 | 8 | } |
| 9 | 9 | |
| 10 | 10 | // error |
| 11 | // backend=stage2 | |
| 12 | // target=native | |
| 13 | 11 | // |
| 14 | // :2:5: error: duplicate union field name | |
| 15 | // :3:5: note: duplicate field here | |
| 12 | // :2:5: error: duplicate union member name 'Bar' | |
| 13 | // :3:5: note: duplicate name here | |
| 16 | 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 | 8 | } |
| 9 | 9 | |
| 10 | 10 | // error |
| 11 | // backend=stage2 | |
| 12 | // target=native | |
| 13 | 11 | // |
| 14 | // :3:9: error: duplicate struct field name | |
| 15 | // :4:9: note: duplicate field here | |
| 12 | // :3:9: error: duplicate struct member name 'e' | |
| 13 | // :4:9: note: duplicate name here | |
| 16 | 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 | 6 | // target=native |
| 7 | 7 | // is_test=true |
| 8 | 8 | // |
| 9 | // :2:1: error: duplicate test name 'thingy' | |
| 10 | // :1:1: note: other test here | |
| 9 | // :1:6: error: duplicate test name 'thingy' | |
| 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 | 25 | const U = struct { |
| 26 | 26 | comptime foo: u32 = 1, |
| 27 | 27 | bar: u32, |
| 28 | fn foo(x: @This()) void { | |
| 28 | fn qux(x: @This()) void { | |
| 29 | 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 | 34 | pub export fn entry4() void { |
| 35 | 35 | const U = struct { |
| 36 | 36 | comptime foo: u32 = 1, |
| 37 | 37 | bar: u32, |
| 38 | fn foo(x: @This()) void { | |
| 38 | fn qux(x: @This()) void { | |
| 39 | 39 | _ = x; |
| 40 | 40 | } |
| 41 | 41 | }; |
| 42 | _ = U.foo(.{ .foo = 2, .bar = 2 }); | |
| 42 | _ = U.qux(.{ .foo = 2, .bar = 2 }); | |
| 43 | 43 | } |
| 44 | 44 | pub export fn entry5() void { |
| 45 | 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 | 5 | } |
| 6 | 6 | |
| 7 | 7 | // error |
| 8 | // backend=stage2 | |
| 9 | // target=native | |
| 10 | 8 | // |
| 11 | // :2:1: error: redeclaration of 'a' | |
| 12 | // :1:1: note: other declaration here | |
| 9 | // :1:4: error: duplicate struct member name 'a' | |
| 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 | // backend=stage2 |
| 6 | 6 | // target=native |
| 7 | 7 | // |
| 8 | // :2:1: error: redeclaration of 'A' | |
| 9 | // :1:1: note: other declaration here | |
| 8 | // :1:7: error: duplicate struct member name 'A' | |
| 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 | // backend=stage2 |
| 6 | 6 | // target=native |
| 7 | 7 | // |
| 8 | // :2:1: error: redeclaration of 'a' | |
| 9 | // :1:1: note: other declaration here | |
| 8 | // :1:5: error: duplicate struct member name 'a' | |
| 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 | // backend=stage2 |
| 6 | 6 | // target=native |
| 7 | 7 | // |
| 8 | // :2:1: error: redeclaration of 'A' | |
| 9 | // :1:1: note: other declaration here | |
| 8 | // :1:7: error: duplicate struct member name 'A' | |
| 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 | 11 | // error |
| 12 | 12 | // target=native |
| 13 | 13 | // |
| 14 | // :2:5: error: duplicate struct field name | |
| 15 | // :3:5: note: duplicate field here | |
| 14 | // :2:5: error: duplicate struct member name 'foo' | |
| 15 | // :3:5: note: duplicate name here | |
| 16 | 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 | 12 | // error |
| 13 | 13 | // target=native |
| 14 | 14 | // |
| 15 | // :3:5: error: duplicate union field name | |
| 16 | // :4:5: note: duplicate field here | |
| 15 | // :3:5: error: duplicate union member name 'a' | |
| 16 | // :4:5: note: duplicate name here | |
| 17 | 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 | 11 | // error |
| 12 | 12 | // target=native |
| 13 | 13 | // |
| 14 | // :2:5: error: duplicate union field name | |
| 15 | // :3:5: note: duplicate field here | |
| 14 | // :2:5: error: duplicate union member name 'foo' | |
| 15 | // :3:5: note: duplicate name here | |
| 16 | 16 | // :1:11: note: union declared here |
test/cases/function_redeclaration.zig+3-2| ... | ... | @@ -8,7 +8,8 @@ fn foo() void { |
| 8 | 8 | |
| 9 | 9 | // error |
| 10 | 10 | // |
| 11 | // :3:1: error: redeclaration of 'entry' | |
| 12 | // :2:1: note: other declaration here | |
| 11 | // :2:4: error: duplicate struct member name 'entry' | |
| 12 | // :3:4: note: duplicate name here | |
| 13 | // :2:1: note: struct declared here | |
| 13 | 14 | // :6:9: error: local variable shadows declaration of 'foo' |
| 14 | 15 | // :5:1: note: declared here |
test/cases/global_variable_redeclaration.zig+3-2| ... | ... | @@ -4,5 +4,6 @@ var foo = true; |
| 4 | 4 | |
| 5 | 5 | // error |
| 6 | 6 | // |
| 7 | // :3:1: error: redeclaration of 'foo' | |
| 8 | // :2:1: note: other declaration here | |
| 7 | // :2:5: error: duplicate struct member name 'foo' | |
| 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 | 92 | \\const a = @import("a.zig"); |
| 93 | 93 | \\ |
| 94 | 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 | 97 | , &[_][]const u8{ |
| 98 | 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 | 102 | \\pub const S = struct { |
| 103 | 103 | \\ comptime foo: u32 = 1, |
| 104 | 104 | \\ bar: u32, |
| 105 | \\ pub fn foo(x: @This()) void { | |
| 105 | \\ pub fn qux(x: @This()) void { | |
| 106 | 106 | \\ _ = x; |
| 107 | 107 | \\ } |
| 108 | 108 | \\}; |