`
jjchen_lian
  • 浏览: 84145 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

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 

破坏描述:此处没有

 

分享到:
评论

相关推荐

    GAS汇编指令小集html格式

    GAS汇编指令小集GAS汇编指令小集GAS汇编指令小集GAS汇编指令小集GAS汇编指令小集GAS汇编指令小集GAS汇编指令小集

    gas汇编器命令[参照].pdf

    gas汇编器命令[参照].pdf

    GUN Binutls gas手册 汇编

    gnu gas汇编手册 binutils

    Gas 汇编语言指南

    《x86 Assembly Language Reference Manual》written by Sun Microsystems, Inc 英文的手册有兴趣就话下来看看!

    面向VLIW处理器的GAS汇编器实现.pdf

    面向VLIW处理器的GAS汇编器实现.pdf

    GNU汇编gas权威手册 using as

    GNU汇编gas权威手册 using as 是GNU官方的as使用手册,包括详尽的GNU汇编编写语法规则,和使用的伪指令。如果你需要看linux的汇编代码,那么这是最好的参考资料之一。

    杨文博著的《自己动手写操作系统》

    是杨文博根据于渊写的《自己动手写操作系统》用gas汇编改写的,目的在于用开源软件自己写操作系统,也是一本初学者学习真正写操作系统的好书。这本书关键在于实践强。

    Linux下的汇编--GAS和NASM的区别

    简单的介绍Linux下的汇编编程,GAS和NASM的区别。

    nasm中文手册 gas手册(英文)

    这个nasm的pdf比较清晰 方便大家下载 另外 附了分gas的英文资料 gcc采用gas汇编格式汇编的c源程序 懂点gas也方便查看使用objdump实用工具反汇编后的文档

    gas-preprocessor.pl

    转换gcc gas 汇编代码为 ios的gcc编译器 可以直接编译通过的 汇编代码 perl脚本

    AT&T汇编(linux汇编)

    如果我们选择的汇编开发工具是GCC/GAS的话,就必须了解AT&T汇编语法,因为GCC/GAS只支持这种汇编语法。

    GNU汇编器as的用户手册

    gas 的用户手册,亲。 汇编器的用户手册,从binutils的as手册说明档翻译而来。你可以对照E文查看。很好的资源。

    AT&T汇编语言--GCC下反汇编格式

    如果你是计算机专业的话,在大学里你应该学习过Intel 格式的8086/80386 汇编,这里就不再讨论。如果我们选择的OS开发工具是GCC 以及GAS 的话,就必须了解AT&T 汇编语言语法,因为GCC/GAS 只支持这种汇编语法。

    GAS

    GAS

    深入理解程序设计使用Linux汇编语言

    《深入理解程序设计:使用Linux汇编语言》介绍了Linux平台下的汇编语言编程,教你从计算机的角度看问题,从而了解汇编语言及计算机的工作方式,为成就自己的优秀程序员之梦夯实基础。 很多人都认为汇编语言晦涩难懂...

    Molecular_Gas_Dynamics

    Molecular Gas Dynamics originates from lectures and seminars delivered by the author at various universities and institutions worldwide. These materials are supplemented and arranged in a form ...

    UE5 GAS 学习笔记 10.2 GASShooter 中文注释源码

    参考原文解析:UE5 GAS 学习笔记 10.2 GASShooter 链接:https://blog.csdn.net/qq_30137245/article/details/125308740

    汇编工具nasm中文手册

    (*) 'gas'是免费的,而且在dos下和unix下都可以使用,但是它是作为'gcc'的一 个后台而设计的,并不是很好,'gcc'一直就提供给它绝对正确的代码,所以它的 错误检测功能相当弱,还有就是对于任何一个想真正利用它...

    对比GAS和NASM

    本文解释两种最流行的 Linux® 汇编器 —— GNU Assembler(GAS)和 Netwide Assembler(NASM) —— 之间一些比较重要的语法 差异和语义差异,包括基本语法、变量和内存访问、宏处理、函数和外部例程、堆栈处理以及...

    Gas Flow Measurement

    Gas Flow Measurement

Global site tag (gtag.js) - Google Analytics