1.
###after linux built
~/objs/linux-5.10.107/arch/arm64/kernel/vmlinux.lds
__initcall_start =
.;
KEEP(*(.initcallearly.init)) __initcall0_start = .;
KEEP(*(.initcall0.init)) KEEP(*(.initcall0s.init)) __initcall1_start = .;
KEEP(*(.initcall1.init)) KEEP(*(.initcall1s.init)) __initcall2_start = .;
KEEP(*(.initcall2.init)) KEEP(*(.initcall2s.init)) __initcall3_start = .;
KEEP(*(.initcall3.init)) KEEP(*(.initcall3s.init)) __initcall4_start = .;
KEEP(*(.initcall4.init)) KEEP(*(.initcall4s.init)) __initcall5_start = .;
KEEP(*(.initcall5.init)) KEEP(*(.initcall5s.init)) __initcallrootfs_start = .;
KEEP(*(.initcallrootfs.init)) KEEP(*(.initcallrootfss.init)) __initcall6_start = .;
KEEP(*(.initcall6.init)) KEEP(*(.initcall6s.init)) __initcall7_start = .;
KEEP(*(.initcall7.init)) KEEP(*(.initcall7s.init)) __initcall_end = .;
2.
~/linux-5.10.107/include/linux/compiler.h
#define __ADDRESSABLE(sym) \
static void * __section(".discard.addressable") __used \
__UNIQUE_ID(__PASTE(__addressable_,sym)) = (void *)&sym;
~/linux-5.10.107/include/linux/init.h
#define ___define_initcall(fn, id, __sec) \
__ADDRESSABLE(fn) \
asm(".section \"" #__sec ".init\", \"a\" \n" \
"__initcall_" #fn #id ": \n" \
".long " #fn " - . \n" \
".previous \n");
3.
~/linux-5.10.107/init/initramfs.c
rootfs_initcall(populate_rootfs);
4.
~/linux-5.10.107/init/main.c
static initcall_entry_t *initcall_levels[] __initdata = {
__initcall0_start,
__initcall1_start,
__initcall2_start,
__initcall3_start,
__initcall4_start,
__initcall5_start,
__initcall6_start,
__initcall7_start,
__initcall_end,
};
int __init_or_module do_one_initcall(initcall_t fn)
{
int count = preempt_count();
char msgbuf[64];
int ret;
if (initcall_blacklisted(fn))
return -EPERM;
do_trace_initcall_start(fn);
ret = fn();
do_trace_initcall_finish(fn, ret);
msgbuf[0] = 0;
if (preempt_count() != count) {
sprintf(msgbuf, "preemption imbalance ");
preempt_count_set(count);
}
if (irqs_disabled()) {
strlcat(msgbuf, "disabled interrupts ", sizeof(msgbuf));
local_irq_enable();
}
WARN(msgbuf[0], "initcall %pS returned with %s\n", fn, msgbuf);
add_latent_entropy();
return ret;
}
static void __init do_initcall_level(int level, char *command_line)
{
initcall_entry_t *fn;
parse_args(initcall_level_names[level],
command_line, __start___param,
__stop___param - __start___param,
level, level,
NULL, ignore_unknown_bootoption);
trace_initcall_level(initcall_level_names[level]);
for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++)
do_one_initcall(initcall_from_entry(fn));
}
5. gedit ./vmlinux_sim.lds
SECTIONS
{
/* 1. Start address after ELF headers */
. = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS;
/* System Metadata: Essential for the Dynamic Linker/Loader */
.interp : { *(.interp) }
.hash : { *(.hash) }
.gnu.hash : { *(.gnu.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.rela.dyn : { *(.rela.dyn) }
.rela.plt : { *(.rela.plt) }
/* Core Code: Executable instructions */
.text : { *(.text .text.*) }
.plt : { *(.plt) }
.plt.got : { *(.plt.got) }
/* Constant Data: Strings and read-only variables */
.rodata : { *(.rodata .rodata.*) }
/* Initcall Table: Since these are "a" (read-only), they stay here */
.initcalls : {
__initcall0_start = .;
KEEP(*(.initcall0.init))
__initcall1_start = .;
KEEP(*(.initcall1.init))
__initcall2_start = .;
KEEP(*(.initcall2.init))
__initcall3_start = .;
KEEP(*(.initcall3.init))
__initcall4_start = .;
KEEP(*(.initcall4.init))
__initcall5_start = .;
KEEP(*(.initcall5.init))
__initcallrootfs_start = .;
KEEP(*(.initcallrootfs.init))
__initcall6_start = .;
KEEP(*(.initcall6.init))
__initcall7_start = .;
KEEP(*(.initcall7.init))
__initcall_end = .;
}
/*
SEGMENT SEPARATOR: Alignment to Page Boundary (4KB)
This prevents the "RWX Permissions" warning by ensuring RX and RW.
*/
. = ALIGN(0x1000);
.data : { *(.data .data.*) }
.dynamic : { *(.dynamic) }
.got : { *(.got .got.plt) }
.bss : { *(.bss .bss.* COMMON) }
}
6. gedit ./api_initramfs.cpp ###full source simulation
#include <unistd.h>
#include <stdint.h>
#include <stdio.h>
typedef int (*initcall_t)(void); //refer to ~/linux-5.10.107/include/linux/init.h
/* keep symbol addressable (avoid GC) */
#define ADDRESSABLE(sym) \
static void * __attribute__((section(".discard.addressable"), used)) __addr_##sym = (void *)&(sym)
/*
NOTE: .long in gas is 4 bytes (PREL32). This requires linker script to place
.initcall*.init sections safely.
.long fn - . 32bits linktime address simulate fail
.quad fn - . 64bits linktime address simulate fail
.quad fn 64bits runtime relocation address simulate success
*/
#define __DEFINE_INITCALL(fn, id) \
ADDRESSABLE(fn); \
asm( \
".section .initcall" #id ".init,\"a\"\n" \
".quad " #fn "\n" \
".previous\n" \
)
/* convenience macros like kernel */
#define pure_initcall(fn) __DEFINE_INITCALL(fn, 0)
#define core_initcall(fn) __DEFINE_INITCALL(fn, 1)
#define postcore_initcall(fn) __DEFINE_INITCALL(fn, 2)
#define arch_initcall(fn) __DEFINE_INITCALL(fn, 3)
#define subsys_initcall(fn) __DEFINE_INITCALL(fn, 4)
#define fs_initcall(fn) __DEFINE_INITCALL(fn, 5)
#define rootfs_initcall(fn) __DEFINE_INITCALL(fn, rootfs)
#define device_initcall(fn) __DEFINE_INITCALL(fn, 6)
#define late_initcall(fn) __DEFINE_INITCALL(fn, 7)
//".quad " #fn need extern "C" for g++
#ifdef __cplusplus
extern "C" {
#endif
int l0_fn(void) {
printf("l0_fn\n");
return 0;
}
int l1_fn(void) {
printf("l1_fn\n");
return 0;
}
int l2_fn(void) {
printf("l2_fn\n");
return 0;
}
int l3_fn(void) {
printf("l3_fn\n");
return 0;
}
int l4_fn(void) {
printf("l4_fn\n");
return 0;
}
int l5_fn(void) {
printf("l5_fn\n");
return 0;
}
int rootfs_fn(void){
printf("rootfs_fn\n");
return 0;
}
int l6_fn(void) {
printf("l6_fn\n");
return 0;
}
int l7_fn(void) {
printf("l7_fn\n");
return 0;
}
#ifdef __cplusplus
}
#endif
/* --- register initcalls into their sections (emit PREL entries) */
pure_initcall(l0_fn);
core_initcall(l1_fn);
postcore_initcall(l2_fn);
arch_initcall(l3_fn);
subsys_initcall(l4_fn);
fs_initcall(l5_fn);
rootfs_initcall(rootfs_fn);
device_initcall(l6_fn);
late_initcall(l7_fn);
/* ---------------------------
* 3) extern labels (define in asm above) and levels array
* --------------------------- */
extern initcall_t __initcall0_start[];
extern initcall_t __initcall1_start[];
extern initcall_t __initcall2_start[];
extern initcall_t __initcall3_start[];
extern initcall_t __initcall4_start[];
extern initcall_t __initcall5_start[];
extern initcall_t __initcall6_start[];
extern initcall_t __initcall7_start[];
extern initcall_t __initcall_end[];
static initcall_t *initcall_levels[] = {
__initcall0_start,
__initcall1_start,
__initcall2_start,
__initcall3_start,
__initcall4_start,
__initcall5_start,
__initcall6_start,
__initcall7_start,
__initcall_end,
};
/* ---------------------------
* 4) simulate do_initcalls loop
* --------------------------- */
int do_one_initcall(initcall_t fn)
{
int ret = 0;
if (fn)
ret = fn();
return ret;
}
static void do_initcall_level(int level)
{
initcall_t *fn;
printf("do_initcall_level: %d\n", level);
for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++) {
do_one_initcall(*fn);
}
}
int main(int argc, char** argv)
{
for (int level = 0; level <= 7; level++)
do_initcall_level(level);
return 0;
}
7. gedit ./Makefile
TARGET = api_initramfs
SRCDIR = ./source
OBJDIR = ./obj
BINDIR = ./bin
#CROSS_COMPILE =
CROSS_COMPILE = /opt/toolchain/x86_64-asustor_x64_g3_2024.02.26-linux-gnu/bin/x86_64-asustor_x64_g3_2024.02.26-linux-gnu-
CXX = $(CROSS_COMPILE)g++
CXXFLAGS = -fmessage-length=0 -std=c++14 -pthread -fPIC -O0 -g
LDFLAGS = -Wl,-T,./vmlinux_sim.lds -lpthread
CXXFILES = $(notdir $(wildcard $(SRCDIR)/*.cpp))
CXXOBJS = $(patsubst %.cpp, $(OBJDIR)/%.o, $(CXXFILES))
$(shell mkdir -p $(OBJDIR))
$(shell mkdir -p $(BINDIR))
$(OBJDIR)/%.o : $(SRCDIR)/%.cpp
$(CXX) -c $(CXXFLAGS) $< -o $@
$(TARGET): $(COBJS) $(CXXOBJS)
$(CXX) $^ $(LDFLAGS) -o $(BINDIR)/$@
all: $(TARGET)
clean:
rm -rf $(OBJDIR) $(BINDIR)
8.
nm -n ./api_initramfs
w __gmon_start__
U __libc_start_main@GLIBC_2.34
U printf@GLIBC_2.2.5
U puts@GLIBC_2.2.5
00000000004002d0 r __abi_tag
0000000000400490 T _start
00000000004004c0 T _dl_relocate_static_pie
00000000004004c1 t deregister_tm_clones
00000000004004e0 t register_tm_clones
0000000000400517 t __do_global_dtors_aux
0000000000400537 t frame_dummy
000000000040053d T l0_fn
0000000000400557 T l1_fn
0000000000400571 T l2_fn
000000000040058b T l3_fn
00000000004005a5 T l4_fn
00000000004005bf T l5_fn
00000000004005d9 T rootfs_fn
00000000004005f3 T l6_fn
000000000040060d T l7_fn
0000000000400627 T _Z15do_one_initcallPFivE
000000000040064f t _ZL17do_initcall_leveli
00000000004006ca T main
0000000000400700 T _init
0000000000400718 T _fini
0000000000400760 R _IO_stdin_used
0000000000400990 r __FRAME_END__
0000000000400a10 r __GNU_EH_FRAME_HDR
0000000000400a8c R __initcall0_start
0000000000400a94 R __initcall1_start
0000000000400a9c R __initcall2_start
0000000000400aa4 R __initcall3_start
0000000000400aac R __initcall4_start
0000000000400ab4 R __initcall5_start
0000000000400abc R __initcallrootfs_start
0000000000400ac4 R __initcall6_start
0000000000400acc R __initcall7_start
0000000000400ad4 R __initcall_end
0000000000401000 D __data_start
0000000000401000 W data_start
0000000000401008 D __dso_handle
0000000000401020 d _ZL15initcall_levels
0000000000401068 d __do_global_dtors_aux_fini_array_entry
0000000000401068 D __TMC_END__
0000000000401070 d __frame_dummy_init_array_entry
0000000000401078 d _ZL12__addr_l0_fn
0000000000401080 d _ZL12__addr_l1_fn
0000000000401088 d _ZL12__addr_l2_fn
0000000000401090 d _ZL12__addr_l3_fn
0000000000401098 d _ZL12__addr_l4_fn
00000000004010a0 d _ZL12__addr_l5_fn
00000000004010a8 d _ZL16__addr_rootfs_fn
00000000004010b0 d _ZL12__addr_l6_fn
00000000004010b8 d _ZL12__addr_l7_fn
00000000004010c0 d _DYNAMIC
00000000004012e0 d _GLOBAL_OFFSET_TABLE_
0000000000401308 b completed.0
ps:
How is rootfs_fn added to the end of level 5? That's not the right question.
The execution of rootfs_fn is not because it is "deliberately placed at the end of level 5".
Is it because rootfs_fn is between initcall_levels[5] and initcall_levels[6], and therefore executed.
refer to:
https://static.sched.com/hosted_files/osseu2020/f5/2020_ELCE_initcalls_myjosserand.pdf
download:
https://www.mediafire.com/file/vb919erkp3s95m1/api_initramfs.tar.xz/file
沒有留言:
張貼留言