装配打印变量和值

时间:2015-12-11 20:16:20

标签: macos assembly nasm x86-64

我有这段代码

global start

section .text

start:
mov rax,0x2000004
mov rdi,1
mov rsi,msg
mov rdx,msg.len
syscall

mov rax,0x2000004
mov rdi,2
mov rsi,msgt
mov rdx,msgt.len
syscall

mov rax,0x2000004
mov rdi,3
mov rsi,msgtn
mov rdx,msgtn.len
syscall

mov rax,0x2000001
mov rdi,0
syscall

section .data

msg: db "This is a string",10
.len: equ $ - msg

var: db 1

msgt: db "output of 1+1: "
.len: equ $ - msgt

msgtn: db 1
.len: equ $ - msg

我想打印变量msgtn。我试过msgt: db "output of 1+1", var 但NASM汇编程序失败了:

second.s:35: error: Mach-O 64-bit format does not support 32-bit absolute addresses

我还尝试"output of 1+1", [1+1]而不是变量,但我得到了:

second.s:35: error: expression syntax error

我也尝试了没有parantheses,没有数字,但只有字符串" 1 + 1"。

我用来组装程序的命令是:

/usr/local/Cellar/nasm/*/bin/nasm -f macho64 second.s && ld -macosx_version_min 10.7.0 second.o second.o

nasm -v显示:

NASM version 2.11.08 compiled on Nov 27 2015

采用Intel核心i5(x86_64程序集)的OS X 10.9.5

1 个答案:

答案 0 :(得分:3)

db指令允许您将汇编时间常量字节放入目标文件中(通常在数据部分中)。您可以使用表达式作为参数,让汇编程序在汇编时为您进行数学运算。任何需要在运行时发生的事情都需要通过您编写的指令来完成,然后才能运行。它不像C ++,全局变量可以有一个在幕后启动时运行的构造函数。

msgt: db "output of 1+1", var

会放置那些ascii字符,然后是({的低字节?)var的绝对地址。你可以使用这种东西(用dddq)来做这样的事情:C int var; int *global_ptr = &var;,你有一个全局/静态指针变量,它开始初始化为点到另一个全局/静态变量。我不确定MacOS X是否允许使用64位指针,或者它是否只是拒绝为32位地址进行重定位。但这就是你得到的原因:

  

second.s:35: error: Mach-O 64-bit format does not support 32-bit absolute addresses

请注意,指针的数值取决于加载代码的虚拟地址空间中的位置。所以地址不是严格来说是汇编时常数。链接器需要标记需要运行时重定位的内容,例如那些64位立即常量地址mov到寄存器(mov rsi,msg)。请参阅this answer以获取有关它与lea rsi, [rel msg]之间差异的一些信息,以便使用RIP相关方法将地址输入寄存器。 (该答案包含更详细信息的链接, wiki也是如此。

您尝试使用db [1+1]:您期待的是什么? NASM语法中的[]表示内存引用。 第一:结果字节必须是汇编时常量。我不确定是否有一个简单的语法来复制其他地址的任何内容,但这不是它。 (我只是定义一个宏并在两个地方都使用它。)第二个2不是有效的地址。

msgt: db "output of 1+1: ",   '0' + 1 + 1,    10

会在目标文件中的那一点放置ASCII字符:output of 1+1: 2\n10是ASCII换行符的十进制值。 '0'是一种写入0x30的方式,ASCII编码字符'0'2字节不是可打印的ASCII字符。那样做的那个版本会在那里打印一个2字节,但你不会注意到除非你将输出传输到hexdump(或od -t x1c或者什么,IDK是OS X提供的。 od不是很好,但它可以广泛使用。)

请注意,此字符串以null结尾。如果你想把它传递给期望隐含长度字符串的东西(比如fputs(3)strchr(3),而不是write(2)memchr(3)),那就加上{{1}在其他一切之后添加一个零字节。

如果你想在运行时进行数学运算,你需要将数据输入寄存器,添加数据,然后将数字的字符串表示存储到某个缓冲区中。 (或者一次打印一个字节,但这太可怕了。)

简单的方法是只需调用, 0,轻松打印一个常量字符串,其中包含一些替换的内容。花时间编写asm代码,用于需要手动调整的代码部分,而不是重新编写代码。实现库函数。

在评论中讨论了int-to-string。

您的链接命令看起来很有趣:

printf

您确定要两次使用相同的ld -macosx_version_min 10.7.0 second.o second.o 吗?

当您不需要在64位reg中使用符号扩展时,您可以仅将.o一些代码字节保存到32位寄存器。例如mov代替mov edi,2保存一个字节(REX前缀),除非NASM很聪明并且无论如何都会这样做(实际上,它确实如此)。

mov rdi,2(或使用lea rsi, [rel msg])是比default rel更短的指令。 (AT& T助记符为mov r64, imm64,但英特尔语法仍将其称为movabs。)

相关问题