【汇编优化】之对nasm中GOT的理解

【汇编优化】之对nasm中GOT的理解

转自:https://blog.csdn.net/listener51/article/details/79686102

参考:https://blog.csdn.net/erazy0/article/details/5452276

##1.Obtaining the Address of the GOT
Each code module in your shared library should define the GOT as an external symbol:

<span style="color:#000000"><code>extern  _GLOBAL_OFFSET_TABLE_   ; in ELF 
extern  __GLOBAL_OFFSET_TABLE_  ; in BSD a.out
</code></span>

At the beginning of any function in your shared library which plans to access your data or BSS sections, you must first calculate the address of the GOT. This is typically done by writing the function in this form:

<span style="color:#000000"><code>func:   push    ebp 
        mov     ebp,esp 
        push    ebx 
        call    .get_GOT 
.get_GOT: 
        pop     ebx 
        add     ebx,_GLOBAL_OFFSET_TABLE_+$$-.get_GOT wrt ..gotpc 

        ; the function body comes here 

        mov     ebx,[ebp-4] 
        mov     esp,ebp 
        pop     ebp 
        ret
</code></span>

(For BSD, again, the symbol _GLOBAL_OFFSET_TABLE requires a second leading underscore.)

The first two lines of this function are simply the standard C prologue to set up a stack frame, and the last three lines are standard C function epilogue. The third line, and the fourth to last line, save and restore the EBX register, because PIC shared libraries use this register to store the address of the GOT.

这个函数的头两行只是简单的标准的C风格的开头,用于设置栈框架,最后的三行是标准的C风格的结尾,第三行,和倒数第四行,分别保存和恢复'EBS'寄存器,因为PIC共享库使用这个寄存器保存GOT的地址。

The interesting bit is the CALL instruction and the following two lines. The CALL and POP combination obtains the address of the label .get_GOT, without having to know in advance where the program was loaded (since the CALL instruction is encoded relative to the current position). The ADD instruction makes use of one of the special PIC relocation types: GOTPC relocation. With the WRT …gotpc qualifier specified, the symbol referenced (here GLOBAL_OFFSET_TABLE, the special symbol assigned to the GOT) is given as an offset from the beginning of the section. (Actually, ELF encodes it as the offset from the operand field of the ADD instruction, but NASM simplifies this deliberately, so you do things the same way for both ELF and BSD.) So the instruction then adds the beginning of the section, to get the real address of the GOT, and subtracts the value of .get_GOT which it knows is in EBX. Therefore, by the time that instruction has finished, EBX contains the address of the GOT.

最关键的是'CALL'指令和接下来的两行代码。'CALL'和'POP'一起用来获得 .get_GOT的地址,不用进一步知道程序被载入到什么地方(因为call指令是解码 成跟当前的位置相关)。‘ADD’指令使用了一个特殊的PIC重定位类型:GOTPC 重定位。通过使用限定符'WRT ..gotpc',被引用的符号(这里是 `_GLOBAL_OFFSET_TABLE_',一个被赋给GOT的特殊符号)被以从段起始地址开始 的偏移的形式给出。(实际上,‘ELF’把它编码为从‘ADD’的操作数域开始的 一个偏移,但NASM把它简化了,所以你在‘ELF’和‘BSD’中可以用同样的方 式处理。)所以,这条指令然后加上段起始地址,然后得到GOT的真正的地址。 然后减去'.get_GOT'的值,当这条指令执行结束的时候,'EBX'中含有'GOT' 的值。

If you didn’t follow that, don’t worry: it’s never necessary to obtain the address of the GOT by any other means, so you can put those three instructions into a macro and safely ignore them:

<span style="color:#000000"><code>%macro  get_GOT 0 

        call    %%getgot 
  %%getgot: 
        pop     ebx 
        add     ebx,_GLOBAL_OFFSET_TABLE_+$$-%%getgot wrt ..gotpc 

%endmacro
</code></span>

###1.1 Obtaining the Address of the GOT的理解
for example: a function(here add_fun) writed by asm, and called by c
add.asm

<span style="color:#000000"><code>extern _GLOBAL_OFFSET_TABLE_
section .data

local_val: db 4
  
section .text
global add_fun
add_fun:
	push ebp  
	mov ebp, esp  
	push ebx
	call .get_GOT
.get_GOT:
	pop ebx
	
	mov ecx, $$
	mov ecx,_GLOBAL_OFFSET_TABLE_ wrt ..gotpc 
	mov ecx,.get_GOT
	
	add ebx,_GLOBAL_OFFSET_TABLE_+$$-.get_GOT wrt ..gotpc 
	mov eax, [esp + 8]  
	mov edx, [esp + 12]  
	add eax, edx;  
	mov edx, [ebx + local_val wrt ..gotoff]
	mov eax,edx
	mov esp, ebp  
	pop ebp  
	ret  
</code></span>
  •  
<span style="color:#000000"><code>#include<stdio.h>
#include<stdlib.h>
extern int add_fun(int a, int b);

int main()
{
	int sum = add_fun(2,3);
        printf("sum = %d\n", sum);
	return 0;
}
</code></span>

make.sh

<span style="color:#000000"><code>#!/bin/sh
gcc -g -m32 -c demo.c -fPIC -I. -o demo.o
yasm -m x86 -f elf -DPIC -I. add.asm -o add.o
gcc -g -m32 -o demo demo.o add.o
</code></span>

after compliled

<span style="color:#000000"><code>Dump of assembler code for function add_fun:
=> 0x56555580 <+0>:	    push   %ebp
   0x56555581 <+1>:	    mov    %esp,%ebp
   0x56555583 <+3>:  	push   %ebx
   0x56555584 <+4>:	    call   0x56555589 <add_fun+9>
   0x56555589 <+9>:	    pop    %ebx
   0x5655558a <+10>:	mov    $0x56555580,%ecx
   0x5655558f <+15>:	mov    $0x1a58,%ecx
   0x56555594 <+20>:	mov    $0x56555589,%ecx
   0x56555599 <+25>:	add    $0x1a4f,%ebx
   0x5655559f <+31>:	mov    0x8(%esp),%eax
   0x565555a3 <+35>:	mov    0xc(%esp),%edx
   0x565555a7 <+39>:	add    %edx,%eax
   0x565555a9 <+41>:	mov    0x30(%ebx),%edx
   0x565555af <+47>:	mov    %edx,%eax
   0x565555b1 <+49>:	mov    %ebp,%esp
   0x565555b3 <+51>:	pop    %ebp
   0x565555b4 <+52>:	ret    
   0x565555b5 <+53>:	xchg   %ax,%ax
   0x565555b7 <+55>:	xchg   %ax,%ax
   0x565555b9 <+57>:	xchg   %ax,%ax
   0x565555bb <+59>:	xchg   %ax,%ax
   0x565555bd <+61>:	xchg   %ax,%ax
   0x565555bf <+63>:	nop
</code></span>
  •  

(1)、0x56555584 <+4>: call 0x56555589 <add_fun+9>对应add.asm中的call .get_GOT
   0x56555589是.get_GOT的地址,另外执行完 0x56555589 <+9>: pop %ebx,ebx中存放的也是.get_GOT的地址(即0x56555589)。

(2)、 0x5655558a <+10>: mov $0x56555580,%ecx对应add.asm中的mov ecx, $$
  0x56555580是当前段的起始地址。

(3)、0x5655558f <+15>: mov $0x1a58,%ecx对应add.asm中的mov ecx,_GLOBAL_OFFSET_TABLE_ wrt ..gotpc
  0x1a58是当前段的偏移。

(4)、0x56555599 <+25>: add $0x1a4f,%ebx对应add.asm中的add ebx,_GLOBAL_OFFSET_TABLE_+$$-.get_GOT wrt ..gotpc
  执行完这条命令后,ebx中存放的是GOT的地址:0x565556fd8 = 0x1a4f + 0x56555589 = 0x1a58 + 0x56555580。

参考网址:http://coding.derkeiler.com/Archive/Assembler/comp.lang.asm.x86/2007-02/msg00041.html
参考网址:http://www.nasm.us/doc/nasmdoc9.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值