gcc内嵌汇编啊,呵呵,我一直在用。
个人感觉......语法非常混乱....|||||||||||||||
使用asm inline的方式是可以的,具体格式如下:
asm(<汇编指令块> : <输入参数> : <输出参数> : <更改寄存器表>);
其中汇编指令块就是指令的列表,格式如下:
指令1 输入参数, ..., 输出参数;
指令2 输入参数, ..., 输出参数;
* 注意: 1. 指令参数的顺序和intel汇编是相反的。(输入在前,输出在后) 2. 数字前面要加$ 3. 寄存器名前面用% 4. 如果要使用C变量,寄存器的前缀还要改...|||| |
举例:
将1赋给eax
asm("mov $1,%eax");
将dx赋给cx
asm("mov %dx, %cx");
扫描C变量test中的第一个标志位,并将编号放到eax
asm("bsf %0, %%eax" : :"m"(test));
解释:
1. 传入了一个C参数,因此用%0表示"第0个参数"
2. 因为一个%被C参数使用了,因此寄存器表示变成了两个%
3. 参数是输入用的,因此放在第二个:后面
4. m的意思是,这个参数是放在内存中的 (如果是放在寄存器里面的,用r表示)
调用rdtsc指令
asm(“rdtsc" : : : "eax", "edx");
解释:
1. 这样写没有什么意义,主要是为了解释更改寄存器表用法
2. 这条指令将64位的CPU指令计数器值放入eax, edx中。
2. 更改寄存器表中给出"eax", "edx"是为了告诉编译器"eax和edx中的值发生了改变";
因为两个寄存器没有明确的在汇编块中出现,编译器可能意识不到这两个寄存器变了,这样程序可能出错。
另外,建议在asm后面加关键字volatile,这样告诉编译器"这里面的东西都要原封不动!"
不然的话,编译器可能自作聪明的将你的汇编的某些指令"优化掉",造成程序死得很难看。
我就遇到过,把我的一个pop指令吃了,结果函数一返回就segfault... >_<
最后再一个稍微复杂点的例子吧:
// 测试变量的一个位是否标记(可以用在if条件中)
static inline int BitTest(register unsigned int R32, register unsigned int Idx)
{
int Ret;
asm volatile ("btl %1, %2;"
"sbbl %0, %0"
: "=r"(Ret)
: "Ir"(Idx), "r"(R32));
return Ret;
}
// 从一个bitmap中取得一个已经标记的位的编号,并且将这个位重置
// 如果没有位标记了,返回-1
#define BitFetch64(M64, Index) \
asm volatile ("movl $-1, %0;" \
"bsfq %1, %%rax;" \
"jz 1f;" \
"btrq %%rax, %1;" \
"movl %%eax, %0;" \
"1:" \
: "=Jr"(Index), "=m"(M64) \
: : "cc", "rax")
这里仅仅是简单介绍一下,要获得详细资料,google关键字: gcc inline assembly howto
-----------------
还有一个问题,就是怎么在c里定义一个指针,指向一个绝对的物理地址。 比如 *p = 0xfff10010;我的编译器还是不吃orz 其实需要的是一个指针指向这里,然后同时传四个参数, 茅盾的是,如果用方程指针,是可以传参数了,但是方程指针只能指向一个自定义的方程,不能让他指向一个地址。 如果用一般指针,就像上面问的,也许能指向地址,但是指针不能当方程用,无法传参数。 我知道这些想法和语言的基本原理不合, 按理说,把四个参数传到一个地址这件事本身就没法解释,但是实际问题就是如此需要。。。orz |
你想说的是调用某个地址的函数吧。
函数指针应该可以赋值,但是需要cast一下,比如:
*(int*)p = 0xfff10010;
觉得麻烦的话,就自己调用吧,注意目标函数使用的calling convention
如果我没有记错,一般的调用参数是push到stack上的:
push 参数1;
push 参数2;
push 参数3;
push 参数4;
call 地址;
如果register调用的话,第一个参数放在eax,第二个edx,第三个ecx,后面的放在stack上。