|
#!/usr/bin/env bash |
|
set -euo pipefail |
|
|
|
cd "${1:-/tmp/bun-wsl1-elf-repro-verified}" |
|
|
|
cp hello-1.3.13 hello-1.3.13-rw-load-fixed-shape |
|
|
|
perl -e ' |
|
use strict; |
|
use warnings; |
|
use Fcntl qw(SEEK_SET); |
|
|
|
my $path = shift; |
|
open my $f, "+<", $path or die $!; |
|
binmode $f; |
|
local $/; |
|
my $data = <$f>; |
|
|
|
sub u64 { unpack("Q<", substr($data, $_[0], 8)) } |
|
sub w64 { substr($data, $_[0], 8) = pack("Q<", $_[1]) } |
|
sub w32 { substr($data, $_[0], 4) = pack("L<", $_[1]) } |
|
|
|
my $rw_ph = 64 + 4 * 56; |
|
my $extra_ph = 64 + 7 * 56; |
|
my $shnum = unpack("S<", substr($data, 60, 2)); |
|
my $shentsize = unpack("S<", substr($data, 58, 2)); |
|
my $old_shoff = u64(40); |
|
my $old_shdr_size = $shnum * $shentsize; |
|
|
|
my $rw_off = u64($rw_ph + 8); |
|
my $rw_vaddr = u64($rw_ph + 16); |
|
my $rw_filesz = u64($rw_ph + 32); |
|
my $rw_memsz = u64($rw_ph + 40); |
|
my $rw_align = u64($rw_ph + 48); |
|
|
|
my $old_file_backed_end = $rw_off + $rw_filesz; |
|
my $old_mem_end_vaddr = $rw_vaddr + $rw_memsz; |
|
my $new_vaddr = ($old_mem_end_vaddr + $rw_align - 1) & ~($rw_align - 1); |
|
my $new_file_offset = $rw_off + ($new_vaddr - $rw_vaddr); |
|
my $aligned_payload_size = 0x1000; |
|
my $new_shoff = $new_file_offset + $aligned_payload_size; |
|
my $new_file_size = $new_shoff + $old_shdr_size; |
|
my $new_filesz = $new_file_offset + $aligned_payload_size - $rw_off; |
|
|
|
my $payload = substr($data, 0x603a000, $aligned_payload_size); |
|
my $shdrs = substr($data, $old_shoff, $old_shdr_size); |
|
|
|
if (length($data) < $new_file_size) { |
|
$data .= "\0" x ($new_file_size - length($data)); |
|
} |
|
|
|
# Any bytes between the old file-backed data and the moved payload become |
|
# file-backed BSS after extending the RW segment. They must be zero. |
|
substr($data, $old_file_backed_end, $new_file_offset - $old_file_backed_end) = "\0" x ($new_file_offset - $old_file_backed_end); |
|
substr($data, $new_file_offset, $aligned_payload_size) = $payload; |
|
substr($data, $new_shoff, $old_shdr_size) = $shdrs; |
|
|
|
w64(40, $new_shoff); |
|
w64($rw_ph + 32, $new_filesz); |
|
w64($rw_ph + 40, $new_filesz); |
|
w32($extra_ph, 0x6474e551); |
|
w64(0x6020000, $new_vaddr); |
|
|
|
# Section header #25 is .bun. |
|
my $bun_sh = $new_shoff + 25 * $shentsize; |
|
w64($bun_sh + 16, $new_vaddr); |
|
w64($bun_sh + 24, $new_file_offset); |
|
|
|
truncate $f, 0; |
|
seek $f, 0, SEEK_SET; |
|
print $f $data; |
|
close $f; |
|
|
|
printf "rw_off=0x%x rw_vaddr=0x%x old_file_backed_end=0x%x old_mem_end_vaddr=0x%x\n", $rw_off, $rw_vaddr, $old_file_backed_end, $old_mem_end_vaddr; |
|
printf "new_file_offset=0x%x new_vaddr=0x%x new_filesz=0x%x new_shoff=0x%x\n", $new_file_offset, $new_vaddr, $new_filesz, $new_shoff; |
|
' hello-1.3.13-rw-load-fixed-shape |
|
|
|
readelf -lW hello-1.3.13-rw-load-fixed-shape | awk '/Program Headers:/,/Section to Segment mapping:/' |
|
readelf -SW hello-1.3.13-rw-load-fixed-shape | grep -E '(^ \[Nr\]|\.bun)' |
|
|
|
./hello-1.3.13-rw-load-fixed-shape |