X86 Assembly/Other Instructions

From Wikibooks, open books for an open world
< X86 Assembly
Jump to: navigation, search

Stack Instructions[edit]

push arg

This instruction decrements the stack pointer and stores the data specified as the argument into the location pointed to by the stack pointer.

pop arg

This instruction loads the data stored in the location pointed to by the stack pointer into the argument specified and then increments the stack pointer. For example:

mov eax, 5
mov ebx, 6
push eax 
The stack is now: [5]
push ebx 
The stack is now: [6] [5]
pop eax 
The topmost item (which is 6) is now stored in eax. The stack is now: [5]
pop ebx 
ebx is now equal to 5. The stack is now empty.

pushf

This instruction decrements the stack pointer and then loads the location pointed to by the stack pointer with the contents of the flag register.

popf

This instruction loads the flag register with the contents of the memory location pointed to by the stack pointer and then increments the contents of the stack pointer.

pusha

This instruction pushes all the general purpose registers onto the stack in the following order: EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI. The value of ESP pushed is the value before the instruction is executed. It is useful for saving state before an operation that could potential change these registers.

popa

This instruction pops all the general purpose registers off the stack in the reverse order of PUSHA. That is, EDI, ESI, EBP, ESP, EBX, EDX, ECX, EAX. Used to restore state after a call to PUSHA.

Flags instructions[edit]

While the flags register is used to report on results of executed instructions (overflow, carry, etc.), it also contains flags that affect the operation of the processor. These flags are set and cleared with special instructions.

Interrupt Flag[edit]

The IF flag tells a processor if it should accept hardware interrupts. It should be kept set under normal execution. In fact, in protected mode, neither of these instructions can be executed by user-level programs.

sti

Sets the interrupt flag. If set, the processor can accept interrupts from peripheral hardware.

cli

Clears the interrupt flag. Hardware interrupts cannot interrupt execution. Programs can still generate interrupts, called software interrupts, and change the flow of execution. Non-maskable interrupts (NMI) cannot be blocked using this instruction.

Direction Flag[edit]

The DF flag tells the processor which way to read data when using string instructions. That is, whether to decrement or increment the esi and edi registers after a movs instruction.

std

Sets the direction flag. Registers will decrement, reading backwards.

cld

Clears the direction flag. Registers will increment, reading forwards.

Carry Flag[edit]

The CF flag is often modified after arithmetic instructions, but it can be set or cleared manually as well.

stc

Sets the carry flag.

clc

Clears the carry flag.

cmc

Complements (inverts) the carry flag.

Other[edit]

sahf

Stores the content of AH register into the lower byte of the flag register.

lahf

Loads the AH register with the contents of the lower byte of the flag register.

I/O Instructions[edit]

in src, dest GAS Syntax
in dest, src Intel syntax


The IN instruction almost always has the operands AX and DX (or EAX and EDX) associated with it. DX (src) frequently holds the port address to read, and AX (dest) receives the data from the port. In Protected Mode operating systems, the IN instruction is frequently locked, and normal users can't use it in their programs.


out src, dest GAS Syntax
out dest, src Intel syntax


The OUT instruction is very similar to the IN instruction. OUT outputs data from a given register (src) to a given output port (dest). In protected mode, the OUT instruction is frequently locked so normal users can't use it.


System Instructions[edit]

These instructions were added with the Pentium II.

sysenter

This instruction causes the processor to enter protected system mode (supervisor mode or "kernel mode").

sysexit

This instruction causes the processor to leave protected system mode, and enter user mode.

Misc Instructions[edit]

RDTSC

RDTSC was introduced in the Pentium processor, the instruction reads the number of clock cycles since reset and returns the value in EDX:EAX. This can be used as a way of obtaining a low overhead, high resolution CPU timing. Although with modern CPU microarchitecture(multi-core, hyperthreading) and multi-CPU machines you are not guaranteed synchronized cycle counters between cores and CPUs. Also the CPU frequency may be variable due to power saving or dynamic overclocking. So the instruction may be less reliable than when it was first introduced and should be used with care when being used for performance measurements.

It is possible to use just the lower 32-bits of the result but it should be noted that on a 600 MHz processor the register would overflow every 7.16 seconds:

	2^{32} cycles * (1 second / 600,000,000 cycles) = 7.16 seconds

While using the full 64-bts allows for 974.9 years between overflows:

	2^{64} cycles * ((1 second / 600,000,000 cycles) / ( 86400 seconds\ in\ a\ day\ *\ 365\ days\ in\ a\ year) ) = 974.9 years

The following program (using NASM syntax) is an example of using RDTSC to measure the number of cycles a small block takes to execute:

global main 
 
extern printf
 
section .data
	align 4
	a:	dd 10.0
	b:	dd 5.0
	c:	dd 2.0
	fmtStr:	db "edx:eax = %llu edx = %d eax = %d", 0x0A, 0
 
section .bss
	align 4
	cycleLow:	resd 1
	cycleHigh:	resd 1
	result:		resd 1
 
section .text
	main:			; Using main since we are using gcc to link
 
;
;	op	dst,  src
;
	xor	eax, eax
	cpuid
	rdtsc
	mov	[cycleLow], eax
	mov	[cycleHigh], edx 
 
				;
				; Do some work before measurements 
				;
	fld	dword [a]
	fld	dword [c]
	fmulp	st1
	fmulp	st1
	fld	dword [b]
	fld	dword [b]
	fmulp	st1
	faddp	st1
	fsqrt
	fstp	dword [result]
				;
				; Done work
				;
 
	cpuid
	rdtsc
				;
				; break points so we can examine the values
				; before we alter the data in edx:eax and
				; before we print out the results.
				;
break1:
	sub	eax, [cycleLow]
	sbb	edx, [cycleHigh]
break2:
	push	eax
	push	edx
	push 	edx
	push	eax
	push	dword fmtStr
	call	printf
	add	esp, 20		; Pop stack 5 times 4 bytes
 
 
				;
				; Call exit(3) syscall
				;	void exit(int status)
				;
	mov	ebx, 0		; Arg one: the status
	mov	eax, 1		; Syscall number:
	int 	0x80

In order to assemble, link and run the program we need to do the following:

$ nasm -felf -g rdtsc.asm -l rdtsc.lst
$ gcc -m32 -o rdtsc rdtsc.o
$ ./rdtsc