Chinaunix首页 | 论坛 | 博客
  • 博客访问: 43010
  • 博文数量: 7
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 60
  • 用 户 组: 普通用户
  • 注册时间: 2014-08-23 18:46
文章分类
文章存档

2015年(3)

2014年(4)

我的朋友

分类: LINUX

2015-10-03 09:38:14

linux-0.11内核学习交流群:470175190

Linux0.11内核中使用了两种汇编器:
as86+ld86:用于产出16位代码(针对INTEL汇编语言),仅用在boot/bootsect.s,/boot/setup.s
gas+GNU ld:产生目标文件(针对AT&汇编语法)

汇编器:用于把汇编语言编译成含机器码的二进制语言或目标文件
bss:未初始化的数据段,通常汇编器输出的目标文件不会为该段保留空间,但在目标文件链接成可执行程序加载到操作系统时会把该段的内容全部初始化为0

引导代码编译
boot.s
#as -0 -a -o boot.o boot.s
#ld86 -0 -s -o boot boot.o
#dd bs=32 if=boot of=boot.img skip=1(删除文件开头的32个字节文件头)
-0:生成8086,16目标程序
-a:生成和GNU as,ld兼容的代码
-s:去除可执行文件中的符号信息
-o:生成可执行目标文件
BOCHS运行
  1. 安装bochs-----百度
  2. 运行dlx,测试安装是否成功(直接双击dlxlinux目录下的bochsrc.bxrc文件)
  3. 运行自己的引导代码
    1.   新建文件linux-0.11
    2. copy dlxlinux 所有内容到linux-0.11目录下
    3. 修改bochsrc.bxrc
  4. bochsrc.bxrc中有两部分需要重点关注
# what disk images will be used
floppya: 1_44=floppya.img, status=inserted #1
floppyb: 1_44=floppyb.img, status=inserted

# hard disk
ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
ata0-master: type=disk, path="bootimage-0.11", cylinders=306, heads=4, spt=17 #2

# choose the boot disk.
boot: c #3
     两种启动手段:
          floppy启动:修改#1:floppya: 1_44=你的文件, status=inserted #1
                     修改#3: boot: a #3表示从floppy启动,也可以写成boot: floppy
           
          disk启动:  修改#:2ata0-master: type=disk, path="你的文件名", cylinders=306,
                           heads=4,                                                                                                             
                     修改#3:boot:c#3表示从disk启动也可以写成boot:disk
extern inline and staic inline
inline函数有两种声明形式,一种是static __inline__,另一种是extern __inline__,inline不都是要展开的么,那么这两种形式有什么不同呢?还是只是形式上的不同?
如果一个函数既是inline又是static,如果所有对函数的调用都能被展开在调用者里面,并且这个函数的地址从来没有被使用过,那么这种 情况下不存在对这个函数本身汇编代码的引用。这时,GNU CC实际上并不输出这个函数的汇编代码,除非加选项“-fkeep-inline-functions”。存在一些由于各种原因不能被展开的调用(比如, 在函数声明前的调用不能被展开,定义中的递归调用同样也不行)。如果存在未展开的函数调用,那么这个函数象通常一样被编译生成汇编代码。如果这个函数被通 过地址引用,那么这个函数也必须象一般函数那样被编译生成,因为那样的引用不能够被展开(inlined)。 
当一个inline函数不是 static时,那么编译器必须假设其他源程序中可能存在调用,因为一个全局符号只能被定义一次,所以这个函数在其他源程序中不能被定义,于是那里的调用 不能够被展开。因此,一个非static的inline函数总是同普通函数一样被编译生成。 
如果函数声明中同时使用了inline和extern,那么这个定义只被用来inline展开。这个函数体的汇编代码从来都不会被编译生成,即使你显示引用了它的地址,显示引用的地址变成一个外部引用,就像你仅仅声明了这个函数,而没有定义它一样。 
inline 和extern的结合几乎达到一个宏定义的效果。使用它的方法是在头文件中使用这些关键字写出函数定义,同时在库文件中放入另一份函数体定义的拷贝(没有 inline和extern)。在头文件中的定义将会使大部分对函数的调用被inline展开。如果存在对这个函数的使用,它们将会引用库中的单一拷贝。
嵌入式汇编:
在汇编语言中调用c语言:程序首先按照逆向顺序把函数的参数压入栈中,最右边的参数最先压栈,让后执行指令CALL函数名调用函数,然后返回后将先前压栈的参数清除掉:
例子:
.c
int add(int a,int b)
{
   return a+b;
}
.s
SYSWRITE = 4
.global main
.data 
        format: .asciz "%d\n"
.text
main:
          pushl %ebp
          movl  %esp, %ebp
          movl  $6,%eax
          pushl %eax
          movl  $5,%eax
          pushl %eax
          call add
          pushl %eax
          pushl $format
          call printf
          movl %ebp,%esp;
          popl %ebp
          ret


在c语言中调用汇编:
callee.s
SYSWRITE = 4
.global mywrite,myadd
.text
mywrite:
          pushl %ebp
          movl  %esp, %ebp
          pushl %ebx
          movl 8(%ebp),%ebx
          movl 12(%ebp),%ecx
          movl 16(%ebp),%edx
          movl $SYSWRITE,%eax
          int  $0x80
          popl %ebx
          movl %ebp,%esp;
          popl %ebp
          ret

myadd:
          pushl %ebp
          movl %esp,%ebp
          movl 8(%ebp),eax
          movl 12(%ebp),edx
          xorl %ecx,%ecx
          addl %eax,%edx
          jo 1f
          movl 16(%ebp),%eax
          movl %edx,(%eax)
          incl %ecx
1:        movl %ecx,%eax
          movl %ebp,%esp
          popl %ebp
          ret
caller.c
#include<stdio.h>
#include<string.h>
int main()
{
     char buf[1024];
     int a,b,res;
     char *mystr="Calculating...\n";
     char *emsg = "Error in adding \n";
     a=5;b=10;
     mywrite(1,mystr,strlen(mystr));
     if(myadd(a,b,&res))
     {
          sprintf(buf,"The result is %d\n",res);
          mywrite(1,buf,strlen(buf));
     }
     else{
          mywrite(1,emsg,strlen(emsg));
     }
     return 0;
};
阅读(1916) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~