authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-01-19 14:08:43-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-01-19 14:08:43-07:00
log287f640cc94d7f1cddb30e9ef57a8c921621a5b9
tree0cc87ff3207394d289324c8bf8f2ad4ac900e049
parentd5d0619aacccd5e3b933b3196fba5ab6f8f9da47

stage2: ELF: fix crash when only 1 function and it gets updated


2 files changed, 46 insertions(+), 3 deletions(-)

src/link/Elf.zig+16-3
...@@ -2377,7 +2377,7 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {...@@ -2377,7 +2377,7 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
2377 const debug_line_sect = &self.sections.items[self.debug_line_section_index.?];2377 const debug_line_sect = &self.sections.items[self.debug_line_section_index.?];
2378 const src_fn = &decl.fn_link.elf;2378 const src_fn = &decl.fn_link.elf;
2379 src_fn.len = @intCast(u32, dbg_line_buffer.items.len);2379 src_fn.len = @intCast(u32, dbg_line_buffer.items.len);
2380 if (self.dbg_line_fn_last) |last| {2380 if (self.dbg_line_fn_last) |last| not_first: {
2381 if (src_fn.next) |next| {2381 if (src_fn.next) |next| {
2382 // Update existing function - non-last item.2382 // Update existing function - non-last item.
2383 if (src_fn.off + src_fn.len + min_nop_size > next.off) {2383 if (src_fn.off + src_fn.len + min_nop_size > next.off) {
...@@ -2400,9 +2400,15 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {...@@ -2400,9 +2400,15 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
2400 src_fn.off = last.off + padToIdeal(last.len);2400 src_fn.off = last.off + padToIdeal(last.len);
2401 }2401 }
2402 } else if (src_fn.prev == null) {2402 } else if (src_fn.prev == null) {
2403 if (src_fn == last) {
2404 // Special case: there is only 1 function and it is being updated.
2405 // In this case there is nothing to do. The function's length has
2406 // already been updated, and the logic below takes care of
2407 // resizing the .debug_line section.
2408 break :not_first;
2409 }
2403 // Append new function.2410 // Append new function.
2404 // TODO Look at the free list before appending at the end.2411 // TODO Look at the free list before appending at the end.
2405 assert(src_fn != last);
2406 src_fn.prev = last;2412 src_fn.prev = last;
2407 last.next = src_fn;2413 last.next = src_fn;
2408 self.dbg_line_fn_last = src_fn;2414 self.dbg_line_fn_last = src_fn;
...@@ -2527,7 +2533,7 @@ fn updateDeclDebugInfoAllocation(self: *Elf, text_block: *TextBlock, len: u32) !...@@ -2527,7 +2533,7 @@ fn updateDeclDebugInfoAllocation(self: *Elf, text_block: *TextBlock, len: u32) !
25272533
2528 const debug_info_sect = &self.sections.items[self.debug_info_section_index.?];2534 const debug_info_sect = &self.sections.items[self.debug_info_section_index.?];
2529 text_block.dbg_info_len = len;2535 text_block.dbg_info_len = len;
2530 if (self.dbg_info_decl_last) |last| {2536 if (self.dbg_info_decl_last) |last| not_first: {
2531 if (text_block.dbg_info_next) |next| {2537 if (text_block.dbg_info_next) |next| {
2532 // Update existing Decl - non-last item.2538 // Update existing Decl - non-last item.
2533 if (text_block.dbg_info_off + text_block.dbg_info_len + min_nop_size > next.dbg_info_off) {2539 if (text_block.dbg_info_off + text_block.dbg_info_len + min_nop_size > next.dbg_info_off) {
...@@ -2549,6 +2555,13 @@ fn updateDeclDebugInfoAllocation(self: *Elf, text_block: *TextBlock, len: u32) !...@@ -2549,6 +2555,13 @@ fn updateDeclDebugInfoAllocation(self: *Elf, text_block: *TextBlock, len: u32) !
2549 text_block.dbg_info_off = last.dbg_info_off + padToIdeal(last.dbg_info_len);2555 text_block.dbg_info_off = last.dbg_info_off + padToIdeal(last.dbg_info_len);
2550 }2556 }
2551 } else if (text_block.dbg_info_prev == null) {2557 } else if (text_block.dbg_info_prev == null) {
2558 if (text_block == last) {
2559 // Special case: there is only 1 .debug_info block and it is being updated.
2560 // In this case there is nothing to do. The block's length has
2561 // already been updated, and logic in writeDeclDebugInfo takes care of
2562 // resizing the .debug_info section.
2563 break :not_first;
2564 }
2552 // Append new Decl.2565 // Append new Decl.
2553 // TODO Look at the free list before appending at the end.2566 // TODO Look at the free list before appending at the end.
2554 text_block.dbg_info_prev = last;2567 text_block.dbg_info_prev = last;
test/stage2/test.zig+30
...@@ -1509,4 +1509,34 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -1509,4 +1509,34 @@ pub fn addCases(ctx: *TestContext) !void {
1509 "",1509 "",
1510 );1510 );
1511 }1511 }
1512
1513 {
1514 var case = ctx.exe("only 1 function and it gets updated", linux_x64);
1515 case.addCompareOutput(
1516 \\export fn _start() noreturn {
1517 \\ asm volatile ("syscall"
1518 \\ :
1519 \\ : [number] "{rax}" (60), // exit
1520 \\ [arg1] "{rdi}" (0)
1521 \\ : "rcx", "r11", "memory"
1522 \\ );
1523 \\ unreachable;
1524 \\}
1525 ,
1526 "",
1527 );
1528 case.addCompareOutput(
1529 \\export fn _start() noreturn {
1530 \\ asm volatile ("syscall"
1531 \\ :
1532 \\ : [number] "{rax}" (231), // exit_group
1533 \\ [arg1] "{rdi}" (0)
1534 \\ : "rcx", "r11", "memory"
1535 \\ );
1536 \\ unreachable;
1537 \\}
1538 ,
1539 "",
1540 );
1541 }
1512}1542}