Loading

汇编:x86

参考

  1. https://www.cnblogs.com/mazhimazhi/p/15241450.html

  2. x86指令解释手册

访存指令

mov

指令格式

mov{b/w/l/q} I/R/M,R/M

从一个位置复制数据到另外一个位置,b/w/l/q分别表示1/2/4/8字节,I/R/M分别表示立即数/寄存器/内存地址

这里有一个特殊指令:

movabs I, R

"abs"表示"absolute", "q"表示64位寄存器。

movs

movs{b/w/l}{w/l/q} I/R/M,R/M

比如movsbw i8 rd就代表:

v = sign_extend(i8, 16)
rd[15:0] = v

movz

movz{b/w/l}{w/l/q} I/R/M,R/M

比如movzbw i8 rd就代表:

v = zero_extend(i8, 16)
rd[15:0] = v

lea

lea a(b, c, d), rd

rd = a + (b+c*d)

neg

neg r/m

如果"ax"中的值为5,那么执行neg ax后为"-5"

xchg 和 cmpxchg

xchg R/M,R/M

对于指定的值进行交换, 具备原子性,CPU会自动加LOCK前缀

The LOCK prefix is automatically assumed for XCHG instruction.

cmpxchg rd, rs or cmpxchg %rs, %rd

Compares the value in the AL, AX, EAX, or RAX register with the first operand (destination operand). If the two values are equal, the second operand (source operand) is loaded into the destination operand. Otherwise, the destination operand is loaded into the AL, AX, EAX or RAX register. RAX register is available only in 64-bit mode.

rax寄存器的值与(rd)寄存器进行比较,如果rax==rd, 则将rs寄存器的值写入rd。否则将rd寄存器的值写入rax。

if rax == v(rd):
	v(rd) = rs
else:
	rax = v(rd)

demo

// https://github.com/bminor/musl/blob/v1.2.4/arch/x86_64/atomic_arch.h#L2
static inline int a_cas(volatile int *p, int t, int s)
{
	__asm__ __volatile__ (
		"lock ; cmpxchg %3, %1"
		: "=a"(t), "=m"(*p) 
		:"a"(t), "r"(s) 
		: "memory" );
	return t;
}
  • lock是为了添加内存屏障

改写一下:

int a_cas(volatile int *p, int old, int new)
{
	__asm__ __volatile__ (
		"lock ; cmpxchg %[new], %[dst]"
		: "+a"(old), [dst]"=m"(*p)
		:[new]"r"(new)
		: "memory" );
	return old;
}

反汇编如下:

mov    %esi,%eax
lock cmpxchg %edx,(%rdi)
retq

逻辑运算指令

not

not 指令用于对于所有的位取反

移位

sal  I,R/M  #算术左移
sar  I,R/M  #算术右移
shl  I,R/M  #逻辑左移
shr  I,R/M  #逻辑右移

流程控制

条件码

image

  • CF: 进位标志。最近的操作使得最高位产生了进位,可用来检查无符号操作的溢出。
  • ZF: 零标志。最近的操作得出的结果为0。
  • SF: 符号标志。最近的操作得到的结果为负数。
  • OF: 溢出标志。最近的操作导致一个补码溢出——正溢出,或者负溢出。

假设存在表达式t=a+b,这里a, b, t都是有符号整型:

标志位 结果 解释
CF (unsigned)t < (unsigned)a 无符号溢出
ZF t==0
SF t<0 负数
OF (a<0 == b<0) && (t<0 != a<0) 有符号溢出
  • 汇编部分代码
	.file	"add.c"
	.text
	.globl	add
	.type	add, @function
add:
.LFB0:
	pushq	%rbp
	movq	%rsp, %rbp
	movl	%edi, -4(%rbp)
	movl	%esi, -8(%rbp)
	movl	-4(%rbp), %edx
	movl	-8(%rbp), %eax
	addl	%edx, %eax
	popq	%rbp
	ret
.LFE0:
	.size	add, .-add
  • CF 测试
int add(int a, int b);
add(0xffffffff, 0xffffffff);
// `-1 + (-1)= -2`, `p $eflags`
[ PF ZF IF ]	=>		[ CF AF SF IF ]
  • ZF 测试
add(1, 1);
// ZF消失
[ PF ZF IF ] => [ IF ]
  • SF测试
add(0, -1)
[ PF ZF IF ] => [ PF SF IF ]
  • OF测试
add(0x7fffffff, 1);
[ PF ZF IF ]
[ PF AF SF IF OF ]

test和cmp

test

功能:对于两个操作数执行逻辑与运算,仅修改标志位,但是不送回结果。

举例

  1. test来测试一个位,例如寄存器
test eax, 100b 
jnz ***** 如果右边第三个`bit=1`,jnz将跳转

call

call I/R/M

相当于

push rip
jmp addr

ret

ret

ret 指令相当于:

pop %rip

enter

image

rbp_a = (uint64_t)(*(rbp)), 函数b的栈帧范围[rsp_b, rbp_b)

push %rbp
move %rsp %rbp

[rsp, rbp)

leave

move %rbp, %rsp
pop %rbp

解释:jnz跳转的条件是ZF=0ZF=0意味着eax不为0,也就是逻辑true

  1. test一个普遍的用法是测试寄存器是否为0
test eax, eax
jz *****

解释:如果exa=0,则设置ZF标志位为1, 发生跳转

cmp

功能:两个操作数做减法,只修改标志位,不送回结果。

cmp eax, 2 如果`eax-2=0`,就设置`ZF=1`
jz ***** 如果设置了ZF=1就跳转

其他

rdtsc(read timestamp counter)

介绍:返回CPU启动以来的时钟周期数;该时钟周期数,即处理器的时间戳。高32位存储在edx中,低32位存储在eax

如果CPU的频率是1GZ,则时钟周期T=1/1GHZ秒,意味着每隔T秒,CPU完成一个最基本的动作,并在寄存器中,对周期数加1。

该周期达到上限了怎么办?

目前不需要担心因为(1<<64)/((10**9)*3600*24*365*4)=146对于一个4GZ的cpu来说,达到上限需要不停机器运转146年。

uint64_t a, d, t;
__asm__ volatile ("rdtsc":"=a"(a), "=d"(d));
t = (d<<32) | a;
printf("%lu\n", t);

各arch时间读取的指令

//https://github.com/loongarch64/rocksdb/blob/main/utilities/transactions/lock/range/range_tree/lib/portability/toku_time.h#L125
static inline tokutime_t toku_time_now(void) {
#if defined(__x86_64__) || defined(__i386__)
  uint32_t lo, hi;
  __asm__ __volatile__("rdtsc" : "=a"(lo), "=d"(hi));
  return (uint64_t)hi << 32 | lo;
#elif defined(__aarch64__)
  uint64_t result;
  __asm __volatile__("mrs %[rt], cntvct_el0" : [rt] "=r"(result));
  return result;
#elif defined(__riscv) && __riscv_xlen == 64
  uint64_t cycles;
  asm volatile("rdcycle %0" : "=r"(cycles));
  return cycles;
#elif defined(__loongarch64)
  unsigned long result;
  asm volatile ("rdtime.d\t%0,$r0" : "=r" (result));
  return result;
#else
#error No timer implementation for this platform
#endif
}
posted @ 2023-08-14 11:32  Mogul_Kahn  阅读(242)  评论(0)    收藏  举报