Why we use dynamic links and GOT tables
- We know that static linking is not so much a matter of directly binding all the functions you want to use together, and the offsets between the individual variables and functions can of course be calculated.
- But that's also the downside of static linking, it's just so bloated to call the same snippet over and over again!
- So we decided to separate the common libraries for everyone to use, we also know that .text is not modifiable, that is, when running can not be referenced like the linker to "fill" in the reserved "pit", so we still have to So we still have to pretend to tell the program where to jump to. For example, if I want to call puts, but I really don't know where the puts are (because dynamic linking occurs when the program is running), I'll also leave a pit called puts@got.
- The got table records the global offsets, i.e., where they are really stored, and is placed in the .data section so that it can be edited. You only need to know the first three table entries are: got [0] saved the address of the .dynamic segment, which describes the module dynamic links to the relevant information; got [1] saved the module's id; got [2] is really to help you find you want to function in which address, for example, he found the puts in the address 0x12345678 at which it fills in got [ 3]. Then when you see puts@got in the future, you jump directly to the address got[3] (this id assignment is planned by the linker).
Why we delayed binding and plt tables
It looks like the problem has been solved completely! The problem of .text not being editable has been solved with got, and it's also "position independent", so that's great!
But imagine if you execute a program that references 100000 functions, and now he's relying on the find function of got[2] to find them one by one ......
It's a disaster! Obviously anyone in their right mind could have thought, why not look for it "when you need it"? What's the point of searching for so long in the first place? What if there's an if-else, and one of the branches references 99% of the external functions, and it turns out that I didn't even get to that branch ......
OK! Now let's look at the plt logic:
- When I call puts@plt, I run to the plt code segment to perform these actions: jump to the got table, and if no one helped me find it on the first call, then the got table's address at this point is where plt just jumped, and it's back to plt!
- So let's continue! First press in the function id I'm looking for, then jmp to plt's public code segment.
- The public code segment is the same for all plt operations, and that is to call on the familiar got[2] to help us find the function.
- When got[2] is found, it will be filled into the got table, then the next time step 1 is executed, the location of the got table at this time is the location of the puts!
- Now it's time to use puts again! I call puts@plt, jump to the puts@plt snippet, then jump to the got table again, and then realize that someone actually got it for us!
I believe the above content can help you easily understand the mechanism of plt got, some specialized terms you can search for yourself. The principle of understanding looks a lot more convenient!