Skip to content

Instantly share code, notes, and snippets.

@knknkn1162
Last active September 21, 2018 07:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save knknkn1162/9ba537b49b10e77f39462a30b274689e to your computer and use it in GitHub Desktop.
Save knknkn1162/9ba537b49b10e77f39462a30b274689e to your computer and use it in GitHub Desktop.
Based on the course, https://pdos.csail.mit.edu/6.828/2018/ Load the HDD into memory at 0x00007c00~0x00007e00.
bootblock.o: file format elf32-i386
Disassembly of section .text:
# Start the first CPU: switch to 32-bit protected mode, jump into C.
# The BIOS loads this code from the first sector of the hard disk into
# memory at physical address 0x7c00 and starts executing in real mode
# with %cs=0 %ip=7c00.
00007c00 <start>:
.code16 # Assemble for 16-bit mode
.globl start
# 0x7c00 ~ 0x7e00
start:
# when xv6 is ready, it will re-enable interrupts
cli # BIOS enabled interrupts; disable
7c00: fa cli
# Zero data segment registers DS, ES, and SS.
# BIOS doesnot guarantee anything about the contents of %ds, %es, %ss.
xorw %ax,%ax # Set %ax to zero
7c01: 31 c0 xor %eax,%eax
movw %ax,%ds # -> Data Segment
7c03: 8e d8 mov %eax,%ds
movw %ax,%es # -> Extra Segment
7c05: 8e c0 mov %eax,%es
movw %ax,%ss # -> Stack Segment
7c07: 8e d0 mov %eax,%ss
00007c09 <seta20.1>:
# Physical address line A20 is tied to zero so that the first PCs
# with 2 MB would run software that assumed 1 MB. Undo that.
# The boot loader must enable the 21st address bit using I/O to the keyboard controller on ports 0x64 & 0x60
seta20.1:
# read the status register form the keyboard controller via the port 0x64
inb $0x64,%al # Wait for not busy
7c09: e4 64 in $0x64,%al
testb $0x2,%al
7c0b: a8 02 test $0x2,%al
# If input buffer is full(bit1 is set), repeat
jnz seta20.1
7c0d: 75 fa jne 7c09 <seta20.1>
# the CPU writes to port 0x64, the byte is interpreted as a command byte.
# Write output port(P2) ..0xd1
movb $0xd1,%al # 0xd1 -> port 0x64
7c0f: b0 d1 mov $0xd1,%al
outb %al,$0x64
7c11: e6 64 out %al,$0x64
00007c13 <seta20.2>:
seta20.2:
inb $0x64,%al # Wait for not busy
7c13: e4 64 in $0x64,%al
testb $0x2,%al
7c15: a8 02 test $0x2,%al
jnz seta20.2
7c17: 75 fa jne 7c13 <seta20.2>
# Command 0xdf: Enable A20 address line
movb $0xdf,%al # 0xdf -> port 0x60
7c19: b0 df mov $0xdf,%al
# If the CPU writes to port 0x60, the byte is interpreted as a data byte.
# WHY?
# suppose that It can be read/written by writing 0x20/0x60 to port 0x64 and then reading/writing a data byte from/to port 0x60.
outb %al,$0x60
7c1b: e6 60 out %al,$0x60
# Switch from real to protected mode. Use a bootstrap GDT that makes
# virtual addresses map directly to physical addresses so that the
# effective memory map doesn't change during the transition.
lgdt gdtdesc
7c1d: 0f 01 16 lgdtl (%esi)
7c20: 78 7c js 7c9e <readsect+0xe>
movl %cr0, %eax
7c22: 0f 20 c0 mov %cr0,%eax
#define CR0_PE 0x00000001 // Protection Enable
orl $CR0_PE, %eax
7c25: 66 83 c8 01 or $0x1,%ax
movl %eax, %cr0
7c29: 0f 22 c0 mov %eax,%cr0
# translation, so that the mapping is still the identity mapping.
#define SEG_KCODE 1 // kernel code
# cannot modify %cs directly, so instead the code executes an ljmp instruction
# set %cs <- $(SEG_CODE<<3) = 0x08, which is at the 2nd GDT entry
ljmp $(SEG_KCODE<<3), $start32
7c2c: ea .byte 0xea
# %cs:($0x007c31)
7c2d: 31 7c 08 00 xor %edi,0x0(%eax,%ecx,1)
00007c31 <start32>:
.code32 # Tell assembler to generate 32-bit code now.
start32:
# Set up the protected-mode data segment registers
#define SEG_KDATA 2 // kernel data+stack
movw $(SEG_KDATA<<3), %ax # Our data segment selector
7c31: 66 b8 10 00 mov $0x10,%ax
# %ds <- 0x10, which is the 3rd index GDT entry
movw %ax, %ds # -> DS: Data Segment
7c35: 8e d8 mov %eax,%ds
movw %ax, %es # -> ES: Extra Segment
7c37: 8e c0 mov %eax,%es
movw %ax, %ss # -> SS: Stack Segment
7c39: 8e d0 mov %eax,%ss
movw $0, %ax # Zero segments not ready for use
7c3b: 66 b8 00 00 mov $0x0,%ax
movw %ax, %fs # -> FS
7c3f: 8e e0 mov %eax,%fs
movw %ax, %gs # -> GS
7c41: 8e e8 mov %eax,%gs
# Set up the stack pointer and call into C.
movl $start, %esp
7c43: bc 00 7c 00 00 mov $0x7c00,%esp
call bootmain
7c48: e8 d5 00 00 00 call 7d22 <bootmain>
# If bootmain returns (it shouldn't), trigger a Bochs
# Bochs is a highly portable open source IA-32 (x86) PC emulator
# breakpoint if running under Bochs, then loop.
movw $0x8a00, %ax # 0x8a00 -> port 0x8a00
7c4d: 66 b8 00 8a mov $0x8a00,%ax
movw %ax, %dx
7c51: 66 89 c2 mov %ax,%dx
outw %ax, %dx
7c54: 66 ef out %ax,(%dx)
# return the Bochs to the debugger prompt. Basically the same as doing CTRL+C.
movw $0x8ae0, %ax # 0x8ae0 -> port 0x8a00
7c56: 66 b8 e0 8a mov $0x8ae0,%ax
outw %ax, %dx
7c5a: 66 ef out %ax,(%dx)
00007c5c <spin>:
spin:
jmp spin
7c5c: eb fe jmp 7c5c <spin>
7c5e: 66 90 xchg %ax,%ax
## Global Destriptor table(8byte*3entries)
00007c60 <gdt>:
## put the LGDT register(2+4byte)
00007c78 <gdtdesc>:
# bootmain.c
## bootmain() loads an ELF kernel image from the disk starting at
## sector 1 on the and then jumps to the kernel entry routine.
00007c7e <waitdisk>:
00007c90 <readsect>:
00007ce3 <readseg>:
00007d22 <bootmain>:
{
00007d22 <bootmain>:
{
7d22: 55 push %ebp
7d23: 89 e5 mov %esp,%ebp
7d25: 57 push %edi
7d26: 56 push %esi
7d27: 53 push %ebx
7d28: 83 ec 0c sub $0xc,%esp
readseg((uchar*)elf, 4096, 0); // 4096 = 0x1000
7d2b: 6a 00 push $0x0
7d2d: 68 00 10 00 00 push $0x1000
// ELF binary places in-memory copy at address 0x10000
// elf = (struct elfhdr*)0x10000; // scratch space
7d32: 68 00 00 01 00 push $0x10000
7d37: e8 a7 ff ff ff call 7ce3 <readseg>
if(elf->magic != ELF_MAGIC)
7d3c: 83 c4 0c add $0xc,%esp
7d3f: 81 3d 00 00 01 00 7f cmpl $0x464c457f,0x10000
7d46: 45 4c 46
7d49: 75 50 jne 7d9b <bootmain+0x79>
ph = (struct proghdr*)((uchar*)elf + elf->phoff);
7d4b: a1 1c 00 01 00 mov 0x1001c,%eax
7d50: 8d 98 00 00 01 00 lea 0x10000(%eax),%ebx
eph = ph + elf->phnum;
7d56: 0f b7 35 2c 00 01 00 movzwl 0x1002c,%esi
7d5d: c1 e6 05 shl $0x5,%esi
7d60: 01 de add %ebx,%esi
for(; ph < eph; ph++){
7d62: 39 f3 cmp %esi,%ebx
7d64: 73 2f jae 7d95 <bootmain+0x73>
pa = (uchar*)ph->paddr;
7d66: 8b 7b 0c mov 0xc(%ebx),%edi
readseg(pa, ph->filesz, ph->off);
7d69: ff 73 04 pushl 0x4(%ebx)
7d6c: ff 73 10 pushl 0x10(%ebx)
7d6f: 57 push %edi
7d70: e8 6e ff ff ff call 7ce3 <readseg>
if(ph->memsz > ph->filesz)
7d75: 8b 4b 14 mov 0x14(%ebx),%ecx
7d78: 8b 43 10 mov 0x10(%ebx),%eax
7d7b: 83 c4 0c add $0xc,%esp
7d7e: 39 c1 cmp %eax,%ecx
7d80: 76 0c jbe 7d8e <bootmain+0x6c>
stosb(pa + ph->filesz, 0, ph->memsz - ph->filesz);
entry();
# Note that `elf = (struct elfhdr*)0x10000; // scratch space`
# And that (char*)elf->entry - (char*)elf = 0x18
# so the address of the `entry` variable is 0x10000 + 0x18.
7d95: ff 15 18 00 01 00 call *0x10018
}
7d9b: 8d 65 f4 lea -0xc(%ebp),%esp
7d9e: 5b pop %ebx
7d9f: 5e pop %esi
7da0: 5f pop %edi
7da1: 5d pop %ebp
7da2: c3 ret
Memory Configuration
Name Origin Length Attributes
*default* 0x00000000 0xffffffff
Linker script and memory map
Address of section .text set to 0x7c00
LOAD bootasm.o
LOAD bootmain.o
[!provide] PROVIDE (__executable_start = SEGMENT_START ("text-segment", 0x8048000))
0x08048054 . = (SEGMENT_START ("text-segment", 0x8048000) + SIZEOF_HEADERS)
.interp
*(.interp)
.note.gnu.build-id
*(.note.gnu.build-id)
.hash
*(.hash)
.gnu.hash
*(.gnu.hash)
.dynsym
*(.dynsym)
.dynstr
*(.dynstr)
.gnu.version
*(.gnu.version)
.gnu.version_d
*(.gnu.version_d)
.gnu.version_r
*(.gnu.version_r)
.rel.init
*(.rel.init)
.rel.text
*(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)
.rel.fini
*(.rel.fini)
.rel.rodata
*(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)
.rel.data.rel.ro
*(.rel.data.rel.ro .rel.data.rel.ro.* .rel.gnu.linkonce.d.rel.ro.*)
.rel.data
*(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)
.rel.tdata
*(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)
.rel.tbss
*(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)
.rel.ctors
*(.rel.ctors)
.rel.dtors
*(.rel.dtors)
.rel.got 0x08048054 0x0
*(.rel.got)
.rel.got 0x08048054 0x0 bootasm.o
.rel.bss
*(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)
.rel.ifunc
*(.rel.ifunc)
.rel.plt 0x08048054 0x0
*(.rel.plt)
[!provide] PROVIDE (__rel_iplt_start = .)
*(.rel.iplt)
.rel.iplt 0x08048054 0x0 bootasm.o
[!provide] PROVIDE (__rel_iplt_end = .)
.init
*(SORT_NONE(.init))
.plt 0x08048058 0x0
*(.plt)
*(.iplt)
.iplt 0x08048058 0x0 bootasm.o
.plt.got
*(.plt.got)
.plt.sec
*(.plt.sec)
.text 0x00007c00 0x1a3
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
*(.text.exit .text.exit.*)
*(.text.startup .text.startup.*)
*(.text.hot .text.hot.*)
*(.text .stub .text.* .gnu.linkonce.t.*)
.text 0x00007c00 0x7e bootasm.o
0x00007c00 start
.text 0x00007c7e 0x125 bootmain.o
0x00007c7e waitdisk
0x00007c90 readsect
0x00007ce3 readseg
0x00007d22 bootmain
*(.gnu.warning)
.fini
*(SORT_NONE(.fini))
[!provide] PROVIDE (__etext = .)
[!provide] PROVIDE (_etext = .)
[!provide] PROVIDE (etext = .)
.rodata
*(.rodata .rodata.* .gnu.linkonce.r.*)
.rodata1
*(.rodata1)
.eh_frame_hdr
*(.eh_frame_hdr)
*(.eh_frame_entry .eh_frame_entry.*)
.eh_frame 0x00007da4 0xb8
*(.eh_frame)
.eh_frame 0x00007da4 0xb8 bootmain.o
*(.eh_frame.*)
.gcc_except_table
*(.gcc_except_table .gcc_except_table.*)
.gnu_extab
*(.gnu_extab*)
.exception_ranges
*(.exception_ranges .exception_ranges*)
0x00007e5c . = .
.eh_frame
*(.eh_frame)
*(.eh_frame.*)
.gnu_extab
*(.gnu_extab)
.gcc_except_table
*(.gcc_except_table .gcc_except_table.*)
.exception_ranges
*(.exception_ranges .exception_ranges*)
.tdata 0x00007e5c 0x0
[!provide] PROVIDE (__tdata_start = .)
*(.tdata .tdata.* .gnu.linkonce.td.*)
.tbss
*(.tbss .tbss.* .gnu.linkonce.tb.*)
*(.tcommon)
.preinit_array 0x00007e5c 0x0
[!provide] PROVIDE (__preinit_array_start = .)
*(.preinit_array)
[!provide] PROVIDE (__preinit_array_end = .)
.init_array 0x00007e5c 0x0
[!provide] PROVIDE (__init_array_start = .)
*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))
*(.init_array EXCLUDE_FILE(*crtend?.o *crtend.o *crtbegin?.o *crtbegin.o) .ctors)
[!provide] PROVIDE (__init_array_end = .)
.fini_array 0x00007e5c 0x0
[!provide] PROVIDE (__fini_array_start = .)
*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))
*(.fini_array EXCLUDE_FILE(*crtend?.o *crtend.o *crtbegin?.o *crtbegin.o) .dtors)
[!provide] PROVIDE (__fini_array_end = .)
.ctors
*crtbegin.o(.ctors)
*crtbegin?.o(.ctors)
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
*(SORT_BY_NAME(.ctors.*))
*(.ctors)
.dtors
*crtbegin.o(.dtors)
*crtbegin?.o(.dtors)
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
*(SORT_BY_NAME(.dtors.*))
*(.dtors)
.jcr
*(.jcr)
.data.rel.ro
*(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*)
*(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*)
.dynamic
*(.dynamic)
.got 0x00007e5c 0x0
*(.got)
.got 0x00007e5c 0x0 bootasm.o
*(.igot)
.got.plt 0x00007e5c 0x0
*(.got.plt)
.got.plt 0x00007e5c 0x0 bootasm.o
*(.igot.plt)
.igot.plt 0x00007e5c 0x0 bootasm.o
.data 0x00007e5c 0x0
*(.data .data.* .gnu.linkonce.d.*)
.data 0x00007e5c 0x0 bootasm.o
.data 0x00007e5c 0x0 bootmain.o
.data1
*(.data1)
0x00007e5c _edata = .
[!provide] PROVIDE (edata = .)
0x00007e5c . = .
0x00007e5c __bss_start = .
.bss 0x00007e5c 0x0
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
.bss 0x00007e5c 0x0 bootasm.o
.bss 0x00007e5c 0x0 bootmain.o
*(COMMON)
0x00007e5c . = ALIGN ((. != 0x0)?0x4:0x1)
0x00007e5c . = ALIGN (0x4)
0x00007e5c . = SEGMENT_START ("ldata-segment", .)
0x00007e5c . = ALIGN (0x4)
0x00007e5c _end = .
[!provide] PROVIDE (end = .)
.stab
*(.stab)
.stabstr
*(.stabstr)
.stab.excl
*(.stab.excl)
.stab.exclstr
*(.stab.exclstr)
.stab.index
*(.stab.index)
.stab.indexstr
*(.stab.indexstr)
.comment 0x00000000 0x11
*(.comment)
.comment 0x00000000 0x11 bootmain.o
0x12 (size before relaxing)
.debug
*(.debug)
.line
*(.line)
.debug_srcinfo
*(.debug_srcinfo)
.debug_sfnames
*(.debug_sfnames)
.debug_aranges 0x00000000 0x40
*(.debug_aranges)
.debug_aranges
0x00000000 0x20 bootasm.o
.debug_aranges
0x00000020 0x20 bootmain.o
.debug_pubnames
*(.debug_pubnames)
.debug_info 0x00000000 0x50e
*(.debug_info .gnu.linkonce.wi.*)
.debug_info 0x00000000 0x26 bootasm.o
.debug_info 0x00000026 0x4e8 bootmain.o
.debug_abbrev 0x00000000 0x1ea
*(.debug_abbrev)
.debug_abbrev 0x00000000 0x14 bootasm.o
.debug_abbrev 0x00000014 0x1d6 bootmain.o
.debug_line 0x00000000 0x12c
*(.debug_line .debug_line.* .debug_line_end)
.debug_line 0x00000000 0x5d bootasm.o
.debug_line 0x0000005d 0xcf bootmain.o
.debug_frame
*(.debug_frame)
.debug_str 0x00000000 0x1e1
*(.debug_str)
.debug_str 0x00000000 0x36 bootasm.o
.debug_str 0x00000036 0x1ab bootmain.o
0x1e2 (size before relaxing)
.debug_loc 0x00000000 0x15c
*(.debug_loc)
.debug_loc 0x00000000 0x15c bootmain.o
.debug_macinfo
*(.debug_macinfo)
.debug_weaknames
*(.debug_weaknames)
.debug_funcnames
*(.debug_funcnames)
.debug_typenames
*(.debug_typenames)
.debug_varnames
*(.debug_varnames)
.debug_pubtypes
*(.debug_pubtypes)
.debug_ranges
*(.debug_ranges)
.debug_macro
*(.debug_macro)
.debug_addr
*(.debug_addr)
.gnu.attributes
*(.gnu.attributes)
/DISCARD/
*(.note.GNU-stack)
*(.gnu_debuglink)
*(.gnu.lto_*)
OUTPUT(bootblock.o elf32-i386)
# set prefix on `i386-jos-elf-`. See detail for the page, https://pdos.csail.mit.edu/6.828/2018/tools.html.
## -nostdinc: no std include
$ gcc -fno-pic -static -fno-builtin -fno-strict-aliasing -O2 -Wall -MD -ggdb -m32 -Werror -fno-omit-frame-pointer -fno-stack-protector -fno-pic -O -nostdinc -I. -c bootmain.c
$ gcc -fno-pic -static -fno-builtin -fno-strict-aliasing -O2 -Wall -MD -ggdb -m32 -Werror -fno-omit-frame-pointer -fno-stack-protector -fno-pic -nostdinc -I. -c bootasm.S
## -m: Emulate the emulation linker. -N: Set the text and data sections to be readable and writable.
## -e start: Use entry as the explicit symbol for beginning execution of your program
## -Ttext 0x7C00: Locate a section in the output file at the absolute address given by 0x7C00.
$ ld -m elf_i386 -N -e start -Ttext 0x7C00 -o bootblock.o bootasm.o bootmain.o -M
$ objdump -S bootblock.o > bootblock.asm
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment