在NASM中每秒更新已经打印的字符串
Update the string that has already been printed every second in NASM
我对组装这件事完全陌生,用谷歌搜索了几个小时,在 SO 上搜索并没有解决问题,所以我来这里问了。
我想达到的目标:
[first second]: hello (stays on the screen for 1 second)
[second second]: world (hello disappeared and now we have `world` in place of it)
而且这个流程是无限循环的
换句话说,我希望我的终端的标准输出在 hello 和 world 之间闪烁(改变)而不附加任何换行符、写入字符串或任何其他东西,我只希望现有的、已经打印的文本被另一个替换文本。
我写了无限循环,它会打印 hello
,然后等一秒钟,然后打印 world
,再等一秒钟。我也把这段代码放在一个无限循环中。
这是我目前拥有的代码:
section .data
hello db "hello",10,0
world db "world",10,0
delay dq 1,0
section .text
global _start
_start:
mov rax, 1
mov rdi, 1
mov rsi, hello
mov rdx, 6
syscall
mov rax, 35
mov rdi, delay
mov rsi, 0
syscall
mov rax, 1
mov rdi, 1
mov rsi, world
mov rdx, 6
syscall
mov rax, 35
mov rdi, delay
mov rsi, 0
syscall
call _start
请注意,我使用 elf64 asm 格式,非常感谢您提出该格式的解决方案。
打印一个 \r
回车 return(ASCII 代码 13)以将光标放在行的开头 而无需 滚动终端 \n
换行符 (ASCII 10) 可以。
然后你可以覆盖你最后写的东西。如果它更短,您可以在可见字符后打印空格以 "erase" 后面的字符仍然存在。
例如因为这两个词的长度相同,你可以这样做:
section .rodata
hello db 13, "hello" ; `\rhello`
hello_len equ $ - hello
world db 13, "world"
world_len equ $ - world
请注意,您的数据中不需要 , 0
,因为您将这些缓冲区传递给 write
而不是 printf
,因此它们不需要 0
] 终止的隐式长度 C 字符串。您也不需要硬编码 mov rdx, 6
,您可以使用 mov rdx, hello_len
并让汇编程序为您计算。
对于休眠部分,您可以使用 sleep
libc 函数,但对于原始系统调用,您必须使用 nanosleep
。 (就像你已经在做的那样。)
对于循环,不要使用call _start
;使用 jmp
。您不想推送 return 地址;最终会堆栈溢出(大约 100 万秒后:8MiB 堆栈大小限制和调用推送一个 8 字节 return 地址。)
使用 Peter Cordes 的有用指导解决了这个问题。
工作代码如下所示:
section .data
hello db "hello",13,0
world db "world",13,0
delay dq 1,0
section .text
global _start
_start:
mov rax, 1
mov rdi, 1
mov rsi, hello
mov rdx, 6
syscall
mov rax, 35
mov rdi, delay
mov rsi, 0
syscall
mov rax, 1
mov rdi, 1
mov rsi, world
mov rdx, 6
syscall
mov rax, 35
mov rdi, delay
mov rsi, 0
syscall
jmp _start
我对组装这件事完全陌生,用谷歌搜索了几个小时,在 SO 上搜索并没有解决问题,所以我来这里问了。
我想达到的目标:
[first second]: hello (stays on the screen for 1 second)
[second second]: world (hello disappeared and now we have `world` in place of it)
而且这个流程是无限循环的
换句话说,我希望我的终端的标准输出在 hello 和 world 之间闪烁(改变)而不附加任何换行符、写入字符串或任何其他东西,我只希望现有的、已经打印的文本被另一个替换文本。
我写了无限循环,它会打印 hello
,然后等一秒钟,然后打印 world
,再等一秒钟。我也把这段代码放在一个无限循环中。
这是我目前拥有的代码:
section .data
hello db "hello",10,0
world db "world",10,0
delay dq 1,0
section .text
global _start
_start:
mov rax, 1
mov rdi, 1
mov rsi, hello
mov rdx, 6
syscall
mov rax, 35
mov rdi, delay
mov rsi, 0
syscall
mov rax, 1
mov rdi, 1
mov rsi, world
mov rdx, 6
syscall
mov rax, 35
mov rdi, delay
mov rsi, 0
syscall
call _start
请注意,我使用 elf64 asm 格式,非常感谢您提出该格式的解决方案。
打印一个 \r
回车 return(ASCII 代码 13)以将光标放在行的开头 而无需 滚动终端 \n
换行符 (ASCII 10) 可以。
然后你可以覆盖你最后写的东西。如果它更短,您可以在可见字符后打印空格以 "erase" 后面的字符仍然存在。
例如因为这两个词的长度相同,你可以这样做:
section .rodata
hello db 13, "hello" ; `\rhello`
hello_len equ $ - hello
world db 13, "world"
world_len equ $ - world
请注意,您的数据中不需要 , 0
,因为您将这些缓冲区传递给 write
而不是 printf
,因此它们不需要 0
] 终止的隐式长度 C 字符串。您也不需要硬编码 mov rdx, 6
,您可以使用 mov rdx, hello_len
并让汇编程序为您计算。
对于休眠部分,您可以使用 sleep
libc 函数,但对于原始系统调用,您必须使用 nanosleep
。 (就像你已经在做的那样。)
对于循环,不要使用call _start
;使用 jmp
。您不想推送 return 地址;最终会堆栈溢出(大约 100 万秒后:8MiB 堆栈大小限制和调用推送一个 8 字节 return 地址。)
使用 Peter Cordes 的有用指导解决了这个问题。
工作代码如下所示:
section .data
hello db "hello",13,0
world db "world",13,0
delay dq 1,0
section .text
global _start
_start:
mov rax, 1
mov rdi, 1
mov rsi, hello
mov rdx, 6
syscall
mov rax, 35
mov rdi, delay
mov rsi, 0
syscall
mov rax, 1
mov rdi, 1
mov rsi, world
mov rdx, 6
syscall
mov rax, 35
mov rdi, delay
mov rsi, 0
syscall
jmp _start