| ... | @@ -477,7 +477,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -477,7 +477,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 477 | .p_paddr = entry_addr, | 477 | .p_paddr = entry_addr, |
| 478 | .p_memsz = file_size, | 478 | .p_memsz = file_size, |
| 479 | .p_align = p_align, | 479 | .p_align = p_align, |
| 480 | .p_flags = elf.PF_X | elf.PF_R, | 480 | .p_flags = elf.PF_X | elf.PF_R | elf.PF_W, |
| 481 | }); | 481 | }); |
| 482 | self.entry_addr = null; | 482 | self.entry_addr = null; |
| 483 | self.phdr_table_dirty = true; | 483 | self.phdr_table_dirty = true; |
| ... | @@ -502,7 +502,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -502,7 +502,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 502 | .p_paddr = got_addr, | 502 | .p_paddr = got_addr, |
| 503 | .p_memsz = file_size, | 503 | .p_memsz = file_size, |
| 504 | .p_align = p_align, | 504 | .p_align = p_align, |
| 505 | .p_flags = elf.PF_R, | 505 | .p_flags = elf.PF_R | elf.PF_W, |
| 506 | }); | 506 | }); |
| 507 | self.phdr_table_dirty = true; | 507 | self.phdr_table_dirty = true; |
| 508 | } | 508 | } |
| ... | @@ -525,7 +525,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -525,7 +525,7 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 525 | .p_paddr = rodata_addr, | 525 | .p_paddr = rodata_addr, |
| 526 | .p_memsz = file_size, | 526 | .p_memsz = file_size, |
| 527 | .p_align = p_align, | 527 | .p_align = p_align, |
| 528 | .p_flags = elf.PF_R, | 528 | .p_flags = elf.PF_R | elf.PF_W, |
| 529 | }); | 529 | }); |
| 530 | self.phdr_table_dirty = true; | 530 | self.phdr_table_dirty = true; |
| 531 | } | 531 | } |
| ... | @@ -2097,7 +2097,6 @@ fn growTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBlock, | ... | @@ -2097,7 +2097,6 @@ fn growTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBlock, |
| 2097 | fn allocateTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 { | 2097 | fn allocateTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 { |
| 2098 | const phdr = &self.program_headers.items[block_list.phdr_index.?]; | 2098 | const phdr = &self.program_headers.items[block_list.phdr_index.?]; |
| 2099 | const shdr = &self.sections.items[block_list.section_index.?]; | 2099 | const shdr = &self.sections.items[block_list.section_index.?]; |
| 2100 | const new_block_ideal_capacity = padToIdeal(new_block_size); | | |
| 2101 | | 2100 | |
| 2102 | // We use these to indicate our intention to update metadata, placing the new block, | 2101 | // We use these to indicate our intention to update metadata, placing the new block, |
| 2103 | // and possibly removing a free list node. | 2102 | // and possibly removing a free list node. |
| ... | @@ -2110,42 +2109,7 @@ fn allocateTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBl | ... | @@ -2110,42 +2109,7 @@ fn allocateTextBlock(self: *Elf, block_list: *TextBlockList, text_block: *TextBl |
| 2110 | // First we look for an appropriately sized free list node. | 2109 | // First we look for an appropriately sized free list node. |
| 2111 | // The list is unordered. We'll just take the first thing that works. | 2110 | // The list is unordered. We'll just take the first thing that works. |
| 2112 | const vaddr = blk: { | 2111 | const vaddr = blk: { |
| 2113 | var i: usize = 0; | 2112 | if (block_list.last_block) |last| { |
| 2114 | while (i < block_list.free_list.items.len) { | | |
| 2115 | const big_block = block_list.free_list.items[i]; | | |
| 2116 | // We now have a pointer to a live text block that has too much capacity. | | |
| 2117 | // Is it enough that we could fit this new text block? | | |
| 2118 | const sym = self.local_symbols.items[big_block.local_sym_index]; | | |
| 2119 | const capacity = big_block.capacity(self.*); | | |
| 2120 | const ideal_capacity = padToIdeal(capacity); | | |
| 2121 | const ideal_capacity_end_vaddr = sym.st_value + ideal_capacity; | | |
| 2122 | const capacity_end_vaddr = sym.st_value + capacity; | | |
| 2123 | const new_start_vaddr_unaligned = capacity_end_vaddr - new_block_ideal_capacity; | | |
| 2124 | const new_start_vaddr = mem.alignBackwardGeneric(u64, new_start_vaddr_unaligned, alignment); | | |
| 2125 | if (new_start_vaddr < ideal_capacity_end_vaddr) { | | |
| 2126 | // Additional bookkeeping here to notice if this free list node | | |
| 2127 | // should be deleted because the block that it points to has grown to take up | | |
| 2128 | // more of the extra capacity. | | |
| 2129 | if (!big_block.freeListEligible(self.*)) { | | |
| 2130 | _ = block_list.free_list.swapRemove(i); | | |
| 2131 | } else { | | |
| 2132 | i += 1; | | |
| 2133 | } | | |
| 2134 | continue; | | |
| 2135 | } | | |
| 2136 | // At this point we know that we will place the new block here. But the | | |
| 2137 | // remaining question is whether there is still yet enough capacity left | | |
| 2138 | // over for there to still be a free list node. | | |
| 2139 | const remaining_capacity = new_start_vaddr - ideal_capacity_end_vaddr; | | |
| 2140 | const keep_free_list_node = remaining_capacity >= min_text_capacity; | | |
| 2141 | | | |
| 2142 | // Set up the metadata to be updated, after errors are no longer possible. | | |
| 2143 | block_placement = big_block; | | |
| 2144 | if (!keep_free_list_node) { | | |
| 2145 | free_list_removal = i; | | |
| 2146 | } | | |
| 2147 | break :blk new_start_vaddr; | | |
| 2148 | } else if (block_list.last_block) |last| { | | |
| 2149 | const sym = self.local_symbols.items[last.local_sym_index]; | 2113 | const sym = self.local_symbols.items[last.local_sym_index]; |
| 2150 | const ideal_capacity = padToIdeal(sym.st_size); | 2114 | const ideal_capacity = padToIdeal(sym.st_size); |
| 2151 | const ideal_capacity_end_vaddr = sym.st_value + ideal_capacity; | 2115 | const ideal_capacity_end_vaddr = sym.st_value + ideal_capacity; |
| ... | @@ -2318,37 +2282,12 @@ fn updateDeclCode(self: *Elf, decl: *Module.Decl, code: []const u8, stt_bits: u8 | ... | @@ -2318,37 +2282,12 @@ fn updateDeclCode(self: *Elf, decl: *Module.Decl, code: []const u8, stt_bits: u8 |
| 2318 | | 2282 | |
| 2319 | assert(decl.link.elf.local_sym_index != 0); // Caller forgot to allocateDeclIndexes() | 2283 | assert(decl.link.elf.local_sym_index != 0); // Caller forgot to allocateDeclIndexes() |
| 2320 | const local_sym = &self.local_symbols.items[decl.link.elf.local_sym_index]; | 2284 | const local_sym = &self.local_symbols.items[decl.link.elf.local_sym_index]; |
| 2321 | if (local_sym.st_size != 0) { | 2285 | { |
| 2322 | const capacity = decl.link.elf.capacity(self.*); | | |
| 2323 | const need_realloc = code.len > capacity or | | |
| 2324 | !mem.isAlignedGeneric(u64, local_sym.st_value, required_alignment); | | |
| 2325 | if (need_realloc) { | | |
| 2326 | const vaddr = try self.growTextBlock(block_list, &decl.link.elf, code.len, required_alignment); | | |
| 2327 | log.debug("growing {s} from 0x{x} to 0x{x}", .{ decl.name, local_sym.st_value, vaddr }); | | |
| 2328 | if (vaddr != local_sym.st_value) { | | |
| 2329 | local_sym.st_value = vaddr; | | |
| 2330 | | | |
| 2331 | log.debug(" (writing new offset table entry)", .{}); | | |
| 2332 | self.offset_table.items[decl.link.elf.offset_table_index] = vaddr; | | |
| 2333 | try self.writeOffsetTableEntry(decl.link.elf.offset_table_index); | | |
| 2334 | } | | |
| 2335 | } else if (code.len < local_sym.st_size) { | | |
| 2336 | self.shrinkTextBlock(block_list, &decl.link.elf, code.len); | | |
| 2337 | } | | |
| 2338 | local_sym.st_size = code.len; | | |
| 2339 | local_sym.st_name = try self.updateString(local_sym.st_name, mem.sliceTo(decl.name, 0)); | | |
| 2340 | local_sym.st_info = (elf.STB_LOCAL << 4) | stt_bits; | | |
| 2341 | local_sym.st_other = 0; | | |
| 2342 | local_sym.st_shndx = block_list.section_index.?; | | |
| 2343 | // TODO this write could be avoided if no fields of the symbol were changed. | | |
| 2344 | try self.writeSymbol(decl.link.elf.local_sym_index); | | |
| 2345 | } else { | | |
| 2346 | const decl_name = mem.sliceTo(decl.name, 0); | 2286 | const decl_name = mem.sliceTo(decl.name, 0); |
| 2347 | const name_str_index = try self.makeString(decl_name); | 2287 | const name_str_index = try self.makeString(decl_name); |
| 2348 | const vaddr = try self.allocateTextBlock(block_list, &decl.link.elf, code.len, required_alignment); | 2288 | const vaddr = try self.allocateTextBlock(block_list, &decl.link.elf, code.len, required_alignment); |
| 2349 | errdefer self.freeTextBlock(block_list, &decl.link.elf); | 2289 | errdefer self.freeTextBlock(block_list, &decl.link.elf); |
| 2350 | log.debug("allocated text block for {s} at 0x{x}", .{ decl_name, vaddr }); | 2290 | log.debug("allocated text block for {s} at 0x{x}", .{ decl_name, vaddr }); |
| 2351 | errdefer self.freeTextBlock(block_list, &decl.link.elf); | | |
| 2352 | | 2291 | |
| 2353 | local_sym.* = .{ | 2292 | local_sym.* = .{ |
| 2354 | .st_name = name_str_index, | 2293 | .st_name = name_str_index, |
| ... | @@ -2366,6 +2305,22 @@ fn updateDeclCode(self: *Elf, decl: *Module.Decl, code: []const u8, stt_bits: u8 | ... | @@ -2366,6 +2305,22 @@ fn updateDeclCode(self: *Elf, decl: *Module.Decl, code: []const u8, stt_bits: u8 |
| 2366 | | 2305 | |
| 2367 | const section_offset = local_sym.st_value - self.program_headers.items[block_list.phdr_index.?].p_vaddr; | 2306 | const section_offset = local_sym.st_value - self.program_headers.items[block_list.phdr_index.?].p_vaddr; |
| 2368 | const file_offset = self.sections.items[block_list.section_index.?].sh_offset + section_offset; | 2307 | const file_offset = self.sections.items[block_list.section_index.?].sh_offset + section_offset; |
| | 2308 | |
| | 2309 | if (self.base.child_pid) |pid| { |
| | 2310 | var code_vec: [1]std.os.iovec_const = .{.{ |
| | 2311 | .iov_base = code.ptr, |
| | 2312 | .iov_len = code.len, |
| | 2313 | }}; |
| | 2314 | var remote_vec: [1]std.os.iovec_const = .{.{ |
| | 2315 | .iov_base = @intToPtr([*]u8, local_sym.st_value), |
| | 2316 | .iov_len = code.len, |
| | 2317 | }}; |
| | 2318 | const rc = std.os.linux.process_vm_writev(pid, &code_vec, &remote_vec, 0); |
| | 2319 | switch (std.os.errno(rc)) { |
| | 2320 | .SUCCESS => assert(rc == code.len), |
| | 2321 | else => |errno| log.warn("process_vm_writev failure: {s}", .{@tagName(errno)}), |
| | 2322 | } |
| | 2323 | } |
| 2369 | try self.base.file.?.pwriteAll(code, file_offset); | 2324 | try self.base.file.?.pwriteAll(code, file_offset); |
| 2370 | | 2325 | |
| 2371 | return local_sym; | 2326 | return local_sym; |
| ... | @@ -3033,6 +2988,7 @@ fn writeOffsetTableEntry(self: *Elf, index: usize) !void { | ... | @@ -3033,6 +2988,7 @@ fn writeOffsetTableEntry(self: *Elf, index: usize) !void { |
| 3033 | } | 2988 | } |
| 3034 | const endian = self.base.options.target.cpu.arch.endian(); | 2989 | const endian = self.base.options.target.cpu.arch.endian(); |
| 3035 | const off = shdr.sh_offset + @as(u64, entry_size) * index; | 2990 | const off = shdr.sh_offset + @as(u64, entry_size) * index; |
| | 2991 | const vaddr = phdr.p_vaddr + @as(u64, entry_size) * index; |
| 3036 | switch (entry_size) { | 2992 | switch (entry_size) { |
| 3037 | 2 => { | 2993 | 2 => { |
| 3038 | var buf: [2]u8 = undefined; | 2994 | var buf: [2]u8 = undefined; |
| ... | @@ -3048,6 +3004,22 @@ fn writeOffsetTableEntry(self: *Elf, index: usize) !void { | ... | @@ -3048,6 +3004,22 @@ fn writeOffsetTableEntry(self: *Elf, index: usize) !void { |
| 3048 | var buf: [8]u8 = undefined; | 3004 | var buf: [8]u8 = undefined; |
| 3049 | mem.writeInt(u64, &buf, self.offset_table.items[index], endian); | 3005 | mem.writeInt(u64, &buf, self.offset_table.items[index], endian); |
| 3050 | try self.base.file.?.pwriteAll(&buf, off); | 3006 | try self.base.file.?.pwriteAll(&buf, off); |
| | 3007 | |
| | 3008 | if (self.base.child_pid) |pid| { |
| | 3009 | var local_vec: [1]std.os.iovec_const = .{.{ |
| | 3010 | .iov_base = &buf, |
| | 3011 | .iov_len = buf.len, |
| | 3012 | }}; |
| | 3013 | var remote_vec: [1]std.os.iovec_const = .{.{ |
| | 3014 | .iov_base = @intToPtr([*]u8, vaddr), |
| | 3015 | .iov_len = buf.len, |
| | 3016 | }}; |
| | 3017 | const rc = std.os.linux.process_vm_writev(pid, &local_vec, &remote_vec, 0); |
| | 3018 | switch (std.os.errno(rc)) { |
| | 3019 | .SUCCESS => assert(rc == buf.len), |
| | 3020 | else => |errno| log.warn("process_vm_writev failure: {s}", .{@tagName(errno)}), |
| | 3021 | } |
| | 3022 | } |
| 3051 | }, | 3023 | }, |
| 3052 | else => unreachable, | 3024 | else => unreachable, |
| 3053 | } | 3025 | } |