gas汇编改写

现在,我们来看看在linux平台上面怎么对之前实现的功能进行改写了。当然这里先说启动区加载程序跟在win下面是一样的代码的,不同的就是C调用汇编程序代码和汇编调用C代码这里不同。以及剩下的就是一些makefile文件的不同。

我们重点放在C于汇编之间的调用,当然我们这里先不讲汇编是怎么调用C的,因为这一部分我也暂时还没看,我就先用米油给的一个entry.S来直接使用了,后面才对这一部分进行分析。

那我们来看看C调用汇编,

用gcc内嵌gas汇编的方法非常好,也非常的高效。

 

只需要用一个宏定义就行了,如要在c中调用汇编的hlt指令,只需要 

#define io_halt() asm("hlt")

 

这样就可以把io_halt()当一个正常的函数用了,但是这是最容易的,有输入,输出参数的函数的调用规则要复杂一些。但是只是一个规则。那么我们可以很快的将之前的代码进行改写

/**********************************************************************
main.c
 **********************************************************************/
#include<header.h>


void bootmain(void)
{
  
 // io_halt();  //有效
// clear_screen(40);   //read
 //color_screen(15);   //white
//  x86上,类似单片机编程的感觉,直接有指针访问Vram
 
  int i;
  unsigned char *p;
  int color;
  int x=320,y=200;
   init_palette();  //after init_palette,对于color不知道是如何控制了
   p=(unsigned char*)0xa0000;
    boxfill8(p,320,110,20,20,250,150);
    
    //draw a window
    boxfill(170,0, 0   ,x-1,y-29);
//task button    
    boxfill(15,0, y-28,x-1,y-28);
    boxfill(27,0, y-27,x-1,y-27);
    boxfill(27,0, y-26,x-1,y-1);
    
    
//left button    
    boxfill(30, 3,  y-24, 59,  y-24);
    boxfill(30, 2,  y-24, 2 ,  y-4);  
    boxfill(20, 3,  y-4,  59,  y-4);
    boxfill(20, 59, y-23, 59,  y-5);
    boxfill(0, 2,  y-3,  59,  y-3);
    boxfill(0, 60, y-24, 60,  y-3);  

// 
//right button    
    boxfill(110, x-47, y-24,x-4,y-24);
    boxfill(110, x-47, y-23,x-47,y-4);  
    boxfill(110, x-47, y-3,x-4,y-3);
    boxfill(110, x-3, y-24,x-3,y-3);

 while(1);
}

 

screen.c
#include<header.h>

void clear_screen(char color) //15:pure white
{
  int i;
  for(i=0xa0000;i<0xaffff;i++)
  {
  write_mem8(i,color);  //if we write 15 ,all pixels color will be white,15 mens pure white ,so the screen changes into white

  }
}

void color_screen(char color) //15:pure white
{
  int i;
  color=color;
  for(i=0xa0000;i<0xaffff;i++)
  {
  write_mem8(i,i);  //if we write 15 ,all pixels color will be white,15 mens pure white ,so the screen changes into white

  }
}


void init_palette(void)
{
  //16种color,每个color三个字节。
  static unsigned char table_rgb[16*3]=
  {
    0x00,0x00,0x00,   /*0:black*/
    0xff,0x00,0x00,   /*1:light red*/ 
    0x00,0xff,0x00,   /*2:light green*/   
    0xff,0xff,0x00,   /*3:light yellow*/
    
    0x00,0x00,0xff,   /*4:light blue*/
    0xff,0x00,0xff,   /*5:light purper*/ 
    0x00,0xff,0xff,   /*6:light blue*/
    0xff,0xff,0xff,   /*7:white*/
 
    0xc6,0xc6,0xc6,   /*8:light gray*/
    0x84,0x00,0x00,   /*9:dark red*/
    0x00,0x84,0x00,   /*10:dark green*/ 
    0x84,0x84,0x00,   /*11:dark yellow*/
   
    0x00,0x00,0x84,   /*12:dark 青*/
    0x84,0x00,0x84,   /*13:dark purper*/
    0x00,0x84,0x84,   /*14:light blue*/
    0x84,0x84,0x84,   /*15:dark gray*/
  };
    set_palette(0,15,table_rgb);
    return;
    
  
}

//设置调色板,  只用到了16个color,后面的都没有用到。
void set_palette(int start,int end, unsigned char *rgb)
{
  int i,eflag;
  eflag=read_eflags();   //记录从前的cpsr值
 
  io_cli(); // disable interrupt

  outb(0x03c8,start);
  for(i=start;i<=end;i++)
  {
    outb(0x03c9,rgb[0]);    
    outb(0x03c9,rgb[1]);   
    outb(0x03c9,rgb[2]);   
    rgb=rgb+3;
  }
  
write_eflags(eflag);  //恢复从前的cpsr
  return;
  
}

void boxfill8(unsigned char *vram,int xsize,unsigned char color,int x0,int y0,int x1,int y1)
{
 int x,y;
 for(y=y0;y<=y1;y++)
 {
   for(x=x0;x<=x1;x++)
   {
      vram[y*xsize+x]=color;
   }
 }
   
}
void boxfill(unsigned char color,int x0,int y0,int x1,int y1)
{
  boxfill8((unsigned char *)0xa0000,320,color,x0,y0,x1,y1);
}

 

head.h文件

#ifndef header
#define header

#include<x86.h>

#define io_halt() asm("hlt")
#define write_mem8(addr,data8)   (*(volatile char *)(addr))=(char)data8
#define io_cli()  asm("cli")
#define io_sti()  asm("sti")
#define io_stihlt() (io_cli();io_halt;)


extern void clear_screen(char color) ; //color=15 pure white color=40 red
extern void color_screen(char color) ;
extern void init_palette(void);//用现成的table_rgb来初始化调色板
extern void set_palette(int start,int end, unsigned char *rgb);
extern void boxfill8(unsigned char *vram,int xsize,unsigned char color,int x0,int y0,int x1,int y1);
extern void boxfill(unsigned char color,int x0,int y0,int x1,int y1);

#endif

 

x86.h
#ifndef JOS_INC_X86_H
#define JOS_INC_X86_H

#include <types.h>

static __inline void breakpoint(void) __attribute__((always_inline));

static __inline uint8_t inb(int port) __attribute__((always_inline));
static __inline void insb(int port, void *addr, int cnt) __attribute__((always_inline));
static __inline uint16_t inw(int port) __attribute__((always_inline));
static __inline void insw(int port, void *addr, int cnt) __attribute__((always_inline));
static __inline uint32_t inl(int port) __attribute__((always_inline));
static __inline void insl(int port, void *addr, int cnt) __attribute__((always_inline));

static __inline void outb(int port, uint8_t data) __attribute__((always_inline));
static __inline void outsb(int port, const void *addr, int cnt) __attribute__((always_inline));
static __inline void outw(int port, uint16_t data) __attribute__((always_inline));

static __inline void outsw(int port, const void *addr, int cnt) __attribute__((always_inline));
static __inline void outsl(int port, const void *addr, int cnt) __attribute__((always_inline));
static __inline void outl(int port, uint32_t data) __attribute__((always_inline));

static __inline void invlpg(void *addr) __attribute__((always_inline));
static __inline void lidt(void *p) __attribute__((always_inline));
static __inline void lldt(uint16_t sel) __attribute__((always_inline));
static __inline void ltr(uint16_t sel) __attribute__((always_inline));
static __inline void lcr0(uint32_t val) __attribute__((always_inline));
static __inline uint32_t rcr0(void) __attribute__((always_inline));
static __inline uint32_t rcr2(void) __attribute__((always_inline));
static __inline void lcr3(uint32_t val) __attribute__((always_inline));
static __inline uint32_t rcr3(void) __attribute__((always_inline));
static __inline void lcr4(uint32_t val) __attribute__((always_inline));
static __inline uint32_t rcr4(void) __attribute__((always_inline));
static __inline void tlbflush(void) __attribute__((always_inline));
static __inline uint32_t read_eflags(void) __attribute__((always_inline));
static __inline void write_eflags(uint32_t eflags) __attribute__((always_inline));
static __inline uint32_t read_ebp(void) __attribute__((always_inline));
static __inline uint32_t read_esp(void) __attribute__((always_inline));
static __inline void cpuid(uint32_t info, uint32_t *eaxp, uint32_t *ebxp, uint32_t *ecxp, uint32_t *edxp);
static __inline uint64_t read_tsc(void) __attribute__((always_inline));

static __inline void
breakpoint(void)
{
	__asm __volatile("int3");
}
//int3会产生软件中断,这个软件中断通常是为调试代码而用的。可以在软件中断服务程序中打印出一些我们需要的信息。
//因为我们现在还没有搞明白ldt的内容,没有有效的中断服务程序,所以调用这个软件中断后,会产生reset的效果。

//in:   read a port
static __inline uint8_t
inb(int port)
{
  //read a byte from port
	uint8_t data;
	__asm __volatile("inb %w1,%0" : "=a" (data) : "d" (port));
	return data;
}

static __inline uint16_t
inw(int port)
{
  //read word from port
	uint16_t data;
	__asm __volatile("inw %w1,%0" : "=a" (data) : "d" (port));
	return data;
}

static __inline uint32_t
inl(int port)
{
	uint32_t data;
	__asm __volatile("inl %w1,%0" : "=a" (data) : "d" (port));
	return data;
}

// out:write a data to a port
static __inline void
outb(int port, uint8_t data)
{
	__asm __volatile("outb %0,%w1" : : "a" (data), "d" (port));
}


static __inline void
outw(int port, uint16_t data)
{
	__asm __volatile("outw %0,%w1" : : "a" (data), "d" (port));
}

static __inline void
outl(int port, uint32_t data)
{
	__asm __volatile("outl %0,%w1" : : "a" (data), "d" (port));
}





static __inline void
insb(int port, void *addr, int cnt)
{
	__asm __volatile("cld\n\trepne\n\tinsb"			:
			 "=D" (addr), "=c" (cnt)		:
			 "d" (port), "0" (addr), "1" (cnt)	:
			 "memory", "cc");
}



static __inline void
insw(int port, void *addr, int cnt)
{
	__asm __volatile("cld\n\trepne\n\tinsw"			:
			 "=D" (addr), "=c" (cnt)		:
			 "d" (port), "0" (addr), "1" (cnt)	:
			 "memory", "cc");
}



static __inline void
insl(int port, void *addr, int cnt)
{
	__asm __volatile("cld\n\trepne\n\tinsl"			:
			 "=D" (addr), "=c" (cnt)		:
			 "d" (port), "0" (addr), "1" (cnt)	:
			 "memory", "cc");
}


static __inline void
outsb(int port, const void *addr, int cnt)
{
	__asm __volatile("cld\n\trepne\n\toutsb"		:
			 "=S" (addr), "=c" (cnt)		:
			 "d" (port), "0" (addr), "1" (cnt)	:
			 "cc");
}



static __inline void
outsw(int port, const void *addr, int cnt)
{
	__asm __volatile("cld\n\trepne\n\toutsw"		:
			 "=S" (addr), "=c" (cnt)		:
			 "d" (port), "0" (addr), "1" (cnt)	:
			 "cc");
}

static __inline void
outsl(int port, const void *addr, int cnt)
{
	__asm __volatile("cld\n\trepne\n\toutsl"		:
			 "=S" (addr), "=c" (cnt)		:
			 "d" (port), "0" (addr), "1" (cnt)	:
			 "cc");
}



static __inline void 
invlpg(void *addr)
{ 
	__asm __volatile("invlpg (%0)" : : "r" (addr) : "memory");
}  

static __inline void
lidt(void *p)
{
	__asm __volatile("lidt (%0)" : : "r" (p));
}

static __inline void
lldt(uint16_t sel)
{
	__asm __volatile("lldt %0" : : "r" (sel));
}

static __inline void
ltr(uint16_t sel)
{
	__asm __volatile("ltr %0" : : "r" (sel));
}

static __inline void
lcr0(uint32_t val)
{
	__asm __volatile("movl %0,%%cr0" : : "r" (val));
}

static __inline uint32_t
rcr0(void)
{
	uint32_t val;
	__asm __volatile("movl %%cr0,%0" : "=r" (val));
	return val;
}

static __inline uint32_t
rcr2(void)
{
	uint32_t val;
	__asm __volatile("movl %%cr2,%0" : "=r" (val));
	return val;
}

static __inline void
lcr3(uint32_t val)
{
	__asm __volatile("movl %0,%%cr3" : : "r" (val));
}

static __inline uint32_t
rcr3(void)
{
	uint32_t val;
	__asm __volatile("movl %%cr3,%0" : "=r" (val));
	return val;
}

static __inline void
lcr4(uint32_t val)
{
	__asm __volatile("movl %0,%%cr4" : : "r" (val));
}

static __inline uint32_t
rcr4(void)
{
	uint32_t cr4;static __inline uint8_t
inb(int port)
{
  //read a byte from port
	uint8_t data;
	__asm __volatile("inb %w1,%0" : "=a" (data) : "d" (port));
	return data;
}
	__asm __volatile("movl %%cr4,%0" : "=r" (cr4));
	return cr4;
}

static __inline void
tlbflush(void)
{
	uint32_t cr3;
	__asm __volatile("movl %%cr3,%0" : "=r" (cr3));
	__asm __volatile("movl %0,%%cr3" : : "r" (cr3));
}


static __inline uint32_t
read_ebp(void)
{
        uint32_t ebp;
        __asm __volatile("movl %%ebp,%0" : "=r" (ebp));
        return ebp;
}

static __inline uint32_t
read_esp(void)
{
        uint32_t esp;
        __asm __volatile("movl %%esp,%0" : "=r" (esp));
        return esp;
}

static __inline void
cpuid(uint32_t info, uint32_t *eaxp, uint32_t *ebxp, uint32_t *ecxp, uint32_t *edxp)
{
	uint32_t eax, ebx, ecx, edx;
	asm volatile("cpuid" 
		: "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
		: "a" (info));
	if (eaxp)
		*eaxp = eax;
	if (ebxp)
		*ebxp = ebx;
	if (ecxp)
		*ecxp = ecx;
	if (edxp)
		*edxp = edx;
}

static __inline uint64_t
read_tsc(void)
{
        uint64_t tsc;
        __asm __volatile("rdtsc" : "=A" (tsc));
        return tsc;
}

//
//read eflags and write_eflags
static __inline uint32_t
read_eflags(void)
{
        uint32_t eflags;
        __asm __volatile("pushfl; popl %0" : "=r" (eflags));
        return eflags;
}

static __inline void
write_eflags(uint32_t eflags)
{
        __asm __volatile("pushl %0; popfl" : : "r" (eflags));
}
#endif /* !JOS_INC_X86_H */

 

我们这里重点讲讲gcc内嵌汇编的一些要点,AT&T我也不太熟悉,不过跟intel汇编是大同小异的。

 

asm volatile( "assembler template" : output : input : clobber);

上面是基本的格式:

其中assembler template为汇编指令部分,output是输出部分,input是输入部分,clobber表示被修改的部分,汇编指令中的数字和前缀%表示样板操作数,例如%0,%1等,用来依次指代后面的输出部分,输入部分等样板操作数。由于这些样板操作数使用了%,因此寄存器前面要加两个%。output,input分别是输出部分和输入部分,clobber是损坏部分。

gcc内嵌汇编限制符

a    对应的变量必须在EAX寄存器

b    EBX

c    ECX

d    EDX

S    ESI

D    EDI

q    EAX,EBX,ECX,EDX中的任何一个

r    EAX,EBX,ECX,EDX,ESI,EDI中的任何一个

A    EAX:EDX组合成一个64位操作数

m    操作数必须是内存中的变量

o    操作是内存变量,并且对操作数的寻址方式为基址加一个偏移量

V    操作数是内存变量,但是寻址方式位基址,没有偏移量

g    操作数可以是内存变量,立即数,EAX,EBX,ECX或者EDX

I    操作数是0-31的立即数(用于32位的移位操作)

J    操作数是0-63的立即数(用于64位的移位操作)

K    操作数必须是0xFF

L    操作数必须是0xFFFF

M    操作数是0,1,2,3

N    操作数可以是0-255中的任何一个数(用于in/out指令)

f    操作数是浮点寄存器

t    第一个浮点寄存器

u    第二个浮点寄存器

=    操作数是只写的(用于输出)

+    操作数是可读可写的(用于输入输出)

&    表示在汇编代码前,对应的操作数会被输入部分修改

memory  用在损坏部分中,表示内存被修改了

static __inline uint8_t

inb(int port)

{

  //read a byte from port

uint8_t data;

__asm __volatile("inb %w1,%0" : "=a" (data) : "d" (port));

return data;

}

inb 是intel x86的一条指令

%w1表示宽度为w的1号占位符

%0表示0号占位符

inb %w1,%0 意思是将%w1读到%0, 

嵌入式汇编除指令外有三部分(可选的),依次为

输出:"=a" (_v),_v0对应0号占位符,=表示只写,a表示最终从%eax / %ax / %al传送给_v

输入:"Nd" (port),port对应1号占位符号,N表示 0-255 之间的立即数 d表示将port传送给%edx / %dx / %dl 

破坏描述:此处没有

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值