Hello everyone. 1
In this section, we will talk about things you should know about x86-64 instructions. 2
I will use some of the instructions in the examples. 3
So if you are a beginner, you can skip this lesson. When you learned the instructions in the following lessons 4
, 5
You can go back here. If you have learned x86 32-bit assembly language, 6
this lesson shows the differences between x86-32 and x86-64 instructions 7
. 8
And you can go to the specific part as they are listed in the timetable. 9
Okay let's get started. 10
In 64-bit mode, immediate value is generally 32 bits wide. So if you use an immediate value 11
larger than 32 bits, most immediate value will be truncated to 32 bits. 12
The only instruction which takes 64-bit immediate value is mov instruction. The format is mov 64-bit register 13
and immediate value. 14
For example, we can mov rax,0x1020304050607080, which has no problem but if we use it 15
in other instructions, say add instruction, we add rbx the same value 16
We first zero out rbx so that we can see clearly that this value is truncated. 17
Let's check it out in debug mode. Click step over. You can see rax holds the 64-bit value. 18
Next we zero out rbx and try add instruction. Ok as you see the value in rbx is 50607080. 19
So only lower 32-bit value is added in rbx. If you want to use 64-bit immediate value, 20
you can first save it in 64-bit register using mov instruction and then use the register 21
in the instructions. 22
The result in rbx is now what we expect. 23
Another thing you should be careful of when using immediate value is that the value may be 24
sign-extended. For example, the add instruction takes 32-bit immediate value. And we use 64-bit register operand 25
in this example, the processor sign extended 26
the immediate value to 64-bit value. What is sign extension? Sign extension basically means 27
copying the sign bit of a value into all the upper bits of a larger-size value, which preserves the original sign and value. 28
. 29
In this case the most significant bit of the immediate value 30
which is bit 31 is 0. 31
So when sign extend it to 64-bit value. The upper 32 bits are filled with 0s. 32
We clear rax and add the immediate value in rax. 33
. 34
If we change it to value 0x80000000, 35
the most significant bit is 1. 36
So this is a negative number. 37
When we add it to rax, it will be sign extended to 64-bit value 38
and the upper 32 bits are filled with 1s. 39
Let's check it out 40
in debug mode. 41
okay. 42
you can see the upper 8 hexadecimal digits are all Fs, which means the upper 32 bits in rax are filled with 1s. 43
. 44
If you want to interpret this value as positive number. You can save it to a register. 45
For example mov rbx,0x80000000 and then add rax rbx. Since mov r64 immediate format 46
can take 64-bit value, 47
we will save the value as it is in rbx. Let’s check it out. 48
As you see, the value of rbx is the value we want to save. And now we can add it to rax. 49
This part is about using 32-bit registers. When you write a value into lower 8 bits or 16 bits of the registers, 50
the upper bits will not be affected. For example, we mov -1 to r10 which is 64-bit register. 51
if we mov 0 to r10b which is 8-bit register, we can see only the lower 8 bits are changed to 0 52
and leave all other bits unchanged. Let's see the result. 53
R10 is equal to -1. We click step over. Ok you can see the last two hexadecimal digits 54
which are 8 bits are changed to 0 and other bits stay unchanged. 55
The same thing happens with 16 bits register. 56
Suppose we mov r10w,0. Let’s see what we get. 57
As you see the last four hexadecimal digits which are 16 bits are changed to 0 and other bits 58
remain unchanged. 59
But when we write a value to 32-bit register, the upper 32 bits of 64-bit register 60
are set to zero. 61
Let's test it 62
with other instructions this time. For example, or instruction. if we or r10d 63
which is 32bits register, 64
then it will set the upper 32 bits in r10 register to 0. 65
Let's see the results. 66
You can see we only get 8 hexadecimal digits showing here which means the upper 32 bits are cleared. 67
So writing data in 32-bit registers will zero out the upper bits of corresponding 64-bit registers. 68
. 69
OK 70
This part is about using 8-bit registers. If we use ah bh ch and dh in an instruction, 71
then we cannot use these 8-bit registers at the same time. For example, mov ah dil, xchg bh sil,xor ch r8b 72
and compare dh r10b. These are all invalid instructions. But we can still use the first 8 registers. 73
so mov ah al, xchg bh ch, xor dh cl have no problem. 74
This part is about push and pop instructions. In 64-bit mode, the default operation size for push and pop instructions 75
is 8 bytes. And push and pop instructions doesn’t accept 32-bit operands. So push eax, pop ebx, 76
push double word var. They are invalid instructions. We cannot do that. But we can still use 16-bit operand. 77
So push ax pop bx push word var have no problem. And also pusha pushad 78
which push all general-purpose registers on the stack, popa popad which pop all general-purpose registers from the stack 79
are invalid instructions.We cannot use them in 64-bit mode. 80
This part is about jump and call instructions. If we use register or memory operand, then we 81
can only use 64-bit operands. For example, call eax, jump ax, call word print and jump double word function 82
are all invalid instructions. So in this case we can only use call rax, jump rax, 83
call quadword print and jump quadword function. 84
Alright this is end of the lesson.