`
jjchen_lian
  • 浏览: 86440 次
  • 性别: 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汇编器命令详解》 在软件开发领域,汇编语言是底层编程的重要工具,而gas(GNU Assembler)是GNU项目中的汇编器,用于将汇编语言代码转换成机器可执行的二进制代码。gas汇编器提供了丰富的命令集,使得程序员...

    GUN Binutls gas手册 汇编

    GNU GAS(GNU Assembler)是GNU Binutils工具集的一部分,它是用于编写机器语言程序的开源汇编器。GNU Binutils是一系列二进制工具的集合,包括汇编器、链接器、目标文件处理工具等,广泛应用于Linux和其他类UNIX...

    Gas 汇编语言指南

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

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

    【标题】:“面向VLIW处理器的GAS汇编器实现.pdf” 【描述】:这篇文档探讨了如何基于GAS(GNU Assembler)为VLIW(Very Long Instruction Word)处理器设计和实现汇编器。VLIW架构的DSP处理器提高了指令级并行度,...

    GNU汇编gas权威手册 using as

    GNU汇编器(gas)是一个广泛使用的汇编语言编译器,它是GNU项目的一部分,专门用于将汇编指令转换为机器码。GNU汇编器的权威手册详细介绍了该工具的使用方法、语法规则、伪指令以及命令行选项。 在Linux环境下,...

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

    ### Linux下的汇编——GAS和NASM的区别 在深入探讨GAS(GNU Assembler)与NASM(Netwide Assembler)之间的区别之前,我们首先需要了解这两种汇编器的基本概念及其在Linux环境下的应用。 #### 一、GAS与NASM简介 ...

    ARM标准汇编与GNU汇编

    《ARM标准汇编与GNU汇编》是一本深入解析ARM架构下汇编语言编程的教程,特别关注在GNU工具链环境中的应用。ARM汇编是针对ARM架构处理器的低级编程语言,而GNU汇编则是GNU开发工具集的一部分,用于在多种架构上编写...

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

    与NASM不同,Gas主要使用AT&T汇编语法,这是Unix系统中常见的汇编语言风格。 Gas手册是学习和理解AT&T汇编语法的关键资源。它涵盖了基本的汇编指令、符号解析、宏定义、伪指令、段管理以及如何与链接器交互。通过...

    gas-preprocessor.pl

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

    AT&T汇编(linux汇编)

    AT&T汇编语言是GCC(GNU Compiler Collection)和GAS(GNU Assembler)在Linux环境下进行底层编程时常用的汇编语法。与Intel汇编不同,AT&T汇编语法的结构和表达方式有其独特之处,这使得它在某些场景下更适合作为...

    AT&T汇编语言和gcc内嵌汇编

    GNU汇编程序GAS用于将汇编语言源文件转换为目标文件,并可以通过LD命令进行连接。例如,汇编和连接的命令分别是"gcc -o executable sourcecode.S"。使用GCC时,S大写可以确保gcc能够识别汇编程序中的C预处理命令,如...

    AT&T汇编语言和GCC内嵌汇编

    GNU汇编程序(GAS)是GNU项目中的一个重要组成部分,用于将汇编语言源文件转换成目标文件。GAS支持多种处理器架构,并且能够很好地与GCC集成。GAS的基本使用方法如下: ```sh as sourcecode.s -o objfile.o ``` ...

    ATT.rar_ATT汇编_at_att_linux 汇编

    "AT&T汇编语言格式uploadby_weball.pdf"这个文档很可能包含了AT&T汇编的详细语法、指令集以及如何使用GAS(GNU Assembler)进行汇编的过程。学习这部分内容可以帮助读者理解和编写AT&T汇编代码,这对于深入理解Linux...

    LINUX汇编格式.doc

    GCC 编译器可以对生成的二进制代码进行优化,而 gas 汇编器可以将汇编代码转换为目标代码,ld 链接器可以将目标代码链接成可执行文件。 在 Linux 平台上编写汇编代码需要注意以下几点: 1. 了解 Linux 的汇编语言...

    AT&T汇编语法总结

    AT&T汇编语法作为GNU汇编语言的一种表现形式,凭借其与GCC编译器和GAS汇编器的良好集成,在Linux下得到了广泛的应用。本文将详细介绍AT&T汇编语法的基本构成和使用规则,旨在帮助开发者更好地理解和应用这种语法。 ...

    汇编语言编辑器

    3. **GAS(GNU Assembler)**:作为GNU工具链的一部分,GAS支持多种处理器架构,并且与GCC编译器配合良好。 4. **TASM(Turbo Assembler)**:由Borland公司开发,主要用于DOS环境下的x86编程。 5. **Visual ...

    汇编语言编译工具汇编语言编译工具

    常见的汇编语言编译工具有NASM(Netwide Assembler)、MASM(Microsoft Macro Assembler)、GAS(GNU Assembler)等。这些工具不仅支持标准的汇编语法,还提供了丰富的扩展功能,如宏定义、条件编译等,以满足不同...

Global site tag (gtag.js) - Google Analytics