人造人 发表于 2020-5-4 17:20:59

01. 人工反编译 - bootsect.s

最近在学习linux 0.11源代码,bootsect.s 文件中有一个 read_it 函数,用来读取软盘上的system模块
这个函数是这个文件中最复杂的一个,相信不少同学被这个函数劝退,我也被劝退n次
这一次我使用人工反编译,把汇编语言翻译成语义上等效的C语言代码
这一次我终于理解了这个函数的逻辑,把自己的翻译结果发上来,希望可以帮到更多的同学,^_^


这个代码可以编译运行,如果有不理解的地方,还可以调试运行这个程序
#define SETUPLEN 4
#define SYSSIZE0x3000
#define SYSSEG   0x1000
#define ENDSEG   (SYSSEG + SYSSIZE)

const int sectors = 18;
int sread = 1 + SETUPLEN;
int head= 0;
int track = 0;

void read_track(int count) {
    (void)count;
}

void read_it(int es) {
    while(es & 0x0fff)
      ;
   
    int offset = 0;
    while(1) {
      if(es >= ENDSEG)
            return;
      
      int count = sectors - sread;
      if(count * 512 + offset > 0x10000)
            count = (0x10000 - offset) / 512;
      read_track(count);
      
      int sum = sread + count;
      if(sum == sectors) {
            if(head == 1) {
                head = 0; ++track;
            }
            else ++head;
            sum = 0;
      }
      
      sread = sum;
      offset += count * 512;
      if(offset < 0x10000)
            continue;
      es += 0x1000;
      offset = 0;
    }
}

int main(void) {
    read_it(SYSSEG);
    return 0;
}

人造人 发表于 2020-5-4 17:22:22

本帖最后由 人造人 于 2020-5-4 17:34 编辑

把 bootsect.s 也贴上来吧
!
! SYS_SIZE is the number of clicks (16 bytes) to be loaded.
! 0x3000 is 0x30000 bytes = 196kB, more than enough for current
! versions of linux
!
SYSSIZE = 0x3000
!
!       bootsect.s            (C) 1991 Linus Torvalds
!
! bootsect.s is loaded at 0x7c00 by the bios-startup routines, and moves
! iself out of the way to address 0x90000, and jumps there.
!
! It then loads 'setup' directly after itself (0x90200), and the system
! at 0x10000, using BIOS interrupts.
!
! NOTE! currently system is at most 8*65536 bytes long. This should be no
! problem, even in the future. I want to keep it simple. This 512 kB
! kernel size should be enough, especially as this doesn't contain the
! buffer cache as in minix
!
! The loader has been made as simple as possible, and continuos
! read errors will result in a unbreakable loop. Reboot by hand. It
! loads pretty fast by getting whole sectors at a time whenever possible.

.globl begtext, begdata, begbss, endtext, enddata, endbss
.text
begtext:
.data
begdata:
.bss
begbss:
.text

SETUPLEN = 4                            ! nr of setup-sectors
BOOTSEG= 0x07c0                     ! original address of boot-sector
INITSEG= 0x9000                     ! we move boot here - out of the way
SETUPSEG = 0x9020                     ! setup starts here
SYSSEG   = 0x1000                     ! system loaded at 0x10000 (65536).
ENDSEG   = SYSSEG + SYSSIZE             ! where to stop loading

! ROOT_DEV:   0x000 - same type of floppy as boot.
!               0x301 - first partition on first drive etc
ROOT_DEV = 0x306

entry start
start:
      mov   ax,#BOOTSEG
      mov   ds,ax
      mov   ax,#INITSEG
      mov   es,ax
      mov   cx,#256
      sub   si,si
      sub   di,di
      rep
      movw
      jmpi    go,INITSEG
go:   mov   ax,cs
      mov   ds,ax
      mov   es,ax
! put stack at 0x9ff00.
      mov   ss,ax
      mov   sp,#0xFF00            ! arbitrary value >>512

! load the setup-sectors directly after the bootblock.
! Note that 'es' is already set up.

load_setup:
      mov   dx,#0x0000            ! drive 0, head 0
      mov   cx,#0x0002            ! sector 2, track 0
      mov   bx,#0x0200            ! address = 512, in INITSEG
      mov   ax,#0x0200+SETUPLEN   ! service 2, nr of sectors
      int   0x13                  ! read it
      jnc   ok_load_setup         ! ok - continue
      mov   dx,#0x0000
      mov   ax,#0x0000            ! reset the diskette
      int   0x13
      j       load_setup

ok_load_setup:

! Get disk drive parameters, specifically nr of sectors/track

      mov   dl,#0x00
      mov   ax,#0x0800            ! AH=8 is get drive parameters
      int   0x13
      mov   ch,#0x00
      seg cs
      mov   sectors,cx
      mov   ax,#INITSEG
      mov   es,ax

! Print some inane message

      mov   ah,#0x03                ! read cursor pos
      xor   bh,bh
      int   0x10
      
      mov   cx,#24
      mov   bx,#0x0007            ! page 0, attribute 7 (normal)
      mov   bp,#msg1
      mov   ax,#0x1301            ! write string, move cursor
      int   0x10

! ok, we've written the message, now
! we want to load the system (at 0x10000)

      mov   ax,#SYSSEG
      mov   es,ax         ! segment of 0x010000
      call    read_it
      call    kill_motor

! After that we check which root-device to use. If the device is
! defined (!= 0), nothing is done and the given device is used.
! Otherwise, either /dev/PS0 (2,28) or /dev/at0 (2,8), depending
! on the number of sectors that the BIOS reports currently.

      seg cs
      mov   ax,root_dev
      cmp   ax,#0
      jne   root_defined
      seg cs
      mov   bx,sectors
      mov   ax,#0x0208            ! /dev/ps0 - 1.2Mb
      cmp   bx,#15
      je      root_defined
      mov   ax,#0x021c            ! /dev/PS0 - 1.44Mb
      cmp   bx,#18
      je      root_defined
undef_root:
      jmp undef_root
root_defined:
      seg cs
      mov   root_dev,ax

! after that (everyting loaded), we jump to
! the setup-routine loaded directly after
! the bootblock:

      jmpi    0,SETUPSEG

! This routine loads the system at address 0x10000, making sure
! no 64kB boundaries are crossed. We try to load it as fast as
! possible, loading whole tracks whenever we can.
!
! in:   es - starting address segment (normally 0x1000)
!
sread:.word 1+SETUPLEN      ! sectors read of current track
head:   .word 0               ! current head
track:.word 0               ! current track

read_it:
      mov ax,es
      test ax,#0x0fff
die:    jne die               ! es must be at 64kB boundary
      xor bx,bx               ! bx is starting address within segment
rp_read:
      mov ax,es
      cmp ax,#ENDSEG          ! have we loaded all yet?
      jb ok1_read
      ret
ok1_read:
      seg cs
      mov ax,sectors
      sub ax,sread
      mov cx,ax
      shl cx,#9
      add cx,bx
      jnc ok2_read
      je ok2_read
      xor ax,ax
      sub ax,bx
      shr ax,#9
ok2_read:
      call read_track
      mov cx,ax
      add ax,sread
      seg cs
      cmp ax,sectors
      jne ok3_read
      mov ax,#1
      sub ax,head
      jne ok4_read
      inc track
ok4_read:
      mov head,ax
      xor ax,ax
ok3_read:
      mov sread,ax
      shl cx,#9
      add bx,cx
      jnc rp_read
      mov ax,es
      add ax,#0x1000
      mov es,ax
      xor bx,bx
      jmp rp_read

read_track:
      push ax
      push bx
      push cx
      push dx
      mov dx,track
      mov cx,sread
      inc cx
      mov ch,dl
      mov dx,head
      mov dh,dl
      mov dl,#0
      and dx,#0x0100
      mov ah,#2
      int 0x13
      jc bad_rt
      pop dx
      pop cx
      pop bx
      pop ax
      ret
bad_rt: mov ax,#0
      mov dx,#0
      int 0x13
      pop dx
      pop cx
      pop bx
      pop ax
      jmp read_track

/*
* This procedure turns off the floppy drive motor, so
* that we enter the kernel in a known state, and
* don't have to worry about it later.
*/
kill_motor:
      push dx
      mov dx,#0x3f2
      mov al,#0
      outb
      pop dx
      ret

sectors:
      .word 0

msg1:
      .byte 13,10
      .ascii "Loading system ..."
      .byte 13,10,13,10

.org 508
root_dev:
      .word ROOT_DEV
boot_flag:
      .word 0xAA55

.text
endtext:
.data
enddata:
.bss
endbss:

老八秘制 发表于 2020-5-4 17:24:10

初学C语言表示瑟瑟发抖{:10_245:}

Hello. 发表于 2020-5-4 17:25:59

十分有用!!

人造人 发表于 2020-5-4 17:27:04

老八秘制 发表于 2020-5-4 17:24
初学C语言表示瑟瑟发抖

^_^

乘号 发表于 2020-5-4 17:50:38

没学c语言表示瑟瑟发抖{:10_245:}

即将被Hello.攻破电脑表示瑟瑟发抖{:10_245:}

人造人 发表于 2020-5-4 17:54:05

乘号 发表于 2020-5-4 17:50
没学c语言表示瑟瑟发抖

即将被Hello.攻破电脑表示瑟瑟发抖

C语言不难,真的,^_^
页: [1]
查看完整版本: 01. 人工反编译 - bootsect.s