Implicit Dynamic Linking or loading

Implicit linking or Implicit dynamic loading in the system process, where the loader of operating system loads the DLL executable at the same time as the executable that uses it.

Dynamic linking happens in two stages.

  • Stage #1 happens during compilation/build time and
  • stage #2 happens during loading time.

Any symbol which is a part of external libraries goes through a different process than any symbol which are present in the other object files. A symbol or function or variable links to the other object file or links to a static library file is linked directly as a payload to the binary. Functions are placed in the .text section and variables are in .data/.bss/.rodata sections. Then they are resolved by the offset address. The effective address is the load address of this section sum with the offset address.

A symbol or function or variable which is not present in object files are the external symbols and they are linked via import libraries. We have to specify the library name with the argument -l to the linker LD. Linker creates few sections in the ELF or COFF binary during linking time to resolve these symbols. C application uses libc as default implicit library.

Let us consider linking printf and getchar function.

#include <stdio.h>
int main (int argc, char *argv[])
{
  printf ("Hello libC %d.%d!!", 2, 0);
  getchar();
  return 0;
}

Libc binary holds a list of functions which can be used by application. Linker adds few sections to the binary to hold information about these functions. String name the function, offset address, index etc are added in the dynamic sections and library is generated. Now we are linking our application along with this libc. Linker checks which functions are not available and if they are present in the library. Here printf and getchar are not present in the object modules and they are present in the dynamic sections of libc. So linker takes these two as resolved symbols. Linker add some sections to tell that libc is the library binary needed when this application is going to execute and these two function has to be resolved by dynamic loader/linker at that time.

Linker adds some sections that are used in dynamic loading purpose. These contain the name of the library, the names of imported functions, offset address entry and table to map virtual address. It also adds a stub table to resolve the symbols. Linker links the function to the procedure linkage table. This table contains a lookup table. Control jumps to the table and from here it jumps to the actual address. Initially the function addresses are zero. These entries will be resolved by dynamic linker.

Dynamic loader loads the executable in virtual memory then it checks the sections for dynamic loading. It checks the library file path and also loads the library in virtual memory. Now it checks the table of imported functions needed by the application. Here dynamic linking process happens. Loader checks the function printf and looks up in the export sections of libc. Libc has the function entry and it has a load address and offset. So virtual address is calculated and it is places in the procedure linkage table. Here actual linking process is completed for printf. Same way getchar also gets the proper address. This way all the entries in procedure linkage table are filled and linking process comes to an end. There after the application is ready to run. So the loader jumps to the entry point of the application.

Dynamic linking

Dynamic sections in C App (Linux)

Dynamic section at offset 0xf14 contains 24 entries:
  Tag        Type                         Name/Value
 0x00000001 (NEEDED)                     Shared library: [libc.so.6]
 ...
 0x6ffffef5 (GNU_HASH)                   0x80481ac
 0x00000005 (STRTAB)                     0x804822c
 0x00000006 (SYMTAB)                     0x80481cc
 0x0000000a (STRSZ)                      84 (bytes)
 0x0000000b (SYMENT)                     16 (bytes)
 0x00000015 (DEBUG)                      0x0
 0x00000003 (PLTGOT)                     0x804a000
 0x00000002 (PLTRELSZ)                   32 (bytes)
 0x00000014 (PLTREL)                     REL
 0x00000017 (JMPREL)                     0x80482b4
 0x00000011 (REL)                        0x80482ac
 ...
 0x00000000 (NULL)                       0x0

Relocation section '.rel.dyn' at offset 0x2ac contains 1 entries:
 Offset     Info    Type            Sym.Value  Sym. Name
08049ffc  00000306 R_386_GLOB_DAT    00000000   __gmon_start__

Relocation section '.rel.plt' at offset 0x2b4 contains 4 entries:
 Offset     Info    Type            Sym.Value  Sym. Name
0804a00c  00000107 R_386_JUMP_SLOT   00000000   printf
0804a010  00000207 R_386_JUMP_SLOT   00000000   getchar
0804a014  00000307 R_386_JUMP_SLOT   00000000   __gmon_start__
0804a018  00000407 R_386_JUMP_SLOT   00000000   __libc_start_main

The decoding of unwind sections for machine type Intel 80386 is not currently supported.

Symbol table '.dynsym' contains 6 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 00000000     0 FUNC    GLOBAL DEFAULT  UND printf@GLIBC_2.0 (2)
     2: 00000000     0 FUNC    GLOBAL DEFAULT  UND getchar@GLIBC_2.0 (2)
     3: 00000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
     4: 00000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@GLIBC_2.0 (2)
     5: 0804850c     4 OBJECT  GLOBAL DEFAULT   15 _IO_stdin_used

Dynamic sections in Libc(Linux)

Symbol table '.dynsym' contains 2394 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 00000000     0 OBJECT  GLOBAL DEFAULT  UND __libc_stack_end@GLIBC_2.1 (34)
     2: 00000000     0 OBJECT  GLOBAL DEFAULT  UND _rtld_global@GLIBC_PRIVATE (35)
   .....
   640: 0004d410    52 FUNC    GLOBAL DEFAULT   12 printf@@GLIBC_2.0
   .....
   919: 00067630   233 FUNC    GLOBAL DEFAULT   12 getchar@@GLIBC_2.0

Dynamic sections in C App (Windows)

Windows world uses PE/COFF format for the executable binary. The section names and data formats are different but the mechanism is same. Linker adds sections various sections to hold the dependent library name, names of these external functions, effective address of these functions, offset table, procedure linkage table etc to the ELF binary.

Windows libc implicit linking

Windows Libc import library

Windows libc msvcrt.lib

List of import symbols by implicit app

windows app import symbols

Dynamic sections in Libc(Windows)

List of export symbols by libc/msvcrt.dll

windows libc msvcrt export symbols

Explicit Dynamic Linking or loading

Operating system loads the DLL on demand at runtime. An executable that uses a DLL by explicit linking must explicitly load and unload the DLL. It must also set up a function pointer to access each function it uses from the DLL. Unlike calls to functions in a statically linked library or an implicitly linked DLL, the client executable must call the exported functions in an explicitly linked DLL through function pointers. Explicit linking is sometimes referred to as dynamic load or run-time dynamic linking.

Windows Explicit Linking

When application does not links the external symbol by import library rather it loads the DLL at runtime. It does the same mechanism as operating system does during loading of the implicit linked DLL calls.

This is done by using Win32 APIs like :

  • LoadLibrary() - loads and links a input library form the DLL path, or current path,
  • GetProcAddress() - finds the symbol/function address by its name for a loaded DLL
  • FreeLibrary() - unloads the loaded DLL instance

Windows DLL project

mathlib-dll-project

mathlib-dll-project-2

mathlib-dll-project-3

mathlib-dll-project-build

#include "stdafx.h"

extern "C" __declspec(dllexport) int add (int a, int b)
{
  return (a + b);
}

extern "C" __declspec(dllexport) int sub (int a, int b)
{
  return (- b);
}

extern "C" __declspec(dllexport) int mul (int a, int b)
{
  return (* b);
}

extern "C" __declspec(dllexport) int div (int a, int b)
{
  return (/ b);
}

BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
           )
{
    return TRUE;
}


Windows App project

mathapp-project-1

mathapp-project-2

mathapp-project-3

mathapp-project-build

mathapp-project-dll-copy

mathapp-project-dll-explicit

#include "stdafx.h"
#include <windows.h>

/*Example of Explicit Call*/
typedef int (add_proc)(int a, int b);
int main(int argc, char *argv[])
{
  add_proc *add;
  HINSTANCE h_dll;
  int a = 1, b = 2, c;
  h_dll = LoadLibrary("mathlib.dll");/*Explicit Load*/
  if(h_dll)
  {
  printf("LoadLibrary returns %x\n", h_dll);
    add = (add_proc *)GetProcAddress(h_dll, "add");
    if(add)
    {
    printf("GetProcAddress returns add = %x\n", add);
      c = add(a, b); /*Explicit Call*/
    printf("add %d + %d = %d\n", a, b, c);
    }
    else
    {
      printf("add() not found in mathlib.dll");
    }
    FreeLibrary(h_dll);
  }
  else
  {
    printf("Unable to load mathlib.dll");
    return(-1);
  }
  return 0;
}

Linux Explicit Linking

Let us consider once again math.c file for explicit linking. The steps for creating a shared library are same as that of implicit linking.
First we compile it with position independent flag on(-fPIC). This is needed for dynamic/static linking.
$cc -fPIC -c mathlib.c -o mathlib.o

Now make a shared library with the object file.
$cc -shared -o libmath.so mathlib.o

To use this shared library in a application we need to load the library then find the function pointer address, invoke the function, and at last unload the library.
Linux provides some dynamic link library APIs to achieve this. Her are some useful frequently use APIs:

  • dlopen() - loads a dynamic link binary
  • dlsym() - returns the function pointer if found the function entry
  • dlclose() - unloads the dynamic link binary

Linux SO project

linux-mathlib-source

int add (int a, int b)
{
  return (a + b);
}

int sub (int a, int b)
{
  return (- b);
}

int mul (int a, int b)
{
  return (* b);
}

int div (int a, int b)
{
  return (/ b);
}

Linux App project

linux-mathapp-source

#include<stdio.h>
#include<dlfcn.h>

typedef int (add_func) (int a, int b);
void *lib_handle = NULL;
add_func * add;
int main (int argc, char *argv[])
{
  int a = 1, b = 2, c;
  lib_handle = (void *)dlopen("./libmath.so", RTLD_LAZY); 
  if(lib_handle) 
  {
    printf("dlopen returns %p\n", lib_handle);
    add = dlsym(lib_handle, "add");
    if(add)
    {
      printf("dlsym returns add = %p\n", add);
      c = add (a, b);
      printf("%d + %d = %d\n", a, b, c);
    }
    else
    {
      printf("Function entry not found in DLL");
    }
    dlclose(lib_handle);
  }
  else
  {
    printf("Unable to open DLL");
  }
}



SO and App build and run

linux-mathapp-source

About our authors: Team EQA

You have viewed 1 page out of 27. Your DLL learning is 0.00% complete. Login to check your learning progress.

#