I am writing a small x86-64 OS. I am trying to make sense of how Linux loads modules at runtime by linking them into the kernel.

I understand that Linux builds a symbol lookup table. Basically, a module is compiled with a special utility which keeps all the symbols intact. Then, the Linux kernel will read the symbols and compare these to the symbol lookup table. Once it has got the address for the symbol, it links the symbol in the module to the actual address of the function in the virtual address space.

This seems quite easy to implement but I wonder how, in C++, you can implement such a symbol lookup table. I know that you can easily get the address of a function with &function. How do you get the symbol of the function in the form of ASCII letters?

Basically, how does Linux build its symbol lookup table? Is it during compilation or at boot? Also, I know that C++ is not the best tool for this because it mangles function names a lot.

  • $\begingroup$ If you write a small (presumably minimal) kernel, why would you want to handle dynamically loadable modules? How about starting e.g. with Xv6? $\endgroup$
    – vonbrand
    Commented Aug 13, 2021 at 23:21
  • $\begingroup$ I will get to ARM or RISC-V architectures eventually. For now, I am working on x86-64 from scratch. I give myself 3 years to have a functionnal OS. I'll bpe working on it during my studies in college. It may become more than minimal eventually. $\endgroup$
    – user123
    Commented Aug 14, 2021 at 2:39

1 Answer 1


I did find this wiki article: https://en.wikipedia.org/wiki/System.map. It states that the nm utility is used to get the System.map file that is then used by the kernel as the symbol lookup table.

I also found this System.map file on my boot partition on my Linux hard-disk. A sample:

user@user-System-Product-Name:/boot$ sudo gedit System.map-5.11.0-25-generic
ffffffff810d4ac0 t perf_trace_sched_numa_pair_template
ffffffff810d4c60 t __bpf_trace_sched_kthread_stop
ffffffff810d4c70 t __bpf_trace_sched_kthread_stop_ret
ffffffff810d4c80 t __bpf_trace_sched_kthread_work_execute_start
ffffffff810d4c90 t __bpf_trace_sched_process_wait
ffffffff810d4ca0 t __bpf_trace_sched_kthread_work_queue_work
ffffffff810d4cb0 t __bpf_trace_sched_kthread_work_execute_end
ffffffff810d4cc0 t __bpf_trace_sched_migrate_task
ffffffff810d4cd0 t __bpf_trace_sched_process_fork
ffffffff810d4ce0 t __bpf_trace_sched_stat_template
ffffffff810d4cf0 t __bpf_trace_sched_switch
ffffffff810d4d00 t __bpf_trace_sched_process_exec
ffffffff810d4d10 t __bpf_trace_sched_stat_runtime
ffffffff810d4d20 t __bpf_trace_sched_move_numa
ffffffff810d4d30 t __bpf_trace_sched_numa_pair_template
ffffffff810d4d40 T preempt_notifier_register
ffffffff810d4d90 t check_same_owner
ffffffff810d4de0 t is_cpu_allowed
ffffffff810d4e60 t cpumask_weight
ffffffff810d4e80 t set_load_weight
ffffffff810d4ef0 t __sched_fork
ffffffff810d5040 T preempt_notifier_inc
ffffffff810d5060 T preempt_notifier_dec
ffffffff810d5080 t __schedule_bug
ffffffff810d50a0 t sched_copy_attr
ffffffff810d5260 T __ia32_sys_sched_getscheduler
ffffffff810d52e0 T __ia32_sys_sched_getparam
ffffffff810d53d0 t nohz_csd_func
ffffffff810d5470 t sched_free_group
ffffffff810d54b0 t sched_free_group_rcu
ffffffff810d54d0 t cpu_cgroup_css_free
ffffffff810d54e0 t cpu_uclamp_min_show
ffffffff810d5590 t cpu_cfs_stat_show
ffffffff810d5650 t cpu_max_show
ffffffff810d5700 t cpu_extra_stat_show

Linux seems to relocate the kernel to 0xffffffff80000000.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.