GCC 内联汇编约束字符“m”的用法

首先是这么一段代码(例一):

#include<stdio.h>
void main()
{
    char c;
    //int tmp;
    char *s="abcdefg";
    asm("movb %1,%0\n\t"
    :"=d"(c)
    :"m"(*s));
    printf("out:%c\n",c);
 
}

这段代码运行后会出现什么结果呢?很显然,是out:a

但是"m"(*s)是什么意思呢?s是字符串指针,现在是把*s字符串传进去了。

事实上,对于"a"、"b"、"c"这些约束符他们都特别指定eax,ebx,ecx寄存器,我们使用它们时是把内存里的值传到寄存器,在输出时再把寄存器值传给内存变量。而"m"则直接指示原始内存位置。也就是说在内联汇编里面对于"m"标示的内存变量将直接对其进行修改。例如,在输出语句指定:"m"(var),那么在asm语句中对于var的修改将直接作用到它的内存位置。

对于上面的代码,看起来似乎是我们通知gcc把整个字符串传进去,但是字符串首地址也是字符a的地址,相当于把字符a传进去了,所以%1似乎代表的字符a。然后把它放到了%0也就是edx里。

如果你把"m"(*s)改为"m"(s),把指针传进去会怎样?我们修改代码为(例二):

#include<stdio.h>
void main()
{
    //char c;
    int tmp;
    char *s="abcdefg";
    printf("%d\n",s);
    asm("movl %1,%0\n\t"
    :"=d"(tmp)
    :"m"(s));
    printf("out:%d\n",tmp);
 
}

我们首先把指针s输出,然后再在内联汇编里传入s,不是传入*s!!我们把%1按照四字节传入edx,再把edx传入tmp整型变量,最后把tmp输出,其实就是我们费尽周折把%1给输出出来了。

结果是怎样呢?在我的电脑上,两个printf输出了同样的数字。这说明了什么,说明%1现在代表了指针s的数值。

之前我们传入字符a,它代表的是字符a,现在传入指针s,%1又代表了指针s的值。是不是有点乱。

再来看下一个例子(例三):

#include<stdio.h>
void main()
{
    char c;
    //int tmp;
    char *s="abcdefg";
    //printf("%d\n",s);
    asm("movb %%ds:%1,%0\n\t"
    :"=d"(c)
    :"m"(*s));
    printf("out:%c\n",c);
 
}

我们把第一段代码的mov指令语句改为了movb %%ds:%1,%0,加了个段前缀。运行结果依然输出out:a

我们把这三段代码分别gcc xxxx.c -S编译成汇编代码查看会发现,%1这个东西到底是什么根本不能确定,它不像%0所代表的edx一样,%1是随着你代码写法的改变由gcc自动选择合适的寻址方式。所以,第一和第三段代码的差距是ds段前缀,但结果不变,因为gcc自动调整了寻址方式。%1随着这种调整,它的意义也在不断发生变化。有时它是字符a(例一),有时它是字符a的偏移地址(例三),有时候它又是一个指针值(例二)。

引用国外一个网站的一句话:In addition to passing information in registers, gcc can understand references to raw memory. This will expand to some more complex addressing mode within the asm string.

就是这样,不必再纠结%1代表了什么,只需记住,把字符串*s整个传进去,相当于传递了它的第一个字符,%1(或者其他占位符)代表了这个字符。把字符串指针s传进去,%1就是这个指针s的值,不过没人这样干,没有意义。把整型变量var(int var=123;)传进去,那%1就代指这个整数。

可以在GDB里慢慢调试这三段代码。仔细看寄存器数值。

如果我说的不对请指正。

Ubuntu 12.04嵌入式交叉编译环境arm-linux-GCC搭建过程图解 

Ubuntu 12.10安装交叉编译器arm-none-linux-gnueabi-GCC 

Ubuntu下Vim+GCC+GDB安装及使用 

Ubuntu下两个GCC版本切换 

GCC 的详细介绍请点这里
GCC 的下载地址请点这里

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/d34f9396405a1f43e7d83ceb6fa280cf.html