GCC 内联汇编

您所在的位置:网站首页 汇编内存操作数 GCC 内联汇编

GCC 内联汇编

2024-05-17 19:29| 来源: 网络整理| 查看: 265

GCC 内联汇编 February 03, 2020

GCC 支持内联汇编, 格式如下:

asm ( assembler template : output operands (optional) : input operands (optional) : list of clobbered registers (optional) );

asm 又可以写作 __asm__, __asm__主要用来避免命名冲突。 assembler template 就是内联的汇编代码, output operands, input operands, list of clobbered registers分别指代 输入操作数,输入操作数,修饰寄存器列表。 参数的顺序从左到右使用数字序号来引用, 例如%0表示第一个参数。 以下是几个 GCC 内联汇编的例子:

1. 内存操作数(Memory operand constraint(m)) __asm__("sidt %0\n" : :"m"(loc));

以上代码的作用等同于*loc = idt(idt 表示中断向量表), "m"表示操作数位于内存中, 其中%0表示第一个参数也就是loc。

2. 参数序号引用(Matching(Digit) constraints) __asm__("incl %0" :"=a"(var):"0"(var));

在这个例子中var既用作输入参数由用作输出参数, =a表示使用eax寄存器来存放变量var, =是修饰符,表示输出变量, 它告诉 GCC 这个变量的值会被覆盖。 “0"表示使用和第一个参数一样的存储来作为输出来源, 在这里就是eax寄存器。 这段代码展开后等价于:

mov var %eax incl %eax mov %eax, var 3. 常用寄存器的代号

我们知道a代表eax寄存器,x86 还有多种可用的寄存器,代号如下:

a %eax b %ebx c %ecx d %edx S %esi D %edi

还有一个特殊的代号r表示由 GCC 来选择可用的寄存器。

4. 修饰寄存器(clobbered register)

修饰寄存器可以理解为保留的不可用的寄存器。

asm ("movl $count, %%ecx; up: lodsl; stosl; loop up;" : /* no output */ :"S"(src), "D"(dst) /* input */ :"%ecx", "%eax" ); /* clobbered list */

lodsl和stosl会隐式的使用eax和ecx寄存器。 但是 GCC 并不知道这一点, 所以它可能会在展开的代码中使用这两个寄存器, 为了避免这种情况我们需要把eax和ecx添加到修饰寄存器列表中。

5. 参数修饰符

上面的例子中我们已经见过=修饰符,除了=以外还有三种修饰符:

+表示操作数在一条指令中既被读又背写 &表示表示输出寄存器不能和输入寄存器重叠,只能用来做输出 %告诉 GCC 该操作数可能被累加 6. 内联汇编的综合例子 int main(void) { int x = 10, y; asm ("movl %1, %%eax; "movl %%eax, %0;" :"=r"(y) /* y is output operand */ :"r"(x) /* x is input operand */ :"%eax"); /* %eax is clobbered register */ }

以上代码展开后就是:

main: pushl %ebp movl %esp,%ebp subl $8,%esp movl $10,-4(%ebp) movl -4(%ebp),%edx /* x=10 is stored in %edx */ #APP /* asm starts here */ movl %edx, %eax /* x is moved to %eax */ movl %eax, %edx /* y is allocated in edx and updated */ #NO_APP /* asm ends here */ movl %edx,-8(%ebp) /* value of y in stack is updated with the value in %edx */

eax在修饰集群器列表中, 所以我们看到内联汇编展开的代码中没有再引用eax寄存器。 可以看到变量x和y都使用edx寄存器存储, 有时候需要保证输入、输出变量使用不同的寄存器, 这个是可以使用&修饰符:

int main(void) { int x = 10, y; asm ("movl %1, %%eax; "movl %%eax, %0;" :"=&r"(y) /* y is output operand, note the & constraint modifier. */ :"r"(x) /* x is input operand */ :"%eax"); /* %eax is clobbered register */ }

展开后的代码是:

main: pushl %ebp movl %esp,%ebp subl $8,%esp movl $10,-4(%ebp) movl -4(%ebp),%ecx /* x, the input is in %ecx */ #APP movl %ecx, %eax movl %eax, %edx /* y, the output is in %edx */ #NO_APP movl %edx,-8(%ebp)

可以看到现在x存在于ecx寄存器, 而y存放于edx寄存器。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3