有人可以解释这个汇编语言程序来查找字符串的反转吗? read() 后使用的 RAX 是否未初始化?
Can some one explain this assembly language program to find reverse of a string? Is RAX used uninitialized after read()?
%macro read 1
Mov ax,3
mov bx,0
mov rcx,%1
mov dx,20
Int 80h
%endmacro
%macro print 2
Mov ax,4
mov bx,1
mov rcx,%1
mov dx,%2
Int 80h
%endmacro
section .Data
len : db 0
section .bss
Str1 resb 20
Str2 resb 20
section .text
global _start:
read str1 ;using macro
mov [len],al
lea rsi,[str1]
lea rdi,[str2]
mov rcx,rax
dec rcx
Add rsi,rcx
loop1:
Dec rsi
Mov al,[rsi]
Mov [rdi],al
Inc rdi
loop loop1
print str2,[len]
Exit:
mov ax,1
Mov bx,0
int 80h
通过上面的汇编代码,我可以找到一个字符串的反转。
但是这里在读取字符串寄存器后 Al 被移动到 len 但是 Register Al 没有被初始化什么数据由 rcx,rax?
持有
有人能简单解释一下上面的代码吗?
很明显 read
return 是 RAX 中的一个长度。这对于函数来说是完全正常的,对于宏也是有意义的。
在这种情况下,是的,它只是针对 read()
的 32 位 int 0x80
ABI 的(错误)包装器,正如手册页所解释的 returns 长度。 Linux 系统调用在 RAX 中执行 return。它还奇怪地将最大长度硬编码为 20。
(这是错误的,因为它只有在 EAX、EBX 和 EDX 已经为零时才有效。它只在调用 32 位 ABI 之前写入这些寄存器的低 16 位。用地址写入完整的 RCX 是无用的; int 0x80
只使用低 32 位。)
AL
是RAX的低字节,这段代码只保存长度的低字节用于打印。 IDK 为什么他们将它保存在内存中而不是像普通人一样保存在另一个寄存器中。特别是当他们将整个 64 位长度复制到 RCX 而不是正常的 mov ecx, eax
以将 32 位值零扩展到 RCX 时。
还要注意后面的 mov ax,1
(32 位 __NR_exit
)是有风险的,不是一个好主意;它可能会在 RAX 的高字节中留下垃圾,导致 -ENOSYS
而不是 _exit(0)
、
用小的buffer size读取会报错(或者return -EFAULT
才可以return超过4096,所以只替换RAX的低16位是安全的案例.
除非read
returns 是负错误代码;那么当最后一个 int 0x80
returns -ENOSYS
而不是退出时,这个程序将崩溃而不是退出。
尝试 运行 它与 ./a.out <&-
关闭标准输入,导致 -EBADF
从标准输入读取, 然后崩溃。
此外,这是 64 位代码,因此使用 32 位 int 0x80
Linux 系统调用 ABI 不是一个好主意。一些 Linux 系统(包括 WSL)没有 CONFIG_IA32_EMULATION
并且会像 int 0x81
或任何其他软件中断一样出现故障。
%macro read 1
Mov ax,3
mov bx,0
mov rcx,%1
mov dx,20
Int 80h
%endmacro
%macro print 2
Mov ax,4
mov bx,1
mov rcx,%1
mov dx,%2
Int 80h
%endmacro
section .Data
len : db 0
section .bss
Str1 resb 20
Str2 resb 20
section .text
global _start:
read str1 ;using macro
mov [len],al
lea rsi,[str1]
lea rdi,[str2]
mov rcx,rax
dec rcx
Add rsi,rcx
loop1:
Dec rsi
Mov al,[rsi]
Mov [rdi],al
Inc rdi
loop loop1
print str2,[len]
Exit:
mov ax,1
Mov bx,0
int 80h
通过上面的汇编代码,我可以找到一个字符串的反转。 但是这里在读取字符串寄存器后 Al 被移动到 len 但是 Register Al 没有被初始化什么数据由 rcx,rax?
持有有人能简单解释一下上面的代码吗?
很明显 read
return 是 RAX 中的一个长度。这对于函数来说是完全正常的,对于宏也是有意义的。
在这种情况下,是的,它只是针对 read()
的 32 位 int 0x80
ABI 的(错误)包装器,正如手册页所解释的 returns 长度。 Linux 系统调用在 RAX 中执行 return。它还奇怪地将最大长度硬编码为 20。
(这是错误的,因为它只有在 EAX、EBX 和 EDX 已经为零时才有效。它只在调用 32 位 ABI 之前写入这些寄存器的低 16 位。用地址写入完整的 RCX 是无用的; int 0x80
只使用低 32 位。
AL
是RAX的低字节,这段代码只保存长度的低字节用于打印。 IDK 为什么他们将它保存在内存中而不是像普通人一样保存在另一个寄存器中。特别是当他们将整个 64 位长度复制到 RCX 而不是正常的 mov ecx, eax
以将 32 位值零扩展到 RCX 时。
还要注意后面的 mov ax,1
(32 位 __NR_exit
)是有风险的,不是一个好主意;它可能会在 RAX 的高字节中留下垃圾,导致 -ENOSYS
而不是 _exit(0)
、
用小的buffer size读取会报错(或者return -EFAULT
才可以return超过4096,所以只替换RAX的低16位是安全的案例.
除非read
returns 是负错误代码;那么当最后一个 int 0x80
returns -ENOSYS
而不是退出时,这个程序将崩溃而不是退出。
尝试 运行 它与 ./a.out <&-
关闭标准输入,导致 -EBADF
从标准输入读取, 然后崩溃。
此外,这是 64 位代码,因此使用 32 位 int 0x80
Linux 系统调用 ABI 不是一个好主意。一些 Linux 系统(包括 WSL)没有 CONFIG_IA32_EMULATION
并且会像 int 0x81
或任何其他软件中断一样出现故障。