首先来看一段代码
int add_x_y(int x,int y){
return x+y;
}
通过执行g++ -c test.cpp
以后生成obj文件,然后通过objdump -d test.o
输出编译后的指令得到
Disassembly of section .text:
0000000000000000 <_Z7add_x_yii>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 89 7d fc mov %edi,-0x4(%rbp)
7: 89 75 f8 mov %esi,-0x8(%rbp)
a: 8b 55 fc mov -0x4(%rbp),%edx
d: 8b 45 f8 mov -0x8(%rbp),%eax
10: 01 d0 add %edx,%eax
12: 5d pop %rbp
13: c3 retq
从而得到一个程序函数的一个执行过程。学习过操作系统的都了解一个多任务的操作系统中是通过时间轮盘算法来对程序进行调度,使得CPU在不同周期执行着不同的指令,通过汇编代码可以看到每个程序都有着自己的描述符号即LDT局部描述符表来组建对变量和代码之间的符号描述。然而此时还需要一个针对全局的,对计算机运行状态进行控制的全局描述符表GDT(Global Descriptor Table)在整个系统中,全局描述符表GDT只有一张(一个处理器对应一个GDT),GDT可以被放在内存的任何位置.
接下来就到了编写时间、在这之前,需要定义一些数据类型
types.h
typedef unsigned short u_short;
typedef unsigned int u_int;
typedef unsigned char u_char;
typedef unsigned long u_long;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned long uint32_t;
#ifndef FRTOS_GDT_H
#define FRTOS_GDT_H
#include "types.h"
class GlobalDescriptorTable {
public:
class SegementDescriptor {
private:
uint16_t limit_lo;
uint16_t base_io;
uint16_t base_hi;
uint16_t type;
uint16_t flags_limit_hi;
uint16_t base_vhi;
public:
SegementDescriptor(uint32_t base, uint32_t limit, uint8_t type);
uint32_t Base();
uint32_t Limit();
};
SegementDescriptor nullSegementDescriptor;
SegementDescriptor unusedSegementDescriptor;
SegementDescriptor codeSegementDescriptor;
SegementDescriptor dataSegementDescriptor;
GlobalDescriptorTable();
~GlobalDescriptorTable();
uint16_t CodeSegementSelector();
uint16_t DataSegementSelector();
};
#endif
gdt.cpp
#include "gdt.h"
#include "types.h"
GlobalDescriptorTable::GlobalDescriptorTable() :
nullSegementDescriptor(0, 0, 0),
unusedSegementDescriptor(0, 0, 0),
codeSegementDescriptor(
0, 64 * 1024 * 1024, 0x9A),
dataSegementDescriptor(0, 64 * 1024 * 1024, 0x92) {
uint32_t i[2];
i[0] = (uint32_t) this;
i[1] = sizeof(GlobalDescriptorTable) << 16;
asm volatile("lgdt (%0)": :"p" (((uint8_t *) i) + 2));
}
GlobalDescriptorTable::~GlobalDescriptorTable() {
}
uint16_t GlobalDescriptorTable::DataSegementSelector() {
return ((uint8_t *) &dataSegementDescriptor - (uint8_t *) this);
}
uint16_t GlobalDescriptorTable::CodeSegementSelector() {
return ((uint8_t *) &codeSegementDescriptor - (uint8_t *) this);
}
GlobalDescriptorTable::SegementDescriptor::SegementDescriptor(uint32_t base, uint32_t limit, uint8_t flags) {
uint8_t *target = (uint8_t *) this;
if (limit <= 65535) {
target[6] = 0x40;
} else {
if ((limit & 0xfff) != 0xfff) {
limit = (limit >> 12) - 1;
} else {
limit = limit >> 32;
}
target[6] = 0xc0;
}
target[0] = limit & 0xff;
target[1] = (limit >> 8) & 0xff;
target[6] |= (limit >> 16) & 0xff;
target[2] = base & 0xff;
target[3] = (base >> 8) & 0xff;
target[4] = (base >> 16) & 0xff;
target[7] = (base >> 24) & 0xff;
target[5] = flags;
}
uint32_t GlobalDescriptorTable::SegementDescriptor::Base() {
uint8_t *target = (uint8_t *) this;
uint8_t result = target[7];
result = (result << 8) + target[4];
result = (result << 8) + target[3];
result = (result << 8) + target[2];
return result;
}
uint32_t GlobalDescriptorTable::SegementDescriptor::Limit() {
uint8_t *target = (uint8_t *) this;
uint8_t result = target[6] & 0xf;
result = (result << 8) + target[1];
result = (result << 8) + target[0];
if ((target[6] & 0xc0) == 0xc0)
result = (result << 32) | 0xfff;
return result;
}