Ubuntu Root
#define
预处理指令从#开始,到其后第一个换行符为止。
C语言中宏定义的#define中有空格(即# define)
Gcc Attribute
Common Function Attributes【Gcc GNU】
__attribute__((section("TEST")))
#include <stdio.h> int __attribute__((section("TEST"))) test1(int a, int b) { return a + b; } int main(void) { static int static_var = 85; static int static_var2; int a = 1; int b; test1(1, 2); return 0; }
编译后得到的段信息为:
readelf -S C5 There are 38 section headers, starting at offset 0x1eb8: Section Headers: [Nr] Name Type Address Offset Size EntSize Flags Link Info Align [ 0] NULL 0000000000000000 00000000 0000000000000000 0000000000000000 0 0 0 [ 1] .interp PROGBITS 0000000000400238 00000238 000000000000001c 0000000000000000 A 0 0 1 [ 2] .note.ABI-tag NOTE 0000000000400254 00000254 0000000000000020 0000000000000000 A 0 0 4 [ 3] .note.gnu.build-i NOTE 0000000000400274 00000274 0000000000000024 0000000000000000 A 0 0 4 [ 4] .gnu.hash GNU_HASH 0000000000400298 00000298 0000000000000060 0000000000000000 A 5 0 8 [ 5] .dynsym DYNSYM 00000000004002f8 000002f8 00000000000001c8 0000000000000018 A 6 1 8 [ 6] .dynstr STRTAB 00000000004004c0 000004c0 00000000000000e1 0000000000000000 A 0 0 1 [ 7] .gnu.version VERSYM 00000000004005a2 000005a2 0000000000000026 0000000000000002 A 5 0 2 [ 8] .gnu.version_r VERNEED 00000000004005c8 000005c8 0000000000000020 0000000000000000 A 6 1 8 [ 9] .rela.dyn RELA 00000000004005e8 000005e8 0000000000000018 0000000000000018 A 5 0 8 [10] .rela.plt RELA 0000000000400600 00000600 0000000000000018 0000000000000018 AI 5 25 8 [11] .init PROGBITS 0000000000400618 00000618 000000000000001a 0000000000000000 AX 0 0 4 [12] .plt PROGBITS 0000000000400640 00000640 0000000000000020 0000000000000010 AX 0 0 16 [13] .plt.got PROGBITS 0000000000400660 00000660 0000000000000008 0000000000000000 AX 0 0 8 [14] .text PROGBITS 0000000000400670 00000670 0000000000000192 0000000000000000 AX 0 0 16 [15] TEST PROGBITS 0000000000400802 00000802 0000000000000014 0000000000000000 AX 0 0 1 [16] .fini PROGBITS 0000000000400818 00000818 0000000000000009 0000000000000000 AX 0 0 4 [17] .rodata PROGBITS 0000000000400824 00000824 0000000000000004 0000000000000004 AM 0 0 4 [18] .eh_frame_hdr PROGBITS 0000000000400828 00000828 000000000000003c 0000000000000000 A 0 0 4 [19] .eh_frame PROGBITS 0000000000400868 00000868 0000000000000114 0000000000000000 A 0 0 8 [20] .init_array INIT_ARRAY 0000000000600e10 00000e10 0000000000000008 0000000000000000 WA 0 0 8 [21] .fini_array FINI_ARRAY 0000000000600e18 00000e18 0000000000000008 0000000000000000 WA 0 0 8 [22] .jcr PROGBITS 0000000000600e20 00000e20 0000000000000008 0000000000000000 WA 0 0 8 [23] .dynamic DYNAMIC 0000000000600e28 00000e28 00000000000001d0 0000000000000010 WA 6 0 8 [24] .got PROGBITS 0000000000600ff8 00000ff8 0000000000000008 0000000000000008 WA 0 0 8 [25] .got.plt PROGBITS 0000000000601000 00001000 0000000000000020 0000000000000008 WA 0 0 8 [26] .data PROGBITS 0000000000601020 00001020 0000000000000014 0000000000000000 WA 0 0 8 [27] .bss NOBITS 0000000000601034 00001034 000000000000000c 0000000000000000 WA 0 0 4 [28] .comment PROGBITS 0000000000000000 00001034 0000000000000035 0000000000000001 MS 0 0 1 [29] .debug_aranges PROGBITS 0000000000000000 00001069 0000000000000040 0000000000000000 0 0 1 [30] .debug_info PROGBITS 0000000000000000 000010a9 000000000000010b 0000000000000000 0 0 1 [31] .debug_abbrev PROGBITS 0000000000000000 000011b4 0000000000000098 0000000000000000 0 0 1 [32] .debug_line PROGBITS 0000000000000000 0000124c 000000000000006a 0000000000000000 0 0 1 [33] .debug_str PROGBITS 0000000000000000 000012b6 000000000000010f 0000000000000001 MS 0 0 1 [34] .debug_ranges PROGBITS 0000000000000000 000013c5 0000000000000030 0000000000000000 0 0 1 [35] .shstrtab STRTAB 0000000000000000 00001d53 000000000000015f 0000000000000000 0 0 1 [36] .symtab SYMTAB 0000000000000000 000013f8 0000000000000720 0000000000000018 37 58 8 [37] .strtab STRTAB 0000000000000000 00001b18 000000000000023b 0000000000000000 0 0 1
从上可以看出通过__attribute__((section("TEST")))指定,最后多生成了TEST段(上中序号15)。
lds
arch/x86/kernel/vmlinux.lds
OUTPUT_FORMAT("elf64-x86-64") OUTPUT_ARCH(i386:x86-64) ENTRY(phys_startup_64) jiffies = jiffies_64; PHDRS { text PT_LOAD FLAGS(5); data PT_LOAD FLAGS(6); percpu PT_LOAD FLAGS(6); init PT_LOAD FLAGS(7); note PT_NOTE FLAGS(0); } SECTIONS { . = (0xffffffff80000000 + ALIGN(0x1000000, 0x200000)); phys_startup_64 = ABSOLUTE(startup_64 - 0xffffffff80000000); .text : AT(ADDR(.text) - 0xffffffff80000000) { _text = .; _stext = .; KEEP(*(.head.text)) . = ALIGN(8); *(.text.hot .text.hot.*) *(.text .text.fixup) *(.text.unlikely .text.unlikely.*) *(.text.unknown .text.unknown.*) . = ALIGN(8); __noinstr_text_start = .; *(.noinstr.text) __noinstr_text_end = .; *(.text..refcount) *(.ref.text) *(.text.asan.* .text.tsan.*) *(.meminit.text*) *(.memexit.text*) . = ALIGN(8); __sched_text_start = .; *(.sched.text) __sched_text_end = .; . = ALIGN(8); __cpuidle_text_start = .; *(.cpuidle.text) __cpuidle_text_end = .; . = ALIGN(8); __lock_text_start = .; *(.spinlock.text) __lock_text_end = .; . = ALIGN(8); __kprobes_text_start = .; *(.kprobes.text) __kprobes_text_end = .; . = ALIGN((1 << 21)); . = ALIGN(8); __entry_text_start = .; *(.entry.text) __entry_text_end = .; . = ALIGN((1 << 21)); . = ALIGN(8); __softirqentry_text_start = .; *(.softirqentry.text) __softirqentry_text_end = .; . = ALIGN(8); __static_call_text_start = .; *(.static_call.text) __static_call_text_end = .; *(.gnu.warning) __indirect_thunk_start = .; *(.text.__x86.*) __indirect_thunk_end = .; } :text =0xcccc _etext = .; . = ALIGN((1 << 12)); . = ALIGN((1 << 21)); . = ALIGN(((1 << 12))); .rodata : AT(ADDR(.rodata) - 0xffffffff80000000) { __start_rodata = .; *(.rodata) *(.rodata.*) . = ALIGN(32); __sched_class_highest = .; *(__stop_sched_class) *(__dl_sched_class) *(__rt_sched_class) *(__fair_sched_class) *(__idle_sched_class) __sched_class_lowest = .; . = ALIGN(8); __start_ro_after_init = .; *(.data..ro_after_init) . = ALIGN(8); __start___jump_table = .; KEEP(*(__jump_table)) __stop___jump_table = .; . = ALIGN(8); __start_static_call_sites = .; KEEP(*(.static_call_sites)) __stop_static_call_sites = .; __start_static_call_tramp_key = .; KEEP(*(.static_call_tramp_key)) __stop_static_call_tramp_key = .; __end_ro_after_init = .; . = ALIGN(8); __start___tracepoints_ptrs = .; KEEP(*(__tracepoints_ptrs)) __stop___tracepoints_ptrs = .; *(__tracepoints_strings) } .rodata1 : AT(ADDR(.rodata1) - 0xffffffff80000000) { *(.rodata1) } .pci_fixup : AT(ADDR(.pci_fixup) - 0xffffffff80000000) { __start_pci_fixups_early = .; KEEP(*(.pci_fixup_early)) __end_pci_fixups_early = .; __start_pci_fixups_header = .; KEEP(*(.pci_fixup_header)) __end_pci_fixups_header = .; __start_pci_fixups_final = .; KEEP(*(.pci_fixup_final)) __end_pci_fixups_final = .; __start_pci_fixups_enable = .; KEEP(*(.pci_fixup_enable)) __end_pci_fixups_enable = .; __start_pci_fixups_resume = .; KEEP(*(.pci_fixup_resume)) __end_pci_fixups_resume = .; __start_pci_fixups_resume_early = .; KEEP(*(.pci_fixup_resume_early)) __end_pci_fixups_resume_early = .; __start_pci_fixups_suspend = .; KEEP(*(.pci_fixup_suspend)) __end_pci_fixups_suspend = .; __start_pci_fixups_suspend_late = .; KEEP(*(.pci_fixup_suspend_late)) __end_pci_fixups_suspend_late = .; } .builtin_fw : AT(ADDR(.builtin_fw) - 0xffffffff80000000) ALIGN(8) { __start_builtin_fw = .; KEEP(*(.builtin_fw)) __end_builtin_fw = .; } . = ALIGN(4); .tracedata : AT(ADDR(.tracedata) - 0xffffffff80000000) { __tracedata_start = .; KEEP(*(.tracedata)) __tracedata_end = .; } __ksymtab : AT(ADDR(__ksymtab) - 0xffffffff80000000) { __start___ksymtab = .; KEEP(*(SORT(___ksymtab+*))) __stop___ksymtab = .; } __ksymtab_gpl : AT(ADDR(__ksymtab_gpl) - 0xffffffff80000000) { __start___ksymtab_gpl = .; KEEP(*(SORT(___ksymtab_gpl+*))) __stop___ksymtab_gpl = .; } __kcrctab : AT(ADDR(__kcrctab) - 0xffffffff80000000) { __start___kcrctab = .; KEEP(*(SORT(___kcrctab+*))) __stop___kcrctab = .; } __kcrctab_gpl : AT(ADDR(__kcrctab_gpl) - 0xffffffff80000000) { __start___kcrctab_gpl = .; KEEP(*(SORT(___kcrctab_gpl+*))) __stop___kcrctab_gpl = .; } __ksymtab_strings : AT(ADDR(__ksymtab_strings) - 0xffffffff80000000) { *(__ksymtab_strings) } __init_rodata : AT(ADDR(__init_rodata) - 0xffffffff80000000) { *(.ref.rodata) *(.meminit.rodata) *(.memexit.rodata) } __param : AT(ADDR(__param) - 0xffffffff80000000) { __start___param = .; KEEP(*(__param)) __stop___param = .; } __modver : AT(ADDR(__modver) - 0xffffffff80000000) { __start___modver = .; KEEP(*(__modver)) __stop___modver = .; } . = ALIGN(16); __ex_table : AT(ADDR(__ex_table) - 0xffffffff80000000) { __start___ex_table = .; KEEP(*(__ex_table)) __stop___ex_table = .; } .notes : AT(ADDR(.notes) - 0xffffffff80000000) { __start_notes = .; KEEP(*(.note.*)) __stop_notes = .; } :text :note __restore_ph : { *(.__restore_ph) } :text . = ALIGN(((1 << 12))); __end_rodata = .; . = ALIGN((1 << 21)); __end_rodata_hpage_align = .; __end_rodata_aligned = .; .data : AT(ADDR(.data) - 0xffffffff80000000) { _sdata = .; . = ALIGN(((1 << 12) << (2 + 0))); __start_init_task = .; init_thread_union = .; init_stack = .; KEEP(*(.data..init_task)) KEEP(*(.data..init_thread_info)) . = __start_init_task + ((1 << 12) << (2 + 0)); __end_init_task = .; . = ALIGN((1 << 12)); *(.data..page_aligned) . = ALIGN((1 << 12)); . = ALIGN((1 << (6))); *(.data..cacheline_aligned) *(.xiptext) *(.data) *(.data..decrypted) *(.ref.data) *(.data..shared_aligned) *(.meminit.data*) *(.memexit.data*) *(.data.unlikely) __start_once = .; *(.data.once) __end_once = .; . = ALIGN(32); *(__tracepoints) . = ALIGN(8); __start___dyndbg_classes = .; KEEP(*(__dyndbg_classes)) __stop___dyndbg_classes = .; __start___dyndbg = .; KEEP(*(__dyndbg)) __stop___dyndbg = .; __start___trace_bprintk_fmt = .; KEEP(*(__trace_printk_fmt)) __stop___trace_bprintk_fmt = .; . = ALIGN(32); __start__bpf_raw_tp = .; KEEP(*(__bpf_raw_tp_map)) __stop__bpf_raw_tp = .; __start___tracepoint_str = .; KEEP(*(__tracepoint_str)) __stop___tracepoint_str = .; CONSTRUCTORS . = ALIGN((1 << 6)); *(.data..read_mostly) . = ALIGN((1 << 6)); _edata = .; } :data . = ALIGN(8); __bug_table : AT(ADDR(__bug_table) - 0xffffffff80000000) { __start___bug_table = .; KEEP(*(__bug_table)) __stop___bug_table = .; } . = ALIGN((1 << 12)); __vvar_page = .; .vvar : AT(ADDR(.vvar) - 0xffffffff80000000) { __vvar_beginning_hack = .; . = __vvar_beginning_hack + 128; *(.vvar__vdso_data) . = __vvar_beginning_hack + (1 << 12); } :data . = ALIGN(__vvar_page + (1 << 12), (1 << 12)); . = ALIGN((1 << 12)); .init.begin : AT(ADDR(.init.begin) - 0xffffffff80000000) { __init_begin = .; } __per_cpu_load = .; .data..percpu 0 : AT(__per_cpu_load - 0xffffffff80000000) { __per_cpu_start = .; *(.data..percpu..first) . = ALIGN((1 << 12)); *(.data..percpu..page_aligned) . = ALIGN((1 << 6)); *(.data..percpu..read_mostly) . = ALIGN((1 << 6)); *(.data..percpu) *(.data..percpu..shared_aligned) . = ALIGN((1 << 12)); *(.data..percpu..decrypted) . = ALIGN((1 << 12)); __per_cpu_end = .; } :percpu . = __per_cpu_load + SIZEOF(.data..percpu); ASSERT(SIZEOF(.data..percpu) < 0x1000000, "per-CPU data too large - increase CONFIG_PHYSICAL_START") . = ALIGN((1 << 12)); .init.text : AT(ADDR(.init.text) - 0xffffffff80000000) { _sinittext = .; *(.init.text .init.text.*) *(.text.startup) _einittext = .; } :init .altinstr_aux : AT(ADDR(.altinstr_aux) - 0xffffffff80000000) { *(.altinstr_aux) } .init.data : AT(ADDR(.init.data) - 0xffffffff80000000) { KEEP(*(SORT(___kentry+*))) *(.init.data init.data.*) . = ALIGN(8); __start_mcount_loc = .; KEEP(*(__mcount_loc)) __stop_mcount_loc = .; ftrace_ops_list_func = arch_ftrace_ops_list_func; *(.init.rodata .init.rodata.*) . = ALIGN(8); __start_ftrace_events = .; KEEP(*(_ftrace_events)) __stop_ftrace_events = .; __start_ftrace_eval_maps = .; KEEP(*(_ftrace_eval_map)) __stop_ftrace_eval_maps = .; . = ALIGN(8); __start_syscalls_metadata = .; KEEP(*(__syscalls_metadata)) __stop_syscalls_metadata = .; . = ALIGN(8); __start_kprobe_blacklist = .; KEEP(*(_kprobe_blacklist)) __stop_kprobe_blacklist = .; . = ALIGN(32); __start_error_injection_whitelist = .; KEEP(*(_error_injection_whitelist)) __stop_error_injection_whitelist = .; . = ALIGN(8); __clk_of_table = .; KEEP(*(__clk_of_table)) KEEP(*(__clk_of_table_end)) . = ALIGN(8); __cpu_method_of_table = .; KEEP(*(__cpu_method_of_table)) KEEP(*(__cpu_method_of_table_end)) . = ALIGN(8); __cpuidle_method_of_table = .; KEEP(*(__cpuidle_method_of_table)) KEEP(*(__cpuidle_method_of_table_end)) . = ALIGN(32); __dtb_start = .; KEEP(*(.dtb.init.rodata)) __dtb_end = .; . = ALIGN(8); __irqchip_acpi_probe_table = .; KEEP(*(__irqchip_acpi_probe_table)) __irqchip_acpi_probe_table_end = .; . = ALIGN(8); __timer_acpi_probe_table = .; KEEP(*(__timer_acpi_probe_table)) __timer_acpi_probe_table_end = .; . = ALIGN(8); __governor_thermal_table = .; KEEP(*(__governor_thermal_table)) __governor_thermal_table_end = .; . = ALIGN(8); __earlycon_table = .; KEEP(*(__earlycon_table)) __earlycon_table_end = .; . = ALIGN(8); __start_lsm_info = .; KEEP(*(.lsm_info.init)) __end_lsm_info = .; . = ALIGN(8); __start_early_lsm_info = .; KEEP(*(.early_lsm_info.init)) __end_early_lsm_info = .; . = ALIGN(8); __kunit_suites_start = .; KEEP(*(.kunit_test_suites)) __kunit_suites_end = .; . = ALIGN(16); __setup_start = .; KEEP(*(.init.setup)) __setup_end = .; __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 = .; __con_initcall_start = .; KEEP(*(.con_initcall.init)) __con_initcall_end = .; . = ALIGN(4); __initramfs_start = .; KEEP(*(.init.ramfs)) . = ALIGN(8); KEEP(*(.init.ramfs.info)) } .x86_cpu_dev.init : AT(ADDR(.x86_cpu_dev.init) - 0xffffffff80000000) { __x86_cpu_dev_start = .; *(.x86_cpu_dev.init) __x86_cpu_dev_end = .; } . = ALIGN(8); .parainstructions : AT(ADDR(.parainstructions) - 0xffffffff80000000) { __parainstructions = .; *(.parainstructions) __parainstructions_end = .; } . = ALIGN(8); .retpoline_sites : AT(ADDR(.retpoline_sites) - 0xffffffff80000000) { __retpoline_sites = .; *(.retpoline_sites) __retpoline_sites_end = .; } . = ALIGN(8); .return_sites : AT(ADDR(.return_sites) - 0xffffffff80000000) { __return_sites = .; *(.return_sites) __return_sites_end = .; } . = ALIGN(8); .altinstructions : AT(ADDR(.altinstructions) - 0xffffffff80000000) { __alt_instructions = .; *(.altinstructions) __alt_instructions_end = .; } .altinstr_replacement : AT(ADDR(.altinstr_replacement) - 0xffffffff80000000) { *(.altinstr_replacement) } . = ALIGN(8); .apicdrivers : AT(ADDR(.apicdrivers) - 0xffffffff80000000) { __apicdrivers = .; *(.apicdrivers); __apicdrivers_end = .; } . = ALIGN(8); .exit.text : AT(ADDR(.exit.text) - 0xffffffff80000000) { *(.exit.text) *(.text.exit) } .exit.data : AT(ADDR(.exit.data) - 0xffffffff80000000) { *(.exit.data .exit.data.*) *(.fini_array .fini_array.*) *(.dtors .dtors.*) } . = ALIGN((1 << 12)); .init.end : AT(ADDR(.init.end) - 0xffffffff80000000) { __init_end = .; } . = ALIGN((1 << 12)); .smp_locks : AT(ADDR(.smp_locks) - 0xffffffff80000000) { __smp_locks = .; *(.smp_locks) . = ALIGN((1 << 12)); __smp_locks_end = .; } .data_nosave : AT(ADDR(.data_nosave) - 0xffffffff80000000) { . = ALIGN((1 << 12)); __nosave_begin = .; *(.data..nosave) . = ALIGN((1 << 12)); __nosave_end = .; } . = ALIGN((1 << 12)); .bss : AT(ADDR(.bss) - 0xffffffff80000000) { __bss_start = .; *(.bss..page_aligned) . = ALIGN((1 << 12)); *(.bss) . = ALIGN((1 << 21)); __start_bss_decrypted = .; *(.bss..decrypted); . = ALIGN((1 << 12)); __start_bss_decrypted_unused = .; . = ALIGN((1 << 21)); __end_bss_decrypted = .; . = ALIGN((1 << 12)); __bss_stop = .; } __end_of_kernel_reserve = .; . = ALIGN((1 << 12)); .brk : AT(ADDR(.brk) - 0xffffffff80000000) { __brk_base = .; . += 64 * 1024; *(.bss..brk) __brk_limit = .; } . = ALIGN((1 << 12)); _end = .; . = ALIGN((1 << 21)); .init.scratch : AT(ADDR(.init.scratch) - 0xffffffff80000000) { __init_scratch_begin = .; *(.init.scratch) . = ALIGN((1 << 21)); __init_scratch_end = .; } .stab 0 : { *(.stab) } .stabstr 0 : { *(.stabstr) } .stab.excl 0 : { *(.stab.excl) } .stab.exclstr 0 : { *(.stab.exclstr) } .stab.index 0 : { *(.stab.index) } .stab.indexstr 0 : { *(.stab.indexstr) } .debug 0 : { *(.debug) } .line 0 : { *(.line) } .debug_srcinfo 0 : { *(.debug_srcinfo) } .debug_sfnames 0 : { *(.debug_sfnames) } .debug_aranges 0 : { *(.debug_aranges) } .debug_pubnames 0 : { *(.debug_pubnames) } .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } .debug_abbrev 0 : { *(.debug_abbrev) } .debug_line 0 : { *(.debug_line) } .debug_frame 0 : { *(.debug_frame) } .debug_str 0 : { *(.debug_str) } .debug_loc 0 : { *(.debug_loc) } .debug_macinfo 0 : { *(.debug_macinfo) } .debug_pubtypes 0 : { *(.debug_pubtypes) } .debug_ranges 0 : { *(.debug_ranges) } .debug_weaknames 0 : { *(.debug_weaknames) } .debug_funcnames 0 : { *(.debug_funcnames) } .debug_typenames 0 : { *(.debug_typenames) } .debug_varnames 0 : { *(.debug_varnames) } .debug_gnu_pubnames 0 : { *(.debug_gnu_pubnames) } .debug_gnu_pubtypes 0 : { *(.debug_gnu_pubtypes) } .debug_types 0 : { *(.debug_types) } .debug_addr 0 : { *(.debug_addr) } .debug_line_str 0 : { *(.debug_line_str) } .debug_loclists 0 : { *(.debug_loclists) } .debug_macro 0 : { *(.debug_macro) } .debug_names 0 : { *(.debug_names) } .debug_rnglists 0 : { *(.debug_rnglists) } .debug_str_offsets 0 : { *(.debug_str_offsets) } .comment 0 : { *(.comment) } .symtab 0 : { *(.symtab) } .strtab 0 : { *(.strtab) } .shstrtab 0 : { *(.shstrtab) } /DISCARD/ : { *(.exitcall.exit) *(__patchable_function_entries) *(.discard) *(.discard.*) *(.modinfo) *(.gnu.version*) } .got.plt (INFO) : { *(.got.plt) } ASSERT(SIZEOF(.got.plt) == 0 || SIZEOF(.got.plt) == 0x18, "Unexpected GOT/PLT entries detected!") .got : { *(.got) *(.igot.*) } ASSERT(SIZEOF(.got) == 0, "Unexpected GOT entries detected!") .plt : { *(.plt) *(.plt.*) *(.iplt) } ASSERT(SIZEOF(.plt) == 0, "Unexpected run-time procedure linkages detected!") .rel.dyn : { *(.rel.*) *(.rel_*) } ASSERT(SIZEOF(.rel.dyn) == 0, "Unexpected run-time relocations (.rel) detected!") .rela.dyn : { *(.rela.*) *(.rela_*) } ASSERT(SIZEOF(.rela.dyn) == 0, "Unexpected run-time relocations (.rela) detected!") } . = ASSERT((_end - 0xffffffff80000000 <= (1024 * 1024 * 1024)), "kernel image bigger than KERNEL_IMAGE_SIZE"); init_per_cpu__gdt_page = ABSOLUTE(gdt_page) + __per_cpu_load; init_per_cpu__fixed_percpu_data = ABSOLUTE(fixed_percpu_data) + __per_cpu_load; init_per_cpu__irq_stack_backing_store = ABSOLUTE(irq_stack_backing_store) + __per_cpu_load; . = ASSERT((fixed_percpu_data == 0), "fixed_percpu_data is not at start of per-cpu area"); . = ASSERT(kexec_control_code_size <= 2048, "kexec control code size is too big");
内核调试方法
调试
使用vscode+qemu+gdb进行调试
vscode + gdb 远程调试 linux 内核源码(附视频)
printk
/proc/sys/kernel/printk是procfs,其控制内核printk函数的打印。
printk(KERN_DEBUG "calling %pS @ %i\n", fn, task_pid_nr(current)); #define printk(fmt, ...) printk_index_wrap(_printk, fmt, ##__VA_ARGS__) #define pr_emerg(fmt, ...) \ printk(KERN_EMERG pr_fmt(fmt), ##__VA_ARGS__) #define pr_alert(fmt, ...) \ printk(KERN_ALERT pr_fmt(fmt), ##__VA_ARGS__) #define pr_crit(fmt, ...) \ printk(KERN_CRIT pr_fmt(fmt), ##__VA_ARGS__) #define pr_err(fmt, ...) \ printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__) #define pr_warn(fmt, ...) \ printk(KERN_WARNING pr_fmt(fmt), ##__VA_ARGS__) #define pr_notice(fmt, ...) \ printk(KERN_NOTICE pr_fmt(fmt), ##__VA_ARGS__) #define pr_info(fmt, ...) \ printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__) #define pr_cont(fmt, ...) \ printk(KERN_CONT fmt, ##__VA_ARGS__) #define pr_devel(fmt, ...) \ printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__) #define KERN_SOH "\001" /* ASCII Start Of Header */ #define KERN_SOH_ASCII '\001' #define KERN_EMERG KERN_SOH "0" /* system is unusable */ #define KERN_ALERT KERN_SOH "1" /* action must be taken immediately */ #define KERN_CRIT KERN_SOH "2" /* critical conditions */ #define KERN_ERR KERN_SOH "3" /* error conditions */ #define KERN_WARNING KERN_SOH "4" /* warning conditions */ #define KERN_NOTICE KERN_SOH "5" /* normal but significant condition */ #define KERN_INFO KERN_SOH "6" /* informational */ #define KERN_DEBUG KERN_SOH "7" /* debug-level messages */ #define KERN_DEFAULT "" /* the default kernel loglevel */ #define KERN_CONT KERN_SOH "c"
Kernel Panic
objdump
backtrace
Kdump
crash工具分析Kdump下vmcore文件常用命令总结(三)
core
Ubuntu 20 core dumped(核心已转储)问题分析
Linux:段错误(核心已转储) Segmentation fault (core dumped)(在Linux上如何得到一个段错误的核心转储)
SysRq
Linux启动分析
Linux 0.11
Linux启动跟踪
宿主机:Ubuntu22.04,内核:6.1.10,模拟器:qemu,ramfs:busybox
secondary_startup_64
arch/x86/kernel/head_64.S
ffffffff81000070 T secondary_startup_64
.Ljump_to_C_code: /* * Jump to run C code and to be on a real kernel address. * Since we are running on identity-mapped space we have to jump * to the full 64bit address, this is only possible as indirect * jump. In addition we need to ensure %cs is set so we make this * a far return. * * Note: do not change to far jump indirect with 64bit offset. * * AMD does not support far jump indirect with 64bit offset. * AMD64 Architecture Programmer's Manual, Volume 3: states only * JMP FAR mem16:16 FF /5 Far jump indirect, * with the target specified by a far pointer in memory. * JMP FAR mem16:32 FF /5 Far jump indirect, * with the target specified by a far pointer in memory. * * Intel64 does support 64bit offset. * Software Developer Manual Vol 2: states: * FF /5 JMP m16:16 Jump far, absolute indirect, * address given in m16:16 * FF /5 JMP m16:32 Jump far, absolute indirect, * address given in m16:32. * REX.W + FF /5 JMP m16:64 Jump far, absolute indirect, * address given in m16:64. */ pushq $.Lafter_lret # put return address on stack for unwinder xorl %ebp, %ebp # clear frame pointer movq initial_code(%rip), %rax pushq $__KERNEL_CS # set correct cs pushq %rax # target address in negative space lretq .Lafter_lret: ANNOTATE_NOENDBR SYM_CODE_END(secondary_startup_64)
secondary_startup_64 ==> x86_64_start_kernel
x86_64_start_kernel
arch/x86/kernel/head64.c
asmlinkage __visible void __init x86_64_start_kernel(char * real_mode_data) { /* * Build-time sanity checks on the kernel image and module * area mappings. (these are purely build-time and produce no code) */ BUILD_BUG_ON(MODULES_VADDR < __START_KERNEL_map); BUILD_BUG_ON(MODULES_VADDR - __START_KERNEL_map < KERNEL_IMAGE_SIZE); BUILD_BUG_ON(MODULES_LEN + KERNEL_IMAGE_SIZE > 2*PUD_SIZE); BUILD_BUG_ON((__START_KERNEL_map & ~PMD_MASK) != 0); BUILD_BUG_ON((MODULES_VADDR & ~PMD_MASK) != 0); BUILD_BUG_ON(!(MODULES_VADDR > __START_KERNEL)); MAYBE_BUILD_BUG_ON(!(((MODULES_END - 1) & PGDIR_MASK) == (__START_KERNEL & PGDIR_MASK))); BUILD_BUG_ON(__fix_to_virt(__end_of_fixed_addresses) <= MODULES_END); cr4_init_shadow(); /* Kill off the identity-map trampoline */ reset_early_page_tables(); clear_bss(); /* * This needs to happen *before* kasan_early_init() because latter maps stuff * into that page. */ clear_page(init_top_pgt); /* * SME support may update early_pmd_flags to include the memory * encryption mask, so it needs to be called before anything * that may generate a page fault. */ sme_early_init(); kasan_early_init(); /* * Flush global TLB entries which could be left over from the trampoline page * table. * * This needs to happen *after* kasan_early_init() as KASAN-enabled .configs * instrument native_write_cr4() so KASAN must be initialized for that * instrumentation to work. */ __native_tlb_flush_global(this_cpu_read(cpu_tlbstate.cr4)); idt_setup_early_handler(); /* Needed before cc_platform_has() can be used for TDX */ tdx_early_init(); copy_bootdata(__va(real_mode_data)); /* * Load microcode early on BSP. */ load_ucode_bsp(); /* set init_top_pgt kernel high mapping*/ init_top_pgt[511] = early_top_pgt[511]; x86_64_start_reservations(real_mode_data); } void __init x86_64_start_reservations(char *real_mode_data) { /* version is always not zero if it is copied */ if (!boot_params.hdr.version) copy_bootdata(__va(real_mode_data)); x86_early_init_platform_quirks(); switch (boot_params.hdr.hardware_subarch) { case X86_SUBARCH_INTEL_MID: x86_intel_mid_early_setup(); break; default: break; } start_kernel(); }
x86_64_start_kernel ==> x86_64_start_reservations ==> start_kernel
start_kernel
init/main.c
asmlinkage __visible void __init __no_sanitize_address start_kernel(void) { char *command_line; char *after_dashes; set_task_stack_end_magic(&init_task); smp_setup_processor_id(); debug_objects_early_init(); init_vmlinux_build_id(); cgroup_init_early(); local_irq_disable(); early_boot_irqs_disabled = true; /* * Interrupts are still disabled. Do necessary setups, then * enable them. */ boot_cpu_init(); page_address_init(); pr_notice("%s", linux_banner); early_security_init(); setup_arch(&command_line); setup_boot_config(); setup_command_line(command_line); setup_nr_cpu_ids(); setup_per_cpu_areas(); smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks */ boot_cpu_hotplug_init(); build_all_zonelists(NULL); page_alloc_init(); pr_notice("Kernel command line: %s\n", saved_command_line); /* parameters may set static keys */ jump_label_init(); parse_early_param(); after_dashes = parse_args("Booting kernel", static_command_line, __start___param, __stop___param - __start___param, -1, -1, NULL, &unknown_bootoption); print_unknown_bootoptions(); if (!IS_ERR_OR_NULL(after_dashes)) parse_args("Setting init args", after_dashes, NULL, 0, -1, -1, NULL, set_init_arg); if (extra_init_args) parse_args("Setting extra init args", extra_init_args, NULL, 0, -1, -1, NULL, set_init_arg); /* Architectural and non-timekeeping rng init, before allocator init */ random_init_early(command_line); /* * These use large bootmem allocations and must precede * kmem_cache_init() */ setup_log_buf(0); vfs_caches_init_early(); sort_main_extable(); trap_init(); mm_init(); ftrace_init(); /* trace_printk can be enabled here */ early_trace_init(); /* * Set up the scheduler prior starting any interrupts (such as the * timer interrupt). Full topology setup happens at smp_init() * time - but meanwhile we still have a functioning scheduler. */ sched_init(); if (WARN(!irqs_disabled(), "Interrupts were enabled *very* early, fixing it\n")) local_irq_disable(); radix_tree_init(); maple_tree_init(); /* * Set up housekeeping before setting up workqueues to allow the unbound * workqueue to take non-housekeeping into account. */ housekeeping_init(); /* * Allow workqueue creation and work item queueing/cancelling * early. Work item execution depends on kthreads and starts after * workqueue_init(). */ workqueue_init_early(); rcu_init(); /* Trace events are available after this */ trace_init(); if (initcall_debug) initcall_debug_enable(); context_tracking_init(); /* init some links before init_ISA_irqs() */ early_irq_init(); init_IRQ(); tick_init(); rcu_init_nohz(); init_timers(); srcu_init(); hrtimers_init(); softirq_init(); timekeeping_init(); time_init(); /* This must be after timekeeping is initialized */ random_init(); /* These make use of the fully initialized rng */ kfence_init(); boot_init_stack_canary(); perf_event_init(); profile_init(); call_function_init(); WARN(!irqs_disabled(), "Interrupts were enabled early\n"); early_boot_irqs_disabled = false; local_irq_enable(); kmem_cache_init_late(); /* * HACK ALERT! This is early. We're enabling the console before * we've done PCI setups etc, and console_init() must be aware of * this. But we do want output early, in case something goes wrong. */ console_init(); if (panic_later) panic("Too many boot %s vars at `%s'", panic_later, panic_param); lockdep_init(); /* * Need to run this when irqs are enabled, because it wants * to self-test [hard/soft]-irqs on/off lock inversion bugs * too: */ locking_selftest(); /* * This needs to be called before any devices perform DMA * operations that might use the SWIOTLB bounce buffers. It will * mark the bounce buffers as decrypted so that their usage will * not cause "plain-text" data to be decrypted when accessed. */ mem_encrypt_init(); #ifdef CONFIG_BLK_DEV_INITRD if (initrd_start && !initrd_below_start_ok && page_to_pfn(virt_to_page((void *)initrd_start)) < min_low_pfn) { pr_crit("initrd overwritten (0x%08lx < 0x%08lx) - disabling it.\n", page_to_pfn(virt_to_page((void *)initrd_start)), min_low_pfn); initrd_start = 0; } #endif setup_per_cpu_pageset(); numa_policy_init(); acpi_early_init(); if (late_time_init) late_time_init(); sched_clock_init(); calibrate_delay(); pid_idr_init(); anon_vma_init(); #ifdef CONFIG_X86 if (efi_enabled(EFI_RUNTIME_SERVICES)) efi_enter_virtual_mode(); #endif thread_stack_cache_init(); cred_init(); fork_init(); proc_caches_init(); uts_ns_init(); key_init(); security_init(); dbg_late_init(); net_ns_init(); vfs_caches_init(); pagecache_init(); signals_init(); seq_file_init(); proc_root_init(); nsfs_init(); cpuset_init(); cgroup_init(); taskstats_init_early(); delayacct_init(); poking_init(); check_bugs(); acpi_subsystem_init(); arch_post_acpi_subsys_init(); kcsan_init(); /* Do the rest non-__init'ed, we're now alive */ arch_call_rest_init(); prevent_tail_call_optimization(); }
asmlinkage
include/linux/linkage.h
#ifdef __cplusplus #define CPP_ASMLINKAGE extern "C" #else #define CPP_ASMLINKAGE #endif #ifndef asmlinkage #define asmlinkage CPP_ASMLINKAGE #endif
asmlinkage在C中为空,在C++中为extern "C"。
__visible
对外可见
// https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-externally_005fvisible-function-attribute #if __has_attribute(__externally_visible__) # define __visible __attribute__((__externally_visible__)) #else # define __visible #endif
__init
#define __init __section(".init.text") __cold __latent_entropy __noinitretpoline // 告诉编译器生成指定的段 #define __section(section) __attribute__((__section__(section))) // 其作用是告诉编译器此函数不太经常被执行,为冷代码,用于优化大小 #define __cold __attribute__((__cold__)) #ifndef __latent_entropy # define __latent_entropy #endif #if defined(__noretpoline) && !defined(MODULE) #define __noinitretpoline __noretpoline #else #define __noinitretpoline #endif #ifdef CONFIG_RETPOLINE #define __noretpoline __attribute__((__indirect_branch__("keep"))) #endif
__no_sanitize_address
#if __has_attribute(__no_sanitize_address__) // 用于通知编译器,在使用选项进行编译时,不应在函数中检测内存访问 #define __no_sanitize_address __attribute__((no_sanitize_address)) #else #define __no_sanitize_address #endif