Я работаю над простым калькулятором, который выполняет следующие операции: +, -, x (*), /, ^; Я уже проверил каждую операцию, но если я использую '^', она завершается сигналом SIGSEGV (Ошибка границы адреса, код состояния 139), но отлично работает с GDB. В строке, отмеченной '!!!!!!!' что-то происходит Если после этой команды я выполнил команду jmp, она не работает и возвращает код выхода 139. Если я прыгаю до '!!!!!!' Строка для выхода выполняется успешно. Таким образом, должна быть проблема с этим разыменованием, но только для '^' и только без GDB.
.code32
.section .data
newline: .ascii "\n"
lngth = . - newline
bplus: .ascii "(+"
lenbplus = . - bplus
b: .ascii ")"
lenb = . - b
ws: .ascii " "
isNeg: .long 0
op1: .long 0 # 1st operand
op2: .long 0 # 2nd operand
count: .long 0
remainder: .long 0
add: .ascii "+"
sub: .ascii "-"
mul: .ascii "x"
div: .ascii "/"
pot: .ascii "^"
operator: .ascii "" # operator
.section .text
.globl _start
_start:
addl $8, %esp # move ESP to first argument of stack
movl (%esp), %esi # move content of ESP to ESI
movl %esi, op1 # move ESI to global variable op1
addl $4, %esp # move ESP on stack forward
movl (%esp), %esi # move content of ESP to ESI
mov (%esi), %eax # !!!!!!!
#jmp _exit
movb %al, operator
addl $4, %esp # move ESP on stack forward
movl (%esp), %esi # move content of ESP to ESI
movl %esi, op2 # move ESI to global variable op2
pushl op1 # push first operand onto the stack
call convertOperand # call function to convert operand from .ascii to .long
movl %eax, op1 # move return value of function to global variable
pushl op2
call convertOperand # call function to convert second operand from .ascii to .long
movl %eax, op2 # move return value of function to global variable
pushl op1 # push operand 1 onto the stack
pushl op2 # push operand 2 onto the stack
movb operator, %al # move the input operator to AL (EAX)
## operand is + ##
movb add, %bl
cmpb %al,%bl
je _add
## operand is - ##
movb sub, %bl
cmpb %al,%bl
je _sub
## operand is * ##
movb mul, %bl
cmpb %al,%bl
je _mul
## operand is / ##
movb div, %bl
cmpb %al,%bl
je _div
## operand is ^ ##
movb pot, %bl
cmpb %al,%bl
je _pot
_add:
call addition
jmp _printResult
_sub:
call subtraction
jmp _printResult
_mul:
call multiplication
jmp _printResult
_div:
call division
jmp _printResult
_pot:
call potentation
jmp _printResult
.type addition, @function
addition:
pushl %ebp # save old base pointer
movl %esp, %ebp # make stack pointer the new base pointer
subl $4, %esp # reserve space for local variable
movl 12(%ebp), %ecx # move 2nd operand to register
movl 8(%ebp), %edx # move 1st operand to register
addl %ecx, %edx # perform addition
movl %edx, -4(%ebp) # save result to local variable
movl -4(%ebp), %eax # put lcal variable to EAX (function return value)
movl %ebp, %esp # restore old ESP (stack pointer)
popl %ebp # restore old EBP (base pointer)
ret # return from function (pops return address
# and moves it into EIP, so execution
# continues where we left before calling the function
.type subtraction, @function
subtraction:
pushl %ebp
movl %esp, %ebp
movl 12(%ebp), %eax
movl 8(%ebp), %edx
subl %edx, %eax
jc _negResult
_posResult:
movl %ebp, %esp
popl %ebp
ret
_negResult:
movl 12(%ebp), %edx
movl 8(%ebp), %eax
subl %edx, %eax
incl isNeg
jmp _posResult
.type multiplication, @function
multiplication:
pushl %ebp
movl %esp, %ebp
movl 12(%ebp), %eax
movl 8(%ebp), %edx
imul %edx
movl %ebp, %esp
popl %ebp
ret
.type division, @function
division:
pushl %ebp
movl %esp, %ebp
movl 12(%ebp),%eax
movl 8(%ebp), %ecx
cmpl $0, %ecx
je _exit_err
movl $0 , %edx
divl %ecx
movl %edx, remainder
movl %ebp, %esp
popl %ebp
ret
.type potentation, @function
potentation:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %edx
movl %edx, count
movl 12(%ebp), %edx
movl %edx, %eax
cmpl $0, count
je _ResultIsOne
_calcPot:
imull %edx, %eax
decl count
cmpl $1, count
jg _calcPot
jmp _returnResult
_ResultIsOne:
movl $1, %eax
_returnResult:
movl $0, count
movl %ebp, %esp
popl %ebp
ret
.type convertOperand, @function #converts a .ascii to .long
convertOperand:
pushl %ebp # save old base pointer
movl %esp, %ebp # make stack pointer to new EBP
subl $4, %esp # reserve space for local variable
movl 8(%ebp), %ecx # move argument (operand) to register
movl (%ecx), %edx # dereference the argument
movb %dl, %bl # move first byte to BL (EBX)
subl $0x30, %ebx # subtract the 0x30 from ascii value to get numeric value
movl %ebx, %eax # move result to EAX
incl %ecx # increment the reference by one byte
movl (%ecx), %edx # dereference the value
movb %dl, %bl # move first byte to BL
cmpb $0, %bl # compare if byte is a null termination
je _nullTerminated
imul $10, %eax # multiply EAX with 10
subl $0x30, %ebx # substract 0x30 from ascii value to get numeric value
addl %ebx, %eax # add numeric value to EAX
incl %ecx # increment the reference by one byte
### loop until no single digit is left of the number ###
_loop:
movl (%ecx), %edx # dereference value to EDX
movb %dl, %bl # move first byte to BL
cmpb $0, %bl # compare if null termination or not
je _nullTerminated
imul $10, %eax # multiplay EAX with 10
subl $0x30, %ebx # substract 0x30 from ascii value to get numeric value
addl %ebx, %eax # add numeric value to EAX
incl %ecx # increment reference by one byte
jmp _loop # back to loop head
_nullTerminated:
movl %ebp, %esp
popl %ebp
ret
### print the result of operation ###
_printResult:
### result already saved in EAX due to operator-function ###
movl %edx, %ebp
cmpl $1, isNeg
je _printMinus
### print sinle digits of result ###
_getSingleDigits:
movl $0, %ecx # sets 0 to ECX
movl $0, %edx # sets 0 to EDX
movl $10, %ebx # moves number 10 to EBX
divl %ebx # divide by EBX (10) to get a single digit
movl %edx, %ecx # save remainder in ECX
addl $0x30, %ecx # adds 0x30 to the digit to get right ascii-code
pushl %ecx # push the correct ascii code of the number onto the stack
incl count # increment count
cmpl $0, %eax # compare if dividend equals 0
jne _getSingleDigits #jump to of _loop id dividend is not 0
### pop the digits from the stack ###
_pop:
movl %esp, %ecx # get single digit from stack
decl count # derement count
movl $1, %edx # EDX message length
movl $1, %ebx # EBX = file descriptor (1 = stdout)
movl $4, %eax # syscall number (4 = write)
int $0x80 # call kernel by interrupt
popl %ecx # pop the stack so the esp is decremented
cmpl $0, count # if count is not 0 -> jump to _pop
jne _pop
### check if Remainder is 0 ###
cmp $0, remainder
jg _printRemainder
### print a newline ###
_new:
movl $lngth, %edx
movl $1, %ebx
movl $newline, %ecx
movl $4, %eax
int $0x80
### exit programm succesfully ###
_exit:
movl $0, %ebx
movl $1, %eax
int $0x80
### exit programm with error code 1 ###
_exit_err:
movl $1, %ebx
movl $1, %eax
int $0x80
### print a '-' ##
_printMinus:
movl %eax, %ebp #store result in EBP inorder to print Minus
movl $1, %edx
movl $1, %ebx
movl $sub, %ecx
movl $4, %eax
int $0x80
movl %ebp, %eax #back shift result to EAX
jmp _getSingleDigits
### print the whole Remainder ##
_printRemainder:
### print ' '(whitespace ###
movl $1, %edx
movl $1, %ebx
movl $ws, %ecx
movl $4, %eax
int $0x80
### print '(+' ###
movl $lenbplus, %edx
movl $1, %ebx
movl $bplus, %ecx
movl $4, %eax
int $0x80
### print actual Remainder ###
movl $remainder, %eax
movl (%eax), %eax
_getRemainderDigits:
movl $0, %ecx # sets 0 to ECX
movl $0, %edx # sets 0 to EDX
movl $10, %ebx # moves number 10 to EBX
divl %ebx # divide by EBX (10) to get a single digit
movl %edx, %ecx # save remainder in ECX
addl $0x30, %ecx # adds 0x30 to the digit to get right ascii-code
pushl %ecx # push the correct ascii code of the number onto the stack
incl count # increment count
cmpl $0, %eax # compare if dividend equals 0
jne _getRemainderDigits #jump to _getRemainderDigits if dividend is not 0
### pop the digits from the stack ###
_pop1:
movl %esp, %ecx # get single digit from stack
decl count # derement count
movl $1, %edx # EDX message length
movl $1, %ebx # EBX = file descriptor (1 = stdout)
movl $4, %eax # syscall number (4 = write)
int $0x80 # call kernel by interrupt
popl %ecx # pop the stack so the esp is decremented
cmpl $0, count # if count is not 0 -> jump to _pop
jne _pop1
### print ')' ###
movl $lenb, %edx
movl $1, %ebx
movl $b, %ecx
movl $4, %eax
int $0x80
jmp _new