Hello, my name is Typhoon.
And now let's delve into the fascinating process of disassembling a binary.
Having witnessed how a binary is compiled, it's time to explore the contents of the object file generated
during the assembly phase of compilation.
Subsequently, I will guide you through the disassembly of the main binary executable, highlighting
the distinctions between its contents and those of the object file.
So this will provide you with a clearer understanding of what resides within an object file and what
is added during the linking phase.
To facilitate our disassembly journey, we will utilize objdump.
Utility.
It's a simple and user friendly disassembler that comes bundled in most Linux distributions.
For now we will rely on Objdump object dump to gain quick insights into the code and data encapsulated
within a binary.
And here what we're going to do here is we'll firstly run this red elf again or the Objdump here.
Objdump.
And SG here aero data and after that we will enter our data file.
In this case my app.au.
And here we will click.
Press enter.
And that's it.
So here we have this output.
And let's try another now another command with this here Objdump uppercase M and let's actually write
it again.
So Objdump uppercase.
M Intel D here.
And after that we will again pass the whole file here and that's it.
So here, if you look at carefully here, so.
You will see.
I called this Objdump twice.
First here.
I tell Objdump to show the contents of the dot or R or data section.
So this stands for read only data and it's part of the binary where all constants are stored.
So including this hello world here.
Right?
So we defined this.
Hello world.
Let me actually find a C file here.
So we define this.
Hello world as constants, right?
We define this macro here.
So here this is a read only data section of our binary file.
And here.
I will return to a more detailed discussion of this error data and on the other sections of Elf binaries
in next lectures, which we will also learn about Elf binary format.
So for now you can see that the contents of error data here consists of Ascii encoding here.
But we can see the Ascii encoding of the string.
And we also so this is the left side output.
On the right side, you can see it's the human readable representations of Jews.
Same bias.
Now let's look again at here we have this comma between the Hello world here.
I don't know why, but it's another mistyped here, probably.
And.
So we are seeing this comma between this hello world because we defined Hello world like that.
I mistyped the comma instead of space here.
Sorry for that.
And here.
That's it.
So.
You may wonder why the call that should reference Potts seems to point into the middle of the main function.
So as I mentioned before, data and code references from object files are not yet fully resolved during
compilation, so the compiler lacks knowledge of the base address at which the file will eventually
be loaded.
Consequently, the call to Potts in the object file remain unsolved.
It awaits the linker to fill in the correct value for this reference.
So you can verify this by employing read elf, which reveals all the relocation symbols present in the
object file.
And.
Here.
We can in second call here.
Um.
With this objdump here.
Disassembles all the code in the object file in Intel syntax, as we mentioned here.
As you can see, it contains only code of the main function.
All right, so.
Uh, this because that's only function defined in the source file.
Right?
So let's try that again here.
As you can see.
Oops, not.
As you can see here, we have this only function integer main function in our program and that's why
we are seeing this.
On the main function here.
So for the most part, the output conforms pretty closely to the assembly code previously produced by
the compilation phase.
Give or take a few the assembly level macros here.
What's interesting to note that is the the pointer to the Hello world string at here.
Eddie here.
This call here.
And we also have this ad.
R d.
A r.
A x.
Here.
This year is set to zero.
So and here the this call that should print the string to the screen using paths here.
Also points to a non-essential location here, as you can see.
So but.
We have the offset of.
I think there's one here.
So.
This prints too.
This shows some nonsensical location to us.
And why does the car that should reference Potts point instead into the middle of a main right and I
previously mentioned that the data and code references from object files are not yet fully resolved
because the compiler doesn't know at what base address the file will eventually be loaded.
That's why the call to the for the linker to fill in the correct value for this reference.
And here we will use the red elf here.
Red elf.
Relax here.
Relax and we will also again use the my app.
That all?
And that's it.
This is our output.
Using the red elf here, we use the relax parameter.
So the relocation.
This is a relocation symbol at here.
Has the linker that it should resolve the reference to the string to point to whatever address it ends
up at in the air or data.
Section.
So similarly, the line marked line, the second line after this offset here.
1A1.
A one.
A1E.
Here.
So.
Here.
Similarly the.
This line tells the linker how to resolve the calls to pots.
Right.
So you may notice that the value for here.
The the first one is zero and the second one is four being subtracted.
From the parts symbol.
So you can ignore that for now.
So the way the linker computes, relocation is a bit involved and the relative output can be confusing
in most cases.
So I will just gloss over the details of relocation here and focus on the bigger picture of this assembly.
A binary instead.
So I will provide more information about relocation symbols in next sections of our course.
And the leftmost column of each line in the output.
Uh, is the offset in the object file here?
Uh, where the resolved reference must be filled in.
So if you are paying close attention, you may notice that in both cases it's equal to the offset of
the instructions that needs to be fixed plus one.
For instance, the call to pots is at code offset.
Here is one.
A1A here, right?
And this is because you only want to override the operand of the instruction.
So not the opcode of the instruction itself.
So it just so happens that for both instructions that need fixing up the opcode is one byte long.
So it point to the instruction operand.
The relocation symbol needs to skip past the opcode byte.