将内容从 .data 部分移动到 NASM 中的寄存器
Moving contents from .data section to register in NASM
我是 NASM 的新手,很难将变量的内容从 .data 部分移动到寄存器。以下代码输出 "Value: 0" 而不是 "Value: 1"。如果我写常量直接注册(mov qword rax, 25
)一切正常。
; /usr/local/bin/nasm -f macho64 sum.asm && ld -macosx_version_min 10.7.0 -lSystem -o sum sum.o && ./sum
section .data
myvar: dq 1234
message: db "Value: %i", 10, 0
.len: equ $ - message
global start
extern _printf
extern _exit
section .text
start:
default rel
; This outputs "Value: 0"
mov qword [myvar], 1
mov rax, [myvar]
; This works:
; mov qword rax, 25
; Output
mov rsi, rax
mov qword rax, 0
lea rdi, [rel message]
call _printf
mov qword rax, 0
call _exit
/usr/local/bin/nasm -v
说:
NASM version 2.11.08 compiled on Mar 10 2015
您的代码是正确的,除了全局入口点 main
是必需的(但不是必需的,您可以调整入口点 -- 使用 link 选项)。您在这里 link 使用 libc printf
和 exit
函数。虽然编译器不同,但使用 printf
而不是 _printf
会有所帮助。
仅进行这些语义更改(并在 Linux 而不是 Mac 上编译),您的代码将提供所需的输出:
section .data
myvar: dq 1234
message: db "Value: %i", 10, 0
.len: equ $ - message
global main
extern printf
extern exit
section .text
main:
default rel
; This outputs "Value: 0"
mov qword [myvar], 1
mov rax, [myvar]
; Output
mov rsi, rax
mov qword rax, 0
lea rdi, [rel message]
call printf
mov qword rax, 0
call exit
编译
$ nasm -felf64 -o obj/label64.o label64.asm
$ ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 /usr/lib64/crt1.o \
/usr/lib64/crti.o obj/label64.o /usr/lib64/crtn.o -lc -o bin/label64
输出
$ ./bin/label64
Value: 1
注意:您可能需要调整link命令所需的路径。否则,您可以只调用 gcc
并让它对路径进行排序。例如:
$ gcc -o bin/label64 obj/label64.o
再次来袭。使用旧版本(如 2.11.06),或修复数据部分中相对符号寻址的新版本。或者使用 yasm
.
正如我在评论中所说,您可以使用 xor eax, eax
将 64 位寄存器归零。这是标准的成语。
写入 32 位寄存器 总是 清除 64 位寄存器的 upper32。与移动 64 位立即数相比,这节省了大量指令字节。
mov qword rax, 25
依然是32bit立即数移动。 qword
是不必要的。该指令确实有一个不需要的 REX 前缀使其成为 64 位写入,而不是通过写入低 32 位自动清除高 32 位。
mov eax, 25
做同样的事情,但指令字节更少。
我是 NASM 的新手,很难将变量的内容从 .data 部分移动到寄存器。以下代码输出 "Value: 0" 而不是 "Value: 1"。如果我写常量直接注册(mov qword rax, 25
)一切正常。
; /usr/local/bin/nasm -f macho64 sum.asm && ld -macosx_version_min 10.7.0 -lSystem -o sum sum.o && ./sum
section .data
myvar: dq 1234
message: db "Value: %i", 10, 0
.len: equ $ - message
global start
extern _printf
extern _exit
section .text
start:
default rel
; This outputs "Value: 0"
mov qword [myvar], 1
mov rax, [myvar]
; This works:
; mov qword rax, 25
; Output
mov rsi, rax
mov qword rax, 0
lea rdi, [rel message]
call _printf
mov qword rax, 0
call _exit
/usr/local/bin/nasm -v
说:
NASM version 2.11.08 compiled on Mar 10 2015
您的代码是正确的,除了全局入口点 main
是必需的(但不是必需的,您可以调整入口点 -- 使用 link 选项)。您在这里 link 使用 libc printf
和 exit
函数。虽然编译器不同,但使用 printf
而不是 _printf
会有所帮助。
仅进行这些语义更改(并在 Linux 而不是 Mac 上编译),您的代码将提供所需的输出:
section .data
myvar: dq 1234
message: db "Value: %i", 10, 0
.len: equ $ - message
global main
extern printf
extern exit
section .text
main:
default rel
; This outputs "Value: 0"
mov qword [myvar], 1
mov rax, [myvar]
; Output
mov rsi, rax
mov qword rax, 0
lea rdi, [rel message]
call printf
mov qword rax, 0
call exit
编译
$ nasm -felf64 -o obj/label64.o label64.asm
$ ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 /usr/lib64/crt1.o \
/usr/lib64/crti.o obj/label64.o /usr/lib64/crtn.o -lc -o bin/label64
输出
$ ./bin/label64
Value: 1
注意:您可能需要调整link命令所需的路径。否则,您可以只调用 gcc
并让它对路径进行排序。例如:
$ gcc -o bin/label64 obj/label64.o
yasm
.
正如我在评论中所说,您可以使用 xor eax, eax
将 64 位寄存器归零。这是标准的成语。
写入 32 位寄存器 总是 清除 64 位寄存器的 upper32。与移动 64 位立即数相比,这节省了大量指令字节。
mov qword rax, 25
依然是32bit立即数移动。 qword
是不必要的。该指令确实有一个不需要的 REX 前缀使其成为 64 位写入,而不是通过写入低 32 位自动清除高 32 位。
mov eax, 25
做同样的事情,但指令字节更少。