linux boot 学习

来源:互联网 发布:多特vs希腊数据 编辑:程序博客网 时间:2024/06/05 16:25

 零、文档【1】 http://lxr.linux.no/linux+v3.3.6/arch/x86/boot/header.S header.S位置 【2】 http://lxr.linux.no/linux+v3.3.6/Documentation/x86/boot.txt header.S的文档【3】 http://lxr.linux.no/linux+v3.3.6/arch/x86/include/asm/bootparam.hsetup_header等数据结构定义【4】 http://lxr.linux.no/linux+v3.3.6/arch/x86/boot/setup.ld  setup部分链接文件,描述了相关的符号一、概述 在2.6以后,系统启动由header.S开始,功能上它是老版本中bootsect.S和setup.S的结合。不过一般情况下,系统都会有loader,bootsect是用不上的。现在的loader会做很多事。这个文件中bootsect的功能已经不支持了,如果从这个文件中的bootsect(开始512字节)启动,则直接提示按任意键重启电脑。真正还有意义的是setup部分,它会进行:磁盘复位,设置堆栈,检查setup.elf的安装,清bss段,跳转到boot/main.c等。 在header.S中有一个核心的数据结构setup_header,它定义在【3】中。它的位置牌bootsect尾部和setup前部。

在setup.ld中有如下两句,说明setup.bin结束位置一定不会超过X+0x8000;hdr位置一定是0x1f1。根据header.S中的分析可知,栈底一定不会超过X+10000,溢出时最大相距X偏移为0xfffc(4字节对齐了)

. = ASSERT(_end <= 0x8000, "Setup too big!");/*若表达式不为真,打印msg,结束链接*/

. = ASSERT(hdr == 0x1f1, "The setup header has the wrong offset!");

# vmlinux#   ^#   |#   +-< $(vmlinux-init)#   |   +--< init/version.o + more#   |#   +--< $(vmlinux-main)#   |    +--< driver/built-in.o mm/built-in.o + more#   |#   +-< kallsyms.o (see description in CONFIG_KALLSYMS section)vmlinux-init := $(head-y) $(init-y)vmlinux-main := $(core-y) $(libs-y) $(drivers-y) $(net-y)vmlinux-all  := $(vmlinux-init) $(vmlinux-main)vmlinux-lds  := arch/$(SRCARCH)/kernel/vmlinux.lds在http://lxr.linux.no/linux+v3.3.6/arch/x86/Makefile中:head-y := arch/x86/kernel/head_$(BITS).ohead-y += arch/x86/kernel/head$(BITS).ohead-y += arch/x86/kernel/head.ohead-y += arch/x86/kernel/init_task.o在arch/x86/kernel目录下存在一些head开头的汇编或c语言源代码的。其中BITS指出是32位还是64位。head.c,head32.c,head64.c,head_32.S,head_64.S,init_task.c(在顶层makefile)而其它子目标都是指向具体的根目录下的子目录了:init-y:= init/drivers-y:= drivers/ sound/ firmware/net-y:= net/libs-y:= lib/core-y:= usr/在http://lxr.linux.no/linux+v3.3.6/arch/x86/boot/Makefile中:bzImage: $(obj)/setup.bin $(obj)/vmlinux.bin $(obj)/tools/build FORCE说明bzImage是依赖于setup.bin vmlinux.bin 和tools的。tools最终会把setup.bin和vmlinux.bin结合成一个内核文件。在http://lxr.linux.no/linux+v3.3.6/arch/x86/boot/Makefile文件中$(obj)/setup.bin: $(obj)/setup.elf FORCE$(obj)/setup.elf: $(src)/setup.ld$(SETUP_OBJS) FORCESETUP_OBJS = $(addprefix $(obj)/,$(setup-y))setup-y         += a20.o bioscall.o cmdline.o copy.o cpu.o cpucheck.osetup-y         += early_serial_console.o edd.o header.o main.o mca.o memory.osetup-y         += pm.o pmjump.o printf.o regs.o string.o tty.o video.osetup-y         += video-mode.o version.osetup-$(CONFIG_X86_APM_BOOT) += apm.o setup-y         += video-vga.osetup-y         += video-vesa.osetup-y         += video-bios.o所以,setup.bin是由上面这些文件构成,并最终和vmlinux结合起来。由此可见,setup.bin是我们最先执行的部分在http://lxr.linux.no/linux+v3.3.6/arch/x86/boot/setup.ld中指出ENTRY(_start)说明_start是setup.bin最终的入口,而这个符号正是来源于header.S中的setup部分(第二个512字节)


二、setup相关

在setup部分有一个核心的数据结构,setup_header(【3】)。它各字段描述在【2】中。这个结构中,有些字段同内核(kernel)给加载器(bootloader)用的,一些是加载器给内核的,一些是加载器读完后再写进去。这三种行为分别称为"读","写","修改"。一个通用的加载器应该将有标志"强制"(obligatory)标志的字段,如果某些加载器想将内核加载到‘非标准’地址,应该改写有"重定位"(reloc)的字段,其它类型的加载器可以忽略这些字段。具体内容参见文档【2】。

三、几个标志

loadflags:
bit 0:LOADED_HIGH,=1表示加载内核到0x100000,=0加载到0x10000
bit 5:QUIET_FLAG,=1不显示早期msg,否则显示之
bit 6:KEEP_SEGMENTS,=1在32bit入口时不重新加载段寄存器,假设都是以0开始的段,否则重加载之
bit 7:CAN_USE_HEAP,=1说明heap_end_ptr 字段中输入的值是可用的,否则不可用

四、代码分析

/* *header.S * *Copyright (C) 1991, 1992 Linus Torvalds * *Based on bootsect.S and setup.S *modified by more people than can be counted * *Rewritten as a common file by H. Peter Anvin (Apr 2007) * * BIG FAT NOTE: We're in real mode using 64k segments.  Therefore segment * addresses must be multiplied by 16 to obtain their respective linear * addresses. To avoid confusion, linear addresses are written using leading * hex while segment addresses are written as segment:offset. * */#include <asm/segment.h>#include <generated/utsrelease.h>#include <asm/boot.h>#include <asm/e820.h>#include <asm/page_types.h>#include <asm/setup.h>#include "boot.h"#include "voffset.h"#include "zoffset.h"BOOTSEG= 0x07C0/* original address of boot-sector */SYSSEG= 0x1000/* historical load address >> 4 */#ifndef SVGA_MODE#define SVGA_MODE ASK_VGA#endif#ifndef RAMDISK#define RAMDISK 0#endif#ifndef ROOT_RDONLY#define ROOT_RDONLY 1#endif/*For COFF targets, the .section directive is used in one of the following ways:.section name [, "flags"].section name [, subsegment]If the optional argument is quoted, it is taken as flags to use for the section. Each flag is a single character. The following flags are recognized:b bss section (uninitialized data)n section is not loadedw writable sectiond data sectionr read-only sectionx executable sections shared section (meaningful for PE targets)*//* * 主要功能:磁盘复位,设置堆栈,检查setup.elf的安装,清0bss段,中转到boot/main.c * 主要数据结构:setup_header */.code16/*这是16位汇编*/.section ".bstext", "ax"/*可分配内存(a,allocatable)、可执行的一个段*/.global bootsect_start/*blobal使此标号对ld可见*/bootsect_start:#ifdef CONFIG_EFI_STUB/*EFI启动相关*/# "MZ", MS-DOS header.byte 0x4d.byte 0x5a#endif# Normalize the start addressljmp$BOOTSEG, $start2/*跳转到start2标号处,BOOTSEG=0x7c0见前面定义*/start2:/*它位于0x7c00处*/movw%cs, %ax/*ax,ds,es,ss都等于cs*/movw%ax, %dsmovw%ax, %esmovw%ax, %ssxorw%sp, %sp/*栈指针sp设置为0*/sti/*开中断*/cld/*清除方向,告诉si,di递增,std告诉它们递减*//* * 下面这段代码实际上是显示bugger_off_msg * 标号处的几句话,调用的int 10h中断 */movw$bugger_off_msg, %si/*bugger_off_msg标号地址放入si*/msg_loop:lodsb/*Load Accumulator from string  将DS:SI处内容取一字节放入al,由上可知  DS=CS */andb%al, %al/*看al是不是0,如果是那个0的话,会提示重启*/jzbs_die/*如果al==0,跳转到bs_die,表示显示结束*/movb$0xe, %ah/*设置int 10h中断参数,0x0E表示显示字符,光标前移*/movw$7, %bx/*AL=字符,BL=颜色*/int$0x10/*int 10中断/jmpmsg_loop/*跳回去显示下一个字符*/bs_die:# Allow the user to press a key, then rebootxorw%ax, %axint$0x16/*从键盘读一字符,AL=字符码,AH=扫描码*/int$0x19/*寻找并加载MBR到0x7c00,并跳去执行(重启了)*/# int 0x19 should never return.  In case it does anyway,# invoke the BIOS reset code.../* * ljmp section,offset,0xffff0是bois位置,即cpu上电后执行的第一句 * 上面返回的话,跳转到0xffff0去,相当于重启 * 两处重启代码,理论上第一处重启代码不会返回 */ljmp$0xf000,$0xfff0#ifdef CONFIG_EFI_STUB/*EFI启动相关*/.org0x3c## Offset to the PE header.#.longpe_header#endif /* CONFIG_EFI_STUB */.section ".bsdata", "a"/*定义一个节*/bugger_off_msg:.ascii"Direct booting from floppy is no longer supported.\r\n".ascii"Please use a boot loader program instead.\r\n".ascii"\n".ascii"Remove disk and press any key to reboot . . .\r\n".byte0#ifdef CONFIG_EFI_STUBpe_header:.ascii"PE".word 0coff_header:#ifdef CONFIG_X86_32.word0x14c# i386#else.word0x8664# x86-64#endif.word2# nr_sections.long0 # TimeDateStamp.long0# PointerToSymbolTable.long1# NumberOfSymbols.wordsection_table - optional_header# SizeOfOptionalHeader#ifdef CONFIG_X86_32.word0x306# Characteristics.# IMAGE_FILE_32BIT_MACHINE |# IMAGE_FILE_DEBUG_STRIPPED |# IMAGE_FILE_EXECUTABLE_IMAGE |# IMAGE_FILE_LINE_NUMS_STRIPPED#else.word0x206# Characteristics# IMAGE_FILE_DEBUG_STRIPPED |# IMAGE_FILE_EXECUTABLE_IMAGE |# IMAGE_FILE_LINE_NUMS_STRIPPED#endifoptional_header:#ifdef CONFIG_X86_32.word0x10b# PE32 format#else.word0x20b # PE32+ format#endif.byte0x02# MajorLinkerVersion.byte0x14# MinorLinkerVersion# Filled in by build.c.long0# SizeOfCode.long0# SizeOfInitializedData.long0# SizeOfUninitializedData# Filled in by build.c.long0x0000# AddressOfEntryPoint.long0x0000# BaseOfCode#ifdef CONFIG_X86_32.long0# data#endifextra_header_fields:#ifdef CONFIG_X86_32.long0# ImageBase#else.quad0# ImageBase#endif.long0x1000# SectionAlignment.long0x200# FileAlignment.word0# MajorOperatingSystemVersion.word0# MinorOperatingSystemVersion.word0# MajorImageVersion.word0# MinorImageVersion.word0# MajorSubsystemVersion.word0# MinorSubsystemVersion.long0# Win32VersionValue## The size of the bzImage is written in tools/build.c#.long0# SizeOfImage.long0x200# SizeOfHeaders.long0# CheckSum.word0xa# Subsystem (EFI application).word0# DllCharacteristics#ifdef CONFIG_X86_32.long0# SizeOfStackReserve.long0# SizeOfStackCommit.long0# SizeOfHeapReserve.long0# SizeOfHeapCommit#else.quad0# SizeOfStackReserve.quad0# SizeOfStackCommit.quad0# SizeOfHeapReserve.quad0# SizeOfHeapCommit#endif.long0# LoaderFlags.long0x1# NumberOfRvaAndSizes.quad0# ExportTable.quad0# ImportTable.quad0# ResourceTable.quad0# ExceptionTable.quad0# CertificationTable.quad0# BaseRelocationTable# Section tablesection_table:.ascii".text".byte0.byte0.byte0.long0.long0x0# startup_{32,64}.long0# Size of initialized data# on disk.long0x0# startup_{32,64}.long0# PointerToRelocations.long0# PointerToLineNumbers.word0# NumberOfRelocations.word0# NumberOfLineNumbers.long0x60500020# Characteristics (section flags)## The EFI application loader requires a relocation section# because EFI applications are relocatable and not having# this section seems to confuse it. But since we don't need# the loader to fixup any relocs for us just fill it with a# single dummy reloc.#.ascii".reloc".byte0.byte0.longreloc_end - reloc_start.longreloc_start.longreloc_end - reloc_start# SizeOfRawData.longreloc_start# PointerToRawData.long0# PointerToRelocations.long0# PointerToLineNumbers.word0# NumberOfRelocations.word0# NumberOfLineNumbers.long0x42100040# Characteristics (section flags)#endif /* CONFIG_EFI_STUB *//* * 以下是内核头部数据结构的第1部分,这部分位于第一个扇区(512)中 * 因为bootsect代码只提供的重启功能,代码量很小,后面这块位置还需要放 * setup相关数据结构。所以,内核头结构是从第一扇区最后跨到第二扇区: * setup_header part1-_start-jmp code-kernel header part2... * 在http://lxr.linux.no/linux+v3.3.6/arch/x86/include/asm/bootparam.h * 中定义了setup_header结构。 */# Kernel attributes; used by setup.  This is part 1 of the# header, from the old boot sector..section ".header", "a".globlhdr/*导出这个符号,实模式内核头部,参考doc/x86/boot.txt*/hdr:setup_sects:.byte 0/* Filled in by build.c */root_flags:.word ROOT_RDONLYsyssize:.long 0/* Filled in by build.c */ram_size:.word 0/* Obsolete */vid_mode:.word SVGA_MODEroot_dev:.word 0/* Filled in by build.c */boot_flag:.word 0xAA55/*MBR最后两字节的特征标志*/# offset 512, entry point/*上面的代码量为512字节的bootsect,下是代码是setup的开始*/.globl_start_start:# Explicitly enter this as bytes, or the assembler# tries to generate a 3-byte jump here, which causes# everything else to push off to the wrong offset./* * 位于0x200处是一个jmp,会直接跳到start_of_setup处 * 实际就是越过内核头部数据结构,跳到代码处 */.byte0xeb# short (2-byte) jump    off:0x200.bytestart_of_setup-1f    #off:0x201,1f是指下面的标号'1'/*以下是内setup_header数据结构的第二部分*/1:# Part 2 of the header, from the old setup.S.ascii"HdrS"# header signature.word0x020a# header version number (>= 0x0105)# or else old loadlin-1.5 will fail).globl realmode_swtchrealmode_swtch:.word0, 0# default_switch, SETUPSEGstart_sys_seg:.wordSYSSEG# obsolete and meaningless, but just# in case something decided to "use" it.wordkernel_version-512 # pointing to kernel version string# above section of header is compatible# with loadlin-1.5 (header v1.5). Don't# change it.type_of_loader:.byte0# 0 means ancient bootloader, newer# bootloaders know to change this.# See Documentation/x86/boot.txt for# assigned ids# flags, unused bits must be zero (RFU) bit within loadflagsloadflags:LOADED_HIGH= 1# If set, the kernel is loaded highCAN_USE_HEAP= 0x80# If set, the loader also has set# heap_end_ptr to tell how much# space behind setup.S can be used for# heap purposes.# Only the loader knows what is free.byteLOADED_HIGHsetup_move_size: .word  0x8000# size to move, when setup is not# loaded at 0x90000. We will move setup# to 0x90000 then just before jumping# into the kernel. However, only the# loader knows how much data behind# us also needs to be loaded.code32_start:# here loaders can put a different# start address for 32-bit code..long0x100000# 0x100000 = default for big kernelramdisk_image:.long0# address of loaded ramdisk image# Here the loader puts the 32-bit# address where it loaded the image.# This only will be read by the kernel.ramdisk_size:.long0# its size in bytesbootsect_kludge:.long0# obsoleteheap_end_ptr:.word_end+STACK_SIZE-512# (Header version 0x0201 or later)# space from here (exclusive) down to# end of setup code can be used by setup# for local heap purposes.ext_loader_ver:.byte0# Extended boot loader versionext_loader_type:.byte0# Extended boot loader typecmd_line_ptr:.long0# (Header version 0x0202 or later)# If nonzero, a 32-bit pointer# to the kernel command line.# The command line should be# located between the start of# setup and the end of low# memory (0xa0000), or it may# get overwritten before it# gets read.  If this field is# used, there is no longer# anything magical about the# 0x90000 segment; the setup# can be located anywhere in# low memory 0x10000 or higher.ramdisk_max:.long 0x7fffffff# (Header version 0x0203 or later)# The highest safe address for# the contents of an initrd# The current kernel allows up to 4 GB,# but leave it at 2 GB to avoid# possible bootloader bugs.kernel_alignment:  .long CONFIG_PHYSICAL_ALIGN#physical addr alignment#required for protected mode#kernel#ifdef CONFIG_RELOCATABLErelocatable_kernel:    .byte 1#elserelocatable_kernel:    .byte 0#endifmin_alignment:.byte MIN_KERNEL_ALIGN_LG2# minimum alignmentpad3:.word 0cmdline_size:   .long   COMMAND_LINE_SIZE-1     #length of the command line,                                                #added with boot protocol                                                #version 2.06hardware_subarch:.long 0# subarchitecture, added with 2.07# default to 0 for normal x86 PChardware_subarch_data:.quad 0payload_offset:.long ZO_input_datapayload_length:.long ZO_z_input_lensetup_data:.quad 0# 64-bit physical pointer to# single linked list of# struct setup_datapref_address:.quad LOAD_PHYSICAL_ADDR# preferred load addr#define ZO_INIT_SIZE(ZO__end - ZO_startup_32 + ZO_z_extract_offset)#define VO_INIT_SIZE(VO__end - VO__text)#if ZO_INIT_SIZE > VO_INIT_SIZE#define INIT_SIZE ZO_INIT_SIZE#else#define INIT_SIZE VO_INIT_SIZE#endifinit_size:.long INIT_SIZE# kernel initialization size# End of setup header #####################################################.section ".entrytext", "ax"/*再来一个段*/start_of_setup:#ifdef SAFE_RESET_DISK_CONTROLLER# Reset the disk controller.movw$0x0000, %ax# Reset disk controllermovb$0x80, %dl# All disksint$0x13/*ah=0,磁盘系统复位*/#endif# Force %es = %dsmovw%ds, %axmovw%ax, %escld# Apparently some ancient versions of LILO invoked the kernel with %ss != %ds,# which happened to work by accident for the old code.  Recalculate the stack# pointer if %ss is invalid.  Otherwise leave it alone, LOADLIN sets up the# stack behind its own code, so we can't blindly put it directly past the heap.movw%ss, %dxcmpw%ax, %dx# %ds == %ss?,ax=ds->ds==ss?movw%sp, %dx# dx设置为栈顶je2f# -> assume %sp is reasonably set# Invalid %ss, make up a new stack,栈不对,整理之/* * 根据setup.ld,从本代码生成setup.elf * 一些符号可从setup.ld中看到 */movw$_end, %dx/* * _end指向setup.elf结尾处,如果下面这个test不是0,说明 * CAN_USE_HEAP被设置。表示可以使用heap,那么就要使用 * 加载器设置的heap结尾值heap_end_ptr,并放入dx中去。 * 若CAN_USE_HEAP标志没设置,说明不能使用堆,则dx是本句 * 的_end标志,指向setup.bin结尾处(此时heap大小为0)。 */testb$CAN_USE_HEAP, loadflagsjz1fmovwheap_end_ptr, %dx/* * CAN_USE_HEAP已设置,heap_end_ptr=_end+STACK_SIZE-512 * 在boot.h中,STACK_SIZE=512,所以heap_end_ptr=_end(setup结尾)   * 此字段是lbligatory的,说明是要loader强制写入的。   * 而此字段要配合CAN_USE_HEAP使用,如果此字段被设置   * 则heap_end_ptr可用,指向堆尾,默认情况下此值与_end相同   * 表示可以使用heap,堆从_end开始,并heap_end_ptr指向堆尾 */1:addw$STACK_SIZE, %dx/*  * 栈是由高地址向低地址方向生长的,栈指针最远指向heap结尾处; * 所以栈底得抬高,给栈创造出一个空间-STACK_SIZE。由_end标志 * 向上,依次是堆开始(_end标志处),堆空间,堆结束(heap_end_ptr) * 栈开始(heap_end_ptr),栈空间(大小STACK_SIZE),栈结束 * (heap_end_ptr+STACK_SIZE) */jnc2f/* 如果dx溢出,则设置dx=0*/xorw%dx, %dx# Prevent wraparound2:# Now %dx should point to the end of our stack spaceandw$~3, %dx# dword align (might as well...)jnz3f/* * 与1111 1111 1111 1100进行and,并且结果为0的值是<=3的, * 包括标志1处的xorw,它的结果是0。就是说只要标志1处jnc 2f * 没跳转,此处(标志2)的jnz也不会跳,因为dx=0<=3。所以给dx一 * 个固定值0xfffc * 总结一下:如果标志1溢出dx=0xfffc,其它<=3的情况应该没有, * 因为STACK_SIZE=512 */movw$0xfffc, %dx/* Make sure we're not zero*/3:movw%ax, %ss/*ax=ss=ds*/movzwl%dx, %esp/* Clear upper half of %esp*//* * esp高端清0,低端设置为dx,即栈顶 * dx=堆尾+STACK_SIZE * 上述标志1,2都顺利跳转的话,堆栈应该是: * *   |esp         | *   |栈          |  *   |heap_end_ptr| *   |堆          |  *   |_end        |   * * 如果真的溢出了,说明堆尾太高了 * 默认会把栈底设置为0xfffc,加载器应该会知道这一点。同时应该注 * 意,实模式代码段寄存器cs不等于0,cs是header.S的加载地址(boot.txt * 中的X处)。这里其它通用寄存器都是相对cs的一个偏移。结合setup.ld * 结尾处可知栈底是不会大于X+10000的,这就是此处为什么设置dx(栈底) * 为0xfffc的原因(4字节对齐,0xffff+1=0x10000)  */sti# Now we should have a working stack,开中断# We will have entered with %cs = %ds+0x20, normalize %cs so# it is on par with the other segments.pushw%dspushw$6flretw/* * 远跳转会影响%cs的值: * 假设内核被加载到了地址X,应该类似远跳转jmp SEG+0x20:0,跳进header.S偏移512处, * 也就是setup开始的部分(第2个512)。进来前,所有段寄存器都相同=X,进来后,%cs多加 * 了0x20。而这里的lretw 会从栈中弹出一个值作为%cs,弹出第二个值作为* %ip。所以, * 这句执行完成后,cs:ip=%ds:标志6。这样的话,cs恢复到了跳转前的位置,即内核加载基 * 址---X。进入main后,也会以X作为基址执行。 */6:# Check signature at end of setup,setup.elf签名检查cmpl$0x5a5aaa55, setup_sigjnesetup_bad# Zero the bssmovw$__bss_start, %dimovw$_end+3, %cxxorl%eax, %eaxsubw%di, %cxshrw$2, %cxrep; stosl/*因al中是0,所以将0放di中,cx为计数*/# Jump to C code (should not return)calllmain/*boot/main.c*/# Setup corrupt somehow...setup_bad:movl$setup_corrupt, %eaxcalllputs/*boot/tty.c*/# Fall through....globldie.typedie, @functiondie:hltjmpdie.sizedie, .-die.section ".initdata", "a"setup_corrupt:.byte7.string"No setup signature found...\n".datadummy:.long0.section .relocreloc_start:.longdummy - reloc_start.long10.word0reloc_end:

五、setup.ld

setup链接脚本这个文件的功能是负责链接后的内存布局的。它规定了符号在内存中出现的位置。/* * setup.ld * * Linker script for the i386 setup code */OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")/*输出格式命令*/OUTPUT_ARCH(i386)ENTRY(_start)/* * ENTRY()命令的意思是将某符号定们输出文件入口点 * ld对入口点处理有一定顺序:1)ld的-e选项,2)链接脚本的ENTRY()命令, * 3)已定义的start符号,4).text区段的第一字节,5)使用0为入口点 */SECTIONS/* * SECTIONS命令告诉ld如何将输入文件的各区段映射到输出文件的区段, * 并规定了区段的位置 */{. = 0;/*  * '.'(句点)代表是当前位置,也叫定位器,这里是说将紧后面的符号 * 定位到offset=0的位置 */.bstext: { *(.bstext) }/* 由于是面定位器原因,这个符号将被加载到offset=0的位置*/.bsdata: { *(.bsdata) }/* 这个符号将在bstext后面出现,位于offset=.bstext的size处, * 与上面一句一样,意思是将所有(*,星号)输入文件的".bsdata"段 * 合并成一个总的(在输出文件中的)".bsdata"段。 */. = 497;/* * 意思是.header区段是从offset497位置开始的,前文说过,     * setup_header的第一部分在第一扇区的最后。有setup_sects等字段     * 到boot_flag共15字节,15+497=512,就是说到boot_flag结束,刚好     * 是512字节(占第一个扇区)。 */.header: { *(.header) }/* header符号位于offset=497*/.entrytext: { *(.entrytext) }.inittext: { *(.inittext) }.initdata: { *(.initdata) }__end_init = .;/* * 句点代表当前位置,这里是将当前位置记录到__end_init符号中, * 其它的"符号=句点"也表示记录当前位置的意思 */.text: { *(.text) }.text32: { *(.text32) }. = ALIGN(16);/* 16字节对齐*/.rodata: { *(.rodata*) }.videocards: {video_cards = .;*(.videocards)video_cards_end = .;}. = ALIGN(16);.data: { *(.data*) }.signature: {/*setup的签名标志*/setup_sig = .;LONG(0x5a5aaa55)}. = ALIGN(16);.bss:/*bss段的开始和结束*/{__bss_start = .;*(.bss)__bss_end = .;}. = ALIGN(16);_end = .;/*全部结束*//DISCARD/ : { *(.note*) }/* * The ASSERT() sink to . is intentional, for binutils 2.14 compatibility: */. = ASSERT(_end <= 0x8000, "Setup too big!");/*若表达式不为真,打印msg,结束链接*/. = ASSERT(hdr == 0x1f1, "The setup header has the wrong offset!");/* Necessary for the very-old-loader check to work... */. = ASSERT(__end_init <= 5*512, "init sections too big!");}


	
				
		
原创粉丝点击