我不久前开始编程(nasm)编程。现在我用汇编实现创建了一个C函数,它打印一个整数。我使用扩展寄存器工作,但是当我想用x64寄存器(rax,rbx,..)编写时,我的实现失败了。你们有没有看到我错过的东西?
main.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
提前致谢!
答案 0 :(得分:4)
我认为您的问题是您尝试在64位模式下使用32位调用约定。如果您从C调用这些程序集例程,那就不会飞了。这里记录了64位调用约定:http://www.x86-64.org/documentation/abi.pdf
另外,不要打开代码系统调用。调用C库中的包装器。那样errno
设置正确,你利用sysenter
/ syscall
,你不必处理正常调用约定和系统调用参数约定之间的差异,并且你与某些低级别的ABI问题隔离开来。 (另一个问题是,对于Linux / x86-64,write
是系统调用号1而不是4。)
编辑抛开:现在有两个,只有两个理由在议会中写任何东西:
否则只要写下C中的任何内容。你的继任者会感谢你。
编辑:已检查系统电话号码。
答案 1 :(得分:2)
我不确定这个答案是否与你所看到的问题有关(因为你没有指明失败的内容),但是64位代码的调用约定与32位代码不同确实。两个主要的64位Intel ABI(Windows和Linux / BSD / Mac OS)都在寄存器中而不是堆栈中传递函数参数。你的程序似乎仍然期待它们在堆栈上,这不是正常的方法。
编辑:现在我看到有一个调用你的函数的C main()
例程,我的答案完全关于你遇到的问题。