Differences in disassembly of an object and executable file - c

Basically, I used objdump -D to dis-assemble an object file and an ELF file. The major difference I see between the two is that.
I see the instructions in the object file (of the individual segments) have an address that starts with 0. Hence the consecutive addresses of are offset by a certain value, probably depending upon the length of the op-code corresponding to that specific instruction.
Disassembly of section .text:
00000000 <main>:
0: 8d 4c 24 04 lea 0x4(%esp),%ecx
4: 83 e4 f0 and $0xfffffff0,%esp
7: ff 71 fc pushl -0x4(%ecx)
a: 55 push %ebp
On the other hand, for an ELF fine I see a 32-bit address space for the instructions.Also If I print the address of main in my program. It is equivalent to the address in my dis-assembled ELF.
08048394 <main>:
8048394: 8d 4c 24 04 lea 0x4(%esp),%ecx
8048398: 83 e4 f0 and $0xfffffff0,%esp
804839b: ff 71 fc pushl -0x4(%ecx)
804839e: 55 push %ebp
The questions here are.
What does the addresses in ELF file actually refer to?
How does the linker compute them?

The ELF file contains code linked together against the preferred load address of the executable (and you can change the preference through linker options). The addresses you're seeing are computed by objdump against that address, which is part of the ELF format.
The object-code has no load address (yet) because it isn't linked into a loadable image. Once it is stitched together with linker (along with the rest of the object code and shared object references) the final output moves all that code into position against the preferred load address (sort of... the loader is what actually does this when the ELF image is loaded for execution). Suggested further reading (and there are a TON of links out there)

Related

Return values in main vs _start

Note, this question already has similar answers here, which I want to point out to:
"global main" in Assembly
What is global _start in assembly language?
However this question is asking more about the return formats of them and how they relate to each other (which I don't think is entirely covered in the above questions).
What are the differences between _start and main ? It seems to me like ld uses _start, but that gcc uses main as the entry point. The other difference that I've noticed is that main seems to return the value in %rax, whereas _start returns the value in %rbx
The following is an example of the two ways I'm seeing this:
.globl _start
_start:
mov $1, %rax
mov $2, %rbx
int $0x80
And to run it:
$ as script.s -o script.o; ld script.o -o script; ./script; echo $?
# 2
And the other way:
.globl main
main:
mov $3, %rax
ret
And to run it:
$ gcc script.s -o script; ./script; echo $?
3
What is the difference between these two methods? Does main automatically invoke _start somewhere, or how do they relate to each other? Why does one return their value in rbx whereas the other one returns it in rax ?
TL:DR: function return values and system-call arguments use separate registers because they're completely unrelated.
When you compile with gcc, it links CRT startup code that defines a _start. That _start (indirectly) calls main, and passes main's return value (which main leaves in EAX) to the exit() library function. (Which eventually makes an exit system call, after doing any necessary libc cleanup like flushing stdio buffers.)
See also Return vs Exit from main function in C - this is exactly analogous to what you're doing, except you're using _exit() which bypasses libc cleanup, instead of exit(). Syscall implementation of exit()
An int $0x80 system call takes its argument in EBX, as per the 32-bit system-call ABI (which you shouldn't be using in 64-bit code). It's not a return value from a function, it's the process exit status. See Hello, world in assembly language with Linux system calls? for more about system calls.
Note that _start is not a function; it can't return in that sense because there's no return address on the stack. You're taking a casual description like "return to the OS" and conflating that with a function's "return value". You can call exit from main if you want, but you can't ret from _start.
EAX is the return-value register for int-sized values in the function-calling convention. (The high 32 bits of RAX are ignored because main returns int. But also, $? exit status can only get the low 8 bits of the value passed to exit().)
Related:
Why am I allowed to exit main using ret?
What happens with the return value of main()?
where goes the ret instruction of the main
What happens if you use the 32-bit int 0x80 Linux ABI in 64-bit code? explains why you should use syscall, and shows some of the kernel side of what happens inside the kernel after a system call.
_start is the entry point for the binary. Main is the entry point for the C code.
_start is specific to a toolchain, main() is specific to a language.
You can't simply start executing compiled C code, you need a bootstrap, some code that preps the minimum things that a high level language like that requires, other languages have a longer list of requirements but for C you need to either through the loader if on an operation system or the bootstrap or both a solution for the stack pointer so that there is a stack, the read/write global data (often called .data) is initialized and the zeroed (often called .bss) data is zeroed. Then the bootstrap can call main().
Because most code runs on some operating system, and the operating system can/does load that code into ram it doesn't need a hard entry point requirement as you would need for booting a processor for example where there is a hard entry point or there is a hard vector table address. So gnu is flexible enough and some operating systems are flexible enough that the entry point of the code doesn't have to be the first machine code in the binary. Now that doesn't mean that _start indicates the entry point per se as you need to tell the linker the entry point ENTRY(_start) for example if you use a linker script for gnu ld. But the tools do expect a label to be found called _start, and if the linker doesn't then it issues a warning, it keeps going but issues a warning.
main() is specific to the C language as the C entry point, the label the bootstrap calls after it does its job and is ready to run the compiled C code.
If loading into ram and if the binary file format supports it and the operating system's loader supports it the entry point into the binary can be anywhere in the binary, indicated in the binary file.
You can kind of think of _start as the entry point into the binary and main as the entry point into the compiled C code.
The return for a C function is defined by the calling convention that C compiler uses, which the compiler authors are free to do whatever they want, but modern times they often conform to a target defined (ARM, x86, MIPS, etc) defined convention. So that C calling convention defines exactly how to return something depending on the thing, so int main () is a return of an int but float myfun() might have a different rule within the convention.
The return from a binary if you can even return, is defined by the operating system or operating environment which is independent of the high level language. So on a mac on an x86 processor the rule may be one thing on Windows on an x86 the rule may be another, on Ubuntu Linux on the same x86 may be another, bsd, another, probably not but Mint Linux another, and so on.
The rules and system calls are specific to the operating system not the processor or computer or certainly not the high level language that does not directly touch the operating system anyway (handled in bootstrap or library code not in high level language code). A number of them you are supposed to make a system call not simply return a value in a register, but clearly the operating system needs to be robust enough to handle an improper return, for malformed binaries. And/or allow that as a legal return without an exiting system call, and in that case would then define a rule for how to return without a system call.
As far as main calling _start you can easily see this yourself:
int main ( void )
{
return(5);
}
readelf shows:
Entry point address: 0x500
objdump shows (not the whole output here)
Disassembly of section .init:
00000000000004b8 <_init>:
4b8: 48 83 ec 08 sub $0x8,%rsp
4bc: 48 8b 05 25 0b 20 00 mov 0x200b25(%rip),%rax # 200fe8 <__gmon_start__>
4c3: 48 85 c0 test %rax,%rax
4c6: 74 02 je 4ca <_init+0x12>
4c8: ff d0 callq *%rax
4ca: 48 83 c4 08 add $0x8,%rsp
4ce: c3 retq
...
Disassembly of section .text:
00000000000004f0 <main>:
4f0: b8 05 00 00 00 mov $0x5,%eax
4f5: c3 retq
4f6: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
4fd: 00 00 00
...
0000000000000500 <_start>:
500: 31 ed xor %ebp,%ebp
502: 49 89 d1 mov %rdx,%r9
505: 5e pop %rsi
506: 48 89 e2 mov %rsp,%rdx
509: 48 83 e4 f0 and $0xfffffffffffffff0,%rsp
50d: 50 push %rax
50e: 54 push %rsp
50f: 4c 8d 05 6a 01 00 00 lea 0x16a(%rip),%r8 # 680 <__libc_csu_fini>
516: 48 8d 0d f3 00 00 00 lea 0xf3(%rip),%rcx # 610 <__libc_csu_init>
51d: 48 8d 3d cc ff ff ff lea -0x34(%rip),%rdi # 4f0 <main>
524: ff 15 b6 0a 20 00 callq *0x200ab6(%rip) # 200fe0 <__libc_start_main#GLIBC_2.2.5>
52a: f4 hlt
52b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
So you can see everything I mentioned above. The entry point for the binary is not at the beginning of the binary. The entry point (for the binary) is _start, somewhere in the middle of the binary. And somewhere after _start (not necessarily as close as seen here, could be buried under other nested calls) main is called from the bootstrap code. It is assumed that .data and .bss and the stack are setup by the loader not by the bootstrap before calling the C entry point.
So in this case which is typical _start is the entry point for the binary, somewhere after it bootstraps for C it calls the C entry point main(). As the programmer though you control which linker script and bootstrap are used and as a result don't have to use _start as the entry point you can create your own (certainly can't be main() though, unless you are not fully supporting C and possibly other exceptions related to the operating system).

data reserved in functions in C

In C programming language, a variable can have a memory address and a value.
And as I understood every function as well have an address and also data which allocated at that address. My question is what is the meaning of the data which these functions point to?
You already got (good) answers, but I think some (obscure?) fact about C should be pointed out, regarding your question:
In C programming language, a variable can have a memory address and a value.
Actually the defining property of a variable is that is always has a value – if it's uninitialized, semantically it still has a value, only that this value is the "undefined value" and reading the "undefined value" invokes undefined behaviour.
But, and this is important, not every variable in C does have an address! There is this little storage classifier register, which exact meaning most people do not fully comprehend. The most widespread – and wrong – interpretation is, that register means that the variable is to be placed in registers only. The problem is: There are instruction architectures in which registers do not exist, but C has been designed to be still viable for them.
The true meaning of the register classifier is, that you can not take the address of a variable that is register, which means you can not create pointers toward it.
The upshot of this is, that a variable that is register the only important thing is its value. And it is perfectly legal for the C compiler to generate code that completely discards the "place" (be it register, memory location or something entirely different) where its value came to be, as long as it able to faithfully recreate the value in a way, that it is semantically conforming to the program text. This also implies that it is perfectly legal to perform a whole re-computation of whatever had to be executed to obtain the final value. Which is why applying the register storage qualifier to variable may result in sudden increase of code size and drop of performance.
As such the register storage qualifier is not a mechanism for optimizing code, but should be treated as a special purpose tool for writing code that's neither time nor size critical but has to operate under very specific, tight constraints. One example would be for example bootloaders or system initialization code, which task it is to initialize memory access in the first place and have to operate with just a few bytes – or even none – of usable memory storage, but can re-compute values required for each step.
The C programming language is (like every programming language) a specification (in some report). It is not a software. You probably should read the n1570 (draft specification of C11) report.
Conceptually, a function does not have any data in C (but its code may refer to static addresses, contain literal constants - including pointers- etc...). It has some behavior, practically implemented by some code. What is code is not defined by the C standard.
Practically speaking, and this depends upon the particular implementation (look into the difference between Harvard machine & computer architectures and Von Neumann ones), a function pointer is some address of machine code (often, the target of the CALL machine instruction translating the C calls to it).
On desktops & laptops & tablets with some usual operating system (like Linux, Windows, MacOSX, iOS, Android...) -all are Von Neumann architectures: x86-64 or ARM-, your process has a single virtual address space containing code segments and data segments and heap data. Then function pointers and data pointers are of the same kind, and it is practically meaningful to cast between them. A canonical example is the usage of POSIX dlsym: you often cast its result to some function pointer (e.g. inside some plugin which is dynamically loaded with dlopen). The address of a function is practically speaking the address of its first machine code instruction (sitting in some code segment in the common address space). Read this & that for creative examples. Another useful example is JIT compilation libraries like asmjit, GNU lightning, libgccjit, LLVM: they enable you to generate machine code at runtime, and to get a (fresh) function pointer from these.
Neither dlsym nor JIT libraries are stricto sensu conforming to the C standard, because in a purely standard conforming C program the set of functions is statically known and any function pointer should point to some existing function of the same signature (read about calling conventions & ABIs), otherwise it is undefined behavior.
On some embedded computers with a Harvard architecture (e.g. some Arduino), code and data sit in different spaces, and a code address might not have the same number of bits than a data address. On such systems, a cast between function and data pointers is meaningless (unless you dive into deep implementation details). The C standard was specified to be general enough to take such weird computers into account.
Read also a lot more about closures and continuations. The C standard don't have them (hence callbacks conventionally take some client data argument). You probably will learn a lot by reading SICP. Read also about homoiconicity.
Read also about Operating Systems: If you use Linux (which I recommend, because it is mostly made of free software whose source code you can study), read Advanced Linux Programming. Read also Operating Systems: Three Easy Pieces.
In other words: your question (on function pointers and addresses) has different approaches. A dogmatic programming language lawyer approach (and the issue is to understand deeply the semantics of function pointers in the C standards; look also into CompCert & Frama-C); a pragmatic operating system and implementation specific approach (and then it depends upon your computer, its instruction set, and its OS and even your particular C compiler -and version- and optimization flags; and you may even have some "magic mechanisms" -like dlsym & dlopen or JIT compilation libraries- to create functions at runtime; which is magic because the C standards don't think of that).
You can find your answer here.
The C language supports two kinds of memory allocation through the variables in C programs:
Static allocation: is what happens when you declare a static or global variable. Each static or global variable defines one block of space, of a fixed size. The space is allocated once, when your program is started (part of the exec operation), and is never freed.
Automatic allocation: happens when you declare an automatic variable, such as a function argument or a local variable. The space for an automatic variable is allocated when the compound statement containing the declaration is entered, and is freed when that compound statement is exited.
In GNU C, the size of the automatic storage can be an expression that varies. In other C implementations, it must be a constant.
Function pointers point to blocks of machine instructions that get executed when you call the function.
Say you have this:
#include <stdio.h>
int plus_42(int x)
{
int res=x+42;
printf("%d + 42 = %d\n", x,res);
return res;
}
int main()
{
return plus_42(1);
}
If you compile it, link it, and run objdump -d on the result:
gcc plus_42.c && objdump -d a.out
you'll get (depending on your architecture, something like):
0000000000400536 <plus_42>:
400536: 55 push %rbp
400537: 48 89 e5 mov %rsp,%rbp
40053a: 48 83 ec 20 sub $0x20,%rsp
40053e: 89 7d ec mov %edi,-0x14(%rbp)
400541: 8b 45 ec mov -0x14(%rbp),%eax
400544: 83 c0 2a add $0x2a,%eax
400547: 89 45 fc mov %eax,-0x4(%rbp)
40054a: 8b 55 fc mov -0x4(%rbp),%edx
40054d: 8b 45 ec mov -0x14(%rbp),%eax
400550: 89 c6 mov %eax,%esi
400552: bf 04 06 40 00 mov $0x400604,%edi
400557: b8 00 00 00 00 mov $0x0,%eax
40055c: e8 af fe ff ff callq 400410 <printf#plt>
400561: 8b 45 fc mov -0x4(%rbp),%eax
400564: c9 leaveq
400565: c3 retq
0000000000400566 <main>:
400566: 55 push %rbp
400567: 48 89 e5 mov %rsp,%rbp
40056a: bf 01 00 00 00 mov $0x1,%edi
40056f: e8 c2 ff ff ff callq 400536 <plus_42>
400574: 5d pop %rbp
400575: c3 retq
400576: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
40057d: 00 00 00
plus some boilerplate.
Here, 0000000000400536 and 0000000000400566 are the addresses of main and plus_42 (= the pointers that main and plus_42 point to) respectively, and the hex numbers you see in the 2nd column is the data, which is decoded in the 3d column into human readable names of the machine instructions that the data represents.

Where is userspace wrapper for ioctl system call defined on x86_64 Linux?

I have (out of curiosity) been wondering where the user space wrapper for the ioctl system call is defined on x86_64 Linux. My first thought was glibc - after checking the exposed symbols on the installed version on my Fedora 24 box, I can see that (unless I'm doing it wrong) libc exposes the ioctl symbol as 'W' meaning it is a weak symbol with a default implementation. The default implementation in the glibc source tree at misc/ioctl.c seems to be a stub though, and just sets errno to ENOSYS and returns -1.
Never the less, ioctl works (obviously or my system wouldn't be very usable). I am aware that it is probably assembly code somewhere in a file that is assembled and linked in somehow, thus overriding the weak symbol exposed by glibc. I am also aware that it is perfectly possible for applications to call ioctl directly using a system call, either via the glibc syscall wrapper or directly with assembly.
That said, given the library source code I happened to be observing (libdrm) includes the standard ioctl header /usr/include/sys/ioctl.h, and doesn't seem to contain its own implementation of the wrapper that I can see either, I am wondering where I should be looking.
This is part of my push to understand the lowest levels of a GNU/Linux system more deeply. Thanks for any pointers, and apologies if this has been asked before but I can't see any answer if it has.
UPDATE: I neglected to mention above but I also checked the virtual vdso library mapped by the kernel - I could find only the following in it:
0000000000000a00 W clock_gettime
0000000000000db0 W getcpu
0000000000000c40 W gettimeofday
0000000000000000 A LINUX_2.6
0000000000000d90 W time
0000000000000a00 T __vdso_clock_gettime
0000000000000db0 T __vdso_getcpu
0000000000000c40 T __vdso_gettimeofday
0000000000000d90 T __vdso_time
UPDATE: It would appear I was incorrect about the glibc default definition being a stub. As nos pointed out in the comments, disassembly shows it is performing the real system call. I have posted an answer to reflect this.
As nos mentioned in the comment to my original question, it is indeed actually defined in libc, in my case as follows:
00000000000f8ce0 <ioctl>:
f8ce0: b8 10 00 00 00 mov $0x10,%eax
f8ce5: 0f 05 syscall
f8ce7: 48 3d 01 f0 ff ff cmp $0xfffffffffffff001,%rax
f8ced: 73 01 jae f8cf0 <ioctl+0x10>
f8cef: c3 retq
f8cf0: 48 8b 0d 71 31 2c 00 mov 0x2c3171(%rip),%rcx # 3bbe68 <_DYNAMIC+0x308>
f8cf7: f7 d8 neg %eax
f8cf9: 64 89 01 mov %eax,%fs:(%rcx)
f8cfc: 48 83 c8 ff or $0xffffffffffffffff,%rax
f8d00: c3 retq
f8d01: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
f8d08: 00 00 00
f8d0b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
It is clearly making a system call here - as nos says, it must be autogenerated which is why I couldn't find it straight off in the glibc source tree.

How can gcc/clang assume a string constant's address is 32-bit?

If I compile this program:
#include <stdio.h>
int main(int argc, char** argv) {
printf("hello world!\n");
return 0;
}
for x86-64, the asm output uses movl $.LC0, %edi / call puts. (See full asm output / compile options on godbolt.)
My question is: How can GCC know that the the string's address can fit in a 32bit immediate operand? Why doesn't it need to use movabs $.LC0, %rdi (i.e. a mov r64, imm64, not a zero or sign-extended imm32).
AFAIK, there's nothing saying the loader has to decide to load the data section at any particular address. If the string is stored at some address above 1ULL << 32 then the higher bits will be ignored by the movl. I get similar behavior with clang, so I don't think this is unique to GCC.
The reason I care is I want to create my own data segment that lives in memory at any arbitrary address I choose (above 2^32 potentially).
In GCC manual:
https://gcc.gnu.org/onlinedocs/gcc-4.5.3/gcc/i386-and-x86_002d64-Options.html
3.17.15 Intel 386 and AMD x86-64 Options
-mcmodel=small
Generate code for the small code model: the program and its symbols
must be linked in the lower 2 GB of the address space. Pointers are 64
bits. Programs can be statically or dynamically linked. This is the
default code model.
-mcmodel=kernel Generate code for the kernel code model. The kernel runs in the negative 2 GB of the address space. This model has to be
used for Linux kernel code.
-mcmodel=medium
Generate code for the medium model: The program is linked in the lower
2 GB of the address space. Small symbols are also placed there.
Symbols with sizes larger than -mlarge-data-threshold are put into
large data or bss sections and can be located above 2GB. Programs can
be statically or dynamically linked.
-mcmodel=large
Generate code for the large model: This model makes no assumptions
about addresses and sizes of sections.
https://gcc.gnu.org/onlinedocs/gcc/AArch64-Options.html
3.18.1 AArch64 Options
-mcmodel=tiny
Generate code for the tiny code model. The program and its statically defined symbols must be within 1GB of each other. Pointers
are 64 bits. Programs can be statically or dynamically linked. This
model is not fully implemented and mostly treated as ‘small’.
-mcmodel=small
Generate code for the small code model. The program and its statically defined symbols must be within 4GB of each other. Pointers
are 64 bits. Programs can be statically or dynamically linked. This is
the default code model.
-mcmodel=large
Generate code for the large code model. This makes no assumptions about addresses and sizes of sections. Pointers are 64 bits. Programs
can be statically linked only.
I can confirm that this happens on 64-bit compilation:
gcc -O1 foo.c
Then objdump -d a.out (notice also that printf("%s\n") can be optimized into puts!):
0000000000400536 <main>:
400536: 48 83 ec 08 sub $0x8,%rsp
40053a: bf d4 05 40 00 mov $0x4005d4,%edi
40053f: e8 cc fe ff ff callq 400410 <puts#plt>
400544: b8 00 00 00 00 mov $0x0,%eax
400549: 48 83 c4 08 add $0x8,%rsp
40054d: c3 retq
40054e: 66 90 xchg %ax,%ax
The reason is that GCC defaults to -mcmodel=small where the static data is linked in the bottom 2G of address space.
Notice that string constants do not go to the data segment, but they're within the code segment instead, unless -fwritable-strings. Also if you want to relocate the object code freely in memory, you'd probably want to compile with -fpic to make the code RIP relative instead of putting 64-bit addresses everywhere.

Disassembler that tracks what value is where

So lately I've been looking at the disassembly of my C++ code, and having to manually track what's in each register, like this:
95: 48 8b 16 mov (%rsi),%rdx ; %rdx = raggedCross.sink
98: 48 8b 42 38 mov 0x38(%rdx),%rax ; %rax = sink.table
9c: 8b 4a 10 mov 0x10(%rdx),%ecx ; %ecx = sink.baseCol
9f: 48 8b 70 50 mov 0x50(%rax),%rsi ; %rsi = table.starts
a3: 89 c8 mov %ecx,%eax ; %eax = baseCol
a5: 83 c1 1c add $0x1c,%ecx ; %ecx = baseCol + 1
And so on. The comments are mine, added by hand, from looking up the offset of various fields (e.g. sink, table, baseCol, starts) in the C++ classes.
It's straight forward to do, but tedius and time consuming: the perfect thing for a program to be doing. gdb seems to know the offset of various fields within a struct: I can do &((Table *)0x1200)->starts and it tells the the right address. So, this information is around.
Is there some disassembler that can use this info to annotate the code for me?
Failing that, I could write my own. Where does gdb get the offsets?
GDB uses the debugging information you included to determine that sort of thing, it's not part of a normal executable; DWARF is one common format used to store debug information
You can use the debugging information (DWARF2) in order to look at the object files. As you're using GCC, you can do an annotated dump using the binutils utility objdump -S. If you dump all sections, the DWARF information is dumped as well.
You could take a look at IDA Pro. It won't completely automate the process, but it'll at least let you define your structure/class in one place, and it'll handle most things from there.

Resources