x86架构汇编语言应该这么学——打印整数

【运行环境】Linux 64bit操作系统,x86_64指令集。

一、调用printf打印整数

在汇编语言中,打印字符串比打印整数要容易很多。打印整数比较复杂,这一篇我们采用调用linux中printf的方式完成整数的打印。

代码如下所示。

%macro write_string 2 
  mov   eax, 4
  mov   ebx, 1
  mov   ecx, %1
  mov   edx, %2
  int   80h
%endmacro
 
;%include        'function.asm'
default rel
extern printf,exit
section .rodata
format db "%#x",10,0
 
section .data
array  db  1,2,3,0,0,0
len db $-array
theSum db 0x0
msg1 db    'Hello, programmers!',0xA,0xD     
len1 equ $ - msg1    

 
section .text
global main
main:
	;mov esi,array
	;mov ecx,len
	write_string msg1, len1  
	
	mov ebx,0
	mov eax,6
	mov ecx,array
	L1:
	add ebx,[ecx]
	add ecx,1
	dec eax
	jnz L1
	
	add ebx,'0'
	mov [theSum],ebx
	write_string theSum,1		
	mov eax,0xA
	mov [theSum],eax
	write_string theSum,1

 	mov eax,00000009h
	mov edx,0h
	mov ecx,1h
	div ecx

	mov ebx,'0'
	add ebx,eax
	mov [theSum],ebx
        write_string theSum,1
        mov eax,0xA
        mov [theSum],eax
        write_string theSum,1

	sub rsp,8
	mov esi,0x12345678
	lea rdi,[rel format]
	xor eax,eax
	call printf
	
	mov eax,1
   	xor ebx,ebx
   	int 0x80

上述代码为了完成编译,需要修改相关的makefile文件,makefile文件如下所示。

ass:ass.o
    gcc -no-pie ass.o -o ass
ass.o:ass.asm
    nasm -f elf64 ass.asm
clean:
    rm ass.o ass

上述makefile文件跟前几次的makefile有区别。主要体现在用gcc还是ld。

另外在代码中global后面gcc的时候使用main,而不是_start。采用上述方法即可打印出来整数。

二、自己编写整数输出代码

mov eax,56987
mov eax,56987
mov esi,0
mov ecx,5
L2:
mov edx,0
mov ebx,10
div ebx
push qword rdx
loop L2

mov ecx,5
L3:
pop rax
mov ebx,'0'
add rbx,rax
mov [theSum],ebx
mov eax,4
mov ebx,1
push rcx
mov ecx,theSum
mov edx,1
int 0x80
pop rcx
loop L3

上述代码的含义采用栈的思想将div之后的余数一个一个添加到栈中,然后对商进一步除以10,然后再将余数放入栈中,以此下去。

打印的时候,将栈中元素一个一个pop出来,然后打印,这样就可以实现数据从高位到地位的打印。

完成程序代码如下:

%macro write_string 2 
  mov   eax, 4
  mov   ebx, 1
  mov   ecx, %1
  mov   edx, %2
  int   80h
%endmacro
 
 
section .data
array  db  1,2,3,0,0,0
len db $-array
theSum db 0x0
msg1 db    'Hello, programmers!',0xA,0xD     
len1 equ $ - msg1    

 
section .text
global _start
_start:
	write_string msg1, len1  
	
	mov eax,56987
	mov esi,0
	mov ecx,5
	L2:
	mov edx,0
	mov ebx,10
	div ebx
	push qword rdx
	loop L2
	
	mov ecx,5
        L3:
	pop rax
	mov ebx,'0'
        add rbx,rax
	mov [theSum],ebx
	mov eax,4
	mov ebx,1
	push rcx
	mov ecx,theSum
	mov edx,1
	int 0x80
	pop rcx
	loop L3

	mov eax,0xA
        mov [theSum],eax
        write_string theSum,1	

	mov eax,1
   	xor ebx,ebx
   	int 0x80

大家会发现上面例子还是有问题的,就是整数长度是手动写到里面的。我们应该自动获取整数的位数。

三、修改后的打印程序

%macro write_string 2 
  mov   eax, 4
  mov   ebx, 1
  mov   ecx, %1
  mov   edx, %2
  int   80h
%endmacro
 
 
section .data
array  db  1,2,3,0,0,0
len db $-array
theSum db 0x0
msg1 db    'Hello, programmers!',0xA
len1 equ $ - msg1    

 
section .text
global _start
_start:	
	mov eax,5
	mov edx,0
	mov ecx,10
	div ecx
	mov ebx,0
	add ebx,'0'
	add ebx,eax
	mov [theSum],ebx
	mov eax,4
        mov ebx,1
	mov ecx,theSum
        mov edx,1
        int 0x80

	mov eax,569879089
	mov esi,0
	mov ecx,0
	L2:
	mov edx,0
	mov ebx,10
	div ebx
	inc ecx
	;mov ebx,0
	;add ebx,'0'
        ;add ebx,edx
        ;mov [theSum],ebx
	;push rax
        ;mov eax,4
        ;mov ebx,1
        ;push rcx
	;push rdx
        ;mov ecx,theSum
        ;mov edx,1
        ;int 0x80
	;pop rdx
	;pop rcx
	;pop rax

	push qword rdx
	cmp eax,0
	jne L2
	
	push rcx
	mov eax,0xA
        mov [theSum],eax
        write_string theSum,1
	pop rcx

	;mov ecx,7
        L3:
	pop rax
	mov ebx,0
	add ebx,'0'
        add ebx,eax
	mov [theSum],ebx
	mov eax,4
	mov ebx,1
	push rcx
	mov ecx,theSum
	mov edx,1
	int 0x80
	pop rcx
	loop L3

	mov eax,0xA
        mov [theSum],eax
        write_string theSum,1	

	mov eax,1
   	xor ebx,ebx
   	int 0x80

push过程中通过rcx进行计数,中间调用write_string会导致rcx的数据丢失,所以需要先push,然后再pop出来。

pop过程中的时候,可以借助ecx中记录的数据的位数进行打印。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

历史哭泣

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值