Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Confused by text at page 307 #36

Closed
yeah-boi opened this issue Aug 15, 2017 · 2 comments
Closed

Confused by text at page 307 #36

yeah-boi opened this issue Aug 15, 2017 · 2 comments

Comments

@yeah-boi
Copy link
Contributor

I'm confused by the following text at page 307:

When the variable is declared as global with its size and type (:data), it will live in the .data section of the executable file rather than the library! Because of this, you will always have to access it through GOT, even in the same file.

Is this really true? Lets modify ex2-main.asm like this:

extern _GLOBAL_OFFSET_TABLE_

global _start

extern sofun

global msg:data (msg.end - msg)

section .rodata

    msg: db "SO function called -- message is stored in 'main'", 10
    .end:

section .text
    
    _start:
        call sofun  wrt ..plt

        mov rax, 1
        mov rdi, 1
        mov rsi, msg ; No need to access via GOT.
        mov rdx, 50
        syscall

        mov rdi, 0
        mov rax, 60
        syscall

Here we are accessing msg directly without GOT and things seem to work fine (the string is printed twice).

@sayon
Copy link
Collaborator

sayon commented Dec 31, 2017

Sorry to have missed this issue for a long time, let me make this a bit more clear.

  1. If any variable is global to the process (is used by multiple objects), it has to be accessed through GOT. The reason is that the dynamic loader will select only one of its copies so that when one object modifies it, the other objects will see the change. It is important if the said variable is modified.

  2. Which object will host the variable in run time depends on which libraries are loaded and in which order. The libraries and their dependencies are first loaded in depth-first-order (for each library, its dependencies are loaded before itself), then the dynamic linker performs symbol resolution.

For each GOT (unique per object) the dynamic linker crawls the libraries in a breadth-first-order. It is building the 'global lookup scope' this way. The first object containing the said variable will be its host. The GOT will be

  1. An optimization occurs: If a variable is declared in both shared library AND main executable file, we are going to select the instance in the main executable file. It is happening for two reasons:
  • The executable file is always first in the global lookup scope, so we can guarantee that this is the good place to store the variable.
  • This allows to bypass GOT usage and use absolute addresses inside the executable when addressing the said variable AND the executable is non-PIC. It is faster (GOT introduces overhead) and, in this context, it is safe. But in the dynamic library compiled with PIC enabled, you should always use GOT to address global-global variables because you can never know, where does this variable belong in run time.

You can check the said facts by declaring a variable in both executable file and a shared library. Then print its address and hang. Something like:
Library:

int g = 10;
void f(void) {
printf("%p\n", &g);
}

Executable:

int g;
int main(void) {
g++;
f();
while (1);
return 0;
}

Then compile it, link and launch in background. Use /proc/<PID>/maps file to check where does this address belong: you are going to see that it belongs to the executable's .data section; moreover, in the disassembly, you are going to see that during the increment this variable is going to be addressed by its absolute address rather than through GOT.

@sayon sayon closed this as completed Jan 13, 2018
@yeah-boi
Copy link
Contributor Author

Thanks for your detailed explanation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants