windows C/C++系列 内联汇编(二)

在内联汇编程序内调用 C /C++函数

__asm 块可以调用 C 函数(包括 C 库例程)。 以下示例调用 printf 库例程:

// InlineAssembler_Calling_C_Functions_in_Inline_Assembly.cpp
// processor: x86
#include <stdio.h>

char format[] = "%s %s\n";
char hello[] = "Hello";
char world[] = "world";
int main( void )
{
   __asm
   {
      mov  eax, offset world
      push eax
      mov  eax, offset hello
      push eax
      mov  eax, offset format
      push eax
      call printf
      //clean up the stack so that main can exit cleanly
      //use the unused register ebx to do the cleanup
      pop  ebx
      pop  ebx
      pop  ebx
   }
}

由于函数自变量在堆栈上传递,因此仅需在调用函数之前推入所需自变量(前面示例中的字符串指针)。 自变量以相反顺序被推动,因此可按所需顺序结束堆栈。 模拟 C 语句:

printf( format, hello, world );

 此示例按照该顺序推送指向 world、hello 和 format 的指针,然后调用 printf。

注意: __asm 块只能调用未重载的全局 C++ 函数。 如果调用重载的全局 C++ 函数或 C++ 成员函数,则编译器会发出错误。

你还可以调用使用 extern "C" 链接声明的任何函数。 由于所有标准头文件都声明库函数具有 extern "C" 链接,这将允许 C++ 程序中的 __asm 块调用 C 库函数。

将 __asm 块定义为 C 宏

利用 C 宏,可以轻松将程序集代码插入源代码中,但执行此操作时要格外小心,因为宏会扩展到单个逻辑行中。 若要创建可靠的宏,请遵循以下规则:

  • 将 __asm 块括在大括号内;
  • 将 __asm 关键字放在每个程序集指令的前面;
  • 使用旧式 C 注释 (/* comment */) 而不是程序集样式的注释 (; comment) 或单行 C 注释 (// comment);

为了演示这一点,下面的示例定义一个简单的宏:

#define PORTIO __asm      \
/* Port output */         \
{                         \
   __asm mov al, 2        \
   __asm mov dx, 0xD007   \
   __asm out dx, al       \
}

 乍一看,最后三个 __asm 关键字是多余的。 但它们是必需的,因为宏将扩展到单个行中:

__asm /* Port output */ { __asm mov al, 2  __asm mov dx, 0xD007 __asm out dx, al }

需要将第三个和第四个 __asm 关键字作为语句分隔符。 在 __asm 块中识别的唯一语句分隔符是换行符和 __asm 关键字。 由于定义为宏的块是一个逻辑行,因此您必须使用 __asm 分隔每个指令。

大括号也是必需的。 如果省略它们,则编译器会对同一行上的 C 或 C++ 语句与宏调用的右侧内容混淆不清。 在没有右大括号的情况下,编译器无法告知程序集代码停止的位置,并且会将 __asm 块后面的 C 或 C++ 语句视为程序集指令。

以分号 (;) 开头的程序集样式注释将继续,直到达到行尾。 这会导致宏出现问题,因为编译器将忽略注释后面的内容,直到到达逻辑行尾。 上述情况同样适用于单行 C 或 C++ 注释 (// comment)。 若要防止错误,请在定义为宏的 /* comment */ 块中使用旧式 C 注释 (__asm)。

编写为 C 宏的 __asm 块可以采用自变量。 但与普通 C 宏不同,__asm 宏不能返回值。 这样您便无法在 C 或 C++ 表达式中使用这些宏。

请注意,不要任意调用此类型的宏。 例如,调用使用 __fastcall 约定声明的函数中的汇编语言宏可能会导致意外的结果。

优化内联汇编程序

如果函数中存在 __asm 块,则会在多个方面影响优化。 首先,编译器不会尝试优化 __asm 块本身。 您在汇编语言中编写的内容就是您获得的内容。 第二,存在 __asm 块将影响寄存器变量存储。 如果寄存器的内容将被 __asm 块更改,编译器将避免在 __asm 块中注册变量。 最后,其他某些函数范围的优化将受函数中包含的汇编语言的影响。

  • 7
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值