首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >GOT与GOTOFF的差异

GOT与GOTOFF的差异
EN

Stack Overflow用户
提问于 2019-10-11 18:04:28
回答 1查看 702关注 0票数 1

我是32位程序集的初学者,我试着将一个简单的C程序编译成程序集。除了使用GOTOFF之外,我大部分都能理解。

代码语言:javascript
复制
    .file   "main.c"
    .text
    .section    .rodata
.LC0:
    .string "Hello world"
    .text
    .globl  main
    .type   main, @function
main:
.LFB0:
    .cfi_startproc
    leal    4(%esp), %ecx
    .cfi_def_cfa 1, 0
    andl    $-16, %esp
    pushl   -4(%ecx)
    pushl   %ebp
    .cfi_escape 0x10,0x5,0x2,0x75,0
    movl    %esp, %ebp
    pushl   %ebx
    pushl   %ecx
    .cfi_escape 0xf,0x3,0x75,0x78,0x6
    .cfi_escape 0x10,0x3,0x2,0x75,0x7c
    call    __x86.get_pc_thunk.ax
    addl    $_GLOBAL_OFFSET_TABLE_, %eax
    subl    $12, %esp
    leal    .LC0@GOTOFF(%eax), %edx     # <- Here
    pushl   %edx
    movl    %eax, %ebx
    call    puts@PLT
    addl    $16, %esp
    movl    $0, %eax
    leal    -8(%ebp), %esp
    popl    %ecx
    .cfi_restore 1
    .cfi_def_cfa 1, 0
    popl    %ebx
    .cfi_restore 3
    popl    %ebp
    .cfi_restore 5
    leal    -4(%ecx), %esp
    .cfi_def_cfa 4, 4
    ret
    .cfi_endproc
.LFE0:
    .size   main, .-main
    .section    .text.__x86.get_pc_thunk.ax,"axG",@progbits,__x86.get_pc_thunk.ax,comdat
    .globl  __x86.get_pc_thunk.ax
    .hidden __x86.get_pc_thunk.ax
    .type   __x86.get_pc_thunk.ax, @function
__x86.get_pc_thunk.ax:
.LFB1:
    .cfi_startproc
    movl    (%esp), %eax
    ret
    .cfi_endproc
.LFE1:
    .ident  "GCC: (GNU) 9.2.0"
    .section    .note.GNU-stack,"",@progbits

为什么要使用GOTOFF?GOT的地址不是已经加载在%eax中了吗?GOT和GOTOFF有什么区别?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-10-11 22:45:48

符号@GOTOFF处理变量本身,相对于GOT基(作为一个方便但任意选择的锚)lea给出符号地址,mov给出符号处的数据。(在本例中,字符串的前几个字节。)

符号@ GOT为该符号提供GOT条目的偏移量(在GOT内)。从那里加载的mov将给出符号的地址。(获取条目由动态链接器填写)。

Why use the Global Offset Table for symbols defined in the shared library itself?有一个访问extern变量的示例,该变量会从GOT获取其地址,然后取消引用。

顺便说一下,这是与位置无关的代码。你的GCC在默认情况下是这样配置的。如果您使用-fno-pie -no-pie来制作一个传统的位置相关的可执行文件,那么您将得到一个正常有效的pushl $.LC0。(32位缺少RIP相对寻址,因此效率很低。)

在非饼类(或64位派)中,GOT几乎不被使用。主可执行文件为符号定义了空间,这样它就可以访问符号,而无需经过GOT。libc代码无论如何都会使用GOT (主要是因为64位代码中的符号插入),因此让主可执行文件提供符号不需要花费任何费用,并且使非饼形可执行文件更快。

我们可以使用-fno-plt直接为共享库函数地址使用GOT,而不是调用PLT并让它使用GOT。

代码语言:javascript
复制
#include <stdio.h>
void foo() { putchar('\n'); }

gcc9.2 -O3 -m32 -fno-plt on Godbolt (与您的系统不同,-fno-pie是戈德波特编译器资源管理器的默认设置)。

代码语言:javascript
复制
foo():
        sub     esp, 20                  # gcc loves to waste an extra 16 bytes of stack 
        push    DWORD PTR stdout         # [disp32] absolute address
        push    10
        call    [DWORD PTR _IO_putc@GOT]
        add     esp, 28
        ret

pushcall都有一个使用32位绝对地址的内存操作数.push正在从一个已知的(链接时间常数)地址加载stdoutFILE*值.(它没有文本重定位。)

call正在加载动态链接器从GOT保存的函数指针。(并直接将其加载到EIP。)

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58346418

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档