Asm-X86

 view release on metacpan or  search on metacpan

lib/Asm/X86.pm  view on Meta::CPAN

	is_valid_64bit_addr_att
	is_valid_addr_att

	is_valid_16bit_addr
	is_valid_32bit_addr
	is_valid_64bit_addr
	is_valid_addr

	conv_att_addr_to_intel
	conv_att_instr_to_intel
	conv_intel_addr_to_att
	conv_intel_instr_to_att

	is_att_suffixed_instr
	is_att_suffixed_instr_fpu
	add_att_suffix_instr

 These check if the given string parameter belongs to the specified
 class of registers or instructions or is a valid addressing mode.
 The "convert*" functions can be used to convert the given instruction
  (including the operands)/addressing mode between AT&T and Intel syntaxes.
 The "_intel" and "_att" suffixes mean the Intel and AT&T syntaxes,
  respectively.
 No suffix means either Intel or AT&T.
 All subroutines work best given input after any pre-processing, i.e. after
  all macros, constants, etc. have been replaced by the real values.

 The following arrays are exported on request:
	@regs8_intel
	@regs16_intel
	@segregs_intel
	@regs32_intel
	@regs64_intel
	@regs_mm_intel
	@regs_fpu_intel
	@regs_opmask_intel
	@regs_intel

	@regs8_att
	@regs16_att
	@segregs_att
	@regs32_att
	@regs64_att
	@regs_mm_att
	@regs_fpu_att
	@regs_opmask_att
	@regs_att

	@instr_intel
	@instr_att
	@instr

 These contain all register and instruction mnemonic names as lower-case strings.
 The "_intel" and "_att" suffixes mean the Intel and AT&T syntaxes, respectively.
 No suffix means either Intel or AT&T.

=head1 DATA

=cut

# =head2 _add_percent
#
#  PRIVATE SUBROUTINE.
#  Add a percent character ('%') in front of each element in the array given as a parameter.
#  Returns the new array.
#
# =cut

sub _add_percent(@) {

	my @result = ();
	foreach (@_) {
		push @result, "%$_";
	}
	return @result;
}

# =head2 _remove_duplicates
#
#  PRIVATE SUBROUTINE.
#  Returns an array of the provided arguments with duplicate entries removed.
#
# =cut
#
sub _remove_duplicates(@) {

	# Use a hash to remove the duplicates:
	my %new_hash;
	foreach (@_) {
		$new_hash{$_} = 1;
	}
	return keys %new_hash;
}

# =head2 _nopluses
#
#  PRIVATE SUBROUTINE.
#  Removes unnecessary '+' characters from the beginning of the given string.
#  Returns the resulting string (or '+' if it was empty).
#
# =cut
#
sub _nopluses($) {

	my $elem = shift;
	$elem =~ s/^\s*\++//o;
	$elem = '+' if $elem eq '';
	return $elem;
}

# =head2 _is_in_array
#
#  PRIVATE SUBROUTINE.
#  Checks if the given element (1st parameter) is a simple word and is present
#	in the array (passed by reference as the 2nd parameter),
#	case-insensitive.
#  Returns 1 if yes.
#
# =cut
#
sub _is_in_array($@) {

	my ($elem, $arr) = @_;
	return 0 unless $elem =~ /^\w+$/o;
	foreach (@$arr) {
		return 1 if /^$elem$/i;
	}
	return 0;
}

# =head2 _is_in_array_att
#
#  PRIVATE SUBROUTINE.
#  Checks if the given element (1st parameter) is a simple word beginning
#	with '%' and is present in the array (passed by reference as the 2nd
#	parameter), case-insensitive.
#  Returns 1 if yes.
#
# =cut
#
sub _is_in_array_att($@) {

	my ($elem, $arr) = @_;
	return 0 unless $elem =~ /^\%\w+$/o;
	foreach (@$arr) {
		return 1 if /^$elem$/i;
	}
	return 0;
}


sub add_att_suffix_instr(@);

=head2 @regs8_intel

 A list of 8-bit registers (as strings) in Intel syntax.

=cut

our @regs8_intel = (
		'al', 'bl', 'cl', 'dl', 'r8b', 'r9b', 'r10b', 'r11b',
		'r12b', 'r13b', 'r14b', 'r15b', 'sil', 'dil', 'spl', 'bpl',
		'ah', 'bh', 'ch', 'dh',
		'r16b', 'r17b', 'r18b', 'r19b', 'r20b', 'r21b', 'r22b', 'r23b',
		'r24b', 'r25b', 'r26b', 'r27b', 'r28b', 'r29b', 'r30b', 'r31b'
		);

=head2 @regs8_att

 A list of 8-bit registers (as strings) in AT&T syntax.

=cut

our @regs8_att = _add_percent @regs8_intel;

=head2 @segregs_intel

 A list of segment registers (as strings) in Intel syntax.

=cut

our @segregs_intel = ( 'cs', 'ds', 'es', 'fs', 'gs', 'ss' );

=head2 @segregs_att

 A list of segment registers (as strings) in AT&T syntax.

=cut

our @segregs_att = _add_percent @segregs_intel;

=head2 @regs16_intel

 A list of 16-bit registers (as strings), including the segment registers,  in Intel syntax.

=cut

our @regs16_intel = (
		'ax', 'bx', 'cx', 'dx', 'r8w', 'r9w', 'r10w', 'r11w',
		'r12w', 'r13w', 'r14w', 'r15w', 'si', 'di', 'sp', 'bp',
		'r16w', 'r17w', 'r18w', 'r19w', 'r20w', 'r21w', 'r22w', 'r23w',
		'r24w', 'r25w', 'r26w', 'r27w', 'r28w', 'r29w', 'r30w', 'r31w',
		@segregs_intel
		);

=head2 @regs16_att

 A list of 16-bit registers (as strings), including the segment registers, in AT&T syntax.

=cut

our @regs16_att = _add_percent @regs16_intel;

my @addressable32 = ('eax', 'ebx', 'ecx', 'edx', 'esi', 'edi', 'esp', 'ebp');

my @addressable32_att = _add_percent @addressable32;

my @r32_in64 = (
		'r8d', 'r8l', 'r9d', 'r9l', 'r10d', 'r10l', 'r11d', 'r11l',
		'r12d', 'r12l', 'r13d', 'r13l', 'r14d', 'r14l', 'r15d', 'r15l',
		'r16d', 'r17d', 'r18d', 'r19d', 'r20d', 'r21d', 'r22d', 'r23d',
		'r24d', 'r25d', 'r26d', 'r27d', 'r28d', 'r29d', 'r30d', 'r31d',
		'r16l', 'r17l', 'r18l', 'r19l', 'r20l', 'r21l', 'r22l', 'r23l',
		'r24l', 'r25l', 'r26l', 'r27l', 'r28l', 'r29l', 'r30l', 'r31l',
		);

my @r32_in64_att = _add_percent @r32_in64;

=head2 @regs32_intel

 A list of 32-bit registers (as strings) in Intel syntax.

=cut

our @regs32_intel = (
		@addressable32,
		'cr0', 'cr2', 'cr3', 'cr4', 'cr8',
		'dr0', 'dr1', 'dr2', 'dr3', 'dr6', 'dr7',
		@r32_in64
		);

=head2 @regs32_att

 A list of 32-bit registers (as strings) in AT&T syntax.

=cut

our @regs32_att = _add_percent @regs32_intel;

=head2 @regs_fpu_intel

 A list of FPU registers (as strings) in Intel syntax.

=cut

our @regs_fpu_intel = ('st0', 'st1', 'st2', 'st3', 'st4', 'st5', 'st6', 'st7');

=head2 @regs_fpu_att

 A list of FPU registers (as strings) in AT&T syntax.

=cut

our @regs_fpu_att = _add_percent @regs_fpu_intel;

=head2 @regs64_intel

 A list of 64-bit registers (as strings) in Intel syntax.

=cut

our @regs64_intel = (
		'rax', 'rbx', 'rcx', 'rdx', 'r8', 'r9', 'r10', 'r11',
		'r12', 'r13', 'r14', 'r15', 'rsi', 'rdi', 'rsp', 'rbp', 'rip',
		'r16', 'r17', 'r18', 'r19', 'r20', 'r21', 'r22', 'r23',
		'r24', 'r25', 'r26', 'r27', 'r28', 'r29', 'r30', 'r31'
		);

=head2 @regs64_att

 A list of 64-bit registers (as strings) in AT&T syntax.

=cut

our @regs64_att = _add_percent @regs64_intel;

=head2 @regs_mm_intel

 A list of multimedia (MMX/3DNow!/SSEn) registers (as strings) in Intel syntax.

=cut

our @regs_mm_intel = (
		'mm0', 'mm1', 'mm2', 'mm3', 'mm4', 'mm5', 'mm6', 'mm7',
		'xmm0', 'xmm1', 'xmm2', 'xmm3', 'xmm4', 'xmm5', 'xmm6', 'xmm7',
		'xmm8', 'xmm9', 'xmm10', 'xmm11', 'xmm12', 'xmm13', 'xmm14', 'xmm15',
		'xmm16', 'xmm17', 'xmm18', 'xmm19', 'xmm20', 'xmm21', 'xmm22', 'xmm23',
		'xmm24', 'xmm25', 'xmm26', 'xmm27', 'xmm28', 'xmm29', 'xmm30', 'xmm31',
		'ymm0', 'ymm1', 'ymm2', 'ymm3', 'ymm4', 'ymm5', 'ymm6', 'ymm7',
		'ymm8', 'ymm9', 'ymm10', 'ymm11', 'ymm12', 'ymm13', 'ymm14', 'ymm15',
		'ymm16', 'ymm17', 'ymm18', 'ymm19', 'ymm20', 'ymm21', 'ymm22', 'ymm23',
		'ymm24', 'ymm25', 'ymm26', 'ymm27', 'ymm28', 'ymm29', 'ymm30', 'ymm31',
		'zmm0', 'zmm1', 'zmm2', 'zmm3', 'zmm4', 'zmm5', 'zmm6', 'zmm7',
		'zmm8', 'zmm9', 'zmm10', 'zmm11', 'zmm12', 'zmm13', 'zmm14', 'zmm15',
		'zmm16', 'zmm17', 'zmm18', 'zmm19', 'zmm20', 'zmm21', 'zmm22', 'zmm23',
		'zmm24', 'zmm25', 'zmm26', 'zmm27', 'zmm28', 'zmm29', 'zmm30', 'zmm31'
		);


=head2 @regs_mm_att

 A list of multimedia (MMX/3DNow!/SSEn) registers (as strings) in AT&T syntax.

=cut

our @regs_mm_att = _add_percent @regs_mm_intel;

=head2 @regs_opmask_intel

 A list of opmask registers (as strings) in Intel syntax.

=cut

our @regs_opmask_intel = ('k0', 'k1', 'k2', 'k3', 'k4', 'k5', 'k6', 'k7');


=head2 @regs_opmask_att

 A list of opmask registers (as strings) in AT&T syntax.

=cut

our @regs_opmask_att = _add_percent @regs_opmask_intel;

=head2 @regs_bound_intel

 A list of bound registers (as strings) in Intel syntax.

=cut

our @regs_bound_intel = ('bnd0', 'bnd1', 'bnd2', 'bnd3');


=head2 @regs_bound_att

 A list of bound registers (as strings) in AT&T syntax.

=cut

our @regs_bound_att = _add_percent @regs_bound_intel;

=head2 @regs_intel

 A list of all x86 registers (as strings) in Intel syntax.

=cut

our @regs_intel = ( @regs8_intel, @regs16_intel, @regs32_intel,
			@regs64_intel, @regs_mm_intel, @regs_fpu_intel,
			@regs_opmask_intel, @regs_bound_intel );

=head2 @regs_att

 A list of all x86 registers (as strings) in AT&T syntax.

=cut

our @regs_att = ( @regs8_att, @regs16_att, @regs32_att,
			@regs64_att, @regs_mm_att, @regs_fpu_att,
			@regs_opmask_att, @regs_bound_att );


=head2 @instr_intel

 A list of all x86 instructions (as strings) in Intel syntax.

=cut

our @instr_intel = (
	'aaa', 'aad', 'aadd', 'aam', 'aand', 'aas', 'adc', 'adcx', 'add', 'addb', 'addd',
	'addpd', 'addps', 'addq','addsd', 'addss', 'addsubpd', 'addsubps', 'addw', 'adox',
	'aesdec', 'aesdec128kl', 'aesdec256kl', 'aesdeclast', 'aesdecwide128kl', 'aesdecwide256kl',
	'aesenc', 'aesenc128kl', 'aesenc256kl', 'aesenclast', 'aesencwide128kl', 'aesencwide256kl',
	'aesimc', 'aeskeygenassist', 'and', 'andb', 'andd', 'andn', 'andnb', 'andnd', 'andnpd',
	'andnps', 'andnq', 'andnw', 'andpd', 'andps', 'andq', 'andw','arpl', 'axor', 'bb0_reset',
	'bb1_reset', 'bextr', 'blcfill', 'blci', 'blcic', 'blcmsk', 'blcs',
	'blendpd', 'blendps', 'blendvpd', 'blendvps', 'blsfill', 'blsi', 'blsic', 'blsmsk', 'blsr',
	'bnd', 'bndcl', 'bndcn', 'bndcu', 'bndldx', 'bndmk', 'bndmov', 'bndstx',
	'bound', 'brkpt', 'bsf', 'bsr', 'bswap', 'bt', 'btc', 'btr', 'bts', 'bzhi', 'call', 'cbw',
	'ccmp', 'ccmpa', 'ccmpae', 'ccmpb', 'ccmpbe', 'ccmpc', 'ccmpe', 'ccmpf', 'ccmpg',
	'ccmpge', 'ccmpl', 'ccmple', 'ccmpna', 'ccmpnae', 'ccmpnb', 'ccmpnbe', 'ccmpnc',
	'ccmpne', 'ccmpng', 'ccmpnge', 'ccmpnl', 'ccmpnle', 'ccmpno', 'ccmpns',
	'ccmpnz', 'ccmpo', 'ccmps', 'ccmpt', 'ccmpz', 'cdq', 'cdqe', 'cfcmova', 'cfcmovae',
	'cfcmovb', 'cfcmovbe', 'cfcmovc', 'cfcmove', 'cfcmovg', 'cfcmovge', 'cfcmovl',
	'cfcmovle', 'cfcmovna', 'cfcmovnae', 'cfcmovnb', 'cfcmovnbe', 'cfcmovnc',
	'cfcmovne', 'cfcmovng', 'cfcmovnge', 'cfcmovnl', 'cfcmovnle', 'cfcmovno', 'cfcmovnp',
	'cfcmovns', 'cfcmovnz', 'cfcmovo', 'cfcmovp', 'cfcmovpe', 'cfcmovpo', 'cfcmovs', 'cfcmovz',
	'clac', 'clc', 'cld', 'cldemote', 'clflush', 'clflushopt',
	'clgi', 'cli', 'clrssbsy','clts', 'clui', 'clwb', 'clzero',
	'cmc', 'cmova', 'cmovae', 'cmovb', 'cmovbe', 'cmovc', 'cmove', 'cmovg', 'cmovge',
	'cmovl', 'cmovle', 'cmovna', 'cmovnae', 'cmovnb', 'cmovnbe', 'cmovnc',
	'cmovne', 'cmovng', 'cmovnge', 'cmovnl', 'cmovnle', 'cmovno', 'cmovnp',
	'cmovns', 'cmovnz', 'cmovo', 'cmovp', 'cmovpe', 'cmovpo', 'cmovs', 'cmovz',
	'cmp', 'cmpaexadd', 'cmpaxadd', 'cmpbexadd', 'cmpbxadd', 'cmpcxadd',
	'cmpeqpd', 'cmpeqps', 'cmpeqsd', 'cmpeqss', 'cmpexadd', 'cmpgexadd', 'cmpgxadd',
	'cmplepd', 'cmpleps', 'cmplesd', 'cmpless', 'cmplexadd',
	'cmpltpd', 'cmpltps', 'cmpltsd', 'cmpltss', 'cmplxadd', 'cmpnaexadd', 'cmpnaxadd',
	'cmpnbexadd', 'cmpnbxadd', 'cmpncxadd', 'cmpneqpd', 'cmpneqps', 'cmpneqsd', 'cmpneqss',
	'cmpnexadd', 'cmpngexadd', 'cmpngxadd','cmpnlepd', 'cmpnleps', 'cmpnlesd', 'cmpnless',
	'cmpnlexadd', 'cmpnltpd', 'cmpnltps', 'cmpnltsd', 'cmpnltss', 

lib/Asm/X86.pm  view on Meta::CPAN

	# (changing "xxx" to "[xxx]", if there's no '$' or '%')

	# (elements of memory operands mustn't be taken as instruction operands, so there are no '()'s here)
	if ( $par =~ /^\s*(\w+)\s+([\$\%\w\+\-]+)\s*,\s*([\$\%\w\+\-]+)\s*,\s*([\$\%\w\+\-]+)/o ) {

		my ($a1, $a2, $a3, $a4);

		$a1 = $1;
		$a2 = $2;
		$a3 = $3;
		$a4 = $4;

		#if ( $a1 !~ /call/io && $a1 !~ /^\s*j[a-z]{1,3}/io ) {

			$a2 = _change_to_intel_addr_if_applicable ($a2);
			$a3 = _change_to_intel_addr_if_applicable ($a3);
			$a4 = _change_to_intel_addr_if_applicable ($a4);

			# (ATTENTION: operand order will be changed later)
			$par = "\t$a1\t$a2, $a3, $a4\n";
		#}
	}

	if ( $par =~ /^\s*(\w+)\s+([\$\%\w\+\-]+)\s*,\s*([\$\%\w\+\-]+)\s*$/o ) {

		my ($a1, $a2, $a3);

		$a1 = $1;
		$a2 = $2;
		$a3 = $3;

		#if ( $a1 !~ /call/io && $a1 !~ /^\s*j[a-z]{1,3}/io ) {

			$a2 = _change_to_intel_addr_if_applicable ($a2);
			$a3 = _change_to_intel_addr_if_applicable ($a3);

			# (ATTENTION: operand order will be changed later)
			$par = "\t$a1\t$a2, $a3\n";
		#}
	}

	if ( $par =~ /^\s*(\w+)\s+([\$\%\w\+\-]+)\s*\s*$/o ) {

		my ($a1, $a2);

		$a1 = $1;
		$a2 = $2;

		# (don't touch "call/jmp xxx")
		if ( $a1 !~ /call/io && $a1 !~ /^\s*j[a-z]{1,3}/io ) {

			$a2 = _change_to_intel_addr_if_applicable ($a2);

			# (ATTENTION: operand order will be changed later)
			$par = "\t$a1\t$a2\n";
		}
	}

	# (removing dollar chars)
	$par =~ s/\$//go;
	# (removing percent chars)
	$par =~ s/%//go;
	# (removing asterisk chars)
	$par =~ s/\*//go;

	# (changing memory references):
	$par = conv_att_addr_to_intel $par;

	# (changing "st[N]" to "stN")
	$par =~ s/(\s)st\[(\d)\]/$1 st$2/go;
	# (changing "st" to "st0")
	$par =~ s/(\s)st(\s|,)/$1 st0$2/go;

	# (changing operands' order, but not for jump/call):
	if ( $par!~ /^\s*l?(jmp|call)/io ) {
		my $i_3op = qr/^\s*(\w+)\s+(\[?[:\.\w\*\+\-\(\)]+\]?)\s*,\s*(\[?[:\.\w\*\+\-\(\)]+\]?)\s*,\s*(\[?[:\.\w\*\+\-\(\)]+\]?)/o;
		my $i_2op = qr/^\s*(\w+)\s+(\[?[:\.\w\*\+\-\(\)]+\]?)\s*,\s*(\[?[:\.\w\*\+\-\(\)]+\]?)([^,]*(;.*)?)$/o;
		my $i_1op = qr/^\s*(\w+)\s+(\[?[:\.\w\*\+\-\(\)]+\]?)([^,]*(;.*)?)$/o;
		if ( $par =~ /$i_3op/ ) {
			if ( is_instr($1) ) {
				$par =~ s/$i_3op/\t$1\t$4, $3, $2/;
			}
		}
		if ( $par =~ /$i_2op/) {
			if ( is_instr($1) ) {
				$par =~ s/$i_2op/\t$1\t$3, $2$4/;
			}
		}
		if ( $par =~ /$i_1op/ ) {
			if ( is_instr($1) ) {
				$par =~ s/$i_1op/\t$1\t$2$3/;
			}
		}
	}

	foreach my $i (@instr) {

		next unless $par =~ /^\s*$i[bwl]\s*.*$/i
			&& $par !~ /^\s*f\w+l\s+.*$/
			&& $par !~ /^\s*mov[sz][bwl][bwl]\s+.*$/;
		$par =~ s/^\s*$i[b]\s*(.*)$/\t$i\tbyte $1/i;
		$par =~ s/^\s*$i[w]\s*(.*)$/\t$i\tword $1/i;
		$par =~ s/^\s*$i[l]\s*(.*)$/\t$i\tdword $1/i;
	}

	$par =~ s/^\s*movsbw\s+(.*)\s*,\s*(.*)$/\tmovsx\t$1, byte $2\n/io;
	$par =~ s/^\s*movsbl\s+(.*)\s*,\s*(.*)$/\tmovsx\t$1, byte $2\n/io;
	$par =~ s/^\s*movswl\s+(.*)\s*,\s*(.*)$/\tmovsx\t$1, word $2\n/io;
	$par =~ s/^\s*movzbw\s+(.*)\s*,\s*(.*)$/\tmovzx\t$1, byte $2\n/io;
	$par =~ s/^\s*movzbl\s+(.*)\s*,\s*(.*)$/\tmovzx\t$1, byte $2\n/io;
	$par =~ s/^\s*movzwl\s+(.*)\s*,\s*(.*)$/\tmovzx\t$1, word $2\n/io;

	my $jmp_mem = qr/^\s*l?(jmp|call)\s*(\[[\w\*\+\-\s]+\])\s*$/io;
	my $jmp_nomem = qr/^\s*l?(jmp|call)\s*([\w\*\+\-]+)\s*$/io;
	if ( $par =~ /$jmp_mem/ ) {
		$par =~ s/$jmp_mem/\t$1\tdword $2/;
	}
	elsif ( $par =~ /$jmp_nomem/ ) {
		$par =~ s/$jmp_nomem/\t$1\tdword $2/;
	}
	$par =~ s/^\s*lret\s*(.*)$/\tret\t$1\t/i;

lib/Asm/X86.pm  view on Meta::CPAN

		$par =~ s/^\s*fi(\w+)\s+qword\s*(.*)/\tfi${1}q\t$2/io;

		$par =~ s/^\s*f([^i]\w+)\s+dword\s*(.*)/\tf${1}s\t$2/io;
		$par =~ s/^\s*f([^i]\w+)\s+qword\s*(.*)/\tf${1}l\t$2/io;
		$par =~ s/^\s*f([^i]\w+)\s+t(word|byte)\s*(.*)/\tf${1}t\t$3/io;
	}

	# (change "xxx" to "$xxx", if there are no "[]")
	# (don't touch "call/jmp xxx")
	if ( $par !~ /^\s*(j[a-z]+|call)/io ) {

		if ( $par =~ /^\s*(\w+)\s+([^,]+)\s*,\s*([^,]+)\s*,\s*([^,]+)\s*/gio ) {

			$a1 = $1;
			$a1 =~ s/\s+$//o;
			$a2 = _remove_size_qualifiers_add_dollar ($2);
			$a3 = _remove_size_qualifiers_add_dollar ($3);
			$a4 = _remove_size_qualifiers_add_dollar ($4);

			$par = "\t$a1\t$a2, $a3, $a4\n";

		} elsif ( $par =~ /^\s*(\w+)\s+([^,]+)\s*,\s*([^,]+)\s*/gio ) {

			$a1 = $1;
			$a1 =~ s/\s+$//o;
			$a2 = _remove_size_qualifiers_add_dollar ($2);
			$a3 = _remove_size_qualifiers_add_dollar ($3);

			$par = "\t$a1\t$a2, $a3\n";

		} elsif ( $par =~ /^\s*(\w+)\s+([^,]+)\s*/gio ) {

			$a1 = $1;
			$a1 =~ s/\s+$//o;
			$a2 = _remove_size_qualifiers_add_dollar ($2);

			$par = "\t$a1\t$a2\n";
		}
	}

	$par =~ s/^\s*cbw\b/\tcbtw/io;
	$par =~ s/^\s*cwde\b/\tcwtl/io;
	$par =~ s/^\s*cwd\b/\tcwtd/io;
	$par =~ s/^\s*cdq\b/\tcltd/io;

	if ( $par =~ /^\s*(jmp|call)\s+/io ) {
		# (adding asterisk chars)
		$par =~ s/^\s*(jmp|call)\s+([dp]word|word|near|far|short)?\s*(\[[\w\*\+\-\s]+\])/\t$1\t*$3/io;
		$par =~ s/^\s*(jmp|call)\s+([dp]word|word|near|far|short)?\s*((0x)?\d+h?)/\t$1\t*$3/io;
		$par =~ s/^\s*(jmp|call)\s+([dp]word|word|near|far|short)?\s*([\w\*\+\-\s]+)/\t$1\t$3/io;
		$par =~ s/^\s*(jmp|call)\s+([^:]+)\s*:\s*([^:]+)/\tl$1\t$2, $3/io;
	}
	$par =~ s/^\s*retf\s+(.*)$/\tlret\t$1/io;

	# (changing memory references):
	$par = conv_intel_addr_to_att $par;

	# (changing "stN" to "st(N)")
	$par =~ s/\bst(\d)\b/\%st($1)/go;

	# (adding percent chars)
	foreach my $r (@regs_intel) {

		$par =~ s/\b$r\b/\%$r/gi;
	}
	foreach my $r (@regs_intel) {

		$par =~ s/\%\%$r\b/\%$r/gi;
	}

	# (REP**: adding the end of line char)
	$par =~ s/^\s*(rep[enz]{0,2})\s+/\t$1\n\t/io;

	return $par;
}

=head1 SUPPORT AND DOCUMENTATION

After installing, you can find documentation for this module with the perldoc command.

    perldoc Asm::X86

You can also look for information at:

    Search CPAN
        https://metacpan.org/dist/Asm-X86

    CPAN Request Tracker:
        https://rt.cpan.org/Public/Dist/Display.html?Name=Asm-X86

=head1 AUTHOR

Bogdan Drozdowski, C<< <bogdro at cpan.org> >>

=head1 COPYRIGHT

Copyright 2008-2025 Bogdan Drozdowski, all rights reserved.

=head1 LICENSE

This program is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.

=cut

1; # End of Asm::X86



( run in 1.665 second using v1.01-cache-2.11-cpan-e93a5daba3e )