linux汇编 约束条件m,GCC 内联汇编约束字符“m”的用法

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

#include

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

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

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里慢慢调试这三段代码。仔细看寄存器数值。

如果我说的不对请指正。

GCC 的详细介绍:请点这里

GCC 的下载地址:请点这里

0b1331709591d260c1c78e86d0c51c18.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值