linux - x64 位汇编

标签 linux assembly integer 64-bit nasm

我不久前开始汇编 (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。)

除编辑外:如今在汇编中编写任何东西有两个,而且只有两个原因:

  1. 您正在编写为数不多的不能单独用 C 编写的深层魔法(一个很好的例子是 libffi 的内容)
  2. 您正在手动优化一个内部循环子例程,该子例程被测量为性能关键型,而 C 编译器在这方面做得不够好。

否则就用 C 写任何东西。你的继任者会感谢你的。

编辑:检查系统调用号码。

关于linux - x64 位汇编,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5022744/

相关文章:

grails - Groovy - 类型测试?

php - 字符串到整数数组php

linux - gcc/g++ 的简易 makefile

c - 错误的指令 - C 代码中的内联汇编语言

c - 如何将这部分代码从汇编语言转换成C语言

python - 如何将列表列表中的所有字符串转换为整数?

python - 通过网页共享脚本输出(不同服务器)

python - 如何防止 Python 的 os.walk 遍历挂载点?

c - Linux 守护进程和 STDIN/STDOUT

assembly - x86 中没有段的直接寻址?