Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
694 views
in Technique[技术] by (71.8m points)

linux - Access .data section in Position Independent Code

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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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      rcx, [rel last_tok wrt ..gotpc]    ; load the address from the GOT
    mov      rax, [rcx]                         ; load the old dq value from there
    ; and/or
    mov      [rcx], rdi                         ; store arg at that address
    ret

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

In a PIE executable, compilers use (the equivalent of) [rel symbol] to access even global variables, on the assumption that the main executable doesn't need or want symbol interposition for its own symbols.

(Symbol interposition, or symbols defined in other shared libraries, is the only reason to load symbol addresses from the GOT on x86-64. But even something like mov rdx, [rel stdin] is safe in a PIE executable: https://godbolt.org/z/eTf87e - the linker creates a definition of the variable in the executable so it's within range and at a link-time-constant offset for RIP-relative addressing.)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...