HOMEVIDEOSCOURSESSTUDENTSSPONSORSDONATIONSEVENTSTUTORIALSLINKSNEWSCONTACT


TUTORIALS 》 Dynamic linking without STDLIB in Linux user-space C programming

This article is submitted by my student:
If you want to feature your article, you can kindly contact me via email and send your article submissions (content and the resources). Once they are reviewed, I should accept and post the same 🤗

11 - Ramin Farajpour Cami, Iran, Iran ↗
LinkedinGithub 🔗
Senior Cyber Security Researcher, EDG (Engineering Development Group) of CCI (Center for Cyber Intelligence).


Dynamic linker is the part of an operating system that loads and links the shared libraries needed by an executable.

Dynamic linking in Linux: Now, let us dig into the process of dynamically linked shared libraries in Linux. When users start an application, they're invoking an Executable and Linking Format (ELF) image (https://www.cs.stevens.edu/~jschauma/631/elf.html). The kernel begins with the process of loading the ELF image into user space virtual memory. The kernel notices an ELF section called .interp, which indicates the dynamic linker to be used /lib/ld-linux.so.
Example:

root@raminfp:~# readelf -l /bin/bash 

Elf file type is EXEC (Executable file)
Entry point 0x420650
There are 9 program headers, starting at offset 64

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  PHDR           0x0000000000000040 0x0000000000400040 0x0000000000400040
                 0x00000000000001f8 0x00000000000001f8  R E    8
  INTERP         0x0000000000000238 0x0000000000400238 0x0000000000400238
                 0x000000000000001c 0x000000000000001c  R      1
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
  LOAD           0x0000000000000000 0x0000000000400000 0x0000000000400000
                 0x00000000000f27d4 0x00000000000f27d4  R E    200000
  LOAD           0x00000000000f3628 0x00000000006f3628 0x00000000006f3628
                 0x000000000000b600 0x00000000000111d0  RW     200000
  DYNAMIC        0x00000000000f5de0 0x00000000006f5de0 0x00000000006f5de0
                 0x00000000000001f0 0x00000000000001f0  RW     8
  NOTE           0x0000000000000254 0x0000000000400254 0x0000000000400254
                 0x0000000000000044 0x0000000000000044  R      4
  GNU_EH_FRAME   0x00000000000d72b0 0x00000000004d72b0 0x00000000004d72b0
                 0x0000000000004094 0x0000000000004094  R      4
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RW     10
  GNU_RELRO      0x00000000000f3628 0x00000000006f3628 0x00000000006f3628
                 0x00000000000029d8 0x00000000000029d8  R      1

 Section to Segment mapping:
  Segment Sections...
   00     
   01     .interp 
   02     .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .plt.got .text .fini .rodata .eh_frame_hdr .eh_frame 
   03     .init_array .fini_array .jcr .data.rel.ro .dynamic .got .got.plt .data .bss 
   04     .dynamic 
   05     .note.ABI-tag .note.gnu.build-id 
   06     .eh_frame_hdr 
   07     
   08     .init_array .fini_array .jcr .data.rel.ro .dynamic .got 

We can find on the Internet many such examples of C source code about dynamic linker. But in this context we going to do Dynamic Linking of sample C user-space program without a standard lib (i.e STDLIB). In one of my earlier articles A Linux system call in C without a standard library I showed how to do a printf() in a sample C code with syscall without STDLIB. Now we can use/refer the same source code(mentioned in my previous article) for writing a dynamic linker.

And here is my GitHub project link https://github.com/raminfp/linux_syscall/tree/master/C_syscall_without_standard_library_linux in which you can refer assm_syscall.c:

int print(){
    write(1, "hello world\n", 13);
    return 0;
}

In the assm_syscall.c, we have this custom API intptr write(int fd, void const* data, uintptr nbytes). So based on this we can create assm_syscall.h and to test dytest.c:
Here is the contents of dytest.c:

#include "assm_syscall.h"
int main(void)
{
    print();
    return 0;
}

And here is the contents of assm_syscall.h:

int print();

And here is the contents of the Makefile:

CC=gcc
ASSMSYSCALLSOURCE=assm_syscall.c
CONFIG=-nostdlib -fno-unwind-tables -fno-asynchronous-unwind-tables
LIBDYNNAME=libdyn.so
DYNTESTSOURCE=dytest.c
DYNELF=dytest

all:
	$(CC) -s -O2 $(CONFIG) -fPIC -shared -o $(LIBDYNNAME)  $(ASSMSYSCALLSOURCE)
	$(CC) -o $(DYNELF) $(DYNTESTSOURCE) ./$(LIBDYNNAME)

nodyn:
	$(CC) -s -O2 $(CONFIG) -fPIC -shared -o $(LIBDYNNAME)  $(ASSMSYSCALLSOURCE)
	$(CC) -o $(DYNELF) $(DYNTESTSOURCE)

clean:
rm -rf $(LIBDYNNAME) $(DYNELF)

We can now compile the same as shown below:

root@raminfp:~# make
gcc -s -O2 -nostdlib -fno-unwind-tables -fno-asynchronous-unwind-tables -fPIC -shared -o libdyn.so  assm_syscall.c
gcc -o dytest dytest.c ./libdyn.so
root@raminfp:~# ./dytest
hello world
root@raminfp:~#
root@raminfp:~# make clean

As you can see we got the output hello world successfully.

Now we can do a test compile once again with the option make nodyn, i.e without the dynamic linker libdyn.so. And by doing so we get the following error.

gcc -s -O2 -nostdlib -fno-unwind-tables -fno-asynchronous-unwind-tables -fPIC -shared -o libdyn.so  assm_syscall.c
gcc -o dytest dytest.c
/tmp/cc4JX5qm.o: In function `main':
dytest.c:(.text+0xa): undefined reference to `print'
collect2: error: ld returned 1 exit status
Makefile:13: recipe for target 'nodyn' failed
make: *** [nodyn] Error 1
root@raminfp:~#

Here is my entire GitHub source-code which you can download HERE for reference.

So this is how you can do dynamic linking without STDLIB in Linux user-space C programming.


Featured Video:



Suggested Topics:


☆ Tutorials :: Arduino UNO Projects ↗


☆ Tutorials :: Network Software Development ↗


☆ Tutorials :: Research and Projects ↗


☆ Tutorials :: Linux (user-space), Systems Architecture ↗


☆ Tutorials :: Linux Kernel Software Development ↗


☆ Tutorials :: Linux Kernel Internals (PDFs) - by Ramin Farajpour ↗


☆ Tutorials :: Software Development (Programming) Tools ↗


☆ Tutorials :: Embedded Projects ↗

Join The Linux Channel :: Facebook Group ↗

Visit The Linux Channel :: on Youtube ↗


💗 Help shape the future: Sponsor/Donate


Recommended Topics:
Featured Video:
Watch on Youtube - [446//0] 297 - Coding Standards - use for() loops and avoid while() or do-until() loops ↗

libpcap Library | Linux User-space Network Stack Development ↗
Sunday' 06-Aug-2023
libpcap is a very popular user-space networking library, with which you can capture and or generate packets. libpcap is the underlying framework for many popular packet capture tools such as tcpdump, Wireshark and so on. In fact libpcap is a part of tcpdump project. But besides just using it as a packet capture tool, you can use libpcap in various applications, such as user-space based networking stack development, etc. In some cases libpcap is yet another alternative to raw-sockets and tun/tap interfaces.

The Linux Channel :: Sponsors ↗
Monday' 30-May-2022
Here is a list of all The Linux Channel sponsors/donors (individual/companies).

Inline Programming | Assembly | Scripts | php, python, shell, etc | Rust in Linux Kernel ↗
Friday' 12-May-2023
Inline programming is a technique where code statements are included directly in the text of a program, instead of being contained in separate files or modules. Inline programming can be useful for small or simple tasks, as it can eliminate the need for a separate script or function. One common example of inline programming is using JavaScripts, Php, etc in HTML documents to create dynamic content. Similarly in Linux Kernel we can find lot of instances where we can find inline programming such as inline assembly and now Rust within the Kernel source.

Linux Kernel /sysfs Interface ↗
Saturday' 14-May-2022
/sysfs is one of the most popular kernel to user-space interface which you can leverage to add an interface to your Kernel code such as Kernel modules, Kernel Device Drivers, etc. Although personally I prefer /proc interface than other alternatives such as /sysfs, ioctl() and so on for my personal Kernel modules/stack. So here is my detailed multi-episode Youtube video series on /sysfs Interface.

Rockchip ROC-RK3566-PC from Firefly | OpenWRT ↗
Thursday' 19-Oct-2023
Here is my multi-episode video series on evaluation of Rockchip ROC-RK3566-PC from Firefly with stock OpenWRT firmware.

What is purpose of Kernel Development - Example SMOAD Networks SDWAN Orchestrator Firewall Kernel Engine ↗
Monday' 18-Jul-2022
Often aspiring students may have this question, that what is the purpose of Linux Kernel Development. Since Linux Kernel is very mature and it has almost everything one would need. Usually, we need custom kernel development in the case of any new driver development for new upcoming hardware. And this happens on and on. But at times we may also come across few features/modules/components which are already provided by the Linux Kernel which are not adequate or atleast not the way we exactly intended to use. So, this is the real-world example, sometimes no matter what Linux Kernel provides as a part of stock Kernel/OS features, sometimes we have to write our own custom kernel stack or module(s) which can specifically cater our exact needs.

Linux Kernel Driver Device Trees ↗
Tuesday' 17-Jan-2023
The Linux kernel is the backbone of the Linux operating system. A device tree is a hierarchical tree structure that describes the various devices that are present in a system, including their properties and relationships to one another. The device tree is used by the Linux kernel to identify and initialize the different devices on a system, and to provide a consistent interface for interacting with them.

Linux Kernel vs User-space - Library APIs - Linux Kernel Programming ↗
Friday' 27-Oct-2023
One of the important aspects a beginner who is into Linux Kernel space systems software development has to understand is that unlike user-space C/C++ programming, where you can freely include any library APIs via respective #include files (which are dynamically linked during run-time via those /lib .so files), in the case of Kernel space programming, these library APIs are written within the Kernel source itself. These are the fundamental APIs which we commonly use, such as memcpy(), memcmp(), strlen(), strcpy(), strcpy() and so on. So here is my detailed Youtube video episode on the same with live demo, walk-through and examples.

Porting Sample libpcap C code to Raw Sockets | User-space Network Stack Framework ↗
Monday' 04-Sep-2023
Here is my multi-episode video series where I demonstrate how you can port the my libpcap sample code, discussed in the earlier episode to raw-socket. This code should further help you to design and architect your own user-space Network stack on top of this fundamental framework.

Roadmap - How to become Systems Software Developer ↗
Friday' 13-May-2022
When you are at the beginning of your career or a student, and aspire to become a software developer, one of the avenues to choose is to become a hard-core Systems Software Developer. However it is easier said than done, since there are many aspects to it as you explore further. As a part of systems developer, you can get into core kernel space developer, kernel device drivers developer, embedded developer and get into things like board bring-up, porting, etc, or can become a user-space systems programmer, and so on. So here is my detailed multi-episode Youtube video series on Roadmap - How to become Systems Software Developer.


Trending Video:
Watch on Youtube - [85//0] 278 The Linux Channel - Managing the Youtube channel and video content ↗

Bluefish IDE - a simple versatile light-weight best editor to edit kernel source files, html files, c source code, text files, SQL schema and so on ↗
Saturday' 13-Mar-2021



Recommended Video:
Watch on Youtube - [4706//0] 145 Linux Kernel Programming - /proc filesystem vs /dev character device drivers ↗