就是镜像的第一个扇区(前512字节),我们写一个简单地C程序

2020-03-20 作者:首页   |   浏览(150)

 小编欢愉的很少 小编很宅 

当大家如此调用

什么是IPL

实质上很简短,正是initial program loader的缩写,正是镜像的率先个扇区(前512字节)。上一篇笔记记录过,Computer运维的时候先物色磁碟的第511,512字节。所以那就注脚前512字节真的不日常。
骨子里操作系统都以十分的大的,所以操作系统只是在前512字节写入自身的开路程序,嗯……能够领略为在前512字节写入叁个函数/方法,Computer运营的时候试行那个办法。

那么针对叁个简单的操作系统demo来讲,本身先用汇编来写一下最带头的512字节,这几个会是叁个很好的起头。下图是二个开机运营呈现hello world的简易小镜像的IPL,能够开采,除了511, 512字节和最开头的129个字节左右,其余一些数据都以00。

图片 1

image.png

1. 汇编

        在修习LINUX内核那门课的在此以前阶段,首先需求调控的正是汇编以致汇编制程序序对于仓库的操作。

        上面大家就来深入分析一下二个大致地C程序是怎么着被汇编制程序序所发表的!

 所以小编来到了这里

从汇编的角度去通晓函数会让您越来越深厚。。。。。。

怎样写自身的首先个IPL

那510个字节固然全都手动敲,也没怎么难度,无非便是工作量嘛,那么就手动来敲一下试一试(汇编语言 DB的情致是defined byte):

DB 0xeb,0x4e,0x90,0x48,0x45,0x4c,0x4c,0x4f,0x49,0x50,0x4c,0x00,0x02,0x01,0x01,0x00
DB 0x02,0xe0,0x00,0x40,0x0b,0xf0,0x09,0x00,0x12,0x00,0x02,0x00,0x00,0x00,0x00,0x00
。。。

明明那样手敲一群不亮堂说怎么着看头的代码是十分不科学的。汇编当然能够那样写,然而还会有更舒畅的写法:

; hello-os
; TAB=4
; 下面这段代码是标准FAT12格式软盘专用代码

    DB 0xeb,0x4e,0x90 ;固定写法
    DB "HelloIPL"   ;8个字节的启动区名称,任意字符,必须是8字节
    DW 512 ;每个扇区的大小,必须是512字节
    DB 1;簇的大小,必须是1个扇区
    DW 1;FAT的起始位置,一般是第一个扇区开始
    DB 2;FAT的个数,必须是2
    DW 224;目录大小,一般是224
    DW 2880;磁盘大小,必须是2880扇区(也就是1.35存软盘的大小)
    DB 0Xf0;磁盘种类
    DW 9;FAT长度,必须是9扇区
    DW 18;1个磁道有几个扇区,必须是18
    DW 2;磁头数,必须是2
    DD 0;不用分区,必须是0
    DD 2880;重写一次磁盘大小
    DB 0,0,0x29;意义不明,固定
    DD 0xffffffff;可能是卷标号码
    DB "hello-os";磁盘名称(11字节)
    DB "FAT12";磁盘格式名称(8字节)
    RESB 18;空出18字节的空白,默认填充0

;程序主体
    DB 0xb8,0x00,0x00,0x8e,0xd0,0xbc,0x00,0x7c
    DB 0x8e,0xd8,0x8e,0xc0,0xbe,0x74,0x7c,0x8a
    DB 0x04,0x83,0xc6,0x01,0x3c,0x00,0x74,0x09
    DB 0xb4,0x0e,0xbb,0x0f,0x00,0xcd,0x10,0xeb
    DB 0xee,0xf4,0xeb,0xfd

;信息显示部分
    DB 0x0a,0x0a;两个换行
    DB "HEllo,world!"
    DB 0x0a;换行
    DB 0

    RESB 0x1fe-$;直到0x1fe,都留空,填充0
    DB 0x55 0xaa

设若用汇编来写的话,是或不是就安适多了?你能够比较早先的那张图片,你会比较轻巧的觉察,汇编是多么的好用。(没有错,汇编现身以前,程序员真的是0101的往里敲的,可是有了汇编,就高端了一步)

以此镜像的IPL相当粗略,有广大地点都以定位写法,也可以有局地地点是原因不明的,笔者索要好好查一下材质,然后再来详细解析这么些IPL。

那么下一篇拜拜吧。

3.汇编代码深入分析

    汇编出的代码,多了成都百货上千支援音讯,为了可以越来越好地看清主干,大家删减一下:

 1 g:
 2     pushl    %ebp            //保存现场,将父函数的栈底寄存器存入当前程序栈中
 3     movl    %esp, %ebp      //构建当前函数堆栈
 4     movl    8(%ebp), %eax   //从父函数堆栈中取得参数,存入ax寄存器
 5     addl    $3, %eax        //完成+3操作
 6     popl    %ebp            //恢复原父函数堆栈
 7     ret                     //pop出原EIP地址,恢复执行
 8 f:
 9     pushl    %ebp            //保存现场,将父函数的栈底寄存器存入当前程序栈中
10     movl    %esp, %ebp      //构建当前函数堆栈
11     subl    $4, %esp        //栈顶加一,用以储存变量传递给g函数
12     movl    8(%ebp), %eax   //取得参数
13     movl    %eax, (%esp)    //将参数传入变量位置
14     call    g               //调用g
15     leave                   //清楚局部变量空间
16     ret                     //返回
17 main:
18     pushl    %ebp
19     movl    %esp, %ebp
20     subl    $4, %esp        //空出局部变量空间
21     movl    $8, (%esp)      //为变量赋值
22     call    f               //调用f
23     addl    $1, %eax        //完成+1操作
24     leave                   //清理局部变量
25     ret                     //返回

大家对f函数进行详细的深入分析:

 1. 首先进行enter指令:

      这时,ebp当前所指向的任务存入栈顶,而且将ebp重定向指向esp:

     图片 2

    2.栈顶加一并存入变量值:

        图片 3 

    3.调用g

  图片 4

    4.从g重回后,重临值储存在AX寄放器中,不用操作,调用leave,清理变量

    图片 5

  5.提起底ret,同期EIP被读出复苏到原岗位继续实施,再次回到值在AX中传送给调用函数

       图片 6

但是本身想让本人的技能到达汇编的水准——精

当call指令试行时 自动将call的下一条指令的地点传入栈中

C程序汇编运维形式简析,汇编形式简析

SJTUBEAWrangler 原创作品转发请表明出处 /《Linux内核解析》MOOC课程

 

 首先注解本人是男的

看那篇作品需求一定的c语言底子和汇编幼功(能基本看懂轻便的汇编指令卡塔尔(قطر‎

2. 到手汇编代码

        首先,大家写多个简易地C程序,命名字为exp1.c:

 1 #include <stdio.h>
 2 
 3 int g(int x)
 4 {
 5     return x+3;
 6 }
 7 
 8 int f(x)
 9 {
10     return g(x);
11 }
12 
13 int main()
14 {
15     return f(8)+1;    
16 }

      程序特别的回顾,大家那儿再经过编写翻译指令将其编译为汇编程序:

1 gcc –S –o main.s main.c -m32

      那样我们就收获了那个大概C程序的汇编代码:

 1     .file    "exp1.c"
 2     .text
 3     .globl    g
 4     .type    g, @function
 5 g:
 6 .LFB0:
 7     .cfi_startproc
 8     pushl    %ebp
 9     .cfi_def_cfa_offset 8
10     .cfi_offset 5, -8
11     movl    %esp, %ebp
12     .cfi_def_cfa_register 5
13     movl    8(%ebp), %eax
14     addl    $3, %eax
15     popl    %ebp
16     .cfi_def_cfa 4, 4
17     .cfi_restore 5
18     ret
19     .cfi_endproc
20 .LFE0:
21     .size    g, .-g
22     .globl    f
23     .type    f, @function
24 f:
25 .LFB1:
26     .cfi_startproc
27     pushl    %ebp
28     .cfi_def_cfa_offset 8
29     .cfi_offset 5, -8
30     movl    %esp, %ebp
31     .cfi_def_cfa_register 5
32     subl    $4, %esp
33     movl    8(%ebp), %eax
34     movl    %eax, (%esp)
35     call    g
36     leave
37     .cfi_restore 5
38     .cfi_def_cfa 4, 4
39     ret
40     .cfi_endproc
41 .LFE1:
42     .size    f, .-f
43     .globl    main
44     .type    main, @function
45 main:
46 .LFB2:
47     .cfi_startproc
48     pushl    %ebp
49     .cfi_def_cfa_offset 8
50     .cfi_offset 5, -8
51     movl    %esp, %ebp
52     .cfi_def_cfa_register 5
53     subl    $4, %esp
54     movl    $8, (%esp)
55     call    f
56     addl    $1, %eax
57     leave
58     .cfi_restore 5
59     .cfi_def_cfa 4, 4
60     ret
61     .cfi_endproc
62 .LFE2:
63     .size    main, .-main
64     .ident    "GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3"
65     .section    .note.GNU-stack,"",@progbits

 学的是软件开拓

像这种类型剖判函数已经够详细了啊如若还看不懂恐怕是幼功相当不够

3.私人商品房的一些醒来:

     程序的调用正是如此嵌套的推行下去,每个函数都有温馨的库房用以积累当前变量以至碰到值,并通过将父函数的EBP归入栈底用以苏醒情状。

     同一时候EIP存入父栈栈顶,便于复苏到原节点处继续推行。

     那样,就足以有规律的直接嵌套下去。

     假若应用递归函数,正是七个码仓库的历程,知道最顶上部分的商旅再次回到,函数仿佛多米诺骨牌相像收回全数的饭馆。

     那也是递归函数占用空间超多的原由之一。若无很好地淡出机制,有相当大恐怕内部存款和储蓄器溢出。

SJTUBEAENCORE原创文章转发请声明出处 /《Linux内核深入分析》MOOC课程 1...

 作者的目标极粗略—— 让谐和现在亦可做三个优质的技师的同一时候成为叁个知情汇编的粗略能手——电子程序员

图片 7

 

那是它的汇编代码

本文由美高梅赌堵59599发布于首页,转载请注明出处:就是镜像的第一个扇区(前512字节),我们写一个简单地C程序

关键词: