汇编语言修改输入字符串错误
assembly language modify input string error
我正在尝试在 Linux 上编写一个 32 位 x86 NASM 程序,它从文本文件中获取一个字符串,编码将字符串中的所有字符向上移动 1 和 printf
它输出到控制台。除了用于进行移位的循环 .rot132
和 printf
之外,几乎所有的东西都能正常工作。每当调用 .rot132
时,它都会给出一个 segmentation_fault(核心转储)。我想当我执行 mov ecx, [eax]
时它会导致某种错误。我怎样才能克服这部分?
;;sddddddddddddddddgsd
[SECTION .data] ; Section containing initialized data
WriteCode db "w",0
OpenCode db "r",0
Filename db "text.txt",0
fileFmt: dd "%c\n",10,0
fileFmt1: dd "%s",10,0
[SECTION .bss] ; Section containing uninitialized data
TextLenght EQU 72 ; Define length of a line of text data
Text resb TextLenght ; Reserve space for disk-based help text line
BUFSIZE EQU 64 ; Define length of text line buffer
Buff resb BUFSIZE+5 ; Reserve space for a line of text
[SECTION .text] ; Section containing code
;; These externals are all from the glibc standard C library:
extern fopen
extern fclose
extern fgets
extern fprintf
extern printf
extern sscanf
extern time
global main ; Required so linker can find entry point
main:
diskhelp:
mov ebx, Filename ; push file name to ebx
push OpenCode ; Push pointer to open-for-read code “r“
push ebx ; Pointer to name of help file is passed in ebx
call fopen ; Attempt to open the file for reading
add esp,8 ; Clean up the stack
cmp eax,0 ; fopen returns null if attempted open failed
jne .disk ; Read help info from disk file...
ret
.disk: mov ebx,eax ; Save handle of opened file in ebx
.rdln: push ebx ; Push file handle on the stack
push dword TextLenght ; Limit line length of text read
push Text ; Push address of text line buffer
call fgets ; Read a line of text from the file
add esp,12 ; Clean up the stack
;cmp eax,0 ; A returned null indicates error or EOF
;jle .rot13 ; If we get 0 in eax, close up & return
;push Text ; Push address of help line on the stack
;call printf ; Call printf to display help line
;add esp,4 ; Clean up the stack
.rot131: ; initial shift and test, this work
mov edx, 0 ; our counter
mov eax, Text ; move string into eax
mov ecx, [eax]; move first char in string into ecx
add ecx, 1 ; shift the char up by 1
push ecx ; push to print
push fileFmt
call printf
add esp, 8 ; clear the stack
inc edx ; increase the counter
.rot132:
inc eax ; shift address of eax into next char
mov ecx, [eax] ; move the char into ecx, replace old char; error ??
add ecx, 1 ; shift the char by 1
push ecx ; print
push fileFmt
call printf
add esp, 8 ; clear the stack
inc edx ;incrase counter
cmp edx,4 ; stop loop after edx = 4
jne .rot132
push ebx ; Push the handle of the file to be closed
call fclose ; Closes the file whose handle is on the stack
add esp,4 ; Clean up the stack
ret ; Go home
gdb 调试:反汇编 .rot132:
0x08048559 <+0>: inc %eax
0x0804855a <+1>: mov (%eax),%ecx
0x0804855c <+3>: add [=11=]x1,%ecx
0x0804855f <+6>: push %ecx
0x08048560 <+7>: push [=11=]x804a035
0x08048565 <+12>: call 0x80483b0 <printf@plt>
0x0804856a <+17>: add [=11=]x8,%esp
0x0804856d <+20>: inc %edx
0x0804856e <+21>: cmp [=11=]x4,%edx
0x08048571 <+24>: jne 0x8048559 <rot132>
0x08048573 <+26>: push %ebx
0x08048574 <+27>: call 0x80483d0 <fclose@plt>
0x08048579 <+32>: add [=11=]x4,%esp
0x0804857c <+35>: ret
0x0804857d <+36>: xchg %ax,%ax
0x0804857f <+38>: nop
fileFmt
需要 db
,而不是 dd
。您正在定义双字字符。
请注意,此代码不如编译器生成的代码好。只需为配置文件顶部明显 CPU 瓶颈的关键循环使用汇编语言,并且您已经在使用一个很好的算法。
一个例子是矩阵乘法。它是 embarassingly parallel,因此强制编译器使用最有效的方法来执行操作通常是有益的,例如使用矢量扩展,如 SSE。
编译器这么好,你通常写 "assembly language" 内在函数,比如 SSE 或 AVX 内在函数,这让编译器不用担心数据流和寄存器分配,让你专注于指令本身.
另请注意 Michael Petch 的好评:允许调用破坏 eax
、ecx
、edx
。您可以相信他们会保留 ebx
、esi
、edi
、ebp
、esp
。这意味着您需要停止对变量使用 ecx
和 edx
并使用保留的内容,例如 ebx
、edi
、esi
、ebp
.
我正在尝试在 Linux 上编写一个 32 位 x86 NASM 程序,它从文本文件中获取一个字符串,编码将字符串中的所有字符向上移动 1 和 printf
它输出到控制台。除了用于进行移位的循环 .rot132
和 printf
之外,几乎所有的东西都能正常工作。每当调用 .rot132
时,它都会给出一个 segmentation_fault(核心转储)。我想当我执行 mov ecx, [eax]
时它会导致某种错误。我怎样才能克服这部分?
;;sddddddddddddddddgsd
[SECTION .data] ; Section containing initialized data
WriteCode db "w",0
OpenCode db "r",0
Filename db "text.txt",0
fileFmt: dd "%c\n",10,0
fileFmt1: dd "%s",10,0
[SECTION .bss] ; Section containing uninitialized data
TextLenght EQU 72 ; Define length of a line of text data
Text resb TextLenght ; Reserve space for disk-based help text line
BUFSIZE EQU 64 ; Define length of text line buffer
Buff resb BUFSIZE+5 ; Reserve space for a line of text
[SECTION .text] ; Section containing code
;; These externals are all from the glibc standard C library:
extern fopen
extern fclose
extern fgets
extern fprintf
extern printf
extern sscanf
extern time
global main ; Required so linker can find entry point
main:
diskhelp:
mov ebx, Filename ; push file name to ebx
push OpenCode ; Push pointer to open-for-read code “r“
push ebx ; Pointer to name of help file is passed in ebx
call fopen ; Attempt to open the file for reading
add esp,8 ; Clean up the stack
cmp eax,0 ; fopen returns null if attempted open failed
jne .disk ; Read help info from disk file...
ret
.disk: mov ebx,eax ; Save handle of opened file in ebx
.rdln: push ebx ; Push file handle on the stack
push dword TextLenght ; Limit line length of text read
push Text ; Push address of text line buffer
call fgets ; Read a line of text from the file
add esp,12 ; Clean up the stack
;cmp eax,0 ; A returned null indicates error or EOF
;jle .rot13 ; If we get 0 in eax, close up & return
;push Text ; Push address of help line on the stack
;call printf ; Call printf to display help line
;add esp,4 ; Clean up the stack
.rot131: ; initial shift and test, this work
mov edx, 0 ; our counter
mov eax, Text ; move string into eax
mov ecx, [eax]; move first char in string into ecx
add ecx, 1 ; shift the char up by 1
push ecx ; push to print
push fileFmt
call printf
add esp, 8 ; clear the stack
inc edx ; increase the counter
.rot132:
inc eax ; shift address of eax into next char
mov ecx, [eax] ; move the char into ecx, replace old char; error ??
add ecx, 1 ; shift the char by 1
push ecx ; print
push fileFmt
call printf
add esp, 8 ; clear the stack
inc edx ;incrase counter
cmp edx,4 ; stop loop after edx = 4
jne .rot132
push ebx ; Push the handle of the file to be closed
call fclose ; Closes the file whose handle is on the stack
add esp,4 ; Clean up the stack
ret ; Go home
gdb 调试:反汇编 .rot132:
0x08048559 <+0>: inc %eax
0x0804855a <+1>: mov (%eax),%ecx
0x0804855c <+3>: add [=11=]x1,%ecx
0x0804855f <+6>: push %ecx
0x08048560 <+7>: push [=11=]x804a035
0x08048565 <+12>: call 0x80483b0 <printf@plt>
0x0804856a <+17>: add [=11=]x8,%esp
0x0804856d <+20>: inc %edx
0x0804856e <+21>: cmp [=11=]x4,%edx
0x08048571 <+24>: jne 0x8048559 <rot132>
0x08048573 <+26>: push %ebx
0x08048574 <+27>: call 0x80483d0 <fclose@plt>
0x08048579 <+32>: add [=11=]x4,%esp
0x0804857c <+35>: ret
0x0804857d <+36>: xchg %ax,%ax
0x0804857f <+38>: nop
fileFmt
需要 db
,而不是 dd
。您正在定义双字字符。
请注意,此代码不如编译器生成的代码好。只需为配置文件顶部明显 CPU 瓶颈的关键循环使用汇编语言,并且您已经在使用一个很好的算法。
一个例子是矩阵乘法。它是 embarassingly parallel,因此强制编译器使用最有效的方法来执行操作通常是有益的,例如使用矢量扩展,如 SSE。
编译器这么好,你通常写 "assembly language" 内在函数,比如 SSE 或 AVX 内在函数,这让编译器不用担心数据流和寄存器分配,让你专注于指令本身.
另请注意 Michael Petch 的好评:允许调用破坏 eax
、ecx
、edx
。您可以相信他们会保留 ebx
、esi
、edi
、ebp
、esp
。这意味着您需要停止对变量使用 ecx
和 edx
并使用保留的内容,例如 ebx
、edi
、esi
、ebp
.