c语言内嵌汇编函数 c语言嵌套汇编语言( 三 )


在内联汇编中 , 可以用 LENGTH、SIZE 和 TYPE 来获取 C/C++ 变量和类型的大大小 。
* LENGTH 操作符用来取得 C/C++ 中数组的元素个数(如果不是一个数组,则结果为 1) 。
* SIZE 操作符可以获取 C/C++ 变量的大?。ㄒ桓霰淞康拇笮∈?LENGTH 和 TYPE 的乘积) 。
* TYPE 操作符可以返回 C/C++ 类型和变量的大?。ㄈ绻淞渴且桓鍪椋?它得到的是数组中单个元素的大?。?。
例如,程序中定义了一个 8 维的整数型变量:
int iArray[8];
下面是 C 和汇编表达式中得到的 iArray 及其元素的相关值:
__asmCSize
LENGTH iArraysizeof(iArray)/sizeof(iArray[0])8
SIZE iArraysizeof(iArray)32
TYPE iArraysizeof(iArray[0])4
8. 注释
内联汇编中可以使用汇编语言的注释,即";" 。例如:
__asm MOV EAX, OFFSET pbBuff; Load address of pbBuff
因为 C/C++ 宏将会展开到一个逻辑行中,为了避免在宏中使用汇编语言注释带来的混乱,内联汇编也允许使用 C/C++ 风格的注释 。
9. _EMIT 伪指令
_EMIT 伪指令相当于 MASM 中的 DB,但是 _EMIT 一次只能在当前代码段(.text 段)中定义一个字节 。例如:
__asm
{
JMP _CodeLabel
_EMIT 0x00; 定义混合在代码段的数据
_EMIT 0x01
_CodeLabel:; 这里是代码
_EMIT 0x90; NOP指令
}
10. 寄存器使用
一般来说,不能假定某个寄存器在 __asm 块开始的时候有已知的值 。寄存器的值将不能保证会从 __asm 块保留到另外一个 __asm 块中 。
如果一个函数声明为 __fastcall 调用方式,则其参数将通过寄存器而不是堆栈来传递 。这将会使 __asm 块产生问题,因为函数无法被告知哪个参数在哪个寄存器中 。如果函数接收了 EAX 中的参数并立即储存一个值到 EAX 中的话 , 原来的参数将丢失掉 。另外,在所有声明为 __fastcall 的函数中,ECX 寄存器是必须一直保留的 。为了避免以上的冲突,包含 __asm 块的函数不要声明为 __fastcall 调用方式 。
提示:如果使用 EAX、EBX、ECX、EDX、ESI 和 EDI 寄存器,你不需要保存它 。但如果你用到了 DS、SS、SP、BP 和标志寄存器,那就应该用 PUSH 保存这些寄存器 。
提示:如果程序中改变了用于 STD 和 CLD 的方向标志,必须将其恢复到原来的值 。
四、 使用 C/C++ 元素
1. 可用的 C/C++ 元素
C/C++ 与汇编语言可以混合使用,在内联汇编中可以使用 C/C++ 变量以及很多其它的 C/C++ 元素,包括:
符号,包括标号、变量和函数名;
常量 , 包括符号常量和枚举型成员;
宏定义和预处理指示符;
注释,包括"/**/"和"//";
类型名,包括所有 MASM 中合法的类型;
typedef 名称,通常使用 PTR 和 TYPE 操作符,或者使用指定的的结构或枚举成员 。
在内联汇编中,可以使用 C/C++ 或汇编语言的基数计数法 。例如,0x100 和 100H 是相等的 。
2. 操作符使用
内联汇编中不能使用诸如""一类的 C/C++ 操作符 。但是,C/C++ 和 MASM 共有的操作符(比如"*"和"[]"操作符),都被认为是汇编语言的操作符,是可以使用的 。举个例子:
int iArray[10];
__asm MOV iArray[6], BX; Store BX at iArray + 6 (Not scaled)
iArray[6] = 0;// Store 0 at iArray+12 (Scaled)
提示:在内联汇编中,可以使用 TYPE 操作符使其与 C/C++ 一致 。比如,下面两条语句是一样的:
__asm MOV iArray[6 * TYPE int], 0; Store 0 at iArray + 12
iArray[6] = 0;// Store 0 at iArray + 12
3. C/C++ 符号使用
在 __asm 块中可以引用所有在作用范围内的 C/C++ 符号 , 包括变量名称、函数名称和标号 。但是不能访问 C++ 类的成员函数 。

推荐阅读