%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
使用上面的asm代码,我可以找到字符串的反序。但是在这里,在读取了字符串寄存器之后,Al移到了[[len,但是Register Al尚未初始化,并且rcx,rax保留了哪些数据?
有人可以简单地解释上面的代码吗?read
返回RAX的长度。对于函数来说,这是完全正常的,对于宏也是有意义的。在这种情况下,是的,它只是int 0x80
的32位read()
ABI周围的一个(粗大的)包装,如手册页所述,它返回一个长度。 Linux系统调用确实以RAX返回。它也奇怪地将最大长度硬编码为20。
read()
)int 0x80
是RAX的低字节,此代码仅保存打印长度的低字节。 IDK为什么他们将其保存在内存中,而不是像普通人一样将其保存在内存中。尤其是当他们将整个64位长度而不是普通的What happens if you use the 32-bit int 0x80 Linux ABI in 64-bit code?复制到RCX以便将32位值零扩展到RCX时。
还请注意,后面的AL
(32位mov ecx, eax
)是有风险的,是个坏主意;它可能会在RAX的高字节中留下垃圾,从而导致mov ax,1
而不是__NR_exit
,
-ENOSYS
,因此在这种情况下仅替换RAX的低16位是安全的。除非_exit(0)
返回负错误代码;那么当最后一个-EFAULT
返回read
而不是退出时,该程序将崩溃而不是退出。
尝试用int 0x80
运行它以关闭stdin,导致从[stdin]读取-ENOSYS
,然后崩溃]
而且,这是64位代码,因此使用32位./a.out <&-
Linux系统调用ABI并不是一个好主意。一些Linux系统(包括WSL)没有-EBADF
,并且会像int 0x80
或任何其他软件中断那样出错。 CONFIG_IA32_EMULATION