簡體   English   中英

混合C和匯編文件

[英]Mixing C and Assembly files

我想使用g ++在我的C ++程序中使用裸函數 不幸的是,與VC ++不同,g ++不支持裸函數,管理它的唯一方法是在單獨的文件中編寫自己的匯編代碼並與C ++文件鏈接。 我試圖找到一些很好的x86教程來混合匯編和C / C ++文件,但找不到任何好的。

如果您知道任何問題,請告訴我。 請注意,除了在C或程序集中使用它們之外,我不是要求內聯匯編而是鏈接C和匯編文件以及在匯編中聲明C的外部變量的方法,反之亦然,以及使用Makefile鏈接C和asm文件的方法。

在C ++文件中:

extern "C" void foo(); // Stop name mangling games

int main() {
  foo();
}

在“裸”的asm文件中,對於x86:

# modified from http://asm.sourceforge.net/howto/hello.html

.text                   # section declaration
    .global foo

foo:

# write our string to stdout

    movl    $len,%edx   # third argument: message length
    movl    $msg,%ecx   # second argument: pointer to message to write
    movl    $1,%ebx     # first argument: file handle (stdout)
    movl    $4,%eax     # system call number (sys_write)
    int $0x80       # call kernel

# and exit

    movl    $0,%ebx     # first argument: exit code
    movl    $1,%eax     # system call number (sys_exit)
    int $0x80       # call kernel

.data                   # section declaration

msg:
    .ascii  "Hello, world!\n"   # our dear string
    len = . - msg           # length of our dear string

編譯,匯編和鏈接(用g ++而不是ld,因為用C ++這樣做更容易)並運行:

ajw@rapunzel:/tmp > g++ -Wall -Wextra test.cc -c -o test.o
ajw@rapunzel:/tmp > as -o asm.o asm.S
ajw@rapunzel:/tmp > g++ test.o asm.o
ajw@rapunzel:/tmp > ./a.out
Hello, world!

如果要將參數傳遞給函數或返回任何需要遵守調用約定的內容。

這是一個實現“裸功能”效果的技巧示例。

#include <stdio.h>

extern "C" int naked_func ();

static void
dummy ()
{
  __asm__ __volatile__
    (
     "  .global naked_func\n"
     "naked_func:\n"
     "  movq    $3141569, %rax\n"
     "  ret\n"
     );
}

int
main ()
{
  printf ("%d\n", naked_func ());
  return 0;
}

這是我在程序集中定義函數的方法,這不需要有一個單獨的匯編程序文件,也不需要轉義每個換行符。 您只需將程序集文件的內容復制到string-literal即可。 注意: 原始多行字符串文字是C ++ 11特性(您還標記了C ++)。 如果要在單個.c - / .cpp文件中編譯所有內容,這很有用。

extern"C" int rand_byte(void);
asm (R"(
    .globl rand_byte
rand_byte:
    call rand
    and eax, 255
    ret
)");

您只能在全局范圍內使用沒有其他參數的基本程序集語句。 使用GCC或Clang和arm處理器時,您可以使用[[gnu::naked]] / __attribute__((naked))

    [[gnu::naked]]
int rand_byte(void) {
    asm volatile (R"(
        push {lr}
        bl rand
        and r0, #255
        pop {pc}
    )");
};

第一種方法總是允許定義裸功能。 這也有助於制作更多可移植的代碼。

    extern"C" int _cdecl rand_byte(void);
    #if defined __x86__
        // NOTE: the names are decorated with a '_' on windows 32-bit
        // You can use extern"C" int _cdecl rand_byte() asm("rand_byte");
        // to make the asm symbol name always be rand_byte, without an _
        asm volatile (R"(
            .globl _rand_byte
        _rand_byte:
            call rand
            and eax, 255
            ret
        )");
    #elif defined __x86_64__
        asm volatile (R"(
            .globl rand_byte
        rand_byte:
            call rand
            and rax, 255    # eax works here, too.  x86-32 and -64 could share the same source.
            ret
        )");
    #elif defined __arm__
        asm (R"(
            .global rand_byte
        rand_byte:
            push {lr}
            bl rand
            and r0, #255
            pop {pc}
        )");
    #else
        #error There is no code for your platform yet...
    #endif

我只想在上一篇文章中添加一件事。 想象一下,你想要一個接受參數的函數:(類似於

int add(int,int);

原型)

segment .text
global add

   add:
   enter 0,0
   mov eax,[ebp+8]  ; first argument
   mov ebx,[ebp+12]  ; second argument
   add eax,ebx
   leave
   ret

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM