kernel移植之linux stage2:启动内核

linux/init/main.c
asmlinkage void __init start_kernel(void)
{
    char * command_line;
    extern struct kernel_param __start___param[], __stop___param[];

    smp_setup_processor_id();

    /*
     * Need to run as early as possible, to initialize the
     * lockdep hash:
     */
    lockdep_init();
    debug_objects_early_init();

    /*
     * Set up the the initial canary ASAP:
     */
    boot_init_stack_canary();

    cgroup_init_early();

    local_irq_disable();
    early_boot_irqs_off();
    early_init_irq_lock_class();

/*
 * Interrupts are still disabled. Do necessary setups, then
 * enable them
 */
    lock_kernel();
    tick_init();
    boot_cpu_init();
    page_address_init();
    printk(KERN_NOTICE "%s", linux_banner);
    setup_arch(&command_line);
    mm_init_owner(&init_mm, &init_task);
    setup_command_line(command_line);
    setup_nr_cpu_ids();
    setup_per_cpu_areas();
    smp_prepare_boot_cpu();    /* arch-specific boot-cpu hooks */

    build_all_zonelists(NULL);
    page_alloc_init();

    printk(KERN_NOTICE "Kernel command line: %s\n", boot_command_line);
    parse_early_param();
    parse_args("Booting kernel", static_command_line, __start___param,
           __stop___param - __start___param,
           &unknown_bootoption);
    /*
     * These use large bootmem allocations and must precede
     * kmem_cache_init()
     */
    pidhash_init();
    vfs_caches_init_early();
    sort_main_extable();
    trap_init();
    mm_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();
    /*
     * Disable preemption - early bootup scheduling is extremely
     * fragile until we cpu_idle() for the first time.
     */
    preempt_disable();
    if (!irqs_disabled()) {
        printk(KERN_WARNING "start_kernel(): bug: interrupts were "
                "enabled *very* early, fixing it\n");
        local_irq_disable();
    }
    rcu_init();
    radix_tree_init();
    /* init some links before init_ISA_irqs() */
    early_irq_init();
    init_IRQ();
    prio_tree_init();
    init_timers();
    hrtimers_init();
    softirq_init();
    timekeeping_init();
    time_init();
    profile_init();
    if (!irqs_disabled())
        printk(KERN_CRIT "start_kernel(): bug: interrupts were "
                 "enabled early\n");
    early_boot_irqs_on();
    local_irq_enable();

    /* Interrupts are enabled now so all GFP allocations are safe. */
    gfp_allowed_mask = __GFP_BITS_MASK;

    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(panic_later, panic_param);

    lockdep_info();

    /*
     * 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();

#ifdef CONFIG_BLK_DEV_INITRD
    if (initrd_start && !initrd_below_start_ok &&
        page_to_pfn(virt_to_page((void *)initrd_start)) < min_low_pfn) {
        printk(KERN_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
    page_cgroup_init();
    enable_debug_pagealloc();
    kmemtrace_init();
    kmemleak_init();
    debug_objects_mem_init();
    idr_init_cache();
    setup_per_cpu_pageset();
    numa_policy_init();
    if (late_time_init)
        late_time_init();
    sched_clock_init();
    calibrate_delay();
    pidmap_init();
    anon_vma_init();
#ifdef CONFIG_X86
    if (efi_enabled)
        efi_enter_virtual_mode();
#endif
    thread_info_cache_init();
    cred_init();
    fork_init(totalram_pages);
    proc_caches_init();
    buffer_init();
    key_init();
    security_init();
    dbg_late_init();
    vfs_caches_init(totalram_pages);
    signals_init();
    /* rootfs populating might need page-writeback */
    page_writeback_init();
#ifdef CONFIG_PROC_FS
    proc_root_init();
#endif
    cgroup_init();
    cpuset_init();
    taskstats_init_early();
    delayacct_init();

    check_bugs();

    acpi_early_init(); /* before LAPIC and SMP init */
    sfi_init_late();

    ftrace_init();

    /* Do the rest non-__init'ed, we're now alive */
    rest_init();
}

stage2的入口函数start_kernel()如上,
在此函数中又调用
line34:printk(KERN_NOTICE "%s", linux_banner);  开机打印出内核版本的就是它,比如
Linux version 2.6.39.4 (root@localhost.localdomain) (gcc version 4.4.3 (ctng-1.6.1) ) #3 Thu Oct 6 20:18:51 CST 2011

然后调用
line35:setup_arch(&command_line),此函数位于arch/arm/kernel/setup.c
void __init setup_arch(char **cmdline_p)
{
	struct tag *tags = (struct tag *)&init_tags;
	struct machine_desc *mdesc;
	char *from = default_command_line;

	unwind_init();

	setup_processor();
	mdesc = setup_machine(machine_arch_type);
	machine_name = mdesc->name;

	if (mdesc->soft_reboot)
		reboot_setup("s");

	if (__atags_pointer)//bootloader传入了非0的tags的物理地址,优先使用bootloader指定地址[luther.gliethttp]
		tags = phys_to_virt(__atags_pointer);
	else if (mdesc->boot_params)//否则使用默认的地址,0x30000100
		tags = phys_to_virt(mdesc->boot_params);//转化成虚拟地址才可以操作,因为此时mmu已经启用

	/*
	 * If we have the old style parameters, convert them to
	 * a tag list.
	 */
	if (tags->hdr.tag != ATAG_CORE)
		convert_to_tag_list(tags);
	if (tags->hdr.tag != ATAG_CORE)
		tags = (struct tag *)&init_tags;

	if (mdesc->fixup)
		mdesc->fixup(mdesc, tags, &from, &meminfo);

	if (tags->hdr.tag == ATAG_CORE) {
		if (meminfo.nr_banks != 0)
			squash_mem_tags(tags);
		save_atags(tags);
		parse_tags(tags);
	}

	init_mm.start_code = (unsigned long) _text;
	init_mm.end_code   = (unsigned long) _etext;
	init_mm.end_data   = (unsigned long) _edata;
	init_mm.brk	   = (unsigned long) _end;

	/* parse_early_param needs a boot_command_line */
	strlcpy(boot_command_line, from, COMMAND_LINE_SIZE);

	/* populate cmd_line too for later use, preserving boot_command_line */
	strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);
	*cmdline_p = cmd_line;

	parse_early_param();

	paging_init(mdesc);
	request_standard_resources(&meminfo, mdesc);

#ifdef CONFIG_SMP
	smp_init_cpus();
#endif

	cpu_init();
	tcm_init();

	/*
	 * Set up various architecture-specific pointers
	 */
	init_arch_irq = mdesc->init_irq;
	system_timer = mdesc->timer;
	init_machine = mdesc->init_machine;

#ifdef CONFIG_VT
#if defined(CONFIG_VGA_CONSOLE)
	conswitchp = &vga_con;
#elif defined(CONFIG_DUMMY_CONSOLE)
	conswitchp = &dummy_con;
#endif
#endif
	early_trap_init();
}
line 11:取得 在stage1中构造的__mach_desc_MINI2440结构,以获取其成员.boot_params(uboot传递给内核的参数在sdram上的地址)
在上篇有行
.boot_params    = S3C2410_SDRAM_PA + 0x100, 

在linux/arch/arm/mach-s3c2410/include/mach/map.h中
#define S3C2410_SDRAM_PA    (S3C2410_CS6)
#define S3C2410_CS6 (0x30000000)


所以.boot_params    = 0x30000100, 即如果uboot未指定tag存放的地址,linux会向这个默认的地址去寻找tag
可参考http://blog.chinaunix.net/space.php?uid=20564848&do=blog&id=73978


在setup.c中有如下结构__initdata
static struct init_tags {
	struct tag_header hdr1;
	struct tag_core   core;
	struct tag_header hdr2;
	struct tag_mem32  mem;
	struct tag_header hdr3;
} init_tags __initdata = {
	{ tag_size(tag_core), ATAG_CORE },
	{ 1, PAGE_SIZE, 0xff },
	{ tag_size(tag_mem32), ATAG_MEM },
	{ MEM_SIZE, PHYS_OFFSET },
	{ 0, ATAG_NONE }
};
而在linux/arch/arm/include/asm/setup.h是有关的tag定义,恩,是不是很眼熟,估计uboot的uboot/include/asm-arm/setup.h里的代码大部分就是从这里考的
/*
 *  linux/include/asm/setup.h
 *
 *  Copyright (C) 1997-1999 Russell King
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 *  Structure passed to kernel to tell it about the
 *  hardware it's running on.  See Documentation/arm/Setup
 *  for more info.
 */
#ifndef __ASMARM_SETUP_H
#define __ASMARM_SETUP_H

#include <linux/types.h>

#define COMMAND_LINE_SIZE 1024

/* The list ends with an ATAG_NONE node. */
#define ATAG_NONE	0x00000000

struct tag_header {
	__u32 size;
	__u32 tag;
};

/* The list must start with an ATAG_CORE node */
#define ATAG_CORE	0x54410001

struct tag_core {
	__u32 flags;		/* bit 0 = read-only */
	__u32 pagesize;
	__u32 rootdev;
};

/* it is allowed to have multiple ATAG_MEM nodes */
#define ATAG_MEM	0x54410002

struct tag_mem32 {
	__u32	size;
	__u32	start;	/* physical start address */
};

/* VGA text type displays */
#define ATAG_VIDEOTEXT	0x54410003

struct tag_videotext {
	__u8		x;
	__u8		y;
	__u16		video_page;
	__u8		video_mode;
	__u8		video_cols;
	__u16		video_ega_bx;
	__u8		video_lines;
	__u8		video_isvga;
	__u16		video_points;
};

/* describes how the ramdisk will be used in kernel */
#define ATAG_RAMDISK	0x54410004

struct tag_ramdisk {
	__u32 flags;	/* bit 0 = load, bit 1 = prompt */
	__u32 size;	/* decompressed ramdisk size in _kilo_ bytes */
	__u32 start;	/* starting block of floppy-based RAM disk image */
};

/* describes where the compressed ramdisk image lives (virtual address) */
/*
 * this one accidentally used virtual addresses - as such,
 * it's deprecated.
 */
#define ATAG_INITRD	0x54410005

/* describes where the compressed ramdisk image lives (physical address) */
#define ATAG_INITRD2	0x54420005

struct tag_initrd {
	__u32 start;	/* physical start address */
	__u32 size;	/* size of compressed ramdisk image in bytes */
};

/* board serial number. "64 bits should be enough for everybody" */
#define ATAG_SERIAL	0x54410006

struct tag_serialnr {
	__u32 low;
	__u32 high;
};

/* board revision */
#define ATAG_REVISION	0x54410007

struct tag_revision {
	__u32 rev;
};

/* initial values for vesafb-type framebuffers. see struct screen_info
 * in include/linux/tty.h
 */
#define ATAG_VIDEOLFB	0x54410008

struct tag_videolfb {
	__u16		lfb_width;
	__u16		lfb_height;
	__u16		lfb_depth;
	__u16		lfb_linelength;
	__u32		lfb_base;
	__u32		lfb_size;
	__u8		red_size;
	__u8		red_pos;
	__u8		green_size;
	__u8		green_pos;
	__u8		blue_size;
	__u8		blue_pos;
	__u8		rsvd_size;
	__u8		rsvd_pos;
};

/* command line: \0 terminated string */
#define ATAG_CMDLINE	0x54410009

struct tag_cmdline {
	char	cmdline[1];	/* this is the minimum size */
};

/* acorn RiscPC specific information */
#define ATAG_ACORN	0x41000101

struct tag_acorn {
	__u32 memc_control_reg;
	__u32 vram_pages;
	__u8 sounddefault;
	__u8 adfsdrives;
};

/* footbridge memory clock, see arch/arm/mach-footbridge/arch.c */
#define ATAG_MEMCLK	0x41000402

struct tag_memclk {
	__u32 fmemclk;
};

struct tag {
	struct tag_header hdr;
	union {
		struct tag_core		core;
		struct tag_mem32	mem;
		struct tag_videotext	videotext;
		struct tag_ramdisk	ramdisk;
		struct tag_initrd	initrd;
		struct tag_serialnr	serialnr;
		struct tag_revision	revision;
		struct tag_videolfb	videolfb;
		struct tag_cmdline	cmdline;

		/*
		 * Acorn specific
		 */
		struct tag_acorn	acorn;

		/*
		 * DC21285 specific
		 */
		struct tag_memclk	memclk;
	} u;
};

struct tagtable {
	__u32 tag;
	int (*parse)(const struct tag *);
};

#define tag_member_present(tag,member)				\
	((unsigned long)(&((struct tag *)0L)->member + 1)	\
		<= (tag)->hdr.size * 4)

#define tag_next(t)	((struct tag *)((__u32 *)(t) + (t)->hdr.size))
#define tag_size(type)	((sizeof(struct tag_header) + sizeof(struct type)) >> 2)

#define for_each_tag(t,base)		\
	for (t = base; t->hdr.size; t = tag_next(t))

#ifdef __KERNEL__

#define __tag __used __attribute__((__section__(".taglist.init")))
#define __tagtable(tag, fn) \
static struct tagtable __tagtable_##fn __tag = { tag, fn }

/*
 * Memory map description
 */
#ifdef CONFIG_ARCH_LH7A40X
# define NR_BANKS 16
#else
# define NR_BANKS 8
#endif

struct membank {
	unsigned long start;
	unsigned long size;
	unsigned short node;
	unsigned short highmem;
};

struct meminfo {
	int nr_banks;
	struct membank bank[NR_BANKS];
};

extern struct meminfo meminfo;

#define for_each_nodebank(iter,mi,no)			\
	for (iter = 0; iter < (mi)->nr_banks; iter++)	\
		if ((mi)->bank[iter].node == no)

#define bank_pfn_start(bank)	__phys_to_pfn((bank)->start)
#define bank_pfn_end(bank)	__phys_to_pfn((bank)->start + (bank)->size)
#define bank_pfn_size(bank)	((bank)->size >> PAGE_SHIFT)
#define bank_phys_start(bank)	(bank)->start
#define bank_phys_end(bank)	((bank)->start + (bank)->size)
#define bank_phys_size(bank)	(bank)->size

#endif  /*  __KERNEL__  */

#endif
linux怎么解析这些参数的,可参考
http://blog.csdn.net/babyfans/article/details/5819837
嵌入式Linux应用开发完全手册 ch16.3 p321

总结一下stage2的流程,start_kernell函数调用了几乎所有的初始化函数,直到建立第1个进程





知道了内核启动流程,就可以判断内核启动打印信息各是哪里发出的了,如下
清晰点的图片见download.csdn.net/detail/songqqnew/3664142

有几个问题,
1.如果uboot向内核传递的内存tag为sdram的起始地址0x3000 0000,大小0x400 0000(64M)和命令行tag中有比如mem=60M的字符串,linux系统最多也只能使用前60M的sdram(见嵌入式linux应用开发完全手册p323),那最后4M干嘛呢?后4M还属于linux的管理范围吗?
2.uboot中已经设置了fclk,hclk,pclk,内核启动时初始化时钟期间,是再去设置一遍呢还是去读取uboot的设置呢?
3.内核启动期间,打印了Virtual kernel memory layout,这些虚拟区间该怎么划分?特别是DMA虚拟区间位于0xffc0 0000--0xffe0 0000,其对应的物理区间可以在sdram的任意部分吗,linux为这些区间建立内核页表的代码在哪里















-------------------------------------------------------------------------------------------------------------------------------------------

2013-12-9 
mini6410_machine_init什么时候调用的?:
setup_arch()调用了setup_machine(machine_arch_type),此函数返回了machine_desc指针,正是通过宏MACHINE_START在板子文件定了的板子描述结构体struct machine_desc  __mach_desc_MINI6410:

MACHINE_START(MINI6410, "MINI6410")
/* Maintainer: Ben Dooks <ben-linux@fluff.org> */
.boot_params = S3C64XX_PA_SDRAM + 0x100,
.init_irq = s3c6410_init_irq,
.map_io = mini6410_map_io,
.init_machine = mini6410_machine_init,
.timer = &s3c24xx_timer,
MACHINE_END

在setup_arch()里面将setup_machine()返回的machine_desc类型指针赋给了全局变量machine_desc

然后在rest_init()->kernel_init->do_basic_setup()->do_initcalls()里面调用customize_machine()调用init_machine()


do_initcalls是怎么调用customize_machine()的?

通过宏arch_initcall(customize_machine);将符号链接到initcall段里面

MACHINE_START主要是定义了"struct machine_desc"的类型,放在 section(".arch.info.init"),是初始化数据,Kernel 起来之后将被丢弃。
其余各个成员函数在setup_arch()中被赋值到内核结构体,在不同时期被调用:
start_kernel()--->setup_arch()--->do_initcalls()--->customize_machine()--->tegra_stingray_init()
1. .init_machine 在 arch/arm/kernel/setup.c 中被 customize_machine 调用,放在 arch_initcall() 段里面,会自动按顺序被调用。
2. .init_irq在start_kernel() --> init_IRQ() --> init_arch_irq()中被调用
3. .map_io 在 setup_arch() --> paging_init() --> devicemaps_init()中被调用
4. .timer是定义系统时钟,定义TIMER4为系统时钟,在arch/arm/plat-s3c/time.c中体现。在start_kernel() --> time_init()中被调用。
5. .boot_params是bootloader向内核传递的参数的位置,这要和bootloader中参数的定义要一致。
http://blog.csdn.net/zhaohc_nj/article/details/7938116

-----------------------------------------------------------------------------------------------------------------------------------------------

2013-12-15 20
编译进内核的驱动怎么被调用?
比如:
static int __init helloinit(void)
{
    printk("Hello, module is installed !\n");
    return 0;
}
module_init(helloinit);
大部分宏和函数实现在inlcude/linux/init.h

module_init(fn)-->>__initcall(fn)-->>device_initcall(fn)-->>__define_initcall("6",fn,6)

其中
#define __define_initcall(level,fn,id) \
static initcall_t __initcall_##fn##id __used \
__attribute__((__section__(".initcall" level ".init"))) = fn
所以
#define __define_initcall(6, helloinit ,6)
static initcall_t __initcall_ helloinit 6 __used 
__attribute__((__section__(".initcall" 6 ".init"))) = helloinit
即:
1) 声明一个名称为 __initcall_ helloinit 6 的函数指针;
2) 将这个函数指针指向 helloinit
3) 编译的时候需要把这个函数指针变量放置到名称为 .initcall6.init的section中。

问题1:__attribute__和__section__的作用:
ATTRIBUTE是属性的说明,多个说明之间以逗号分隔。GCC可以支持十几个属性,__section__便是其中之一。
属性section用于函数和变量,连接器可以把相同节的代码或数据安排在一起,Linux 内核很喜欢使用这种技术,比如__init修饰的所有代码都会被放在.init.text节里,初始化结束后就可以释放这部分内存。
问题2:很多宏,如下,都是调用了__define_initcall来将自己放入某个init节里面。就包括了和mini6410_machine_init相关的arch_initcall,而arch_initcall作用于init3,所以mini6410_machine_init位于init3。

#define pure_initcall(fn) __define_initcall("0",fn,0)
#define core_initcall(fn) __define_initcall("1",fn,1)
#define core_initcall_sync(fn) __define_initcall("1s",fn,1s)
#define postcore_initcall(fn) __define_initcall("2",fn,2)
#define postcore_initcall_sync(fn) __define_initcall("2s",fn,2s)
#define arch_initcall(fn)__define_initcall("3",fn,3)
#define arch_initcall_sync(fn) __define_initcall("3s",fn,3s)
#define subsys_initcall(fn) __define_initcall("4",fn,4)
#define subsys_initcall_sync(fn) __define_initcall("4s",fn,4s)
#define fs_initcall(fn) __define_initcall("5",fn,5)
#define fs_initcall_sync(fn) __define_initcall("5s",fn,5s)
#define rootfs_initcall(fn) __define_initcall("rootfs",fn,rootfs)
#define device_initcall(fn)__define_initcall("6",fn,6)
#define device_initcall_sync(fn) __define_initcall("6s",fn,6s)
#define late_initcall(fn) __define_initcall("7",fn,7)
#define late_initcall_sync(fn) __define_initcall("7s",fn,7s)

既然这个 __initcall_ helloinit 6指针定义在了.initcall6.init节,那么是什么时候被调用的呢?
rest_init()->kernel_init->do_basic_setup()->do_initcalls()
init/main.c
static void __init do_initcalls(void)
{
initcall_t *fn;
for (fn = __early_initcall_end; fn < __initcall_end; fn++)
do_one_initcall(*fn);
}
会依次调用下面各个init节中的函数
include/asm-generic/vmlinux.lds.h
#define INITCALLS							\
	*(.initcallearly.init)						\
	VMLINUX_SYMBOL(__early_initcall_end) = .;			\
  	*(.initcall0.init)						\
  	*(.initcall0s.init)						\
  	*(.initcall1.init)						\
  	*(.initcall1s.init)						\
  	*(.initcall2.init)						\
  	*(.initcall2s.init)						\
  	*(.initcall3.init)						\
  	*(.initcall3s.init)						\
  	*(.initcall4.init)						\
  	*(.initcall4s.init)						\
  	*(.initcall5.init)						\
  	*(.initcall5s.init)						\
	*(.initcallrootfs.init)						\
  	*(.initcall6.init)						\
  	*(.initcall6s.init)						\
  	*(.initcall7.init)						\
  	*(.initcall7s.init)

所有编译进内核的驱动都被链接在built-in.o,使用arm-linux-readelf -S查看此重定位文件中包含的各个init段:
不过只发现initcall2.init,initcall4.init,initcall5.init,initcall6.init,initcall7.init
root@song-virtual-machine:drivers# arm-linux-readelf -S built-in.o 
There are 107 section headers, starting at offset 0x22d0ca8:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
 *[60] .initcall4.init   PROGBITS        00000000 277954 000028 00  WA  0   0  4
  [61] .rel.initcall4.in REL             00000000 2357598 000050 08     105  60  4
  [62] .init.setup       PROGBITS        00000000 27797c 000048 00  WA  0   0  4
  [63] .rel.init.setup   REL             00000000 23575e8 000060 08     105  62  4
  [64] .data..read_mostl PROGBITS        00000000 2779c4 0002f8 00  WA  0   0  4
  [65] .rel.data..read_m REL             00000000 2357648 000010 08     105  64  4
 *[66] .initcall6.init   PROGBITS        00000000 277cbc 0002d4 00  WA  0   0  4
  [67] .rel.initcall6.in REL             00000000 2357658 0005a8 08     105  66  4
  [68] .init.data        PROGBITS        00000000 277f90 003174 00  WA  0   0  4
  [69] .rel.init.data    REL             00000000 2357c00 000de8 08     105  68  4
  [70] .exitcall.exit    PROGBITS        00000000 27b104 0002e8 00  WA  0   0  4
  [71] .rel.exitcall.exi REL             00000000 23589e8 0005d0 08     105  70  4
 *[72] .initcall2.init   PROGBITS        00000000 27b3ec 00000c 00  WA  0   0  4
  [73] .rel.initcall2.in REL             00000000 2358fb8 000018 08     105  72  4
  [74] .con_initcall.ini PROGBITS        00000000 27b3f8 000008 00  WA  0   0  4
  [75] .rel.con_initcall REL             00000000 2358fd0 000010 08     105  74  4
 *[76] .initcall5.init   PROGBITS        00000000 27b400 000008 00  WA  0   0  4
  [77] .rel.initcall5.in REL             00000000 2358fe0 000010 08     105  76  4
 *[78] .initcall7.init   PROGBITS        00000000 27b408 00000c 00  WA  0   0  4
  [79] .rel.initcall7.in REL             00000000 2358ff0 000018 08     105  78  4

而是用arm-linux-readelf -s built-in.o |grep 66,可以查看连接在initcall6.init段里的符号:
 24044: 00000258     4 OBJECT  LOCAL  DEFAULT   66 __initcall_s3c_tvenc_init
 24066: 00167e88     0 NOTYPE  LOCAL  DEFAULT    1 $a
 24110: 0000025c     0 NOTYPE  LOCAL  DEFAULT   66 $d
 24111: 0000025c     4 OBJECT  LOCAL  DEFAULT   66 __initcall_s3c_tvscaler_p
 24166: 00006fe4     0 NOTYPE  LOCAL  DEFAULT    3 $a
 24180: 00000260     0 NOTYPE  LOCAL  DEFAULT   66 $d
 24181: 00000260     4 OBJECT  LOCAL  DEFAULT   66 __initcall_s3c_rotator_in
 24266: 0000c520     0 NOTYPE  LOCAL  DEFAULT   56 $d
 24299: 00000264     0 NOTYPE  LOCAL  DEFAULT   66 $d
 24300: 00000264     4 OBJECT  LOCAL  DEFAULT   66 __initcall_s3c_jpeg_init6
 24366: 0016ad74     0 NOTYPE  LOCAL  DEFAULT    1 $d
 24373: 00000268     0 NOTYPE  LOCAL  DEFAULT   66 $d
 24374: 00000268     4 OBJECT  LOCAL  DEFAULT   66 __initcall_s3c_g2d_init6

----------------------------------------------------------------------------------------------------------------------------------------------

NAME
  readelf - Displays information about ELF files.

SYNOPSIS
       readelf [-a|--all]
               [-h|--file-header]//elf文件头,包含Entry point address
               [-l|--program-headers|--segments]
               [-S|--section-headers|--sections]//段信息
               [-g|--section-groups]
               [-t|--section-details]
               [-e|--headers]
               [-s|--syms|--symbols]//符号表
               [--dyn-syms]
               [-n|--notes]
               [-r|--relocs]
               [-u|--unwind]
               [-d|--dynamic]
               [-V|--version-info]
               [-A|--arch-specific]
               [-D|--use-dynamic]
               [-x <number or name>|--hex-dump=<number or name>]
               [-p <number or name>|--string-dump=<number or name>]
               [-R <number or name>|--relocated-dump=<number or name>]
               [-c|--archive-index]
               [-w[lLiaprmfFsoRt]|
                --debug-dump[=rawline,=decodedline,=info,=abbrev,=pubnames,=aranges,=macro,=frames,=frames-interp,=str,=loc,=Ranges,=pubtypes,=trace_info,=trace_abbrev,=trace_aranges,=gdb_index]]
               [-I|--histogram]
               [-v|--version]
               [-W|--wide]
               [-H|--help]
               elffile...
NAME
       objdump - display information from object files.

SYNOPSIS
       objdump [-a|--archive-headers]
               [-b bfdname|--target=bfdname]
               [-C|--demangle[=style] ]
               [-d|--disassemble]
               [-D|--disassemble-all]
               [-z|--disassemble-zeroes]
               [-EB|-EL|--endian={big | little }]
               [-f|--file-headers]
               [-F|--file-offsets]
               [--file-start-context]
               [-g|--debugging]
               [-e|--debugging-tags]
               [-h|--section-headers|--headers]//段头
               [-i|--info]
               [-j section|--section=section]
               [-l|--line-numbers]
               [-S|--source]//汇编和c组合显示的源代码
               [-m machine|--architecture=machine]
               [-M options|--disassembler-options=options]
               [-p|--private-headers]
               [-r|--reloc]
               [-R|--dynamic-reloc]
               [-s|--full-contents]//二进制代码
               [-W[lLiaprmfFsoRt]|
                --dwarf[=rawline,=decodedline,=info,=abbrev,=pubnames,=aranges,=macro,=frames,=frames-interp,=str,=loc,=Ranges,=pubtypes,=trace_info,=trace_abbrev,=trace_aranges,=gdb_index]]
               [-G|--stabs]
               [-t|--syms]
               [-T|--dynamic-syms]
               [-w|--wide]
               [--start-address=address]
               [--stop-address=address]
               [--prefix-addresses]
               [--[no-]show-raw-insn]
               [--adjust-vma=offset]
               [--special-syms]
               [--prefix=prefix]
               [--prefix-strip=level]
               [--insn-width=width]
               [-V|--version]
               [-H|--help]
               objfile...

-------------------------------------------------------------------------------------------------------------------------------------------
关于程序的连接原理及实例
待续
-------------------------------------------------------------------------------------------------------------------------------------------
linux image的生成过程
待续
-------------------------------------------------------------------------------------------------------------------------------------------


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值