linux内核加载扩展内核问题!

新手园地& & & 硬件问题Linux系统管理Linux网络问题Linux环境编程Linux桌面系统国产LinuxBSD& & & BSD文档中心AIX& & & 新手入门& & & AIX文档中心& & & 资源下载& & & Power高级应用& & & IBM存储AS400Solaris& & & Solaris文档中心HP-UX& & & HP文档中心SCO UNIX& & & SCO文档中心互操作专区IRIXTru64 UNIXMac OS X门户网站运维集群和高可用服务器应用监控和防护虚拟化技术架构设计行业应用和管理服务器及硬件技术& & & 服务器资源下载云计算& & & 云计算文档中心& & & 云计算业界& & & 云计算资源下载存储备份& & & 存储文档中心& & & 存储业界& & & 存储资源下载& & & Symantec技术交流区安全技术网络技术& & & 网络技术文档中心C/C++& & & GUI编程& & & Functional编程内核源码& & & 内核问题移动开发& & & 移动开发技术资料ShellPerlJava& & & Java文档中心PHP& & & php文档中心Python& & & Python文档中心RubyCPU与编译器嵌入式开发驱动开发Web开发VoIP开发技术MySQL& & & MySQL文档中心SybaseOraclePostgreSQLDB2Informix数据仓库与数据挖掘NoSQL技术IT业界新闻与评论IT职业生涯& & & 猎头招聘IT图书与评论& & & CU技术图书大系& & & Linux书友会二手交易下载共享Linux文档专区IT培训与认证& & & 培训交流& & & 认证培训清茶斋投资理财运动地带快乐数码摄影& & & 摄影器材& & & 摄影比赛专区IT爱车族旅游天下站务交流版主会议室博客SNS站务交流区CU活动专区& & & Power活动专区& & & 拍卖交流区频道交流区
白手起家, 积分 43, 距离下一级还需 157 积分
论坛徽章:0
Unable to handle kernel paging request for data at address 0xffef7ffd
Faulting instruction address: 0xc0014bc4
Oops: Kernel access of bad area, sig: 11 [#1]
MPC8536 DS
Modules linked in:
NIP: c0014bc4 LR: c0225874 CTR:
REGS: ef827dc0 TRAP: 0300& &Not tainted&&(2.6.32-rc5)
&EE,ME,CE&&&CR: &&XER:
DEAR: ffef7ffd, ESR:
TASK = ef] 'swapper' THREAD: ef826000
ef827e70 ef830000 ffef7ffd c02e1cff ffef7ffc ef00000
efffaf59 cf940daf 00000
GPR16: 3ffb0a78
efe3d3c c02e3d4c c02e3d60 c02e3d58 c02e3d68
GPR24: ef827ef8 ef827f20 00000 efffeadc ef827ea8 c02e1d00 cfffffff
NIP [c0014bc4] strcmp+0x8/0x24
LR [c0225874] of_find_property+0x4c/0x7c
Call Trace:
[ef827e70] [c0131a7c] kobject_set_name_vargs+0x6c/0x84 (unreliable)
[ef827e90] [c02258b4] of_get_property+0x10/0x34
[ef827ea0] [c0225e44] of_device_is_compatible+0x24/0xa0
[ef827ed0] [c0226174] of_find_compatible_node+0x78/0xc4
[ef827ef0] [c0343a5c] fsl_usb_of_init+0x148/0x4a0
[ef827fa0] [c0001dc8] do_one_initcall+0x40/0x1dc
[ef827fd0] [c033c1e0] kernel_init+0xc4/0x130
[ef827ff0] [c000f550] kernel_thread+0x4c/0x68
Instruction dump:
3884ffff 8cc2fff8 38a5ffff 8ccc050001
4082fff4 4ea3ffff 3884ffff &8cccc601851
---[ end trace 31fd0ba7d8756001 ]---
Kernel panic - not syncing: Attempted to kill init!
Call Trace:
[ef827cb0] [c0007004] show_stack+0x3c/0x17c (unreliable)
[ef827cf0] [c0022818] panic+0x94/0x168
[ef827d40] [c00262d0] do_exit+0x4e0/0x5e8
[ef827d80] [c000cf70] kernel_bad_stack+0x0/0x50
[ef827da0] [c0012e8c] bad_page_fault+0x98/0xe8
[ef827db0] [c000fc80] handle_page_fault+0x7c/0x80
[ef827e70] [c0131a7c] kobject_set_name_vargs+0x6c/0x84
[ef827e90] [c02258b4] of_get_property+0x10/0x34
[ef827ea0] [c0225e44] of_device_is_compatible+0x24/0xa0
[ef827ed0] [c0226174] of_find_compatible_node+0x78/0xc4
[ef827ef0] [c0343a5c] fsl_usb_of_init+0x148/0x4a0
[ef827fa0] [c0001dc8] do_one_initcall+0x40/0x1dc
[ef827fd0] [c033c1e0] kernel_init+0xc4/0x130
[ef827ff0] [c000f550] kernel_thread+0x4c/0x68
Rebooting in 180 seconds..
&&nbsp|&&nbsp&&nbsp|&&nbsp&&nbsp|&&nbsp&&nbsp|&&nbsp
富足长乐, 积分 7205, 距离下一级还需 795 积分
论坛徽章:1
freescale的usb驱动启动的时候出问题,你可以把这个usb驱动先拿掉看看。
巨富豪门, 积分 22803, 距离下一级还需 17197 积分
论坛徽章:15
把出问题的内核模块干掉试试。
白手起家, 积分 43, 距离下一级还需 157 积分
论坛徽章:0
linuxfellow
& & 谢谢,以下算是初始化完内存和中断了,那接下去的oops是什么,是网络部分吗?
MMU: Allocated 136 bytes of context maps for 31 contexts
Built 1 zonelists in Zone order, mobility grouping on.&&Total pages: 260096
Kernel command line:
PID hash table entries: 4096 (order: 2, 16384 bytes)
Dentry cache hash table entries: 131072 (order: 7, 524288 bytes)
Inode-cache hash table entries: 65536 (order: 6, 262144 bytes)
Memory: 48576k available (3172k kernel code, 12644k reserved, 200k data, 217k bss, 140k init)
Kernel virtual memory layout:
&&* 0xfffef000..0xfffff000&&: fixmap
&&* 0xffxffc00000&&: highmem PTEs
&&* 0xff7b6000..0xff800000&&: early ioremap
&&* 0xfxff7b6000&&: vmalloc & ioremap
SLUB: Genslabs=13, HWalign=32, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
Hierarchical RCU implementation.
NR_IRQS:512
mpic: Setting up MPIC & OpenPIC&&& version 1.2 at ffe40000, max 1 CPUs
mpic: ISU size: 256, shift: 8, mask: ff
mpic: Initializing for 256 sources
clocksource: timebase mult[3c00275] shift[22] registered
Console: colour dummy device 80x25
Mount-cache hash table entries: 512
NET: Registered protocol family 16
Unable to handle kernel paging request for data at address 0xfb7ffe7f
Faulting instruction address: 0xc008bd9c
Oops: Kernel access of bad area, sig: 11 [#1]
MPC8536 DS
Modules linked in:
NIP: c008bd9c LR: c0310764 CTR:
REGS: ef827e70 TRAP: 0300& &Not tainted&&(2.6.32-rc5)
&ME,CE&&&CR: &&XER:
DEAR: fb7ffe7f, ESR:
TASK = ef] 'swapper' THREAD: ef826000
ef827f20 efd0 ef82a000 ef00000
GPR08: 50000 ef84215c cda7 00000
GPR16: 3ffb0a78 08 c02a3ec0 c025a3e8 c5a3d8
GPR24: c00002 ef8021c0 efd0
NIP [c008bd9c] kmem_cache_alloc+0x58/0x9c
LR [c0310764] cacheinfo_cpu_online+0x314/0x3ec
Call Trace:
[ef827f20] [x1 (unreliable)
[ef827f40] [c0310764] cacheinfo_cpu_online+0x314/0x3ec
[ef827f80] [c03101bc] register_cpu_online+0x10/0x20
[ef827f90] [c02f87ec] topology_init+0x58/0x70
[ef827fb0] [c0001df0] do_one_initcall+0x68/0x1e8
[ef827fe0] [c02f61d4] kernel_init+0xb8/0x120
[ef827ff0] [c000e768] kernel_thread+0x4c/0x68
Instruction dump:
f9f20 7cc802a6 38eeb78 38a0ffff 4bfffacd
7c7f1b78 3a &7c1f002e& fc00
---[ end trace 31fd0ba7d8756001 ]---
Kernel panic - not syncing: Attempted to kill init!
Rebooting in 180 seconds..
富足长乐, 积分 7205, 距离下一级还需 795 积分
论坛徽章:1
本帖最后由 linuxfellow 于
06:00 编辑
prettyguyzq
现在问题出在topology_init。 系统在初始化系统多cpu拓扑结构时出问题。
你这样一步一步向前推很花时间。一般的做法是,下载一个能工作的版本, 尽量不做任何改动让这个版本先运行起来。从这个版本开始,逐步加上自己的模块。
白手起家, 积分 43, 距离下一级还需 157 积分
论坛徽章:0
linuxfellow
& & 我这个板子也是自己做的,官方开发板是DDR2内存条的,我改成DDR3的了,现在不加模块驱动还好,一打开一个就出现如下一大堆内存初始化的问题,感觉无从下手啊
BUG: Bad page state in process swapper&&pfn:3fdf4,
page:c0b78e80 flagsnull) count:0 mapcount:1 mappingnull) index:0
Call Trace:
[c033df30] [c0006abc] show_stack+0x58/0x164 (unreliable)
[c033df70] [c006a8f0] bad_page+0x10c/0x134
[c033df90] [c02f59d8] mem_init+0x138/0x2a8
[c033dfc0] [c02f0720] start_kernel+0x14c/0x2b0
[c033dff0] [c0000398] skpinv+0x2b0/0x2ec
BUG: Bad page state in process swapper&&pfn:3fdf5
page:c0b78ea0 flagsnull) count:0 mapcount:1 mappingnull) index:0
Call Trace:
[c033df30] [c0006abc] show_stack+0x58/0x164 (unreliable)
[c033df70] [c006a8f0] bad_page+0x10c/0x134
[c033df90] [c02f59d8] mem_init+0x138/0x2a8
[c033dfc0] [c02f0720] start_kernel+0x14c/0x2b0
[c033dff0] [c0000398] skpinv+0x2b0/0x2ec
小富即安, 积分 3430, 距离下一级还需 1570 积分
论坛徽章:1
把完整的log贴出来啊
小富即安, 积分 3430, 距离下一级还需 1570 积分
论坛徽章:1
把完整的log贴出来啊
白手起家, 积分 43, 距离下一级还需 157 积分
论坛徽章:0
arm-linux-gcc
& & WARNING: could not find compatible node fsl-usb2-mph or fsl-usb2-dr: FDT_ERR_NOTFOUND.
Using MPC8536 DS machine description
Memory CAM mapping: 256/256/256 Mb, residual: 256Mb
Linux version 2.6.32-rc5 (root@lhjhit) (gcc version 4.2.2) #35 Tue Mar 11 16:51:19 CST 2014
bootconsole [udbg0] enabled
setup_arch: bootmem
mpc8536_ds_setup_arch()
Found FSL PCI host bridge at 0xffe08000. Firmware bus number: 0-&0
PCI host bridge /pci@ffe08000 (primary) ranges:
MEM 0x000008fffffff -& 0x0000
&&IO 0xffc000000ffc0ffff -& 0x0000
/pci@ffe08000: PCICSRBAR @ 0xfff00000
Found FSL PCI host bridge at 0xffe09000. Firmware bus number: 0-&0
PCI host bridge /pcie@ffe09000&&ranges:
MEM 0x000009fffffff -& 0x0000
&&IO 0xffc200000ffc2ffff -& 0x0000
/pcie@ffe09000: PCICSRBAR @ 0xfff00000
Found FSL PCI host bridge at 0xffe0a000. Firmware bus number: 0-&1
PCI host bridge /pcie@ffe0a000&&ranges:
MEM 0x0000097ffffff -& 0x0000
&&IO 0xffc100000ffc1ffff -& 0x0000
/pcie@ffe0a000: PCICSRBAR @ 0xffffffff
Found FSL PCI host bridge at 0xffe0b000. Firmware bus number: 0-&0
PCI host bridge /pcie@ffe0b000&&ranges:
MEM 0x00000bfffffff -& 0x0000
&&IO 0xffc300000ffc3ffff -& 0x0000
/pcie@ffe0b000: PCICSRBAR @ 0xfff00000
MPC8536 DS board from Freescale Semiconductor
arch: exit
Zone PFN ranges:
&&DMA& && &0x -& 0x
&&Normal& &0x -& 0x
&&HighMem&&0x -& 0x
Movable zone start PFN for each node
early_node_map[1] active PFN ranges
& & 0: 0x -& 0x
MMU: Allocated 136 bytes of context maps for 31 contexts
Built 1 zonelists in Zone order, mobility grouping on.&&Total pages: 260096
Kernel command line:
PID hash table entries: 4096 (order: 2, 16384 bytes)
Dentry cache hash table entries: 131072 (order: 7, 524288 bytes)
Inode-cache hash table entries: 65536 (order: 6, 262144 bytes)
Memory: 48576k available (3508k kernel code, 12984k reserved, 200k data, 223k bss, 144k init)
Kernel virtual memory layout:
&&* 0xfffef000..0xfffff000&&: fixmap
&&* 0xffxffc00000&&: highmem PTEs
&&* 0xff7b6000..0xff800000&&: early ioremap
&&* 0xfxff7b6000&&: vmalloc & ioremap
SLUB: Genslabs=13, HWalign=32, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
Hierarchical RCU implementation.
NR_IRQS:512
mpic: Setting up MPIC & OpenPIC&&& version 1.2 at ffe40000, max 1 CPUs
mpic: ISU size: 256, shift: 8, mask: ff
mpic: Initializing for 256 sources
clocksource: timebase mult[3c00275] shift[22] registered
Console: colour dummy device 80x25
Mount-cache hash table entries: 512
NET: Registered protocol family 16
Unable to handle kernel paging request for data at address 0xfdfffbff
Faulting instruction address: 0xc008c58c
Oops: Kernel access of bad area, sig: 11 [#1]
MPC8536 DS
Modules linked in:
NIP: c008c58c LR: c008c538 CTR:
REGS: ef827d90 TRAP: 0300& &Not tainted&&(2.6.32-rc5)
&ME,CE&&&CR: &&XER:
DEAR: fdfffbff, ESR:
TASK = ef] 'swapper' THREAD: ef826000
ef827e40 ef9d250
c00d4da4 00001
GPR08: a0000 ef80b9d8 c037dc90 f940fa7 00000
GPR16: 3ffb0a78 00 ffb0
GPR24: 0a1ff 0da4
NIP [c008c58c] __kmalloc_track_caller+0xa0/0xe8
LR [c008c538] __kmalloc_track_caller+0x4c/0xe8
Call Trace:
[ef827e40] [ef827e58] 0xef827e58 (unreliable)
[ef827e60] [c007542c] kstrdup+0x3c/0x68
[ef827e80] [c00d4da4] sysfs_new_dirent+0x30/0x100
[ef827ec0] [c00d5d6c] sysfs_do_create_link+0x88/0x140
[ef827ef0] [c0173488] device_add+0x19c/0x598
[ef827f30] [c0173950] device_create_vargs+0x9c/0xd4
[ef827f60] [c01739c8] device_create+0x40/0x50
[ef827f90] [c035b298] vtconsole_class_init+0xac/0x104
[ef827fb0] [c0001df0] do_one_initcall+0x68/0x1e8
[ef827fe0] [c03491d4] kernel_init+0xb8/0x120
[ef827ff0] [c000e768] kernel_thread+0x4c/0x68
Instruction dump:
f9f20 7f86e378 38eeb78 38a0ffff 4bfff2dd
7c7f1b78 3a &7c1f002e& fc00
---[ end trace 31fd0ba7d8756001 ]---
Kernel panic - not syncing: Attempted to kill init!
Rebooting in 180 seconds..
小富即安, 积分 3430, 距离下一级还需 1570 积分
论坛徽章:1
看不到cmdline,你这个log截的不全啊<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
您的访问请求被拒绝 403 Forbidden - ITeye技术社区
您的访问请求被拒绝
亲爱的会员,您的IP地址所在网段被ITeye拒绝服务,这可能是以下两种情况导致:
一、您所在的网段内有网络爬虫大量抓取ITeye网页,为保证其他人流畅的访问ITeye,该网段被ITeye拒绝
二、您通过某个代理服务器访问ITeye网站,该代理服务器被网络爬虫利用,大量抓取ITeye网页
请您点击按钮解除封锁&linux内核LCD驱动加载问题
[问题点数:40分,结帖人wowooooooooooo]
linux内核LCD驱动加载问题
[问题点数:40分,结帖人wowooooooooooo]
不显示删除回复
显示所有回复
显示星级回复
显示得分回复
只显示楼主
本帖子已过去太久远了,不再提供回复功能。当PC启动时,Intel系列的CPU首先进入的是实模式,并开始执行位于地址0xFFFF0处的代码,也就是ROM-BIOS起始位置的代码。BIOS先进行一系列的系统自检,然后初始化位于地址0的中断向量表。最后BIOS将启动盘的第一个扇区装入到0x7C00,并开始执行此处的代码。这就是对内核初始化过程的一个最简单的描述。最初,linux核心的最开始部分是用8086汇编语言编写的。当开始运行时,核心将自己装入到绝对地址0x90000,再将其后的2k字节装入到地址0x90200处,最后将核心的其余部分装入到0x10000。当系统装入时,会显示Loading...信息。装入完成后,控制转向另一个实模式下的汇编语言代码boot/Setup.S。Setup部分首先设置一些系统的硬件设备,然后将核心从0x10000处移至0x1000处。这时系统转入保护模式,开始执行位于0x1000处的代码。接下来是内核的解压缩。0x1000处的代码来自于文件Boot/head.S,它用来初始化寄存器和调用decompress_kernel()程序。decompress_kernel()程序由Boot/inflate.c,Boot/unzip.c和Boot../misc.c组成。解压缩后的数据被装入到了0x100000处,这也是linux不能在内存小于2M的环境下运行的主要原因。解压后的代码在0x1010000处开始执行,紧接着所有的32位的设置都将完成:IDT、GDT和LDT将被装入,处理器初始化完毕,设置好内存页面,最终调用start_kernel过程。这大概是整个内核中最为复杂的部分。[系统开始运行]linuxkernel最早的C代码从汇编标记startup_32开始执行startup_32:start_kernellock_kerneltrap_initinit_IRQsched_initsoftirq_inittime_initconsole_init#ifdefCONFIG_MODULESinit_modules#endifkmem_cache_initsticalibrate_delaymem_initkmem_cache_sizes_initpgtable_cache_initfork_initproc_caches_initvfs_caches_initbuffer_initpage_cache_initsignals_init#ifdefCONFIG_PROC_FSproc_root_init#endif#ifdefined(CONFIG_SYSVIPC)ipc_init#endifcheck_bugssmp_initrest_initkernel_threadunlock_kernelcpu_idle?startup_32[arch/i386/kernel/head.S]?start_kernel[init/main.c]?lock_kernel[include/asm/smplock.h]?trap_init[arch/i386/kernel/traps.c]?init_IRQ[arch/i386/kernel/i8259.c]?sched_init[kernel/sched.c]?softirq_init[kernel/softirq.c]?time_init[arch/i386/kernel/time.c]?console_init[drivers/char/tty_io.c]?init_modules[kernel/module.c]?kmem_cache_init[mm/slab.c]?sti[include/asm/system.h]?calibrate_delay[init/main.c]?mem_init[arch/i386/mm/init.c]?kmem_cache_sizes_init[mm/slab.c]?pgtable_cache_init[arch/i386/mm/init.c]?fork_init[kernel/fork.c]?proc_caches_init?vfs_caches_init[fs/dcache.c]?buffer_init[fs/buffer.c]?page_cache_init[mm/filemap.c]?signals_init[kernel/signal.c]?proc_root_init[fs/proc/root.c]?ipc_init[ipc/util.c]?check_bugs[include/asm/bugs.h]?smp_init[init/main.c]?rest_init?kernel_thread[arch/i386/kernel/process.c]?unlock_kernel[include/asm/smplock.h]?cpu_idle[arch/i386/kernel/process.c]start_kernel()程序用于初始化系统内核的各个部分,包括:*设置内存边界,调用paging_init()初始化内存页面。*初始化陷阱,中断通道和调度。*对命令行进行语法分析。*初始化设备驱动程序和磁盘缓冲区。*校对延迟循环。最后的function'rest_init'作了以下工作:?开辟内核线程'init'?调用unlock_kernel?建立内核运行的cpu_idle环,如果没有调度,就一直死循环实际上start_kernel永远不能终止.它会无穷地循环执行cpu_idle.最后,系统核心转向move_to_user_mode(),以便创建初始化进程(init)。此后,进程0开始进入无限循环。初始化进程开始执行/etc/init、/bin/init或/sbin/init中的一个之后,系统内核就不再对程序进行直接控制了。之后系统内核的作用主要是给进程提供系统调用,以及提供异步中断事件的处理。多任务机制已经建立起来,并开始处理多个用户的登录和fork()创建的进程。[init]init是第一个进程,或者说内核线程initlock_kerneldo_basic_setupmtrr_initsysctl_initpci_initsock_initstart_context_threaddo_init_calls(*call())-&kswapd_initprepare_namespacefree_initmemunlock_kernelexecve[目录]--------------------------------------------------------------------------------启动步骤系统引导:涉及的文件./arch/$ARCH/boot/bootsect.s./arch/$ARCH/boot/setup.sbootsect.S这个程序是linuxkernel的第一个程序,包括了linux自己的bootstrap程序,但是在说明这个程序前,必须先说明一般IBMPC开机时的动作(此处的开机是指"打开PC的电源"):一般PC在电源一开时,是由内存中地址FFFF:0000开始执行(这个地址一定在ROMBIOS中,ROMBIOS一般是在FEOOOh到FFFFFh中),而此处的内容则是一个jump指令,jump到另一个位於ROMBIOS中的位置,开始执行一系列的动作,包括了检查RAM,keyboard,显示器,软硬磁盘等等,这些动作是由系统测试代码(systemtestcode)来执行的,随着制作BIOS厂商的不同而会有些许差异,但都是大同小异,读者可自行观察自家机器开机时,萤幕上所显示的检查讯息。紧接着系统测试码之后,控制权会转移给ROM中的启动程序(ROMbootstraproutine),这个程序会将磁盘上的第零轨第零扇区读入内存中(这就是一般所谓的bootsector,如果你曾接触过电脑病毒,就大概听过它的大名),至於被读到内存的哪里呢?--绝对位置07C0:0000(即07C00h处),这是IBM系列PC的特性。而位在linux开机磁盘的bootsector上的正是linux的bootsect程序,也就是说,bootsect是第一个被读入内存中并执行的程序。现在,我们可以开始来看看到底bootsect做了什么。第一步首先,bootsect将它"自己"从被ROMBIOS载入的绝对地址0x7C00处搬到0x90000处,然后利用一个jmpi(jumpindirectly)的指令,跳到新位置的jmpi的下一行去执行,第二步接着,将其他segmentregisters包括DS,ES,SS都指向0x9000这个位置,与CS看齐。另外将SP及DX指向一任意位移地址(offset),这个地址等一下会用来存放磁盘参数表(diskpara-metertable)第三步接着利用BIOS中断服务int13h的第0号功能,重置磁盘控制器,使得刚才的设定发挥功能。第四步完成重置磁盘控制器之后,bootsect就从磁盘上读入紧邻着bootsect的setup程序,也就是setup.S,此读入动作是利用BIOS中断服务int13h的第2号功能。setup的image将会读入至程序所指定的内存绝对地址0x90200处,也就是在内存中紧邻着bootsect所在的位置。待setup的image读入内存后,利用BIOS中断服务int13h的第8号功能读取目前磁盘的参数。第五步再来,就要读入真正linux的kernel了,也就是你可以在linux的根目录下看到的"vmlinuz"。在读入前,将会先呼叫BIOS中断服务int10h的第3号功能,读取游标位置,之后再呼叫BIOS中断服务int10h的第13h号功能,在萤幕上输出字串"Loading",这个字串在bootlinux时都会首先被看到,相信大家应该觉得很眼熟吧。第六步接下来做的事是检查rootdevice,之后就仿照一开始的方法,利用indirectjump跳至刚刚已读入的setup部份第七步setup.S完成在实模式下版本检查,并将硬盘,鼠标,内存参数写入到INITSEG中,并负责进入保护模式。第八步操作系统的初始化。
相关问题略懂社热议相关搜索
hey! 我们在略懂,邀你速体验Linux内核分析(9)
张家骥+ 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程
1.编译链接的过程和ELF可执行文件格式
从一个源代码文件到一个可执行程序文件大概要经历如下过程:
以C代码为例子,有如下代码的一个hello.c文件
#include &stdio.h&
int main()
printf("hello world!");
在shell中,用gcc把其编译,链接成一个可执行程序,可以分解为以下步骤:(-m32代表将其编译成32位代码)
1. gcc -E -o hello.cpp hello.c -m32
参数-E是预处理,负责把include的文件包含进来,以及宏替换等工作。
gcc -x cpp-output -S -o hello.s hello.cpp -m32
参数-x cpp-output -S是编译过程,将.cpp文件编译成汇编代码。
gcc -x assembler -c hello.s -o hello.o -m32
参数-x assembler -c是汇编过程,将.s文件中的汇编代码汇编成二进制目标代码。
gcc -o hello hello.o -m32
将hello.o动态链接成可执行程序。
gcc -o hello-static hello.o -m32 -static
参数-static代表将hello.o静态链接成可执行程序。
最后得到的hello和hello-static文件就是目标文件。那么目标文件格式是怎么样的?
目标文件中的内容至少有编译后的机器指令代码、数据。没错,除了这些内容以外,目标文件中还包括了链接时所须要的一些信息,比如符号表、调试信息、字符串等。
现在Linux下主要使用ELF格式(EXECUTABLE AND LINKABLE FORMAT)的目标文件,它的具体格式如下图所示:
ELF头描述了该文件的组织情况,(使用命令readelf -h hello 可以查看hello文件的elf头,其中一个很重要的项是Entry point address,它指定了该程序的代码起点地址。)其结构定义如下:
text节:被编译程序的机器代码。
rodata节:诸如printf语句中的格式串和switch语句的跳转表等只读数据。
data节:已初始化的全局变量。
bss节(.comm 节):未初始化的全局变量,在目标文件中不占实际的空间。
链接是一个收集、组织程序所需的不同代码和数据的过程,以便程序能被装入内存并被执行。链接过程分为两步:
-空间与地址分配
扫描所有的输入目标文件,获得它们的各个段的长度、属性和位置,并且将输入目标文件中的符号定义和符号引用收集起来,统一放到一个全局符号表。这一步中,链接器将能获得所有输入目标文件的段长度,并且将它们合并,计算出输出文件中各个段合并后的长度与位置,并建立映射关系。
-符号解析与重定位
使用上面第一步中收集到的所有信息,读取输入文件中段的数据、重定位信息,并且进行符号解析与重定位、调整代码中的地址等。事实上第二步是链接过程的核心,特别是重定位过程。
可执行程序文件,要被装入内存才能执行,那么其在内存中的映像与文件中的映像是如何对应的呢?
2. 编程使用exec*库函数加载一个可执行文件,动态链接分为可执行程序装载时动态链接和运行时动态链接,编程练习动态链接库的这两种使用方式
动态链接分为可执行程序装载时动态链接和运行时动态链接,如下代码演示了这两种动态链接。
1.先从本周第二节课程下载源代码,放入一个目录中:
2.准备.so文件
shlibexample.h (1.3 KB) - Interface of Shared Lib Example
shlibexample.c (1.2 KB) - Implement of Shared Lib Example
编译成libshlibexample.so文件
$ gcc -shared shlibexample.c -o libshlibexample.so -m32
dllibexample.h (1.3 KB) - Interface of Dynamical Loading Lib Example
dllibexample.c (1.3 KB) - Implement of Dynamical Loading Lib Example
编译成libdllibexample.so文件
$ gcc -shared dllibexample.c -o libdllibexample.so -m32
分别以共享库和动态加载共享库的方式使用libshlibexample.so文件和libdllibexample.so文件
(1.9 KB) - Main program
3.编译main,注意这里只提供shlibexample的-L(库对应的接口头文件所在目录)和-l(库名,如libshlibexample.so去掉lib和.so的部分),并没有提供dllibexample的相关信息,只是指明了-ldl
$ gcc main.c -o main -L/path/to/your/dir -lshlibexample -ldl -m32
$ export LD_LIBRARY_PATH=$PWD
This is a Main program!
Calling SharedLibApi() function of libshlibexample.so!
This is a shared libary!
Calling DynamicalLoadingLibApi() function of libdllibexample.so!
This is a Dynamical Loading libary!
使用的main.c代码如下:
#include &stdio.h&
#include "shlibexample.h"
#include &dlfcn.h&
int main()
printf("This is a Main program!\n");
printf("Calling SharedLibApi() function of libshlibexample.so!\n");
SharedLibApi();
void * handle = dlopen("libdllibexample.so",RTLD_NOW);
if(handle == NULL)
printf("Open Lib libdllibexample.so Error:%s\n",dlerror());
int (*func)(void);
func = dlsym(handle,"DynamicalLoadingLibApi");
if((error = dlerror()) != NULL)
printf("DynamicalLoadingLibApi not found:%s\n",error);
printf("Calling DynamicalLoadingLibApi() function of libdllibexample.so!\n");
dlclose(handle);
return SUCCESS;
装入时动态链接:
就是在开头include了shlibexample.h,那么在装入时,就会将libshlibexample.so中的SharedLibApi()装入进程映像中。
运行时动态链接:
先使用dlopen(),打开一个动态链接库,并返回动态链接库的句柄。他相当于Win32 API函数LoadLibrary()。
void * handle = dlopen("libdllibexample.so",RTLD_NOW);
然后定义了一个函数指针,其指针数据类型要与调用的so引出函数相吻合:
int (*func)(void);
然后使用了dlsym(),根据 动态链接库 操作句柄(handle)与符号(symbol),返回符号对应的地址。使用这个函数不但可以获取函数地址,也可以获取变量地址。相当于Win32 API函数GetProcAddress()。
func = dlsym(handle,"DynamicalLoadingLibApi");
这样就可以函数指针func就来调用so函数。
最后用dlclose()来卸载打开的库。
dlclose(handle);
3. Linux系统加载可执行程序所需处理过程的理解
3.1 新的可执行程序是从哪里开始执行的?
当execve()系统调用终止且进程重新恢复它在用户态执行时,执行上下文被大幅度改变,要执行的新程序已被映射到进程空间,从elf头中的程序入口点开始执行新程序。
如果这个新程序是静态链接的,那么这个程序就可以独立运行,elf头中的这个入口地址就是本程序的入口地址。
如果这个新程序是动态链接的,那么此时还需要装载共享库,elf头中的这个入口地址是动态链接器ld的入口地址。
3.2 为什么execve系统调用返回后新的可执行程序能顺利执行?
首先我们看,新的可执行程序执行,需要哪些东西:
1. 它所需要的库函数。
2. 属于它的进程空间:代码段,数据段,内核栈,用户栈等。
它所需要的运行参数。
4. 它所需要的系统资源。
如果满足以上4个条件,那么新的可执行程序就会处于可运行态,只要被调度到,就可以正常执行。我们一个一个看这几个条件能不能满足。
条件1:如果新进程是静态链接的,那么库函数已经在可执行程序文件中,条件满足。如果是动态链接的,新进程的入口地址是动态链接器ld的起始地址,可以完成对所需库函数的加载,也能满足条件。
条件2:execve系统调用通过大幅度修改执行上下文,将用户态堆栈清空,将老进程的进程空间替换为新进程的进程空间,新进程从老进程那里继承了所需要的进程空间,条件满足。
条件3:我们一般在shell中,输入可执行程序所需要的参数,shell程序把这些参数用函数参数传递的方式传给给execve系统调用,然后execve系统调用以系统调用参数传递的方式传给sys_execve,最后sys_execve在初始化新程序的用户态堆栈时,将这些参数放在main函数取参数的位置上。条件满足。
条件4:如果当前系统中没有所需要的资源,那么新进程会被挂起,直到资源有了,唤醒新进程,变为可运行态,条件可以满足。
综上所述,新的可执行程序可以顺利执行。
3.3 对于静态链接的可执行程序和动态链接的可执行程序execve系统调用返回时会有什么不同?
execve系统调用会调用sys_execve,然后sys_execve调用do_execve,然后do_execve调用do_execve_common,然后do_execve_common调用exec_binprm,在exec_binprm中:
ret = search_binary_handler(bprm);//寻找符合文件格式的对应解析模块(如ELF)
一个循环:
retval = fmt-&load_binary(bprm);
对于ELF文件格式,fmt函数指针实际会执行load_elf_binary,load_elf_binary会调用start_thread,在start_thread中通过修改内核堆栈中EIP的值,使其指向elf_entry,跳转到elf_entry执行。
对于静态链接的可执行程序,elf_entry是新程序的执行起点。对于动态链接的可执行程序,需要先加载链接器ld,
elf_entry = load_elf_interp(…)
将CPU控制权交给ld来加载依赖库,再由ld在完成加载工作后将CPU控制权还给新进程。
4. 使用gdb跟踪分析一个execve系统调用内核处理函数sys_execve ,验证您对Linux系统加载可执行程序所需处理过程的理解
首先从github下载最新的代码,然后进入menu目录:
然后用test_exec.c 替换test.c,再重新编译生成根文件系统:
然后启动调试内核:
再开一个shell,打开gdb,并加载符号表,连接到端口1234:
然后在gdb,中设置断点:这里我设置了sys_execve,load_elf_binary,
start_thread三处断点。
然后在menu界面中输入命令:exec ,触发了断点。
发现程序第一个断点停在了sys_execve处:
按s,单步执行,发现接下来会运行do_execve:
按c继续执行,发现接下来停在了load_elf_binary处:
按c继续执行,发现接下来停在了start_thread处,这时使用命令:
po new_ip 查看new_ip的值,它等于0x8048d0a,再另外打开一个shell,使用命令readelf -h hello查看hello的elf头,可以看到elf头中的程序入口点地址正是0x8048d0a
按s,单步执行,可以看到在start_thread中对进程栈的修改。
5. 自己对“Linux内核装载和启动一个可执行程序”的理解
可执行文件是一个普通的文件,它描述了如何初始化一个新的执行上下文,也就是如何开始一个新的计算。可执行文件类别有很多,在内核中有一个链表,在init的时候会将支持的可执行程序解析程序注册添加到链表中,那么在对可执行文件进行解析时,就从链表头开始找,找到匹配的处理函数就可以对其进行解析。
在shell中启动一个可执行程序时,会创建一个新进程,它通过覆盖父进程(也就是shell进程)的进程环境,并将用户态堆栈清空,获得说需要的执行上下文环境。
命令行参数和环境变量会通过shell传递给execve,excve通过系统调用参数传递,传递给sys_execve,最后sys_execve在初始化新进程堆栈的时候拷贝进去。
load_elf_binary-&start_thread(…)通过修改内核堆栈中EIP的值作为新程序的起点。
如果新程序的动态链接的,那么就需要加载所需要的库函数,动态连接器ld会负责加载过程,动态链接库的装载过程类似于一个图的广度优先遍历过程,装载完成后,ld将CPU控制权交给可执行程序,继续执行可执行程序。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:2575次
排名:千里之外
原创:10篇

我要回帖

更多关于 加载扩展内核 的文章

 

随机推荐