一、背景
又是关于汇编,头真是大,当年欠吴旭老师的汇编终究还是要还的。
在看nws源码的时候,里面有这样一段代码
二、基础知识
这段代码是内嵌汇编代码(C与C++代码混合在一起叫内嵌汇编),为什么要使用内嵌汇编代码?可以大大的提升代码的运行速度,在nginx中广泛应用了CAS(compare-and-swap)操作来完成进程同步,也就是nginx的无锁机制,linux内核大量代码亦是如此(比如include/asm-i386/cmpxchg.h)
2.1 内嵌汇编常识介绍
GCC在C语言中内嵌汇编 asm volatile
2.2 cmpxchgq
cmpxchg是汇编指令
作用:比较并交换操作数.
如:CMPXCHG r/m,r 将累加器AL/AX/EAX/RAX中的值与首操作数(目的操作数)比较,如果相等,第2操作数(源操作数)的值装载到首操作数,zf置1。如果不等,首操作数的值装载到AL/AX/EAX/RAX并将zf清0
2.3 代码分析
以上面cmpxchg汇编为例, LOCK”cmpxchgq %2,%1” 就是汇编指令, output operands和inpupt operands指定参数,它们从左到右依次排列,用’,’分割,编号从0开始。,(prev)对应0,(* (volatile long )(ptr))对应1,(set)对应2,(old)对应3,如果在汇编中用到”%2”,那么就是指代set,”%1”指代 ( (volatile long *)(ptr))。
“=a”(prev) 和 “0”(old) 用的寄存器都是eax
一般cmpxchg有两种存在形式
cmpxchg bx, cx:
如果AX与BX相等,则CX送BX且ZF置1;否则BX送AX,且ZF清0
换成AT&T的格式就是
由于ATT汇编与Intel不同,操作数2,和操作数1互换。
cmpxchg %cx, %bx
针对代码解释
比较old和(* (volatile long * )(ptr))的值,如果相同,ZF标志被设置,同时set的值被写到(* (volatile long * )(ptr)),否则,清ZF标志,并且把(* (volatile long *)(ptr))的值写回 old。
在理解不了看看这个
/*
* “cmpxchgl r, [m]”:
*
* if (eax == [m]) {
* zf = 1;
* [m] = r;
* } else {
* zf = 0;
* eax = [m];
* }
*/
这篇文章也可以帮助理解:
cpu cmpxchg 指令理解 (CAS)