天天看点

Windows Interlocked系列函数

本文以InterlockedIncrement为例,来说明Windows Interlocked系列函数的实现原理。

一、InterlockedIncrement反汇编代码

如下C++代码:

#include <windows.h>

int main()

{

LONG l = 1;

LONG j = InterlockedIncrement(&l);

return 0;

}

对应的反汇编代码如下:

LONG l = 1;

002D08A8 mov dword ptr [l],1

LONG j = InterlockedIncrement(&l);

002D08AF mov eax,1

002D08B4 lock xadd dword ptr [l],eax

002D08B9 inc eax

002D08BA mov dword ptr [j],eax

这里写图片描述

从上面代码可以看出,InterlockedIncrement主要是通过lock和xadd这2个汇编指令来实现的。

二、lock与xadd指令

2.1 lock

lock前缀用于锁定指定的内存地址,当这个特定内存地址被锁定后,它就可以阻止其他的系统总线读取或修改这个内存地址,从而实现原子操作。

可以结合lock使用的汇编指令如下:

BT, BTS, BTR, BTC

XCHG, XADD

ADD, OR, ADC, SBB

AND, SUB, XOR

NOT, NEG, INC, DEC

2.2 xadd

xadd指令完成交换并相加的功能。如XADD r/m32, r32,即交换r32 与r/m32;并将相加的和存储到 r/m32中。

关于xadd指令可以参考:

http://scc.qibebt.cas.cn/docs/optimization/VTune(TM)%20User’s%20Guide/mergedProjects/analyzer_ec/mergedProjects/reference_olh/instruct32_hh/vc325.htm

三、InterlockedIncrement过程分析

InterlockedIncrement的处理过程如下:

【1】将eax赋值为1,即mov eax, 1

【2】使用一个xadd命令完成了下面的操作,通过伪代码表示如下:

// [l]和eax交换

temp = [l]

[l] = eax

eax = temp

// 将相加的和保存到[l]参数中

[l] = eax + [l]

从上面伪代码可以看到,一个xadd指令完成了多步操作,且是针对内存地址的操作,所以这行指令使用了lock前缀修饰。

【3】因为InterlockedIncrement函数返回值也会返回自增的结果,且因win32汇编的函数返回值保存在eax中,所以此时eax还要自增1(即inc eax)。