- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我按照一个简单的教程创建了一个 NASM x86_64 程序,该程序使用定义的函数打印变量,并在末尾添加了一个新行。 sprintLF 调用 sprint ,它反过来打印 rax 中设置了适当系统调用的任何内容。返回时,sprintLF 用 0Ah 更新 rax 换行代码,然后将换行代码推送到堆栈,并在再次调用 sprint 之前将 rax 重新分配给 0Ah 的堆栈地址,并将换行代码写入标准输出。在我在 gdb 中调试 sprint 的所有代码下面,这表明所有正确的寄存器都存储了与系统调用 4 关联的值,我不知道为什么变量字符串被成功打印但换行符没有。
调用代码
;; Hello World Program (Externam file include)
;; Compile with: nasm -f elf64 helloworld-if.asm
;; Link with ld helloworld-if.o -o helloworld-if
;; Run with ./helloworld-inc
%include 'function.asm' ; include our external file
SECTION .data
msg1 db 'Hello, brave new world!', 0h ;our first message string add null terminating byte
msg2 db 'This is how we recycle in NASM.', 0h ; our second message string add null terminating byte
SECTION .text
global _start
_start:
mov rax, msg1 ; mov the address of our first message string into RAX
call sprintLF ; call our string printing function
mov rax, msg2 ; move the address of our second message string into RAX
call sprintLF ; call our string printing function
call quit ; call our quit function
效用函数
; -------------------------------------------------------------------------------------------------------------------
; int slen(String message)
; String length calculation function
slen: ; this is our first function declaration
push rbx ; push the value in RBX onto the stack to preserve it while we use RBX in this function
mov rbx, rax ; move this address in RAX into RBX ( Both point to the same segment in memory)
nextchar:
cmp byte [rax], 0 ; this is the same as lesson 3
jz finished
inc rax
jmp nextchar
finished:
sub rax, rbx
pop rbx ; pop the value on the stack back into RBX
ret ; return to where the function was called
;; ---------------------------------------------------------------------------------------------------------
;; void sprint(String message)
;; String printing function
sprint:
push rdx
push rcx
push rbx
push rax
call slen
mov rdx, rax
pop rax
mov rcx, rax
mov rbx, 1
mov rax, 4
int 80h
pop rbx
pop rcx
pop rdx
ret
;; ----------------------------------------------------------------------------------------------------------
;; void sprintLF(String message)
;; String printing with line feed function
sprintLF:
call sprint
push rax ; push rax onto the stack to preserve it while we use the rax register in this function
mov rax, 0Ah ; push 0Ah into rax, 0Ah is the ascii character for a linefeed
push rax ; push the linefeede onto the stack so we can get the address
mov rax, rsp ; move the address of the current stack pointer into rax for sprint -> because write requires a memory address
call sprint ; call our sprint function
pop rax ; restore out linefeed character from the stack
pop rax ; return to our program
ret
;; -----------------------------------------------------------------------------------------------------------
;; void exit()
;; Exit program restore resources
quit:
mov rbx, 0
mov rax, 1
int 80h
ret
用于执行代码和输出的命令如下:
nasm -f elf64 helloworld-if.asm
ld helloworld-if.o -o hellworld-if
./hellworld-if
Hello, brave new world!This is how we recycle in NASM.
在另一个程序中,我尝试在将参数放入堆栈后打印参数,所以我只能猜测系统调用不喜欢从堆栈中获取它的值,但我是汇编新手,这让我感到困惑.
最佳答案
您一直在尝试将使用 int0x80
的 32 位 Linux 代码转换为 64 位代码。虽然这适用于很多情况,但并不适用于所有情况。 int 0x80
是 32 位系统调用接口(interface),但由于 IA32 兼容性内置于 Linux 内核(大多数发行版的默认设置),您仍然可以使用 int 0x80
。问题在于,当内核处理您的 int 0x80
请求时,仅寄存器的低 32 位被识别。
您第一个问题中的代码没有出现任何问题,但这段代码不起作用。原因是 RSP 中的堆栈指针通常是一个不能用 32 位值寻址的地址。当你执行 mov rax,rsp
时,RSP 的完整 64 位值被移动到 RAX,但是 sprint
的 int 0x80
调用只会查看 RAX(EAX 寄存器)的底部 32 位。
解决这个问题的方法是使用 64 位 syscall
接口(interface)。不幸的是,传入的系统调用号和寄存器参数已经改变。 Ryan Chapman's blog有一个很好的 64 位 syscall
系统调用编号及其参数表。
表中的sys_write
系统调用号和参数为:
根据此信息,您可以通过执行以下操作将 sprint
转换为使用 syscall
接口(interface):
sprint:
push r11 ; R11 and RCX are clobbered by syscall as well
push rcx
push rdx
push rsi
push rdi
push rax
call slen
mov rdx, rax ; RDX = number of characters to print
pop rax
mov rsi, rax ; RSI = address of characters to print
mov rdi, 1 ; RDI = file descriptor (1=STDOUT)
mov rax, 1 ; System call number 1 = sys_write
syscall ; 64-bit system call (rather than int 0x80)
pop rdi
pop rsi
pop rdx
pop rcx
pop r11
ret
这是相当低效的,可以清理。我以这种方式呈现,以便您可以从原始代码的角度理解更改。我已经评论了相关的行。
注意:您真的应该使用 Ryan Chapman 的表作为指南将所有 int 0x80
调用转换为 syscall
。我将其留作 OP 的练习。
关于linux - 换行字节 0Ah 被 x86_64 系统调用打印程序忽略,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55128338/
在 Vaadin 7.0,显示时JavaBean Table 中的数据与 BeanContainer ,用新数据刷新表的正确方法是什么? 最佳答案 该表通过监听器监视表项的属性。如果您通过表的 Ite
首先,我使用的是带有 Axis2 1.6.2 的 eclipse,我正在 tomcat 6 上部署我创建的 Web 服务。Web 服务是在 eclipse 中通过自上而下的方法创建的。 我被要求使对我
我已将 Rails 3.1.1 应用程序升级到 Rails 3.1.3,现在,对于每个请求,它仅响应错误数量的参数(3 for 1)。不幸的是,它没有说明错误在哪里,并且应用程序跟踪为空。我认为存在一
我是一名优秀的程序员,十分优秀!