Access .data section in Position Independent Code

2019-02-25 07:52发布

问题:

I'm building a shared library with NASM. In that library, in some function, I need what we'd call a static variable in C. Basically, I think it is some space in the .data section:

    SECTION .data
last_tok:       dq 0 ; Define a QWORD

The problem arises when I try to access last_tok in my function.

I read the NASM Manual: 8.2 Writing Linux/ELF Shared Libraries which explains the problem and gives the solution.

    SECTION .data
last_tok:              dq 0     ; Define a QWORD

    SECTION .text
    EXTERN _GLOBAL_OFFSET_TABLE_
    GLOBAL strtok:function
strtok:
    enter    0, 0
    push     rbx
    call     .get_GOT
.get_GOT:
    pop      rbx
    add      rbx, _GLOBAL_OFFSET_TABLE_ + $$ - .get_GOT wrt ..gotpc

    mov      [rbx + last_tok wrt ..gotoff], rdi ; Store the contents of RDI at last_tok

    mov      rbx, [rbp - 8]
    leave
    ret

It may work with ELF32, but with ELF64 I get the following error:

nasm -f elf64  -o strtok.o strtok.s
strtok:15: error: ELF64 requires ..gotoff references to be qword
<builtin>: recipe for target 'strtok.o' failed
make: *** [strtok.o] Error 1

What am I doing wrong?

回答1:

The effective address format only allows for 32 bit displacement that is sign extended to 64 bit. According to the error message, you need full 64 bits. You can add it via a register, such as:

mov      rax,  last_tok wrt ..gotoff
mov      [rbx + rax], rdi 

Also, the call .get_GOT is a 32 bit solution, in 64 bit mode you have rip relative addressing which you can use there. While the above may compile, but I am not sure it will work. Luckily the simple solution is to use the mentioned rip relative addressing to access your variable thus:

    SECTION .data
    GLOBAL last_tok
last_tok:              dq 0     ; Define a QWORD

    SECTION .text
    GLOBAL strtok:function
strtok:
    mov      [rel last_tok wrt ..gotpc], rdi ; Store the contents of RDI at last_tok
    ret

Note that for a private (static) variable you can just use [rel last_tok] without having to mess with the got at all.