64位下的相对指令地址-X86指令格式(操作码列和指令列解释)
寻找64位系统某符号特征码时发现他的MOV指令⽤的是相对地址,之前32位下从来没听说MOV还能⽤相对地址,故查阅了下Intel指令⼿册。在MOV指令介绍下找到如下介绍:
In 64-bit mode, the instruction’s default operation size is 32 bits. U of the REX.R prefix permits access to additional
registers (R8-R15). U of the REX.W prefix promotes operation to 64 bits. See the summary chart at the
beginning of this ction for encoding data and limits.
在64位下仍使⽤32位操作数,REX.R扩展寄存器,REX.W扩展指令。
REX前缀结构:
羽高念什么
关于RIP的介绍:
2.2.1.6 RIP-Relative Addressing
A new addressing form, RIP-relative (relative instruction-pointer) addressing, is implemented in 64-bit mode. An
effective address is formed by adding displacement to the 64-bit RIP of the next instruction.
In IA-32 architecture and compatibility mode, addressing relative to the instruction pointer is available only with
control-transfer instructions. In 64-bit mode, instructions that u ModR/M addressing can u RIP-relative
addressing. Without RIP-relative addressing, all ModR/M modes address memory relative to zero.
RIP-relative addressing allows specific ModR/M modes to address memory relative to the 64-bit RIP using a signed
32-bit displacement. This provides an offt range of ±2GB from the RIP. Table 2-7 shows the ModR/M and SIB
encodings for RIP-relative addressing. Redundant forms of 32-bit displacement-addressing exist in the current
ModR/M and SIB encodings. There is one ModR/M encoding and there are veral SIB encodings. RIP-relative
addressing is encoded using a redundant form.
In 64-bit mode, the ModR/M Disp32 (32-bit displacement) encoding is re-defined to be RIP+Disp32 rather than
displacement-only. See Table 2-7.
The ModR/M encoding for RIP-relative addressing does not depend on using a prefix. Specifically, the r/m bit field
encoding of 101B (ud to lect RIP-relative addressing) is not affected by the REX prefix. For example, lecting
R13 (REX.B = 1, r/m = 101B) with mod = 00B still results in RIP-relative addressing. The 4-bit r/m field of REX.B
combined with ModR/M is not fully decoded. In order to address R13 with no displacement, software must encode
婚姻存续期R13 + 0 using a 1-byte displacement of zero.
RIP-relative addressing is enabled by 64-bit mode, not by a 64-bit address-size. The u of the address-size prefix
does not disable RIP-relative addressing. The effect of the address-size prefix is to truncate and zero-extend the
computed effective address to 32 bits.
RIP是64位的新特性,在64位下,指令使⽤特定的Mod\rm来使⽤RIP,RIP的偏移是32位故寻址范围为上下2GB。RIP的计算时相对于当前指令的下⼀条指令的地址来计算的,既⽬标地址=下⼀条指令地址+偏移。RIP中ModR\M不取决于指令前缀,⽐如指令前缀与R\M指定了R13寄存器,但mod是00,指令仍然使⽤RIP⽽不是r13寄存器。
举个例⼦,原始指令:4c8b2dedd9eaff
其中4c是REX,打开了W和R,即R和reg联合制定了r13寄存器,但不⽤SIB,2d则是00101101,就是使⽤RIP,后⾯是32位偏移。
在计算MOV指令的地址时可以这样算:
//算出ObpLookupObjectByName的地址
ULONG_PTR ObpLookupObjectByName = (ULONG_PTR)((PUCHAR)tg1_addr + 0x301 + 5 + offt);
//在ObpLookupObjectByName的偏移62C处是指令MOV R13,ObRootDirectoryObject
//⽽加7则定位到下⼀条指令
ULONG_PTR next_code = (ULONG_PTR)((PUCHAR)ObpLookupObjectByName + 0x62C + 7);
//取出偏移值
UINT32 rip = *(PINT32)((PUCHAR)ObpLookupObjectByName + 0x62C + 3);
//⽤下⼀条指令地址+偏移值即可得到⽬标地址
POBJECT_DIRECTORY ObRootDirectoryObject= (POBJECT_DIRECTORY)((ULONG_PTR)next_code+rip);
IMMEDIATE ⽴即数
REGISTER 寄存器操作数
MEMORY 内存操作数
REGISTER_RIP 寄存器相对指令地址
AT&T汇编语⾔语法与Intel的类似,你可以参考gas⼿册。
区别在下⾯⼏点(摘⾃gas manual):
AT&T Syntax versus Intel Syntax //AT&T语法与Intel语法的对⽐
-------------------------------
orignal:
In order to maintain compatibility with the output of gcc, as supports AT&T System V/386 asmbler syntax.
This is quite different from Intel syntax.
We mention the differences becau almost all 80386 documents ud only Intel syntax.
Notable differences between the two syntaxes are:
翻译:
为了与gcc的output(gcc -s source_file)保持兼容,因为gcc⽀持AT&T System V/386汇编语法格式。
这种AT&T的汇编语法格式与Intel的汇编语法格式有显著的不同。难忘的一次
我们之所以提到这些不同,是因为⼏乎所有的80386 documents ⽂档都使⽤Intel的语法格式。
这两种语法格式的显著区别如下:
1>⽴即数:(immediate operand)
AT&T immediate operands are preceded by `$'; //AT&T的⽴即数前有前导的'$‘;
Intel immediate operands are undelimited (Intel `push 4' is AT&T `pushl $4'). //Intel的⽴即数没有限定符
2>寄存器操作数:(register operand)
AT&T register operands are preceded by `%'; //AT&T的寄存器操作数前有前导的%限定
Intel register operands are undelimited. //Intel的寄存器操作数没有限定。
3>绝对跳转指令:(absolute jump/call)
AT&T absolute (as oppod to PC relative) jump/call operands are prefixed by `*'; //AT&T的绝对跳转指令前有前缀*;
they are undelimited in Intel syntax. //Intel的绝对跳转指令前没有限定。
4> 源操作数和⽬的操作数的位置:(source and destination location)
AT&T and Intel syntax u the opposite order for source and destination operands. //两者源操作数与⽬的操作数的位置相反Intel `add eax, 4' is `addl $4, %eax'. // Intel的格式: op-code ⽬的操作数,源操作数;
// AT&T的格式:op-code源操作数,⽬的操作数;
The `source, dest' convention is maintained for compatibility with previous Unix asmblers.
//AT&T的这种’源操作数,⽬的操作数‘的约定(规约)是为了与先前的Unix Asmblers保持兼容性。
5>内存操作数的size:(b, w, l, )
//在AT&T语法格式中,操作数的存储尺⼨是由op-code最后⼀个字符决定的:
//b (byte, 8), w(word,16), l(long, 32)。
In AT&T syntax the size of memory operands is determined from the last character of the opcode name.
Opcode suffixes of `b', `w', and `l' specify byte (8-bit), word (16-bit), and long (32-bit) memory references.
//Intel 语法实现操作数的size通过,operand的前缀,如,byte ptr (byte, 8), word ptr(word,16), dword ptr(double word, 32) Intel syntax accomplishes this by prefixes memory operands (not the opcodes themlves)
with `byte ptr', `word ptr', and `dword ptr'.
//两者间的等价举例:
Thus, Intel `mov al, byte ptr foo' is `movb foo, %al' in AT&T syntax.
6>长jump/call 和长ret (long jumps/calls and long ret)
Immediate form long jumps and calls are `lcall/ljmp $ction, $offt' in AT&T syntax;
//AT&T语法格式:lcall/ljmp $ction, $offt
the Intel syntax is `call/jmp far ction:offt'.
//Intel语法格式:call/jmp far ction:offt
//同样 long return,指令也相似:
Also, the far return instruction is `lret $stack-adjust' in AT&T syntax; //AT&T语法格式
Intel syntax is `ret far stack-adjust'. //Intel语法格式
7>其他: multiple ctions
The AT&T asmbler does not provide support for multiple ction programs.
//AT&T asbmler 不提供对多段程序的⽀持。
Unix style systems expect all programs to be single ctions.
Unix风格的系统认为所有的程序都是⼀个段。
8> references: 参考书⽬:
补充:
Brennan's Guide to Inline Asmbly
by Brennan "Bas" Underwood
Document version 1.1.2.2
Ok. This is meant to be an introduction to inline asmbly under DJGPP. DJGPP is bad on GCC, s
o it us the AT&T/UNIX syntax and has a somewhat unique method of inline asmbly. I spent many hours figuring some of this stuff out and told Info that I hate it, many times.
Hopefully if you already know Intel syntax, the examples will be helpful to you. I've put variable names, register names and other literals in bold type.
The Syntax电脑强制重启
So, DJGPP us the AT&T asmbly syntax. What does that mean to you?
Register naming:
Register names are prefixed with "%". To reference eax:
AT&T: %eax
Intel: eax
Source/Destination Ordering:
In AT&T syntax (which is the UNIX standard, BTW) the source is always on the left, and the destinati
on is always on the right.
So let's load ebx with the value in eax:
4人斗地主AT&T: movl %eax, %ebx
第九套广播体操教案
Intel: mov ebx, eax
Constant value/immediate value format:
You must prefix all constant/immediate values with "$".
Let's load eax with the address of the "C" variable booga, which is static.
AT&T: movl $_booga, %eax
Intel: mov eax, _booga
Now let's load ebx with 0xd00d:
公司管理制度大全完整版AT&T: movl $0xd00d, %ebx
Intel: mov ebx, d00dh
Operator size specification:
You must suffix the instruction with one of b, w, or l to specify the width of the destination register as a byte, word or longword. If you omit this, GAS (GNU asmbler) will attempt to guess. You don't want GAS to guess, and guess wrong! Don't forget it.
AT&T: movw %ax, %bx
Intel: mov bx, ax
The equivalent forms for Intel is byte ptr, word ptr, and dword ptr, but that is for when
Referencing memory:
DJGPP us 386-protected mode, so you can forget all that real-mode addressing junk, including the restrictions on which register has what default gment, which registers can be ba or index pointers. Now, we just get 6 general purpo registers. (7 if you u ebp, but be sure to restore it yourlf or compile with -fomit-frame-pointer.)
Here is the canonical format for 32-bit addressing:
AT&T: immed32(bapointer,indexpointer,indexscale)
Intel: [bapointer + indexpointer*indexscale + immed32]
You could think of the formula to calculate the address as:
immed32 + bapointer + indexpointer * indexscale
You don't have to u all tho fields, but you do have to have at least 1 of immed32, bapointer and you MUST add the size suffix to the operator!
Let's e some simple forms of memory addressing:
Addressing a particular C variable:
AT&T: _booga
Intel: [_booga]
Note: the underscore ("_") is how you get at static (global) C variables from asmbler. This only works with global variables.
Otherwi, you can u extended asm to have variables preloaded into registers for you. I address that farther down.
Addressing what a register points to:
AT&T: (%eax)
Intel: [eax]
Addressing a variable offt by a value in a register:
AT&T: _variable(%eax)
Intel: [eax + _variable]
Addressing a value in an array of integers (scaling up by 4):
AT&T: _array(,%eax,4)
Intel: [eax*4 + array]
You can also do offts with the immediate value:
C code: *(p+1) where p is a char *
新教师自我介绍
AT&T: 1(%eax) where eax has the value of p
Intel: [eax + 1]
You can do some simple math on the immediate value:
AT&T: _struct_pointer+8
I assume you can do that with Intel format as well.
Addressing a particular char in an array of 8-character records:
eax holds the number of the record desired. ebx has the wanted char's offt within the record.
AT&T: _array(%ebx,%eax,8)
Intel: [ebx + eax*8 + _array]
Whew. Hopefully that covers all the addressing you'll need to do. As a note, you can put esp into the address, but only as the ba register.
Basic inline asmbly