Skip to content

Instantly share code, notes, and snippets.

@reveng007
Last active April 17, 2024 12:26
Show Gist options
  • Save reveng007/b9ef8c7c7ed7a46b10a325f4dee42ac4 to your computer and use it in GitHub Desktop.
Save reveng007/b9ef8c7c7ed7a46b10a325f4dee42ac4 to your computer and use it in GitHub Desktop.
`Static` vs `Dynamic` library in `Linux`, `PIC`,`PIE`, `plt`, `got`, `Virtual vs Physical Addresses`:

Static vs Dynamic library in Linux, PIC, PIE, plt, got, Virtual vs Physical Addresses:


plt ---> procedure linkage table
logical addresses ---> virtual addresses
virtual address space (VAS) or address space ---> is the set of ranges of virtual addresses that an operating system makes available to a process.
memory management unit (MMU) or paged memory management unit (PMMU) ---> is a computer hardware unit having all memory references passed through itself, primarily performing the translation of virtual memory addresses to physical addresses.
Virtual address space randomization ----> Address space layout randomization ----> (ASLR)

NOTE:

Position-independent executables (PIE) are executable binaries made entirely from position-independent code PIC

PIE works very much like what PIC does for dynamic libraries, the difference is that a Procedure Linkage Table (PLT) is not created, instead PC-relative relocation is used.

See ASLR and DEP detailed in another gist file

Also See, Hand-written notes...

All Explanations are done w.r.t. gcc:

See:

  1. the .drawio file: Open Static_and_dynamic_Query_flowchart.drawio in soumya22092001@gmail.com account Follow Tutorial to open this .drawio file.

  2. Load-time relocation of shared libraries

  3. Position Independent Code (PIC) in shared libraries, GOT, PLT

  4. IAT vs PLT&GOT ---> See malware Anlysis notes for the working of IAT

  5. Wiki: Position-independent code

  6. Memory Management Glossary

  7. Wiki: Memory management unit

  8. Wiki: Page table

  9. Virtual vs Physical Addresses

  10. Wiki: Virtual address space

  11. Wiki: Memory address

  12. Wiki: Relocation (computing)

  13. Stackoverflow: PIC vs PIE

  14. PLT and GOT - the key to code sharing and dynamic libraries

  15. Stackoverflow: What is the purpose of the procedure linkage table?

ASLR (For Windows as well as linux):

Note that ASLR predates PIE binaries, and does not in any way require PIE. When ASLR was introduced, it randomized placement of stack, heap, and shared libraries. The placement of (non-PIE) main executable could not be randomized.

  1. Stackoverflow: ELF, PIE ASLR
  2. ASLR Threat Research

--> In fact, Windows only attempts to randomize 8 bits of a 32-bit address. Those are bits 16 through 23, affecting only the page directory entry and page table entry portion of the address

  1. ASLR and DEP
  2. On the effectiveness of DEP and ASLR
  3. What Is ASLR, and How Does It Keep Your Computer Secure?
  4. Differences Between ASLR on Windows and Linux

--> For this reason, there really is no reason to link anything without the /DYNAMICBASE option, which enables ASLR. With /DYNAMICBASE enabled, a module's load address is randomized, which means that it cannot easily be used in Return Oriented Programming (ROP) attacks.

--> If a goal of ASLR is to have executable code at an unpredictable address, why is there such a difference between the Windows and Linux implementations? It's important to note that ASLR compatibility

  • on Windows is a link-time option, while
  • on Linux it's a compile-time option.

Surface lvl difference:

  • ASLR in Windows:
 ---> The code is patched at run time for relocation purposes.
  • ASLR in Linux/Unix:
The relocation technique is known as text relocation.

With Linux, ASLR is achieved in a different way.

In linux, unlike Windows (i.e. patching the code at runtime), code is compiled in a way that makes it position independent. 

That is, it can be loaded at any memory address and still function properly.

Why did the Linux developers choose this technique for implementing ASLR?

--> As with most things security, there is a tradeoff. Because text relocations involve patching, loading such a module would trigger copy-on-write, which subsequently increases the memory footprint of a system. Position-independent code does not require patching, and therefore does not trigger copy-on-write. For a much more detailed look into the position-independent code implementation on Linux, as well as a comparison to load-time relocation, see Eli Bendersky's blog entry: Position Independent Code (PIC) in shared libraries

What does this mean for most Linux users?

-->

  • ASLR is not as prevalent in most Linux distributions as it is on modern Windows systems.
  • ASLR cannot be force-enabled for applications on Linux, as EMET can do on Windows.

One thing to consider is that the x86 architecture is becoming less relevant as time passes. The x86_64 architecture doesn't have a significant performance penalty for position-independent code. This smaller penalty is because x86_64 has twice as many general-purpose registers as x86 and because unlike x86, it supports a PC-relative addressing scheme.

Copy on Write and Dirty Cow:

  1. Computerfile
  2. LiveOverflow

All YT platlists:

  1. Playlist: "All the Youtube videos I followed"
  2. Playlist: Virtual Memory
  3. Playlist: Information Security - 5 - Secure Systems Engineering

Acc. to man page of gcc in 2021: (check it again, if incase it has been updated)

$ man gcc

-fpic

+ Generate position-independent code (PIC) suitable for use in a shared library

Generate position-independent code (PIC) suitable for use in a shared library, if supported for the target machine. 
Such code accesses all constant addresses through a global offset table (GOT).  The dynamic loader resolves the GOT 
entries when the program starts (the dynamic loader is not part of GCC; it is part of the operating system). 
+ If the GOT size for the linked executable exceeds a machine-specific maximum size, you get an error message 
+ from the linker indicating that -fpic does not work; in that case, recompile with -fPIC instead. 

(These maximums are 8k on the SPARC, 28k on AArch64 and 32k on the m68k and RS/6000.  The x86 has no such limit.)

Position-independent code requires special support, and therefore works only on certain machines.  For the x86, 
GCC supports PIC for System V but not for the Sun 386i.  Code generated for the IBM RS/6000 is always 
position-independent.

When this flag is set, the macros "__pic__" and "__PIC__" are defined to 1.

-fPIC

+ If supported for the target machine, emit position-independent code(PIC), suitable for dynamic linking and avoiding any 
+ limit on the size of the global offset table(GOT)

If supported for the target machine, emit position-independent code, suitable for dynamic linking and avoiding any 
limit on the size of the global offset table. This option makes a difference on 
AArch64, m68k, PowerPC and SPARC.

Position-independent code requires special support, and therefore works only on certain machines.

When this flag is set, the macros "__pic__" and "__PIC__" are defined to 2.

-fpie
-fPIE
+ These options are similar to -fpic and -fPIC, but the generated position-independent code(PIC) can be 
+ only linked into executables. Usually these options are used to compile code that will be linked using the GCC option:
  `-pie`

-fpie and -fPIE both define the macros "__pie__" and "__PIE__".  The macros have the value 1 for -fpie and 2 for -fPIE.

-fno-plt
Do not use the PLT for external function calls in position-independent code(PIC).  Instead, load the callee address 
at call sites from the GOT and branch to it.  This leads to more efficient code by eliminating PLT stubs and exposing 
GOT loads to optimizations.  On architectures such as 32-bit x86 where PLT stubs expect the GOT pointer in a 
specific register, this gives more register allocation freedom to the compiler. 

+ Lazy binding requires use of the PLT; with -fno-plt all external symbols are resolved at load time.

+ Alternatively, the function attribute "noplt" can be used to avoid calls through the PLT for specific external 
+ functions.

+ In position-dependent code, a few targets also convert calls to functions that are marked to not use the PLT to use 
+ the GOT instead.

-pie
+ Produce a dynamically linked position independent executable(PIC) on targets that support it. 
+ For predictable results, you must also specify the same set of options used for compilation 
+ (-fpie, -fPIE, or model suboptions) when you specify this linker option.

-no-pie
Don't produce a dynamically linked position independent executable(PIE). 

=> dynamically linked executable (i.e. no shared object => no PIE)  => I will show it with example later in this file

-static-pie
+ Produce a static position independent executable on targets that support it. 

+ A static position independent executable is similar to a static executable, but can be loaded at any address 
+ without a dynamic linker.  

For predictable results, you must also specify the same set of options used for compilation
(-fpie, -fPIE, or model suboptions) when you specify this linker option.

-static
+ On systems that support dynamic linking, this overrides -pie and prevents linking with the shared libraries. On other
+ systems, this option has no effect.

-shared
+ Produce a shared object which can then be linked with other objects to form an executable.  Not all systems support
+ this option.  For predictable results, you must also specify the same set of options used for compilation 
+ (-fpic, -fPIC, or model suboptions) when you specify this linker option.[1]

-Wall
This enables all the warnings about constructions that some users consider questionable, and that are easy to avoid (or
modify to prevent the warning), even in conjunction with macros.  This also enables some language-specific warnings
described in C++ Dialect Options and Objective-C and Objective-C++ Dialect Options.

-Wall turns on the following warning flags:

  -Waddress -Warray-bounds=1 (only with -O2) -Wbool-compare -Wbool-operation -Wc++11-compat  -Wc++14-compat -Wcatch-value
  (C++ and Objective-C++ only) -Wchar-subscripts -Wcomment -Wduplicate-decl-specifier (C and Objective-C only)
  -Wenum-compare (in C/ObjC; this is on by default in C++) -Wformat -Wint-in-bool-context -Wimplicit (C and Objective-C
  only) -Wimplicit-int (C and Objective-C only) -Wimplicit-function-declaration (C and Objective-C only) -Winit-self
  (only for C++) -Wlogical-not-parentheses -Wmain (only for C/ObjC and unless -ffreestanding) -Wmaybe-uninitialized
  -Wmemset-elt-size -Wmemset-transposed-args -Wmisleading-indentation (only for C/C++) -Wmissing-attributes
  -Wmissing-braces (only for C/ObjC) -Wmultistatement-macros -Wnarrowing (only for C++) -Wnonnull -Wnonnull-compare
  -Wopenmp-simd -Wparentheses -Wpessimizing-move (only for C++) -Wpointer-sign -Wreorder -Wrestrict -Wreturn-type
  -Wsequence-point -Wsign-compare (only in C++) -Wsizeof-pointer-div -Wsizeof-pointer-memaccess -Wstrict-aliasing
  -Wstrict-overflow=1 -Wswitch -Wtautological-compare -Wtrigraphs -Wuninitialized -Wunknown-pragmas -Wunused-function
  -Wunused-label -Wunused-value -Wunused-variable -Wvolatile-register-var

  Note that some warning flags are not implied by -Wall.  Some of them warn about constructions that users generally do
  not consider questionable, but which occasionally you might wish to check for; others warn about constructions that are
  necessary or hard to avoid in some cases, and there is no simple way to modify the code to suppress the warning. Some
  of them are enabled by -Wextra but many of them must be enabled individually.

-Wextra

This enables some extra warning flags that are not enabled by -Wall. (This option used to be called -W.  The older name
is still supported, but the newer name is more descriptive.)

  -Wclobbered -Wcast-function-type -Wdeprecated-copy (C++ only) -Wempty-body -Wignored-qualifiers
  -Wimplicit-fallthrough=3 -Wmissing-field-initializers -Wmissing-parameter-type (C only) -Wold-style-declaration (C
  only) -Woverride-init -Wsign-compare (C only) -Wredundant-move (only for C++) -Wtype-limits -Wuninitialized
  -Wshift-negative-value (in C++03 and in C99 and newer) -Wunused-parameter (only with -Wunused or -Wall)
  -Wunused-but-set-parameter (only with -Wunused or -Wall)

  The option -Wextra also prints warning messages for the following cases:

  *   A pointer is compared against integer zero with "<", "<=", ">", or ">=".

  *   (C++ only) An enumerator and a non-enumerator both appear in a conditional expression.

  *   (C++ only) Ambiguous virtual bases.

  *   (C++ only) Subscripting an array that has been declared "register".

  *   (C++ only) Taking the address of a variable that has been declared "register".

  *   (C++ only) A base class is not initialized in the copy constructor of a derived class.
+ ACC. to my research,

use of: "-static" and "-no-pie" together   ----->  statically Linked, LSB executable   

=> I will show it with example later in this file


use of: only "-static"  ------> dynamically linked, LSB executable

=> I will show it with example later in this file

Statically linked file:

Acc. to Medium

[?] I am unable to figure out What type of linking is it....!?

Codes are: lib_add.c, lib_sub.c, main.c and calc.h

//Code 1: lib_add.c

#include<stdio.h>

void add(int a, int b)
{
  printf("Addition result=%d\n", a+b);
}
//Code 2: lib_sub.c

#include<stdio.h>

void sub(int a, int b)
{
  printf("Addition result=%d\n", a-b);
}
//Code 3: calc.h

void add(int a, int b);
void sub(int a, int b);
//Code 4: main.c

#include<stdio.h>
#include"calc.h"

int main()
{
  int x=10, y=5;
  add(x,y);
  sub(x,y);
  return 0;
}
// Creation of object files

$ gcc -c lib_add.c
$ gcc -c lib_sub.c
$ gcc -c main.c

// Creation of static library

$ gcc -rc lib_calc.a lib_add.o lib_sub.o 
//Statically linking

$ gcc -o main_1st_static main.o -L. lib_calc.a

$ gcc -o main_2nd_static main.o -L. -l_calc

$ gcc -o main_3rd_static main.c -L. -l_calc


$ ./main_1st_static 
Addition result=15
Substraction result=5

$ ./main_2nd_static
Addition result=15
Substraction result=5

$ ./main_3rd_static
Addition result=15
Substraction result=5

$ ll main*_static
-rwxrwxr-x 1 ubuntu ubuntu 17K May  5 01:31 main_1st_static*
-rwxrwxr-x 1 ubuntu ubuntu 17K May  5 01:31 main_2nd_static*
-rwxrwxr-x 1 ubuntu ubuntu 17K May  5 01:31 main_3rd_static*

Up here, above, there is one catch:

If in the same directory, lib_calc.a(static library) and lib_calc.so(shared object) is present, and we want to run the above 3 gcc scripts, -l_calc will consider lib_calc.so as the static library and will make a copy of it to the final executable. The result will be erronious So before running those 3 scripts, please remove that shared library.

+ Why it happens I don't know, till now, Do a bit reseach on it.
Also find out, what will happen, if I `lib_calc.so` gets copied to the final executable.
+ My intusions say something will come up...
$ file main_1st_static 
main_1st_static: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=9a492c858e7e3bd9e3ca51d3c93b0e6051f6397a, for GNU/Linux 3.2.0, not stripped

$ file main_2nd_static
main_2nd_static: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=9a492c858e7e3bd9e3ca51d3c93b0e6051f6397a, for GNU/Linux 3.2.0, not stripped

$ file main_3rd_static
main_3rd_static: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=9a492c858e7e3bd9e3ca51d3c93b0e6051f6397a, for GNU/Linux 3.2.0, not stripped

- Dynamically linked !!! X

$ readelf -a main_1st_static | grep Shared && readelf -a main_1st_static | grep interpreter
- Type:                              DYN (Shared object file)             ----> we are seeing shared library, 
- 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]     ----> But this is said to be static    X
-      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]


$ readelf -a main_2nd_static | grep Shared && readelf -a main_2nd_static | grep interpreter
-  Type:                              DYN (Shared object file)            ----> we are seeing shared library, 
- 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]     ----> But this is said to be static     X
-      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]


$ readelf -a main_3rd_static | grep Shared && readelf -a main_3rd_static | grep interpreter
-  Type:                              DYN (Shared object file)               ----> we are seeing shared library, 
- 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]        ----> But this is said to be static    X
-      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
      

$ ldd main_1st_static
-	linux-vdso.so.1 (0x00007ffecf95d000)                                     -----+
-	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f460ee8a000)             |
-	/lib64/ld-linux-x86-64.so.2 (0x00007f460f098000)                              |
                                                                                |
                                                                                |
$ ldd main_2nd_static                                                           |
-	linux-vdso.so.1 (0x00007fff0cda4000)                                          |
-	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fe8f6a09000)             |--------> Same result as readelf -a
-	/lib64/ld-linux-x86-64.so.2 (0x00007fe8f6c17000)                              |          =>  X
                                                                                |
                                                                                |
$ ldd main_3rd_static                                                           |
-	linux-vdso.so.1 (0x00007ffdbb9a4000)                                          |
-	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f039be7b000)             |
-	/lib64/ld-linux-x86-64.so.2 (0x00007f039c089000)                              |
-                                                                         ------+

Dynamically linked file:

Acc. to Medium

[?] I am unable to figure out What type of linking is it....!?

Code is present in notes: lib_add.c, lib_sub.c, main.c and calc.h

// Creating object files:

+ used -fpic: snapshot of the man page present at the top of this .md file

$ gcc -c lib_add.c lib_sub.c -fpic
$ gcc -c main.c
// Creating shared/ dynamic library:  

$ gcc lib_add.o lib_sub.o -shared -o lib_calc.so
// Dynamically linking:  gcc -g -wall -o app app.c liball.so

$ gcc -o main_1st_dynamic main.o  -L. lib_calc.so
$ gcc -o main_2nd_dynamic main.o  -L. -l_calc
$ gcc -o main_3rd_dynamic main.c  -L. -l_calc

$ file main_1st_dynamic
main_1st_dynamic: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=ceccf4b798dac2a20fdccde3f1c0684c5c1b1ae0, for GNU/Linux 3.2.0, not stripped

$ file main_2nd_dynamic
main_2nd_dynamic: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=ceccf4b798dac2a20fdccde3f1c0684c5c1b1ae0, for GNU/Linux 3.2.0, not stripped

$ file main_3rd_dynamic
main_3rd_dynamic: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=ceccf4b798dac2a20fdccde3f1c0684c5c1b1ae0, for GNU/Linux 3.2.0, not stripped


$ ./main_1st_dynamic 
./main_1st_dynamic: error while loading shared libraries: lib_calc.so: cannot open shared object file: No such file or directory

$ ldd main_1st_dynamic 

  linux-vdso.so.1 (0x00007ffd8fdee000)
- lib_calc.so => not found
  libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fd90a4bb000)
  /lib64/ld-linux-x86-64.so.2 (0x00007fd90a6c9000)


$ readelf -a main_1st_dynamic | grep Shared
  Type:                              DYN (Shared object file)
 0x0000000000000001 (NEEDED)             Shared library: [lib_calc.so]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]

$ readelf -a main_1st_dynamic | grep interpreter
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]


$ ./main_2nd_dynamic 
./main_2nd_dynamic: error while loading shared libraries: lib_calc.so: cannot open shared object file: No such file or directory

$ ldd main_2nd_dynamic 
	
  linux-vdso.so.1 (0x00007ffd353b9000)
-	lib_calc.so => not found
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f7ed42c9000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f7ed44d7000)

$ readelf -a main_2nd_dynamic | grep Shared
  Type:                              DYN (Shared object file)
 0x0000000000000001 (NEEDED)             Shared library: [lib_calc.so]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]

$ readelf -a main_2nd_dynamic | grep interpreter
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]


$ ./main_3rd_dynamic 
./main_3rd_dynamic: error while loading shared libraries: lib_calc.so: cannot open shared object file: No such file or directory

$ ldd main_3rd_dynamic 

	linux-vdso.so.1 (0x00007ffd604cd000)
-	lib_calc.so => not found
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fcd3d63b000)
	/lib64/ld-linux-x86-64.so.2 (0x00007fcd3d849000)

$ readelf -a main_3rd_dynamic | grep Shared
  Type:                              DYN (Shared object file)
 0x0000000000000001 (NEEDED)             Shared library: [lib_calc.so]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]

$ readelf -a main_3rd_dynamic | grep interpreter
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]


+ 1) We have to use: "export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH" to link `lib_calc.so` to the program
+ 2) Altervatively, We can also do it, by copying "lib_calc.so" to "/usr/lib" directory

$ export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH

$ ./main_1st_dynamic 
Addition result=15
Substraction result=5

$ ./main_2nd_dynamic 
Addition result=15
Substraction result=5

$ ./main_3rd_dynamic 
Addition result=15
Substraction result=5

$ ll main*_dynamic

-rwxrwxr-x 1 ubuntu ubuntu 17K May  5 05:38 main_1st_dynamic*
-rwxrwxr-x 1 ubuntu ubuntu 17K May  5 05:55 main_2nd_dynamic*
-rwxrwxr-x 1 ubuntu ubuntu 17K May  5 05:58 main_3rd_dynamic*

$ ll main*_static

-rwxrwxr-x 1 ubuntu ubuntu 17K May  5 01:31 main_1st_static*
-rwxrwxr-x 1 ubuntu ubuntu 17K May  5 01:31 main_2nd_static*
-rwxrwxr-x 1 ubuntu ubuntu 17K May  5 01:31 main_3rd_static*

- STRANGE THING:
- HERE,
+ Both, dynamically linked and statically files have 17k size...
+ Lets look deep into the matter.

+ One thing is, all of the 6 files (dynamically and statically linked) are 
"dynamically linked, LSB Shared Object"
//Finding info within objdump files of Statically linked(so called, in this case) file:

+ from all 3 static files, these keywords( keyword does not have any special meaning here, just used it to mention those functions ) are found which are same for all. 
- (There can be more, but I have given these keywords priority as these keywords came many times while getting my hands dirty with these stuffs)

.plt.got

.got

.dynamic

.plt.sec

<printf@plt>

<add>

<sub>
//Finding info within objdump files of Dynamically linked file:

+ from all 3 static files, these keywords( keyword does not have any special meaning here, just used it to mention those functions ) are found which are same for all. 
- (There can be more, but I have given these keywords priority as these keywords came many times while getting my hands dirty with these stuffs)

.plt.got

.got

.dynamic

.plt.sec

<add@plt>

<sub@plt>

Dynamically linked file (in asm): Also see notes.

Acc. to embeddedarmdev

  1. Youtube: Introduction to Compiling
  2. Youtube: Static and Dynamic Linking using GCC for Linux
  3. Youtube: Creating and Linking Shared Libraries
// dynamic linking

$ gcc -o hello_dynamic hello.c -lm
$ gcc -o hello_dynamic_no-pie hello.c -lm

hello_dynamic

$ file hello_dynamic
hello_dynamic: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=9feb7848a6933278a7a5150df4f4dad3e726812b, for GNU/Linux 3.2.0, not stripped


$ readelf -a hello_dynamic | grep interpreter
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]

$ readelf -a hello_dynamic | grep Shared
  Type:                              DYN (Shared object file)
 0x0000000000000001 (NEEDED)             Shared library: [libm.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]

$ ldd hello_dynamic
	linux-vdso.so.1 (0x00007ffc35156000)
	libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fc895b71000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fc89597f000)
	/lib64/ld-linux-x86-64.so.2 (0x00007fc895cdc000)
+ //In objdump file:

.plt.got

.plt.sec

.dynamic

.got

<puts@plt>

<time@plt>

<srand@plt>

<rand@plt>

<sqrt@plt>

<printf@plt>

No presence of:   .got.plt

//From objdump file:

call   10b0 <puts@plt>
+--> means directs to the `puts` section of the plt(procedure linkage table)
+     |
+     |---> Disassembly of section .plt.sec:

+ ----> This is how actually linkage happens

+ 1st printf ----> <puts@plt>  => printf doesn't contain any format specifier

+ 2nd printf ----> <printf@plt>  => Here, it contains format specifiers, so <printf@plt> was shown

- But actually, why??  => I don't the reason...

00000000000010b0 <puts@plt>:
    10b0:       f3 0f 1e fa             endbr64
    10b4:       f2 ff 25 e5 2e 00 00    bnd jmp QWORD PTR [rip+0x2ee5]        # 3fa0 <puts@GLIBC_2.2.5>
    10bb:       0f 1f 44 00 00          nop    DWORD PTR [rax+rax*1+0x0]

+                         ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+                         |         Each and everything is under .plt.sec                |
+                         ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
$ ll hello_dynamic*
-rwxrwxr-x 1 ubuntu ubuntu  17K May  4 10:22 hello_dynamic*
-rwxrwxr-x 1 ubuntu ubuntu  17K May  4 10:23 hello_dynamic_no-pie*

NOTE: hello_dynamic_no-pie: Same file size as hello_dynamic, same use of plt.

$ file hello.o
+ hello.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped

Explanation:

A relocatable object file holds sections containing code and data. This file is suitable to be linked with other relocatable object files to create dynamic executable files, shared object files, or another relocatable object. A dynamic executable file holds a program that is ready to execute.

[*] More on plt in the upcoming videos ....

hello_dynamic_no-pie

$ file hello_dynamic_no-pie
hello_dynamic_no-pie: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=227a0d32d7a1d2c7630fa1d41238841acf041dc8, for GNU/Linux 3.2.0, not stripped


$ readelf -a hello_dynamic_no-pie | grep interpreter
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]

$ readelf -a hello_dynamic_no-pie | grep Shared
 0x0000000000000001 (NEEDED)             Shared library: [libm.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]

$ ldd hello_dynamic_no-pie
	linux-vdso.so.1 (0x00007ffea03e2000)
	libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f668c503000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f668c311000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f668c669000)
+ //In objdump file:

SAME "keywords" AS PREVOIUS: hello_dynamic

BUT: No presence of: .plt.got ;     Intead has:  .got.plt
+ DYNAMICALLY LINKED:

$ ll hello_dynamic*.dump  
-rw-rw-r-- 1 ubuntu ubuntu 53K May  6 06:14 hello_dynamic.dump
-rw-rw-r-- 1 ubuntu ubuntu 47K May  6 06:15 hello_dynamic_no-pie.dump

Statically linked file (in asm): Also see notes.

Acc. to embeddedarmdev

  1. Youtube: Introduction to Compiling
  2. Youtube: Static and Dynamic Linking using GCC for Linux
  3. Youtube: Creating and Linking Static Libraries
//Code

#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#include<time.h>


int main(void)
{
        printf("Hello World!\n");       //libc

        //needed to create a random number
        time_t t;
        srand((unsigned) time(&t));
        int rNum = rand();

        double sr = sqrt(rNum);         //libm    -lm

        printf("Square root of %d is %f\n", rNum, sr);          //libc
        return 0;
}
//Static linking

$ gcc -static -o hello_static hello.c -lm                       -----> static
$ gcc -no-pie -static -o hello_static_no-pie hello.c -lm     ----> static (-no-pie) 

hello_static_no-pie

$ $ file hello_static_no-pie 
hello_static_no-pie: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, BuildID[sha1]=fb97b74e03cf365404be8a694c84c92f03f42409, for GNU/Linux 3.2.0, not stripped

$ readelf -a hello_static_no-pie | grep Shared
-----> X

$ readelf -a hello_static_no-pie | grep interpreter
-----> X

$ ldd hello_static_no-pie 
	not a dynamic executable
+ //In objdump file:

+ PRESENCE of: .got.plt

NOTE:
Nothing else has matched with dynamic objdump keywords(I have took this word "keyword" as indication
							there is no special meaning related to it)

hello_static

$ file hello_static
hello_static: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=e38b4b4b318b1ead9910799d28cefc7b78e79ca3, for GNU/Linux 3.2.0, not stripped


$ readelf -a hello_static | grep interpreter
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]

$ readelf -a hello_static | grep Shared
 0x0000000000000001 (NEEDED)             Shared library: [libm.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]

$ ldd hello_static
	linux-vdso.so.1 (0x00007ffdcd34d000)
	libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f9a223e1000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9a221ef000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f9a22547000)

+ //In objdump file:

.got.plt

.plt.sec

.dynamic

.got

<puts@plt>

<time@plt>

<srand@plt>

<rand@plt>

<sqrt@plt>

<printf@plt>

No presence of:  .plt.got
+ HERE MOST OF THE THINGS HAVE MATCHED with:
+ ------------------------------------------

dynamic (with -no-pie) ----> gcc -no-pie -o hello_dynamic_no-pie hello.c -lm   ---> (1)

static ----> gcc -static -o hello_static hello.c -lm                           --->  (2)

+ HENCE    =>  (1) MATCHED (2)

SO, THESE are same ......

+// SAME size
$ ll hello_dynamic_no-pie.dump hello_static.dump 
-rw-rw-r-- 1 ubuntu ubuntu 47K May  6 06:15 hello_dynamic_no-pie.dump
-rw-rw-r-- 1 ubuntu ubuntu 47K May  6 07:01 hello_static.dump

+// SAME description
$ file hello_static && file hello_dynamic_no-pie

hello_static: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=e38b4b4b318b1ead9910799d28cefc7b78e79ca3, for GNU/Linux 3.2.0, not stripped

hello_dynamic_no-pie: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=227a0d32d7a1d2c7630fa1d41238841acf041dc8, for GNU/Linux 3.2.0, not stripped

+// SAME presence of interpreter
$ readelf -a hello_static | grep interpreter && readelf -a hello_dynamic_no-pie | grep interpreter
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]

+// SAME presence Shared library
$ readelf -a hello_static | grep Shared && readelf -a hello_dynamic_no-pie | grep Shared

 0x0000000000000001 (NEEDED)             Shared library: [libm.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libm.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]

+// SAME result of ldd
$ ldd hello_static && ldd hello_dynamic_no-pie 
	linux-vdso.so.1 (0x00007ffdeb3c3000)
	libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f5fe603e000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f5fe5e4c000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f5fe61a4000)
	
	linux-vdso.so.1 (0x00007ffe49fe6000)
	libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f0c61746000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f0c61554000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f0c618ac000)


+// According to these result, 

(gcc -no-pie -o hello_dynamic_no-pie hello.c -lm) = (gcc -static -o hello_static hello.c -lm)

Is it True!!??

________________________________________________________________________________________________
+//STATICALLY LINKED:

$ ll hello_static*.dump 
-rw-rw-r-- 1 ubuntu ubuntu 47K May  6 07:01 hello_static.dump
-rw-rw-r-- 1 ubuntu ubuntu 12M May  6 07:01 hello_static_no-pie.dump

________________________________________________________________________________________________
All files are COMPARED:

$ ll hello_dynamic*.dump  
-rw-rw-r-- 1 ubuntu ubuntu 53K May  6 06:14 hello_dynamic.dump
-rw-rw-r-- 1 ubuntu ubuntu 47K May  6 06:15 hello_dynamic_no-pie.dump

$ ll hello_static*.dump 
-rw-rw-r-- 1 ubuntu ubuntu 47K May  6 07:01 hello_static.dump
-rw-rw-r-- 1 ubuntu ubuntu 12M May  6 07:01 hello_static_no-pie.dump


________________________________________________________________________________________________

According to GCC man page:
"-no-pie:
  
  Don't produce a dynamically linked position independent executable." 


static ----> -no-pie ---> statically linked

static ----> without -no-pie -----> dynamic linked



normal (i.e. shared) ----> -no-pie  -----> dynamic linked

normal (i.e. shared) ----> without -no-pie  -----> dynamic linked

We could see here in statically linked file , each and every functions are copied from external libraries into the final executable binary.

<mxfile host="Electron" modified="2021-05-08T02:44:15.090Z" agent="5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/14.5.1 Chrome/89.0.4389.82 Electron/12.0.1 Safari/537.36" etag="jXK0txKz2EX0Un5aSqnT" version="14.5.1" type="device"><diagram name="Page-1" id="42789a77-a242-8287-6e28-9cd8cfd52e62">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</diagram></mxfile>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment