Возвращение результата и передача параметров в процедуру ассемблера в коде на C/C++

Последнее обновление: 03.07.2023

Мы можем вызывать как в коде ассемблера функции C/C++, так и в коде С/С++ процедуры ассемблера. А также передавать параметры и получать результаты.

Возвращение результата из ассемблера

Согласно Windows ABI, функции (процедуры) возвращают целые числа и значения указателей (которые умещаются в 64 бита) в регистре RAX. Поэтому, если какой-то код С/C++ ожидает, что процедура ассемблера вернет целочисленный результат, то код на ассемблере должен проместить целочисленный результат в регистр RAX перед возвратом из процедуры.

Например, определим следующий файл hello.asm

option casemap:none
.data 
    text byte "Hello Asm", 0
.code
; определяем процедуру hello
public hello
hello proc

    lea rax, text  ; в регистр rax загружаем адрес строки text
    ret
hello endp
end

Здесь функция hello формально возвращает строку text. Фактически же это выражается в загрузке в регистр rax адрес строки text.

Также определим файл app.c, где получим строку и выведим ее на консоль:

#include <stdio.h>

extern char* hello(void);

int main()
{
    char* message = hello();
    printf(message);
}

Посольку в регистр rax загружаетс адрес строки, то для C/C++ возвращаемым типом функции будет тип char*. Соответственно мы можем получить эту строку:

char* message = hello();

Скомпилируем и запустим программу

c:\asm>ml64 /c hello.asm
Microsoft (R) Macro Assembler (x64) Version 14.36.32532.0
Copyright (C) Microsoft Corporation.  All rights reserved.

 Assembling: hello.asm

c:\asm>cl app.c hello.obj
Microsoft (R) C/C++ Optimizing Compiler Version 19.36.32532 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

app.c
Microsoft (R) Incremental Linker Version 14.36.32532.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:app.exe
app.obj
hello.obj

c:\asm>app
Hello Asm
c:\asm>

Передача параметров в процедуры ассемблера

Рассмотрим передачу параметров в процедуру на ассемблере и для этого возьмем следующий пример. Пусть в файле hello.asm определен следующий ассемблерный код:

option casemap:none

.code
; определяем функцию sum
; мы ожидаем два параметра - два числа
; по соглашениям первые два параметра в регистрах RCX и RDX
; возвращаемое значение - в регистре RAX
public sum
sum proc
    mov rax, rcx    ; помещаем в rax первый параметр - из регистра rcx
    add rax, rdx    ; складываем со вторым параметром - из регистра rdx
    ret
sum endp
end

Здесь определена процедура sum, которая должна складывать два числа и возращать их сумму. Согласно соглашениям первые два параметра передаются через регистры RCX и RDX, а результат помещается в регистр RAX. Поэтому функция sum получает из регистров RCX и RDX переданные значения и их сумму помещает в RAX.

Определим файл app.c, в котором вызовем данную процедуру и получим ее результат:

#include <stdio.h>

#define int64  unsigned long long

extern int64 sum(int64, int64);

int main()
{
    int64 a = 5;
    int64 b = 6;
    int64 result = sum(a, b);
    printf("result = %lld \n", result); // result = 11
}

Все параметры и результат у нас представдяют беззнаковый 64-разрядный целочисленный тип, то есть unsigned long long, и для краткости для него определен псевдоним int64

В вызов функции sum передаются значения переменных a и b. В итоге значение переменной a будет помещено в регистр RCX, а значение переменной b - в регистр RDX. Значение из регистра RAX мы можем получить в качестве результата функции

int64 result = sum(a, b);

Результат работы программы:

c:\asm>ml64 /c hello.asm
Microsoft (R) Macro Assembler (x64) Version 14.36.32532.0
Copyright (C) Microsoft Corporation.  All rights reserved.

 Assembling: hello.asm

c:\asm>cl app.c hello.obj
Microsoft (R) C/C++ Optimizing Compiler Version 19.36.32532 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

app.c
Microsoft (R) Incremental Linker Version 14.36.32532.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:app.exe
app.obj
hello.obj

c:\asm>app
result = 11

c:\asm>
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850