Disassembler command and Hidden facts of main function.6 min read

A disassembler is very useful for debugging. This tutorial will provide information regards ELF file format and disassembler command. As an add-on Some hidden facts of the main function explained with examples.

इस लेख को हिंदी में पढ़ने के लिए, यहाँ क्लिक करें!

Learn about the ELF file format.

What is EFL file format?

  • EFL means “Executable and Linkable Format” (EFL, formerly named Extensible Linking Format).
  • It is a common standard file format for executable files, object code, shared libraries, and core dumps.

More you can read about it here!


Disassembler command

A disassembler is a computer code that translates machine language (binary code) into assembly language. In simple words it is an inverse operation to that of an assembler.

Hex Editors (Disassembler): Which converts binary code to assembly code

COMMAND: objdump (Object dump)

objdump is by default available in UNIX/Linux Disassembler. Which is mainly used to edit an object file (binary file) using Disassembler.

To learn about object file creation click here!

objdump command in Linux is used to get in detail information of an object file.

This command is mainly used by the compiler programmers, but still, it is a handy tool for normal programmers also for debugging of code.

Syntax:

$ objdump [options] <object file>...

Eg.

$ objdump -D prog.o
Direct use of Disassembler command obj dump code is not giving user friendly output

This is how objdump gives output. It directly takes you to down is not user friendly way to go-through.

Problem means there is a solution.

Solution:

Use “less” or “more” command if you want the output in page wise display.

Extra info- ” | “ is a pipe (we will learn in linux tutorial).

Eg.

$ objdump -D prog.o | less

Or

$ objdump -D prog.o | more

Navigation:

W = go one page up

D = one page down

S = one line down

Or you can use arrow keys of keyboard and page down and page up button.

Q = to quit the page view

Less and more command use

When you disassemble object file you can see that program execution starts from startup function wherein startup function main function is called & main executed & returns to the startup function.

NOTE: main is called by startup function, main returns to startup function so that’s why we never call the main function, it only does by startup function.


Q) Why size of object file and executable files are different?

$ size prog.o
Performed size command on prog.o file
$ size prog
performed size command on prog file

prog.o object file is nothing but an object code of our written main code. While the Executable file prog file is created by linker; the task of a linker is to link OS supported files and other object files to it.

That’s a reason for executable file size is larger than the object file.


Interesting main() function.

If the return type is not mentioned then default return type will be int but some compiler will throw warnings and warnings are annoying.

main( ) == int main( ) == main(void) == int main(void)

Personal opinion:

Always start with a good habits.

<return type> function name (arguments)

This is a prototype of a function and if we follow, in future it will very helpful.

Reason in the future we will see main is also having arguments and sometimes we forgot to write the arguments and makes the unnecessary debugging task. That’s a pro point.

main() is always a calling function i.e it is not a called function.

In simple terms we can not call main() in code.

Execution starts from main and ends with main.


But what if I not use main() in code?

Lets test this:

This is our source code test.c

This is our test.c source code.

proprocessor stage is also passed without error

Our source code passed Preprocessor stage, means no error.

No error in Translator stage

Our source code passed Translator stage, means no error.

Assembler stage also passed

Our source code passed Assembler stage, means no error.

In linker stage code thrown an error

Whoa! Linker has thrown an error. Error found because the linker does not found main( ) in startup function. Let’s break it out in small chunks.

Undefined symbols for architecture x86_64:
  "_main", referenced from:
     implicit entry/start for main executable
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Part 1:

Undefined symbols for architecture x86_64:
  "_main", referenced from:
     implicit entry/start for main executable
ld: symbol(s) not found for architecture x86_64

in x86 architecture _main is a implicit function. What is a meaning of implicit?

definition of implicit function

Part 2:

clang: error: linker command failed with exit code 1 (use -v to see invocation)

So as per definition main function should be there. that’s why linker exited with code 1.

Solution:

Every linker starts execution with main( ).

To overcome linking error use the following command.

$ gcc -nostartfiles test.c
-nostartfiles working

If you like this article. Comment your views. It will motivate us.

Leave a Comment