#!/usr/bin/perl # test_x86dis.pl # ... actually this is a general test utility for libdisasm; however, it # is also useful for comparing the AT&T syntax output of x86dis (which is # generated by libdisasm) against what GNU as(1) expects. # NOTE: this script expects to be run from $LIBDISASM/libdisasm/test # and uses the instructions in ia32_test_insn.S to test disassembly. use warnings; use strict; # assembler settings my $asm_file = 'ia32_test_insn.S'; my $obj_file = '/tmp/ia32.o'; my $text_off = 0x34; # hopefully this won't change :) my $text_size = 1986; # same my $as = `which as`; # relative path, ld_library_path for running x86dis from compile dir my $x86dis = '../x86dis/x86dis'; # path is not needed now that libtool is being used #my $ldpath = 'LD_LIBRARY_PATH="../libdisasm"'; my $ldpath = ''; my $x86dis_opt_str = "-f $obj_file -s att -r %d %d"; # uninitialized stuff my ($line, @asm_lines, $x86dis_opts, $output, @disasm_lines, @bytes, $i); my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$jnk); my ($a_mnem, $d_mnem, $a_op, $d_op); print "## open asm file \n"; open ASMFILE, $asm_file || die "Cannot open $asm_file : $!\n"; foreach () { chomp; next if /^#/; # skip comment lines $line = $_; $line =~ s/\s+/ /g; $line =~ s/\s+$//; $line =~ s/#.*//; $line = lc $line; push @asm_lines, $line; } $as =~ s/\n//g; print "## assemble asm file: $as -o $obj_file $asm_file\n"; system "$as -o $obj_file $asm_file"; exit(1) if ($? != 0); print "## stat obj file $obj_file\n"; ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$jnk) = stat $obj_file; #$x86dis_opts = sprintf $x86dis_opt_str, $text_off, $size; $x86dis_opts = sprintf $x86dis_opt_str, $text_off, $text_size; print "## disasm obj file: $ldpath $x86dis $x86dis_opts\n"; $output = `$ldpath $x86dis $x86dis_opts`; exit(1) if ($? != 0); foreach ( split /\n/, $output ) { chomp; next if /^#/; # skip comment lines $line = $_; $line =~ s/\s+/ /g; $line =~ s/\s+$//; $line =~ s/#.*//; $line = lc $line; $line =~ s/^[0-9][0-9a-f]+\s+(([0-9a-f]{2} )+)//; push @bytes, $1; push @disasm_lines, $line; } my $status = 0; for ( $i = 0; $i <= $#disasm_lines and $i <= $#asm_lines; $i = $i + 1 ) { if ( $disasm_lines[$i] ne $asm_lines[$i] ) { # check if this is a jump or call, in which case # the targets will be different addresses ($a_mnem, $a_op, $jnk) = split / /, $asm_lines[$i]; ($d_mnem, $d_op, $jnk) = split / /, $disasm_lines[$i]; if ( $a_mnem eq $d_mnem and ($d_mnem =~ /^j/ or $d_mnem =~/call/ or $d_mnem =~ /loop/ ) and $a_op =~ /^[-0-9]+/ ){ next; } print "ERROR: orig '$asm_lines[$i]'\n"; print " dis '$disasm_lines[$i]' BYTES $bytes[$i]\n"; $status = 1; } } exit($status);