LINUX.ORG.RU

История изменений

Исправление AlexVR, (текущая версия) :

myfunc.asm:

global  myfunc

section .text
myfunc: 
        mov     rax, rdi        ; Первый пареметр
        add     rax, rsi        ; Второй параметр
        add     rax, rdx        ; Третий параметр
        cqo                     ; Расширяем RAX до RDX:RAX с учётом знака
        mov     rcx, 3          ; Делитель в RCX, что бы не сохранять RBX 
        idiv    rcx             ; RDX:RAX делим на RCX, частное в RAX (результат), остаток в EDX (побоку)
        ret

test.c:

#include <stdio.h>
#include <inttypes.h>

extern int64_t myfunc(int64_t a, int64_t b, int64_t c);

void test_myfunc(int64_t a, int64_t b, int64_t c) {
  printf("myfunc(%" PRId64 ", %" PRId64 ", %" PRId64 ")=%" PRId64 "\n", a, b, c, myfunc(a,b,c));
}

int main() {
  test_myfunc(1, 2, 3);
  test_myfunc(-1,0,1);
  test_myfunc(-1,-2,-3);
  return 0;
}

Компиляция и сборка:

$ nasm -f elf64 -o myfunc.o myfunc.asm
$ gcc -std=c99 test.c myfunc.o

З.Ы.: Аккуратно смотри под какую платформу компилируешь и пишешь, самое главное понять что есть такое «соглашение о вызове». Это позволит понять в каком порядке передаются параметры, какие регистры можно менять, а какие надо восстановить. Для 64-битных Linux - это System V Application Binary Interface AMD64 Architecture Processor Supplement (на странице 21 про использование регистров).

Исходная версия AlexVR, :

myfunc.asm:

global  myfunc

section .text
myfunc: 
        mov     rax, rdi        ; Первый пареметр
        add     rax, rsi        ; Второй параметр
        add     rax, rdx        ; Третий параметр
        cqo                     ; Расширяем RAX до RDX:RAX с учётом знака
        mov     rcx, 3          ; Делитель в RCX, что бы не сохранять RBX 
        idiv    rcx             ; RDX:RAX делим на RCX, частное в RAX (результат), остаток в EDX (побоку)
        ret

test.c:

#include <stdio.h>
#include <inttypes.h>

extern int64_t myfunc(int64_t a, int64_t b, int64_t c);

void test_myfunc(int64_t a, int64_t b, int64_t c) {
  printf("myfunc(%" PRId64 ", %" PRId64 ", %" PRId64 ")=%" PRId64 "\n", a, b, c, myfunc(a,b,c));
}

int main() {
  test_myfunc(1, 2, 3);
  test_myfunc(-1,0,1);
  test_myfunc(-1,-2,-3);
  return 0;
}

Компиляция и сборка:

$ nasm -f elf64 -o myfunc.o myfunc.asm
$ gcc -std=c99 test.c myfunc.o

З.Ы.: Аккуратно смотри под какую платформу компилируешь и пишешь, самое главное понять что есть такое «соглашение о вызове». Это позволит понять в каком порядке передаются параметры, какие из них можно менять, а какие надо восстановить. Для 64-битных Linux - это System V Application Binary Interface AMD64 Architecture Processor Supplement (на странице 21 про использование регистров).