【问题标题】:calling printf from assembly language on 64bit and 32bit architecture using nasm使用 nasm 在 64 位和 32 位架构上从汇编语言调用 printf
【发布时间】:2017-03-20 10:10:40
【问题描述】:

我想在linux的汇编语言中调用printf函数。

我想知道 64 位和 32 位汇编语言程序的方法。

1) 如果我想用字符串在 printf 中传递 32 位争论和 64 位争论,请告诉我两种情况。我该怎么做?

2) 对于 x86 32 位架构,如果我想做与第 1 点相同的事情。

请告诉我代码。让我知道我需要为这两种情况调整堆栈吗?我只需要在寄存器中传递参数吗?

非常感谢

【问题讨论】:

  • 我使用的是 corei7 64 位架构。但我想知道在 32 位和 64 位程序中调用 printf 的方法。我想知道在哪里传递争论以及是否需要在调用后手动调整堆栈。请给我这两种情况的例子。在这两种情况下都使用字符串传递 32 位和 64 位参数。
  • 谷歌搜索 "printf nasm""x86-64 printf nasm" 时的第一击是包含大量示例程序的页面,包括调用printf

标签: linux assembly printf 64-bit nasm


【解决方案1】:

在 Linux 中有两种用汇编语言打印字符串的方法。

1) 对 x64 使用 syscall,对 x86 使用 int 0x80。这不是printf,而是内核例程。您可以找到更多here (x86)here (x64)

2) 使用来自 glibc 的 printf。我假设你熟悉 NASM 程序的结构,所以这里有一个来自acm.mipt.ru 的不错的 x86 示例:

global main

;Declare used libc functions
extern exit
extern puts
extern scanf
extern printf

section .text

main:

;Arguments are passed in reversed order via stack (for x86)
;For x64 first six arguments are passed in straight order
;  via RDI, RSI, RDX, RCX, R8, R9 and other are passed via stack
;The result comes back in EAX/RAX
push dword msg
call puts
;After passing arguments via stack, you have to clear it to
;  prevent segfault with add esp, 4 * (number of arguments) 
add esp, 4

push dword a
push dword b
push dword msg1
call scanf
add esp, 12
;For x64 this scanf call will look like:
;  mov rdi, msg1
;  mov rsi, b
;  mov rdx, a
;  call scanf

mov eax, dword [a]
add eax, dword [b]
push eax
push dword msg2
call printf
add esp, 8

push dword 0
call exit
add esp, 4
ret

section .data
msg  : db "An example of interfacing with GLIBC.",0xA,0
msg1 : db "%d%d",0
msg2 : db "%d", 0xA, 0

section .bss
a resd 1
b resd 1

对于 x86,您可以使用 nasm -f elf32 -o foo.o foo.asm 组装它并使用 gcc -m32 -o foo foo.o 链接。对于 x64,只需将 elf32 替换为 elf64 并将 -m32 替换为 -m64。请注意,您需要gcc-multilib 才能使用 gcc 在 x64 系统上构建 x86 程序。

【讨论】:

  • 您实际上需要gcc -nostartfiles 来链接定义_start.o(而不是main)。有关详细信息,请参阅stackoverflow.com/questions/36861903/…
  • 另外,在 CALL 之后,您需要添加,而不是 sub。 sub esp, 12 保留更多的堆栈空间。或者不理会 ESP 并将其存储到您没有使用 MOV 指令弹出的空间中,以便为下一个 CALL 做好准备。
  • exit()保证不退货;它不能失败。所以你不需要在它之后弹出 arg 和 ret 。或者您可以首先从 main 返回 0,这也是同样的事情。看到你在call exit 之后添加了add esp, 4,我很高兴:P
猜你喜欢
  • 2014-01-22
  • 2017-04-27
  • 1970-01-01
  • 2015-06-29
  • 2013-12-03
  • 2011-02-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多