1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
|
#!/usr/bin/env perl
use strict;
use warnings;
use Getopt::Long;
#use Data::Dumper;
my %OPTIONS = (break_ret => 1);
GetOptions(\%OPTIONS, qw(break_ret! crlf));
my %names;
my %labels;
my @instructions;
my $next_global = 0;
my $riprel = undef;
local $/ = "\r\n" if $OPTIONS{crlf};
while (<>) {
chomp;
next unless m/^\s*([A-F0-9]+):\s+([A-F0-9]{2} ?)+\s+(\w+)\s+(.+)$/i;
my ($addr, $opcode, $arg) = (hex($1), $3, $4);
# remove lines with value bytes
next if $opcode =~ m/^[0-9A-F]{2}$/i;
# remove comments
$arg =~ s/\s+(#.+)$//;
# rip-relative labels are defined by their end position, hence
# they are calculate from the address of the next instruction
if (defined $riprel) {
$labels{$addr+$riprel} = 1;
$riprel = undef;
}
if ($opcode =~ m/^j\w+$/ && $arg =~ m/^0x/) {
my $pos = hex($arg);
$labels{$pos} = 1;
} elsif ($arg =~ m/\[rip\+(0x[0-9a-f]+)/i) {
$riprel = hex($1);
} elsif ($opcode eq 'movabs') {
my ($reg,$val) = split /,/, $arg;
$names{$val} = sprintf('global_%03d', ++$next_global) unless exists $names{$val};
}
push @instructions, [$addr, $opcode, $arg];
}
sub sortn { sort { $a <=> $b } @_ }
# assign labels in code order
@labels{sortn keys %labels} = 1..(scalar keys %labels);
for (my $i = 0; $i < @instructions; $i++) {
my ($addr, $opcode, $arg) = @{$instructions[$i]};
if (exists $labels{$addr}) {
# label_ is 6 char, 3 num, 1 colon, 2 space
print sprintf("label_%03d: ", $labels{$addr});
} else {
print ' ' x 12;
}
if ($opcode eq 'movabs') {
my ($reg,$val) = split /,/, $arg;
$arg = sprintf('%s,%s', $reg, $names{$val});
} elsif ($opcode =~ m/^j\w+$/ && $arg =~ m/^0x/) {
$arg = sprintf('label_%03d', $labels{hex($arg)});
} elsif ($arg =~ m/\[rip\+(0x[0-9a-f]+)\]/i) {
my $pos = hex($1) + $instructions[$i+1]->[0];
$arg = substr($arg,0,$-[0]) . sprintf('label_%03d # rip', $labels{$pos});
}
print "$opcode $arg\n";
last if $OPTIONS{break_ret} and $opcode eq 'ret';
}
|