gpt4 book ai didi

linux - 如何在 GAS 汇编中使用 "repne scasb"?

转载 作者:太空狗 更新时间:2023-10-29 12:38:53 26 4
gpt4 key购买 nike

所以我写了一个基于NASM的程序,接收用户输入(准确的说是两个数),然后实现两个数的加减,然后打印回来。该程序在 NASM 中运行良好,但我在使用 GAS 时遇到了问题。由于段错误,使用 repne scasb 指令计算字符串长度的子例程让我很头疼。

我已经检查了代码中是否存在段错误,我已将错误定位在 repne scasb 行。

我基本上做的是将我制作的 NASM 代码翻译成相应的 GAS 代码。但是,正如我之前所说,它给了我一个段错误。在我从用户那里得到第一个号码后,更具体地说。

.section .data
msg: .ascii "Insert a number: "
msgLen = .-msg

msg2: .ascii "Insert another number: "
msg2Len = .-msg2

errorMsg: .ascii "Error: invalid character!\n"
errorMsgLen = .-errorMsg

displaySuma: .ascii "The result of the addition is: "
displaySumaLen = .-displaySuma

displayResta: .ascii "The result of the difference is: "
displayRestaLen = .-displayResta

enterChar: .ascii "\n"

terminator: .byte 0

.section .bss
.lcomm num1, 8

.lcomm num2, 8

.lcomm buffer, 10
.lcomm buffer2, 10

.section .text
.global _start

_start:
call _clear #clear registers. Probably an useless routine
call _msg1 #Display msg1
call _num1 #Read num1

movl num1, %edi

call _lenString #ECX now has num1 length

lea (num1), %esi
call _stringToInt #EAX now has num1 in integer

movl %eax, %r15d #R15D now has the integer

call _msg2 #Display msg2
call _num2 #Read num2

xor %edi, %edi #Clear EDI
movl num2, %edi #Moving num2 to EDI register to call _lenstring
xor %ecx, %ecx #Clear ECX

call _lenString #ECX has num2 length

xor %esi, %esi #clear ESI
lea (num2), %esi
call _stringToInt #EAX now has integer value of num2

mov %eax,%r14d ###R14D has num2 now

#Addition
#r8d = num1 + num2
mov %r15d, %r8d
add %r14d, %r8d #R8D has num1 + num2

#Difference
#If num1 > num2 =======> r9d = num1 - num2
#If num1 < num2 =======> r9d = num2 - num1
cmp %r14d, %r15d
jg .greater

mov %r14d, %r9d
sub %r15d, %r9d #R9D has num1 - num2
jmp .next

.greater:
mov %r15d, %r9d
sub %r14d, %r9d #R9D has num2 - num1
jmp .next

.next:
mov %r8d, %eax #Sum is now at EAX to convert it to ascii characters

lea (buffer), %esi
call _intToString
#EAX ascii of the sum

mov %eax, %r10d #Using R10D to store the new string

mov %r9d, %eax #Difference result is now at EAX

lea (buffer2), %esi
call _intToString
#EAX has the pointer to the difference result.

mov %eax, %r11d #Storing string in R10D

xor %edi, %edi
xor %r15d, %r15d
xor %r14d, %r14d

mov %r10d, %edi
call _lenString #ECX length of sum string
mov %ecx, %r15d #R15D now has that value

call _suma #This prints the sum result

xor %edi, %edi #Clear EDI
mov %r11d, %edi
call _lenString #ECX has length of dif. string
mov %ecx, %r14d #R14D has that value

call _resta #Print dif. result

movl $1, %eax #End of the program
movl $0, %ebx
int $0x80

_stringToInt:
xor %ebx, %ebx

.next_digit:
movzxb (%esi), %eax

cmp $0x30, %eax #These 4 lines check for invalid characters
jb _errorMsg
cmp $0x39, %eax
ja _errorMsg

inc %esi
sub $0x30, %eax ###Sub 48 (converts to integer)
imul $10, %ebx
add %eax, %ebx #ebx = ebx*10 + eax
loop .next_digit #loop [ECX] times
mov %ebx, %eax
ret

_intToString:
add $10, %esi
mov (terminator),%esi

mov $10, %ebx

.next_digit1:
xor %edx, %edx
div %ebx
add $0x30, %edx ##
dec %esi
mov %dl, (%esi)
test %eax, %eax
jnz .next_digit1
mov %esi, %eax
ret


#######################################################################################################


_msg1:
movl $4, %eax #msg1 routine
movl $1, %ebx
movl $msg, %ecx
movl $msgLen, %edx
int $0x80
ret

_num1:
movl $3, %eax #Reads first number
movl $0, %ebx
movl $num1, %ecx
movl $8, %edx
int $0x80
ret

_msg2:
movl $4, %eax #msg2 display
movl $1, %ebx
movl $msg2, %ecx
movl $msg2Len, %edx
int $0x80
ret

_num2:
movl $3, %eax #Reads the next number
movl $0, %ebx
movl $num2, %ecx
movl $8, %edx
int $0x80
ret

_salir:
movl $1, %eax #Exit
movl $0, %ebx
int $0x80

_errorMsg:
movl $4, %eax #Error msg
movl $1, %ebx
movl $errorMsg, %ecx
movl $errorMsgLen, %edx
int $0x80

jmp _salir

_lenString:
xor %ecx, %ecx
not %ecx
xor %al, %al
mov $0xA, %al
cld
repne scasb #Segmentation fault is caused by this line
not %ecx
dec %ecx
ret

_suma:
movl $4, %eax
movl $1, %ebx
movl $displaySuma, %ecx
movl $displayRestaLen, %edx
int $0x80

movl $4, %eax
movl $1, %ebx
mov %r10d, %ecx
mov %r15d, %edx
int $0x80

movl $4, %eax
movl $1, %ebx
movl $enterChar, %ecx
movl $1, %edx
int $0x80
ret

_resta:
movl $4, %eax
movl $1, %ebx
movl $displayResta, %ecx
movl $displayRestaLen, %edx
int $0x80

movl $4, %eax
movl $1, %ebx
mov %r11d, %ecx
mov %r14d, %edx
int $0x80

movl $4, %eax
movl $1, %ebx
movl $enterChar, %ecx
movl $1, %edx
int $0x80
ret

_clear:
xor %eax, %eax
xor %ebx, %ebx
xor %ecx, %ecx
xor %edx, %edx
xor %esi, %esi
xor %edi, %edi
xor %r8d, %r8d
xor %r9d, %r9d
xor %r10d, %r10d
xor %r11d, %r11d
xor %r14d, %r14d
xor %r15d, %r15d
ret

我正在使用这个 makefile 来创建 .o 和 .exe 文件(由我的教授提供):

#*************************************************
# Executable name : hola
# Version : 2.0
# Created date : February 12, 2019
# Authors :
# Eduardo A. Canessa M
# Description : simple makefile for GAS
# Important Notice: To be used for GAS only
#*************************************************
#change the name "ejemplo" for the name of your source file
name=addSubInteger
#program to use as the assembler (you could use NASM or YASM for this makefile)
ASM=as
#flags for the assember
#ASM_F= #*** place here flags if needed ***

#program to use as linker
LINKER=ld

#link executable
$(name): $(name).o
$(LINKER) -o $(name) $(name).o

#assemble source code
$(name).o: $(name).s
$(ASM) $(ASM_F) -o $(name).o $(name).s

程序读取第一个用户输入后出现段错误。

这是 the NASM code of my program (希望您不介意其中的西类牙注释,但它与 GAS 上编写的程序本质上是相同的程序)。

我知道我已经编写了一些更高级的意大利面条代码,但这是我得出的解决方案。

最佳答案

movl num1, %edi
call _lenString #ECX now has num1 length
lea (num1), %esi
call _stringToInt #EAX now has num1 in integer

第一条指令不加载 %edi 中的地址。您可以像接下来调用 _stringToInt 一样使用 lea。或者,如果您关心更短的编码,请编写 mov $num1, %edi

lea  (num1), %edi
call _lenString #ECX now has num1 length

第二个数字存在同样的问题:

movl num2, %edi      SAME PROBLEM
xor %ecx, %ecx
call _lenString

_intToString 子例程有 2 个问题!

  1. 您通过在其中写入一个随机值来销毁 %esi 中的地址。
  2. 您(尝试)在内存中写入超出通过 .lcomm buffer, 10 保留的缓冲区。这将破坏 buffer2 中的第一个字节。

由于转换 32 位整数可以产生(最多)10 个字符,因此您需要将缓冲区扩大到 11 个字节,以便可以安全地存储字节大小的终止符。

.lcomm buffer, 11
.lcomm buffer2, 11

然后使用这段代码:

_intToString:
mov $10, %ebx
add %ebx, %esi #Instead of 'ADD $10, %ESI' now that EBX==10
mov (terminator), %dl
mov %dl, (%esi)
.next_digit1:
xor %edx, %edx
div %ebx
add $0x30, %edx ##
dec %esi
mov %dl, (%esi)
test %eax, %eax
jnz .next_digit1
mov %esi, %eax
ret

原始 NASM 来源使用

STRING_TERMINATOR   equ 10

equ 在运行时不消耗内存。您的 terminator: .byte 0 确实使用了运行时内存! equ 的一个好的翻译是

.set terminator,0

现在你可以写了

_intToString:
mov $10, %ebx
add %ebx, %esi #Instead of 'ADD $10, %ESI' now that EBX==10
movb $terminator, (%esi)

关于linux - 如何在 GAS 汇编中使用 "repne scasb"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57774233/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com