我不久前开始汇编 (nasm) 编程。现在我创建了一个带有汇编实现的 C 函数,它打印一个整数。我使用扩展寄存器让它工作,但是当我想用 x64 寄存器(rax、rbx、..)编写它时,我的实现失败了。你们有人看到我错过了什么吗?
主.c:
#include <stdio.h>
extern void printnum(int i);
int main(void)
{
printnum(8);
printnum(256);
return 0;
}
32 位版本:
; main.c: http://pastebin.com/f6wEvwTq
; nasm -f elf32 -o printnum.o printnum.asm
; gcc -o printnum printnum.o main.c -m32
section .data
_nl db 0x0A
nlLen equ $ - _nl
section .text
global printnum
printnum:
enter 0,0
mov eax, [ebp+8]
xor ebx, ebx
xor ecx, ecx
xor edx, edx
push ebx
mov ebx, 10
startLoop:
idiv ebx
add edx, 0x30
push dx ; With an odd number of digits this will screw up the stack, but that's ok
; because we'll reset the stack at the end of this function anyway.
; Needs fixing though.
inc ecx
xor edx, edx
cmp eax, 0
jne startLoop
push ecx
imul ecx, 2
mov edx, ecx
mov eax, 4 ; Prints the string (from stack) to screen
mov ebx, 1
mov ecx, esp
add ecx, 4
int 80h
mov eax, 4 ; Prints a new line
mov ebx, 1
mov ecx, _nl
mov edx, nlLen
int 80h
pop eax ; returns the ammount of used characters
leave
ret
x64 版本:
; main.c : http://pastebin.com/f6wEvwTq
; nasm -f elf64 -o object/printnum.o printnum.asm
; gcc -o bin/printnum object/printnum.o main.c -m64
section .data
_nl db 0x0A
nlLen equ $ - _nl
section .text
global printnum
printnum:
enter 0, 0
mov rax, [rbp + 8] ; Get the function args from the stac
xor rbx, rbx
xor rcx, rcx
xor rdx, rdx
push rbx ; The 0 byte of the string
mov rbx, 10 ; Dividor
startLoop:
idiv rbx ; modulo is in rdx
add rdx, 0x30
push dx
inc rcx ; increase the loop variable
xor rdx, rdx ; resetting the modulo
cmp rax, 0
jne startLoop
push rcx ; push the counter on the stack
imul rcx, 2
mov rdx, rcx ; string length
mov rax, 4
mov rbx, 1
mov rcx, rsp ; the string
add rcx, 4
int 0x80
mov rax, 4
mov rbx, 1
mov rcx, _nl
mov rdx, nlLen
int 0x80
pop rax
leave
ret ; return to the C routine
提前致谢!
最佳答案
我认为您的问题是您试图在 64 位模式下使用 32 位调用约定。如果您从 C 调用这些汇编例程,那是行不通的。此处记录了 64 位调用约定:http://www.x86-64.org/documentation/abi.pdf
另外,不要打开代码系统调用。调用 C 库中的包装器。这样 errno
就可以正确设置,你可以利用 sysenter
/syscall
,你不必处理正常调用之间的差异约定和系统调用参数约定,并且您可以避免某些低级 ABI 问题。 (您的另一个问题是 write
是 Linux/x86-64 的系统调用编号 1,而不是 4。)
除编辑外:如今在汇编中编写任何东西有两个,而且只有两个原因:
- 您正在编写为数不多的不能单独用 C 编写的深层魔法(一个很好的例子是 libffi 的内容)
- 您正在手动优化一个内部循环子例程,该子例程被测量为性能关键型,而 C 编译器在这方面做得不够好。
否则就用 C 写任何东西。你的继任者会感谢你的。
编辑:检查系统调用号码。
关于linux - x64 位汇编,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5022744/