html5响应式网站制作,网上销售网站建设,珠海网,wordpress 收费课程上一篇文章学习了链接脚本的语法与相关概念#xff1a;链接脚本的概念
在继续学习链接器的内容的同时#xff0c;先学习一个新内容#xff1a;内嵌汇编。
GCC编译器一般支持C/C内嵌汇编语言#xff0c;这样可以实现语言本身无法实现的内容。我们本文主要介绍C语言中的内嵌…上一篇文章学习了链接脚本的语法与相关概念链接脚本的概念
在继续学习链接器的内容的同时先学习一个新内容内嵌汇编。
GCC编译器一般支持C/C内嵌汇编语言这样可以实现语言本身无法实现的内容。我们本文主要介绍C语言中的内嵌汇编C语言也是一样的规则。
首先要知道以下内容 x86汇编的两种语法intel语法和ATT语法 x86汇编一直存在两种不同的语法在intel的官方文档中使 用intel语法Windows也使用intel语法而UNIX平台的汇编器一 直使用ATT语法所以本文是ATT语法。 mov %edx,%eax 这条 指令如果用intel语法来写就是 mov eax,edx 寄存器名不加 % 号 并且源操作数和目标操作数的位置互换。本文不详细讨论这两种 语法之间的区别读者可以参考[AssemblyHOWTO]。 介绍x86汇编的书很多UNIX平台的书都采用ATT语法例 如[GroudUp]其它书一般采用intel语法例如[x86Assembly]。 1、C语言中的内嵌汇编
首先看一下C语言中的内嵌汇编语法格式
上述的volatile 关键字在以后会讲解具体作用这里知道它是禁止编译器优化即可可选参数的意思是这些参数可以没有汇编指令是必须有的项
上述的解释还不是很好理解我们可以看一个示例 在以上的内嵌汇编中我们可以来分析一下它的语法规则
“movl %1, %0\n” 这句话中%的意思是占位的意思。%1代表是一个input对应的寄存器%0代表的是result对应的寄存器。他们所对应的寄存器是任意的因为下面的限制符前面是 r 代表编译器自动将通用寄存器与变量进行关联。当然这里也可以直接指定通用寄存器不用占位符。上面的图中说r这个限制符只是建议编译器用通用寄存器来与变量相关但是编译器不一定听比如如果在某个时候通用寄存器已经被被人占用此时编译器就不会使用通用寄存器来关联我们的变量。带 号的是输出参数即result是输出参数input是输入参数上述汇编的意思是将输入参数input的值传送给输出参数的值result。所以执行完上述汇编代码后result与input的值都为1.
看了上面的解释我们大概学会了内嵌汇编的组成大致有汇编指令这是必须存在的可选参数这是不必须存在的。
我们注意到上面的限制符 r 代表编译器指定一个通用寄存器关联变量这是让编译器做主。但是我们也可以自己做主自己指定一个寄存器来关联我们的变量。那么都有哪些限制符以及他们对应的寄存器呢常用的见下表 上述的r代表通用寄存器很明显与我们刚学习的一样。
1.1 代码实验
在知道了上述规则之后我们来看看一个例子
9-1.c
#include stdio.hint main()
{int result 0;int input 1;int a 1;int b 2;asm volatile (movl %1, %0\n: r(result): r(input));printf(result %d\n, result);printf(input %d\n, input);asm volatile (movl %%eax, %%ecx\nmovl %%ebx, %%eax\nmovl %%ecx, %%ebx\n: a(a), b(b): a(a), b(b));printf(a %d\n, a);printf(b %d\n, b);return 0;
}编译
gcc 9-1.c
运行结果如下
分析上述代码
第一个汇编代码上述已经分析过是将input值赋给result第二个汇编代码块是交换a与b的值。 分析第二个代码块 a(a), b(b) 代表输出参数且将EAX寄存器与变量a关联将EBX寄存器与b相连a(a), b(b) 代表输入参数且将EAX寄存器与变量a关联将EBX寄存器与b相连movl %%eax, %%ecx\n 将EAX寄存器的值也就是a的值传送给ECX寄存器movl %%ebx, %%eax\n 将EBX寄存器的值也就是b的值传送给EAX相当于将b赋给amovl %%ecx, %%ebx\n 将ECX寄存器的值也就是a的值传送给EBX相当于将a赋给b
经过了上面的操作就交换了a与b的值。
2、使用内嵌汇编进行系统调用
在程序中我们经常使用printf打印东西。中所周知printf是一个系统函数我们如何在不使用printf的前提下打印字符串
使用内嵌汇编可以进行系统调用。
可以通过INT 0X80H 指令进行系统调用
INT指令用于使用Linux内核服务这是一个中断指令众所周知中断会使执行流切换到内核80H是一个中断向量号用于执行系统调用 我们还是具体来看一个例子吧
上面的解释是非常清楚的。注意区分传递的是立即数还是占位符即可。
同时上面的例子 加了保留列表。它的意思是保留寄存器不用于关联变量因为这些寄存器已经被我们用于做系统调用以及传参数了。
那么上述汇编代码执行后参数s与参数l会被传给系统调用函数sys_write 。
下面再给出一个示例来看看与上面的示例有什么区别 上面这个示例没有可选参数与保留列表。也就是没有输入输出参数没有保留列表。
除了上述的区别还有什么区别
很明显这个寄存器的前面是一个%,而刚刚那个是%%两个百分号。这是什么原因
那么在内嵌汇编中就有如下注意事项 嵌入汇编时除了汇编语言的指令不能省略可选参数与保留列表都可以省略 当省略的参数在中间时 对应分隔符 “ ”不可省略.如下图中的输出参数的分隔符 当省略保留列表时对应的“ ”可忽略 当省略可选参数时寄存器前使用 % 作为前缀 当有可选参数时寄存器前使用 %% 作为前缀
2.1 代码实验
在学习了上述的一系列原理后我们写出如下代码
9-2.c
#include stdio.hint main()
{char* s D.T.Software\n;int l 13;printf(main begin\n);asm volatile(movl $4, %%eax\nmovl $1, %%ebx\nmovl %0, %%ecx\nmovl %1, %%edx\nint $0x80 \n:: r(s), r(l): eax, ebx, ecx, edx);asm volatile(movl $1, %eax\nmovl $42, %ebx\nint $0x80 \n);printf(main end\n);return 0;
}运行结果
可以看出我们使用内嵌汇编打印出了D.T.Software\n; 并且在第二个汇编代码块中进行系统调用调用了sys_exit 函数直接退出进程运行了所以第二个printf(main end\n); 并没有执行。
当然我们也可以使用以下命令查看最近一次的一个进程退出时的退出状态码
echo $?
得出
很明显退出状态码是42正好与我们程序中写的一样。
3、 总结
C程序中支持内嵌汇编通过寄存器到汇编的关联可以实现汇编到C程序的交互内嵌汇编代码时可以使用占位符指定交互的变量限制符建议编译器将合适的寄存器关联到变量通过内嵌汇编可以直接进行系统调用
本文参考狄泰软件学院相关课程 想学习的可以加狄泰软件学院群 群聊号码199546072
学习探讨加个人可以免费帮忙下载CSDN资源 qq1126137994 微信liu1126137994