13 hours 15 minutes
Hello. This is Dr Miller, and this is Episode 15.5 of Assembly.
Today we're gonna talk about static linking and dynamic linking, and that will include the got and the plt.
So static, linking
static linking provides the ability for us to reuse code. And when we do that, all of that code gets placed inside of the binary that we are building.
And so, for example, if you want to use open SSL, then you can include all of the open SSL code inside of your binary.
Now, what this does is is going to use more space
and then if multiple programs are going to use that library, so like openess s L, then that library is going to get loaded multiple times.
Another issue is that if you update the library, then you have to rebuild your entire code. Um, toe add that library in there
so we can contrast that with dynamic linking.
So in dynamic linking, the
code is said, it run time, and this provides the ability for us to have shared code.
And one of the things that we're going to have with security is address, space layout, random ization. So a S o. R.
And what this does is every time a library runs, it's going to run at a different address. And so the actual address where that that library gets loaded is changed by the Oso. It's different every single time.
And this makes hacking and attacking exploits more difficult because the addresses aren't known beforehand. So this is one technique that was used a lot, was to hard code addresses for specific binaries and then use those in order to, um, leverage when you're doing an attack.
No, on Lenox, these dynamic libraries air called shared objects or dot Esso's
and then on Windows they're called dynamically linked libraries or DLL.
And then we also have, ah, notion of what's called absolute code.
That is, a piece of code is loaded at a specific address, and then the linker or loader will actually remap that code to a bunch of new addresses.
And so a lot of times with old binaries, we would see that they actually get created all at the same address, and then whatever binary is loaded first, the linker the loader will remap it to the new address is so that that code can run.
But one of the notions that we have in Lennox is this notion of position, independent code or pick.
And so in this, the code doesn't actually at reference an absolute address. And this is usually made possible by the fact that on 64 bit operating systems we have the ability to do. Um, address is based on the program counter, and so then you can have things relative to each other
in a way that
makes it so. It's easy to create position, independent code,
so the global offset table or got.
So this is a tables of addresses that points to dynamic addresses,
and this will be the the address of variable. So if you create a static variable or a function, and so these are the things that a shared library is going to provide, it will provide
variables, are constants and provide functions that the programmer can use.
And then the way this is set up is that initially, each one of these pointers points to the dynamic linker, and so the first time it gets used, the dynamic Linker is going to actually update that offset.
And then after that, it's going to use the new updated address instead of pointing to the linker. So the pointer gets changed so that every time after the first time it'll go faster and this is generally called lazy initialization or lazy resolution.
We also have the procedure linking table or PLT,
and what this does is it provides a mechanism to resolve dynamic memory addresses. So if I need to get the memory just of
a function, the PLT has the ability in order to do that. And so it has those addresses of where those, um, libraries are located.
And so it allows us to create pick and pi code or position independent code or position independent. Execute herbal.
So one example is the Lin X dynamic loader or L D.
And it's in L d d I S O. And this provides us the ability to look up different libraries.
So a couple of places that it typically looks in is slash lib or slash user slip lib, and it uses those absolute pass, or it can use the LD library path environment variable. And so, if you're gonna build a binary and you don't wanna put it in user lib or in Lib
and you want to go test it in your own space. You can use the LD library path
variable for that.
So here's an example. So that the first time that we call the puts function. So I put a couple different examples of using puts. So it called it two different times and so we can see inside of here. It's going to jump at the puts at PLT,
and so when we do this call, it's going to jump into the puts at the PLT inside of the code. And we can see that again. We're going to use rip or the um R i P
for that. And so we're using addresses based on the instruction pointer and not absolute addresses.
So we can hear See here that the puts is going to jump into here, which then is going to jump into a, um, location in memory
And what this is if you look inside of here. So I just did a trace. As I was stepping through this program, we can see that this is running the d l runtime resolve Ah, function inside of there.
So again, the first time we call it. It ends up trying to resolve what that address is for the function called puts, which is in a shared library.
But then when we call it a second time, we see again. We call puts that plt. It's going to do a jump
into the location at this address, and now we are actually in the puts library.
So the first time it ends up getting to the puts library didn't put that in the screen shot. But here we reduce that step. And so this is how the dynamic linker and will resolve
the address of whatever function it is that you're trying to get.
So today we talked about static linking and then dynamic linking using the got and the PLT.
In a future lecture, we'll talk about creating example Dynamic library.
You have questions you can email me Miller MJ at you and Kate I e d U and can find me on Twitter at Milhouse 30