Взаимодействие с кодом C/C++

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

Программа на ассемблере ARM64 в Windows также может взаимодействовать с кодом С/С++, как и в Linux. Но есть ряд особенностей. Рассмотрим различные сценарии.

Подключение в ассемблер стандартных функций С

Для вызова в коде ассемблера стандартных библиотечных функций С/С++ в общем случае необходимо, чтобы код ассемблера запускался в программе на С/С++. Это не всегда удобно, если мы хотим написать программу целиком на ассемблере, но при этом задействовать некоторые стандартные функции C/C+, например, printf. В этом случае надо дополнительно вызвать в коде ассемблера функцию _CRT_INIT. Например, определим в файле "hello.asm" следующую программу на ассемблере:

    global __main
    extern printf     ; импортируем функцию printf
    extern _CRT_INIT
    area main, CODE
__main
    str lr, [sp, #-16]! ; Сохраняем регистр LR в стек

    bl _CRT_INIT        ; инициализация CRT

    ldr x0, =message        ; отображаемое сообщение
    bl printf           ; вызываем функцию printf

    ldr lr, [sp], #16    ; Восстанавливаем регистр LR из стека
    ret 
    area DATA         
message dcb "Hello METANIT.COM!",0     ; сообщение в окне
    end

Здесь обращаемся к стандартной функции printf() для вывода строки на консоль. Через регистр Х0 эта функция получает первый и единственный аргумент - собственно строку для вывода. Но перед вызовом этой функции также вызывается функция _CRT_INIT

При компоновки необходимо передать компоновщику библиотеки "legacy_stdio_definitions.lib" и "msvcrt.lib". Процесс компиляции, компоновки и выполнения программы:

c:\arm64>armasm64 hello.asm -o hello.obj
Microsoft (R) ARM Macro Assembler Version 14.36.32537.0 for 64 bits
Copyright (C) Microsoft Corporation.  All rights reserved.


c:\arm64>link hello.obj legacy_stdio_definitions.lib msvcrt.lib /entry:__main /subsystem:console
Microsoft (R) Incremental Linker Version 14.36.32537.0
Copyright (C) Microsoft Corporation.  All rights reserved.


c:\arm64>hello
Hello METANIT.COM!
c:\arm64>

Вызов своих функций С/С++

Подобным образом мы можем вызывать в коде ассемблера и свои функции С/С++. Например, пусть у нас есть файл sum.c, в котором определена функция sum:

#include <stdio.h>

int sum(int a, int b)
{
    printf("a=%d\n", a);
    printf("b=%d\n", b);
    int result = a + b;
    printf("result=%d\n", result);
    return result;
}

Это примитивная функция сложения, которая принимает два числа и возвращает их сумму, попутно логируя параметры и результат.

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

    global __main
    extern _CRT_INIT
    extern sum          ; импортируем функцию sum
    area main, CODE
__main
    str lr, [sp, #-16]! ; Сохраняем регистр LR в стек

    bl _CRT_INIT

    mov x0, #10        ; a = 10
    mov x1, #12        ; b = 12
    bl sum          ; вызываем функцию sum

    ldr lr, [sp], #16    ; Восстанавливаем регистр LR из стека
    ret
    end

Здесь через регистры Х0 и Х1 передаем функции sum соответственно значения для первого и второго параметров, затем вызываем функцию. Причем опять же перед этим вызываем функцию _CRT_INIT. Для компиляции кода на С используем программу компилятора cl. Процесс компиляции, компоновки и вызова программы будет следующим:

c:\arm64>armasm64 hello.asm -o hello.obj
Microsoft (R) ARM Macro Assembler Version 14.36.32537.0 for 64 bits
Copyright (C) Microsoft Corporation.  All rights reserved.


c:\arm64>cl hello.obj sum.c /link /entry:__main /subsystem:console legacy_stdio_definitions.lib msvcrt.lib /NODEFAULTLIB:libcmt.lib
Microsoft (R) C/C++ Optimizing Compiler Version 19.36.32537 for ARM64
Copyright (C) Microsoft Corporation.  All rights reserved.

sum.c
Microsoft (R) Incremental Linker Version 14.36.32537.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:hello.exe
/entry:__main
/subsystem:console
legacy_stdio_definitions.lib
msvcrt.lib
/NODEFAULTLIB:libcmt.lib
hello.obj
sum.obj

c:\arm64>hello
a=10
b=12
result=22

c:\arm64>echo %ERRORLEVEL%
22

c:\arm64>

Здесь мы видим, что команда echo %ERRORLEVEL%, которая возвращает по сути значение из регистра Х0, возвратила число 22 - результ выполнения функции sum. Как и следовало ожидать.

Выполнение кода ассемблера в программе на С/С++

Выше был представлен подход, когда основная программа написана на ассемблере. Однако обычно применяется другой подход - когда функция на C/C++ вызывает код на ассемблере. Хотя код ассемблере при этом также может обращаться к функциям С/С++.

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

    global _hello
    extern printf     ; импортируем функцию printf
    area hello, CODE
_hello
    str lr, [sp, #-16]! ; Сохраняем регистр LR в стек

    ldr x0, =message       ; устанавливаем параметр для функции printf
    bl printf         ; вызываем функцию printf

    ldr lr, [sp], #16    ; Восстанавливаем регистр LR из стека
    ret 
    area DATA         
message dcb "Hello METANIT.COM!\n",0     ; сообщение в окне
    end

Здесь определена функция _hello, которая импортирует и вызывает стандартную функцию printf для вывода сообщения на экран. Никаких импортов и вызово функции _CRT_INIT здесь уже нет. Важно, что эта функция определена с директивой global:

global _hello

Несмотря на то, что это больше не точка входа в программу.

Далее определим файл app.c со следующим кодом на языке C:

#include <stdio.h>
// подключаем внешнюю функцию hello из файла hello.asm
extern void _hello(void);
 
int main()
{
    printf("_hello starts\n");
    _hello();
    printf("_hello ends\n");
}

Здесь подключаем ранее определенную в коде ассемблера функцию _hello и вызываем ее в функции main. Точкой входа в программу теперь будет данная функция main.

Сначала скомпилируем из файла hello.asm объектный файл hello.obj

armasm64 hello.asm -o hello.obj

Затем с помощью программы компилятора cl скомпилируем всю программу:

cl app.c hello.obj

Полный консольный вывод с компиляцией и выполнением программы:

c:\arm64>armasm64 hello.asm -o hello.obj
Microsoft (R) ARM Macro Assembler Version 14.36.32537.0 for 64 bits
Copyright (C) Microsoft Corporation.  All rights reserved.


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

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

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

c:\arm64>app
_hello starts
Hello METANIT.COM!
_hello ends

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