文档章节

在gcc中使用intel风格的内联汇编

simpower
 simpower
发布于 06/21 20:01
字数 1039
阅读 8
收藏 0
点赞 0
评论 0

很简单,内联汇编使用asm(“.intel_syntax noprefix/n”)声明一下,以后的内联汇编就可以用intel风格了,构建可执行文件时给gcc加上-masm=intel参数。
先写一个小程序测试一下:


[cpp] view plain copy

  1. #include <stdio.h>  
  2. int main() {  
  3.         int a = 3;  
  4.         asm(".intel_syntax noprefix/n");  
  5.         asm("mov dword ptr a,10/n");  
  6.         printf("%d/n", a);  
  7.         return 0;  
  8. }  


[root@jcwkylk src]# gcc -masm=intel test.c -o test
/tmp/ccgWTkUF.o: In function `main':
test.c:(.text+0x1a): undefined reference to `a'
collect2: ld returned 1 exit status
出错,说符号a没有定义。看看编译后的结果是什么样子:
[root@jcwkylk src]# gcc -S test.c
输出不长,把test.s的内容全部贴出来:
[c-sharp] view plain copy

  1.         .file   "test.c"  
  2.         .section        .rodata  
  3. .LC0:  
  4.         .string "%d/n"  
  5.         .text  
  6. .globl main  
  7.         .type   main, @function  
  8. main:  
  9.         leal    4(%esp), %ecx  
  10.         andl    $-16, %esp  
  11.         pushl   -4(%ecx)  
  12.         pushl   %ebp  
  13.         movl    %esp, %ebp  
  14.         pushl   %ecx  
  15.         subl    $36, %esp  
  16.         movl    $3, -8(%ebp)  
  17. #APP  
  18.         .intel_syntax noprefix  
  19.         mov dword ptr a,10  
  20. #NO_APP  
  21.         movl    -8(%ebp), %eax  
  22.         movl    %eax, 4(%esp)  
  23.         movl    $.LC0, (%esp)  
  24.         call    printf  
  25.         movl    $0, %eax  
  26.         addl    $36, %esp  
  27.         popl    %ecx  
  28.         popl    %ebp  
  29.         leal    -4(%ecx), %esp  
  30.         ret  
  31.         .size   main, .-main  
  32.         .ident  "GCC: (GNU) 4.1.1 20061011 (Red Hat 4.1.1-30)"  
  33.         .section        .note.GNU-stack,"",@progbits  


从上面看出来,夹在#APP和#NO_APP之间的部分就是.intel_syntax,它保持了原样,而代码中的a原本是个局部变量,只有在函数运行时它才会动态在栈上分配,使用ebp加上偏移量来访问它,这就是问题所在。因为全局变量的变量名会保存在符号表中,所以如果要在内联汇编中使用变量名,也只能使用全局变量的变量名。只为在内联汇编中用名称来访问变量而把一个局部变量变成全局的是不合理的,所以我们这里也用ebp+offset的方式来访问局部变量。
要这么做,就得了解gcc编译时是如何为函数分配栈的,以及调用函数时寄存器约定是怎样的。从上面的汇编代码可以看出来:
[c-sharp] view plain copy

  1. main:  
  2.         leal    4(%esp), %ecx   ; ecx=[esp+4],  
  3.         andl    $-16, %esp  
  4.         pushl   -4(%ecx)  
  5.         pushl   %ebp  
  6.         movl    %esp, %ebp  
  7.         pushl   %ecx  
  8.         subl    $36, %esp  


这几行代码用来初始化mai函数的调用栈,和cl编译器不同的是在push ebp前面多出来了几行,有个esp &= -16的操作,-16=0xfffffff0,这个作用可能是为了对齐,esp应该是保持16字节对齐的。但这些细节在这里作用都不大。最关键的是这三行:
        pushl   %ebp
        movl    %esp, %ebp
        pushl   %ecx
有一个把ecx寄存器压栈的操作,所以第一个局部变量的起始地址应该是ebp-8。
另一个注意的地方是printf的调用:
        movl    -8(%ebp), %eax
        movl    %eax, 4(%esp)
        movl    $.LC0, (%esp)
        call    printf
在这个代码中printf有两个参数,但却没有看到期望的push。gcc用了另外一种方法:直接操作esp。上面这三行代码,首先把[ebp-8]也就是第一个局部变量即a的值给了eax,然后把这个值传递到esp+4这个地址指向的内存单元,然后esp指向printf的第一个参数——那个格式控制字符串。之后call printf会把下一条指令的地址压入栈中,然后跳转到printf,所以,对printf来说,ebp+4仍然是返回地址,ebp+8仍然是第一个参数,ebp+0xc仍然是第二个参数。一切都没变。
最后有这一行代码:movl    $0, %eax
看来返回值仍然是存放在eax寄存器中。
好,现在写一个比较完整的测试程序:
[cpp] view plain copy

  1. #include <stdio.h>  
  2. int add(int a, int b) {  
  3.         return a+b;  
  4. }  
  5. int main() {  
  6.         int a = 3;  
  7.         asm(".intel_syntax noprefix/n");  
  8.         asm("mov dword ptr [ebp-8],10/n");  
  9.         printf("%d/n", a);  
  10.         asm("push dword ptr [ebp-8]/n");  
  11.         asm("push 25/n");  
  12.         asm("call add/n");  
  13.         asm("add esp, 8/n");  
  14.         asm("mov dword ptr [ebp-8], eax/n");  
  15.         printf("%d/n", a);  
  16.         return 0;  
  17. }  


[root@jcwkylk src]# gcc -masm=intel test.c -o test
[root@jcwkylk src]# ./test
10
35

本文转载自:https://blog.csdn.net/jcwKyl/article/details/4989777

共有 人打赏支持
simpower
粉丝 24
博文 456
码字总数 21045
作品 0
海淀
程序员
Essential Linux Device Driver附录A . Linux汇编

图A.1显示了Linux在PC兼容系统上的引导顺序,是第2章“内核一瞥”中图2.1的缩减版。图中的固件组件是用不同的汇编语法实现的: · BIOS通常全部用汇编编写。一些流行的PC BIOS使用像Microso...

21cnbao
2012/09/17
0
0
Linux 汇编语言开发指南

Linux 汇编语言开发指南 肖文鹏 (xiaowp@263.net), 北京理工大学计算机系硕士研究生 肖文鹏是北京理工大学计算机系的一名硕士研究生,主要从事操作系统和分布式计算环境的研究,喜爱Linux和P...

晨曦之光
2012/03/09
598
0
郁闷大了,请教 GCC版本支持64位汇编指令的问题

我正在对做内容更新。在处理clk计数器的时候,遇到个问题。 通过intel的rdtsc指令,是可以实现频率计数获取。这个是我一直用来测试算法性能使用的。通常系统的测试时间只能到毫秒。用rdtsc可...

中山野鬼
2012/04/09
1K
4
最牛X的GCC 内联汇编

简介 1.1 版权许可 Copyright (C) 2003 Sandeep S. 本文档自由共享;你可以重新发布它,并且/或者在遵循自由软件基金会发布的 GNU 通用公共许可证下修改它;也可以是该许可证的版本 2 或者(...

linuxprobe
2016/09/19
37
0
AT&T的汇编格式&X86内联汇编

AT&T的汇编格式 一 基本语法 语法上主要有以下几个不同. ★ 寄存器命名原则 AT&T: %eax Intel: eax ★源/目的操作数顺序 AT&T: movl %eax,%ebx Intel: mov ebx,eax ★常数/立即数的格式 AT...

AlphaJay
2012/05/18
0
0
__asm__ __volatile__ GCC的内嵌汇编语法 AT&T汇编语言语法

开 发一个OS,尽管绝大部分代码只需要用C/C++等高级语言就可以了,但至少和硬件相关部分的代码需要使用汇编语言,另外,由于启动部分的代码有大小限 制,使用精练的汇编可以缩小目标代码的S...

Dicky
2012/08/24
0
0
求解gcc编译c内联汇编标号报错的一个问题

使用gcc编译c语言内联汇编使用-O优化时,是标号部分报错,请问有知道怎么解决的吗? unsigned long strcpy0(char dst,const char src){asm volatile(".intel_syntax noprefixn""POS2:n""lods...

不高兴你咬我
2016/09/03
177
2
从汇编看for和while循环的效率

这事情得从C语言开始说起,先编写下面这两段代码: 1、 #include<stdio.h> int main(void) { int i; for(i = 0; i < 10; i++) { } return 0;} 2、 #include<stdio.h> int main(void) { int i......

firebroo
2015/04/25
0
3
ARM嵌入式开发中的GCC内联汇编简介

ARM嵌入式开发中的GCC内联汇编简介 嵌入式开发交流群280352802,欢迎加入! 在针对ARM体系结构的编程中,一般很难直接使用C语言产生操作协处理器的相关代码,因此使用汇编语言来实现就成为了...

长平狐
2013/06/03
70
1
GCC and C99 inline

C语言的inline 转以前我用Docbook写的一篇关于C语言inline关键字使用的文章。唉,要是能用docbook直接写Blog就好了。用得越多发现Docbook这个东西真是越好用啊~~ 本文介绍了GCC和C99标准中...

长平狐
2012/09/03
108
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

华为nova3超级慢动作酷玩抖音,没有办法我就是这么强大

华为nova3超级慢动作酷玩抖音,没有办法我就是这么强大!华为nova3超级慢动作酷玩抖音,没有办法我就是这么强大! 在华为最新发布的nova 3手机上,抖音通过华为himedia SDK集成了60fps、超级...

华为终端开放实验室
22分钟前
0
0
多 SSH Key 实现同一台服务器部署多 Git 仓库

本文以以下需求为背景,介绍详细的做法: 需在同一台服务器同时部署两个不同的 Github 仓库(对 Bitbucket 等 git 服务同样适用) root 用户可在远程登录 SSH 后附上预期的 SSH Key 进行 gi...

yeahlife
25分钟前
0
0
003. es6数值的扩展

一、普通扩展 Number 方法,将字符串、数值转为十进制 : Number('0b111') Number.isFinite() 用来检查一个数值是否为有限的:Number.isFinite(15) Number.isNan() 用来检查一个值是否为NaN N...

秋季长青
39分钟前
0
0
rabbitmq学习(二)

基本队列:Producer直接发送信息到Queue中,Consumer接收Queue发送过来的信息 简而言之,一个生产者发送信息,一个消费者接收信息。 获取连接工具类: package com.example.demo.utils;i...

人觉非常君
43分钟前
0
0
C语言数组和指针的语法糖

对于C语言,我可以这样秀:比如当创建一个数组arr[n]之后,一般我们去遍历数组的时候是for (int i = 0; i < n; i++) { a[i]; }但是我知道下表访问符[]是个语法糖,也就是说a[i]在编译器看来是...

ustbgaofan
47分钟前
0
0
Call to undefined function bcmath()的解决方法

乐意黎的ECS主机环境,Centos7.2 + PHP7 由于使用了bcdiv()函数,运行时总在抛错。 Fatal error: Call to undefined function bcmath() in /usr/loca/apache/htdocs/... on line 4 一查得知:......

dragon_tech
53分钟前
0
0
css优先级

..

architect刘源源
57分钟前
0
0
【转】Twitter的分布式自增ID算法snowflake

结构 snowflake的结构如下(每部分用-分开): 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000 第一位为未使用,接下来的41位为毫秒级时间(41位的长度可以...

talen
今天
0
0
hive支持行级修改

Hive从0.14版本开始支持事务和行级更新,但缺省是不支持的,需要一些附加的配置。要想支持行级insert、update、delete,需要配置Hive支持事务。 一、Hive具有ACID语义事务的使用场景 1. 流式...

hblt-j
今天
0
0
Python---scrapy框架的学习

scrapy框架的学习 先熟悉下scrapy项目结构: scrapyTest/scrapyTest/ _init_.py用来初始化项目信息 scrapyTest/scrapyTest/ items.py文件为爬虫项目的数据容器文件,主要用来定义我们的数据....

android-key
今天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部