【发布时间】:2018-01-12 13:29:46
【问题描述】:
我是@coding 初学者,这是我关于堆栈溢出的第一个问题,尽管您的一些很棒的答案已经给我带来了一些进展..
在尝试此assembler-tutorial 时,我在运行程序后遇到了分段错误。我试图注释掉每一行,并注意到当我在第 30 行“调用 printString”时程序崩溃了。
当我尝试使用 gdb 进行调试时(哎呀,我真的不知道我在那里做什么..)我在 lenString 调用中的函数“iterateChar”中出现错误。 (在我的函数文件中 - baseOperators.asm - 第 50 行)
我怀疑,我不知何故弄乱了 eax 寄存器中的信息,但我不知道为什么,发生了什么以及如何解决这个问题。我的代码看起来与 asmtutor.com 上教程 16 中的代码非常相似——无论出于何种原因,我都编写了该代码,并且成功了。请帮忙。
(我正在使用“$ nasm -f elf assemblerTutorial.asm”+“$ ld -m elf_i386 assemblerTutorial.o -o assemblerTutorial)进行编译
;------------------------------------------
; my Assembler learning Environment
;%include "calculate.asm"
%include "baseOperators.asm"
%include "print.asm"
SECTION .text
global _start
_start:
pop ecx
mov edx, 0
argumentsLoop:
cmp ecx, 0h
jz argumentsEnd
pop eax
call atoi
add edx, eax
dec ecx
jmp argumentsLoop
argumentsEnd:
mov eax, edx
call printString
call breakLine
call quit
我的 baseOperators.asm:
;------------------------------------------
; int atoi(Integer number)
; Ascii to integer function (atoi)
atoi:
push ebx ; preserve ebx on the stack to be restored after function runs
push ecx ; preserve ecx on the stack to be restored after function runs
push edx ; preserve edx on the stack to be restored after function runs
push esi ; preserve esi on the stack to be restored after function runs
mov esi, eax ; move pointer in eax into esi (our number to convert)
mov eax, 0 ; initialise eax with decimal value 0
mov ecx, 0 ; initialise ecx with decimal value 0
.conversionLoop:
xor ebx, ebx ; resets both lower and uppper bytes of ebx to be 0
mov bl, [esi+ecx] ; move a single byte into ebx register's lower half
cmp bl, 48 ; compare ebx register's lower half value against ascii value 48 (char value 0)
jl .conversionEnd ; jump if less than to label finished
cmp bl, 57 ; compare ebx register's lower half value against ascii value 57 (char value 9)
jg .conversionEnd ; jump if greater than to label finished
cmp bl, 10 ; compare ebx register's lower half value against ascii value 10 (linefeed character)
je .conversionEnd ; jump if equal to label finished
cmp bl, 0 ; compare ebx register's lower half value against decimal value 0 (end of string)
jz .conversionEnd ; jump if zero to label finished
sub bl, 48 ; convert ebx register's lower half to decimal representation of ascii value
add eax, ebx ; add ebx to our interger value in eax
mov ebx, 10 ; move decimal value 10 into ebx
mul ebx ; multiply eax by ebx to get place value
inc ecx ; increment ecx (our counter register)
jmp .conversionLoop ; continue multiply loop
.conversionEnd:
mov ebx, 10 ; move decimal value 10 into ebx
div ebx ; divide eax by value in ebx (in this case 10)
pop esi ; restore esi from the value we pushed onto the stack at the start
pop edx ; restore edx from the value we pushed onto the stack at the start
pop ecx ; restore ecx from the value we pushed onto the stack at the start
pop ebx ; restore ebx from the value we pushed onto the stack at the start
ret
;------------------------------------------
; int lenString(String message)
; String length calculation function
lenString:
push ebx
mov ebx, eax
iterateChar:
cmp byte [eax], 0
jz finalize
inc eax
jmp iterateChar
finalize:
sub eax, ebx
pop ebx
ret
;------------------------------------------
; void breakLine()
; Break a line - linefeed
breakLine:
push eax ; push eax on the stack
mov eax, 0x0a ; move linefeed into eax - 0x0a = 0Ah
push eax ; linefeed on stack to get adress
mov eax, esp ; move adress of current pointer into eax
call printString
pop eax
pop eax
ret ; return
;------------------------------------------
; void exit()
; Exit program and restore resources
quit:
mov eax, 1 ; invoke SYS_EXIT (kernel opcode 1)
mov ebx, 0 ; return 0 status on exit - 'No Errors'
int 0x80 ; 0x80=80h
ret
以及 print.asm 中的打印函数:
;------------------------------------------
; void printInteger (Integer number)
; Integer printing function (itoa)
printInteger:
push eax ; preserve eax on the stack to be restored after function runs
push ecx ; preserve ecx on the stack to be restored after function runs
push edx ; preserve edx on the stack to be restored after function runs
push esi ; preserve esi on the stack to be restored after function runs
mov ecx, 0 ; counter of how many bytes we need to print in the end
divideLoop:
inc ecx ; count each byte to print - number of characters
mov edx, 0 ; empty edx
mov esi, 10 ; mov 10 into esi
idiv esi ; divide eax by esi
add edx, 48 ; convert edx to it's ascii representation - edx holds the remainder after a divide instruction
push edx ; push edx (string representation of an intger) onto the stack
cmp eax, 0 ; can the integer be divided anymore?
jnz divideLoop ; jump if not zero to the label divideLoop
printLoop:
dec ecx ; count down each byte that we put on the stack
mov eax, esp ; mov the stack pointer into eax for printing
call printString ; call our string print function
pop eax ; remove last character from the stack to move esp forward
cmp ecx, 0 ; have we printed all bytes we pushed onto the stack?
jnz printLoop ; jump is not zero to the label printLoop
pop esi ; restore esi from the value we pushed onto the stack at the start
pop edx ; restore edx from the value we pushed onto the stack at the start
pop ecx ; restore ecx from the value we pushed onto the stack at the start
pop eax ; restore eax from the value we pushed onto the stack at the start
ret
;------------------------------------------
; void printString(String message)
; String printing function
printString:
push edx
push ecx
push ebx
push eax
call lenString
mov edx, eax ; nbytes - number of bytes to write (len), one for each letter plus the zero terminating byte
pop eax
mov ecx, eax ; buffer - move the memory address of our message string into ecx
mov ebx, 1 ; fd - filedescriptor, write to the STDOUT file
mov eax, 4 ; invoke SYS_WRITE (with fd, buf, nbytes / kernel opcode 4)
int 0x80 ; prozessor interupt 0x80 jump to system call, stack clean, 0x80=80h
pop ebx
pop ecx
pop edx
ret
感谢任何提示,
亲切的问候
【问题讨论】:
-
idiv是有符号除法:您应该准备使用cdq将eax符号扩展为edx:eax,而不是通过将edx归零来进行零扩展。 (在div之前这样做)。 -
一些gdb小技巧,见底部x86 tag wiki。
标签: assembly