【运行环境】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中记录的数据的位数进行打印。