12.12日OS学习总结——第六章内联汇编

1.nasm在编译汇编文件的时候一定要注意其形成的elf文件类型,默认是形成32位可执行文件,如果想生成64位可执行文件好与其他文件连接在一起的话输入

nasm -f elf64 <filename>

2.在链接顺序上, 遵从于“调用在前,实现在后”的顺序。(这个和我们平时写函数调用过程恰恰相反)
3.GCC内联汇编

参考文章:https://www.ibm.com/developerworks/cn/linux/sdk/assemble/inline/index.html
GCC(用于 Linux 的 GNU C 编译器)使用 AT&T 汇编语法。注意哦不是intel的那一套语法~

寄存器命名
寄存器名称有 % 前缀。即,如果必须使用 eax,它应该用作 %eax。

源操作数和目的操作数的顺序
在所有指令中,先是源操作数,然后才是目的操作数。这与将源操作数放在目的操作数之后的 Intel 语法不同。

mov %eax, %ebx transfers the contents of eax to ebx.

操作数大小
根据操作数是字节 (byte)、字 (word) 还是长型 (long),指令的后缀可以是 b、w 或 l。这并不是强制性的;GCC 会尝试通过读取操作数来提供相应的后缀。但手工指定后缀可以改善代码的可读性,并可以消除编译器猜测不正确的可能性。

movb %al, %bl -- Byte move
movw %ax, %bx -- Word move
movl %eax, %ebx -- Longword move

立即操作数
通过使用 $ 指定直接操作数。

movl $0xffff, %eax -- will move the value of 0xffff into eax register.

间接内存引用
任何对内存的间接引用都是通过使用 ( ) 来完成的。

movb (%esi), %al -- will transfer the byte in the memory pointed by esi into al register

GCC的内联汇编结构

扫描二维码关注公众号,回复: 4557854 查看本文章
asm( assembler template
: output operands (optional)
: input operands (optional)
: list of clobbered registers (optional)
);

例子:给cr0的某一个bit置位

uint32_t cr0;
asm volatile ("mov %%cr0,%0\n" : "=r"(cr0));
cr0 |= 0x80000000;
asm volatile ("movl %0,%%cr0\n" :: "r"(cr0));
  • volatitle : No reordering; No elimination 不需要做进一步优化和调整顺序
  • %0 : The first constraint following 第一个用到的寄存器
  • r : A constraint;GCC is free to use any register 任意寄存器

意思是 先把cr0这个寄存器里的内容读到%0寄存器里面去,这个%0的内容最终赋值给cr0这个变量

然后下一条指令就是将cr0变量里的值写会cr0寄存器中。

内联汇编的基本要素

例子,使用汇编指令使"b"的值等于"a"
{
    int a=10, b;
    asm ("movl %1, %%eax;   
      movl %%eax, %0;"
        :"=r"(b)  /* output */    
        :"r"(a)       /* input */
        :"%eax"); /* clobbered register */
}
  • “b” 是输出操作数,由 %0 引用,“a” 是输入操作数,由 %1 引用。在汇编程序模板内部,操作数由数字引用。
  • “r” 是操作数的约束,它指定将变量 “a” 和 “b” 存储在寄存器中。请注意,输出操作数约束应该带有一个约束修饰符 “=”,指定它是输出操作数。
  • 要在 “asm” 内使用寄存器 %eax,%eax 的前面应该再加一个 %,换句话说就是 %%eax,因为 “asm” 使用 %0、%1 等来标识变量。任何带有一个 % 的数都看作是输入/输出操作数,而不认为是寄存器。
  • 第三个冒号后的修饰寄存器 %eax 告诉将在 “asm” 中修改 GCC %eax 的值,这样 GCC 就不使用该寄存器存储任何其它的值。
  • movl %1, %%eax 将 “a” 的值移到 %eax 中, movl %%eax, %0 将 %eax 的内容移到 “b” 中。
  • 因为 “b” 被指定成输出操作数,因此当 “asm” 的执行完成后,它将反映出更新的值。换句话说,对 “asm” 内 “b” 所做的更改将在 “asm” 外反映出来。

上述中详细每一项的含义请见这里

寄存器的约束
a:表示寄存器 eax/ax/al
b:表示寄存器 ebx/bx/bl
c:表示寄存器 eex/ex/cl
d:表示寄存器 edx/dx/dl
D:表示寄存器 edi/di
S:表示寄存器 esi/si
q:表示任意这 4 个通用寄存器之一: eax/ebx/ecx/edx
r:表示任意这 6 个通用寄存器之一 :eax/ebx/ecx/e也/esi/edi
g:表示可以存放到任意地点(寄存器和内存)。相当于除了同 q一样外,还可以让 gcc安排在内存中
A:把 eax和 edx组合成 64位整数
f:表示浮点寄存器
t:表示第 1 个浮点寄存器
u:表示第 2个浮点寄存器

4. 在写内敛汇编的时候我发现会报错,报错关于nasm生成的是32位的一系列值,pusha popa的话没法在64位模式上弹出32位的寄存器的值

这是个大坑

目前我的解决办法是:开一个32位的虚拟机现勉强做下去吧。。。

5.

猜你喜欢

转载自blog.csdn.net/qq_37414405/article/details/84964065