本文为看雪论坛优秀文章
看雪论坛作者ID:genliese
一、背景
二、声明
1. 为了便于读者理解,本文大量复制《程序员的自我修养--链接、装载与库》中的文字。
三、目的
CRT库功能
入口函数
初始化
堆管理
基本IO
C++库功能
new/delete
类:stream、string
四、意义
五、实现
Linux实验环境:18.04.1-Ubuntu 64位,gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04)
Windows实验环境:Win10 2004 64位,cl 19.26.28805 版
首先Mini CRT应该以ANIS C的标准库为目标,尽量做到与其接口相一致。
具有自己的入口函数(mini_crt_entry)
基本的进程相关操作(exit)
支持堆操作(malloc、free)
支持基本的文件操作(fopen、fread、fwrite、fclose、fseek)
支持基本的字符串操作(strcpy、strlen、strcmp)
支持格式化字符串和输出操作(printf、sprintf)
支持atexit()函数
最后,Mini CRT应该是跨平台的。我们计划让Mini CRT能够同时支持Windows和 Linux两个操作系统
Mini CRT的实现应该尽量简单,以展示CRT的实现为目的,并不追求功能和性能,基本上是“点到为止”
#ifdef WIN32
//Windows部分代码
#else
//Linux部分实现代码
#endif
int flag = 0;
int argc = 0;
char* argv[16];
char* cl = GetCommandLineA();
//解析命令行
//算法缺陷:有多余的空格,会得到"\0"的字符串
argv[0] = cl;
argc++;
while (*cl)
{
if (*cl == '\"')
{
if (flag == 0)
{
flag = 1;
}else{
flag = 0;
}
}
else if (*cl == ' ' && flag == 0)
{
if (*(cl+1))
{
argv[argc] = cl + 1;
argc++;
}
*cl = '\0';
}
cl++;
}
...
push ebp
mov ebp,esp
...
int argc = 0;
char** argv = 0;
char* ebp_reg = 0;
// ebp_reg = %ebp;
asm("movl %%ebp,%0 \n"
:"=r"(ebp_reg));
argc = *(int*)(ebp_reg + 4);
argv = (char**)(ebp_reg + 8);
if (mini_crt_heap_init() == -1)
{
crt_fatal_error("heap initialize failed");
}
if (mini_crt_io_init() == -1)
{
crt_fatal_error("IO initialize failed");
}
//do_global_ctors();
ret = main(argc,argv);
exit(ret);
void exit(int exitCode){
//mini_crt_call_exit_routine();
#ifdef WIN32
ExitProcess(exitCode);
#else
asm("movl %0,%%ebx \n"
"movl $1,%%eax \n"
"int $0x80 \n"
"hlt \n"
:
:"m"(exitCode)
:"%ebx");
#endif
//malloc.c
#include "minicrt.h"
typedef struct __heap_header{
enum{
HEAP_BLOCK_FREE = 0xABABABAB,
HEAP_BLOCK_USED = 0xCDCDCDCD,
} type;
unsigned size; //block size including header
struct __heap_header* next;
struct __heap_header* prev;
} heap_header;
#define ADDR_ADD(a,o) (((char*)(a)) + o)
#define HEADER_SIZE (sizeof(heap_header))
static heap_header* list_head = NULL;
void free(void* ptr){
heap_header* header = (heap_header*)ADDR_ADD(ptr,-HEADER_SIZE);
if (header->type != HEAP_BLOCK_USED)
{
return;
}
//合并前一块
...完整代码请点击阅读原文
//stdio.c
#include "minicrt.h"
int mini_crt_io_init()
{
return 0;
}
#ifdef WIN32
#include <Windows.h>
FILE *fopen(const char *filename, const char *mode)
{
HANDLE hFile = 0;
int access = 0;
int creation = 0;
if (strcmp(mode, "w") == 0)
{
access |= GENERIC_WRITE;
creation |= CREATE_ALWAYS;
}
if (strcmp(mode, "w+") == 0)
{
access |= GENERIC_WRITE | GENERIC_READ;
creation |= CREATE_ALWAYS;
}
if (strcmp(mode, "r") == 0)
{
access |= GENERIC_READ;
creation |= OPEN_EXISTING;
}
if (strcmp(mode, "r+") == 0)
{
access |= GENERIC_WRITE | GENERIC_READ;
creation |= OPEN_EXISTING;
}
hFile = CreateFileA(filename, access, 0, 0, creation, 0, 0);
if (hFile == INVALID_HANDLE_VALUE)
{
return (FILE*)-1;
}
return (FILE*)hFile;
}
...完整代码请点击阅读原文
typedef int FILE;
#define EOF (-1)
#ifdef WIN32
#define stdin ((FILE*)(GetStdHandle(STD_INPUT_HANDLE)))
#define stdout ((FILE*)(GetStdHandle(STD_OUTPUT_HANDLE)))
#define stderr ((FILE*)(GetStdHandle(STD_ERROR_HANDLE)))
#else
#define stdin ((FILE*)0)
#define stdout ((FILE*)1)
#define stderr ((FILE*)2)
#endif
//string.c
//int n:只支持十进制
//不支持radix不是十进制且n<0的情况
char* itoa(int n,char* str,int radix){
char digit[]="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char* p = str;
char* head = str;
if (!p || radix < 2 || radix > 36)
{
return p;
}
//我觉得是可以行的
if (radix != 10 && n < 0)
{
return p;
}
if (n == 0)
{
*p++ = '0';
*p = 0;
return p;
}
if (radix == 10 && n < 0)
{
*p++ = '-';
n = -n;
}
while (n)
{
*p++ = digit[n % radix];
n /= radix;
}
...完整代码请点击阅读原文
printf实现仅支持%d、%s,且不支持格式控制(比如%08d)。
实现fprintf和vfprintf,实际上printf是fprintf的特殊形式,即目标文件为标准输出的fprintf。
实现与文件字符串操作相关的几个函数,fputc和fputs。
//printf.c
#include "minicrt.h"
//返回字符
int fputc(int c,FILE* stream){
if (fwrite(&c,1,1,stream) == -1)
{
return EOF;
}else{
return c;
}
}
//返回字符串长度
int fputs(const char* str,FILE* stream){
int len = strlen(str);
if (fwrite(str,len,1,stream) == -1)
{
return EOF;
}else{
return len;
}
}
#ifndef WIN32
#define va_list char*
#define va_start(ap,arg) (ap=(va_list)&arg+sizeof(arg))
#define va_arg(ap,t) (*(t*)((ap+=sizeof(t)) - sizeof(t)))
#define va_end(ap) (ap=(va_list)0)
#else
#include <Windows.h>
#endif
...点击阅读原文查看完整代码
//minicrt.h
#ifndef __MINI_CRT_H__
#define __MINI_CRT_H__
#ifdef __cplusplus
extern "C"{
#endif
//malloc
#ifndef NULL
#define NULL (0)
#endif
#ifndef _SIZE_T_DEFINED
typedef unsigned int size_t;
#define _SIZE_T_DEFINED
#endif /* _SIZE_T_DEFINED */
void free(void* ptr);
void* malloc(unsigned size);
// static int brk(void* end_data_segment);
static void* mmap2(void *addr, unsigned len, int prot,
int flags, int fd, int offset);
int mini_crt_heap_init();
//字符串
...点击阅读原文查看w完整代码
gcc -c -fno-builtin -nostdlib -fno-stack-protector -m32 entry.c malloc.c stdio.c string.c printf.c
ar -rs minicrt.a malloc.o printf.o stdio.o string.o
cl /c /DWIN32 /utf-8 /GS- entry.c malloc.c printf.c stdio.c string.c
lib entry.obj malloc.obj printf.obj stdio.obj string.obj /OUT:minicrt.lib
//test.c
#include "minicrt.h"
int main(int argc,char* argv[]){
int i;
FILE* fp;
//1.拷贝参数到堆
char** v = malloc(argc*sizeof(char*));
for ( i = 0; i < argc; i++)
{
v[i] = malloc(strlen(argv[i])+1);
strcpy(v[i],argv[i]);
}
//2.写入文件
fp = fopen("test.txt","w");
for ( i = 0; i < argc; i++)
{
int len = strlen(v[i]);
fwrite(&len,sizeof(int),1,fp);
fwrite(v[i],strlen(v[i])+1,1,fp);
}
fclose(fp);
//3.读取文件
fp = fopen("test.txt","r");
for ( i = 0; i < argc; i++)
{
int len;
char* buf;
fread(&len,sizeof(int),1,fp);
buf = malloc(len+1);
fread(buf,len+1,1,fp);
printf("%d %s\n",len,buf);
free(buf);
free(v[i]);
}
fclose(fp);
return 0;
}
gcc -c -ggdb -fno-builtin -nostdlib -fno-stack-protector -m32 test.c
ld -static -m elf_i386 -e mini_crt_entry entry.o test.o minicrt.a -o test
cl /c /DWIN32 /utf-8 test.c
link test.obj minicrt.lib kernel32.lib /NODEFAULTLIB /DEBUG /entry:mini_crt_entry
//test.cpp
#include "iostream"
#include "string"
using namespace std;
string abc("abcd");
class Person{
private:
int age;
char* name;
public:
Person(){
printf("Person\n");
}
~Person(){
printf("~Person\n");
}
};
int main(int argc,char* argv[]){
Person* arr = new Person[2];
string* msg = new string("Hello World");
cout << *msg << endl;
cout << abc << endl;
delete msg;
delete[] arr;
return 0;
}
string类的实现。
stream类的实现,包括操纵符(Manupilator) (endl)。
全局对象构造和析构( cout、abc)。
new/delete。
* HelloWorld程序无须用到的功能就不实现,比如异常。
#include <stdlib.h>
class C{
public:
C(){
}
~C(){
}
};
int main(int argc,char** argv){
C* c = (C*)malloc(sizeof(C));
free(c);
return 0;
}
g++ -c test.c
objdump -dr test.o
#include <stdlib.h>
class C{
public:
C(){
}
~C(){
}
};
int main(int argc,char** argv){
C* c = new C;
delete c;
return 0;
}
g++ -c test.c
objdump -dr test.o
//new_delete.cpp
#include "minicrt.h"
extern "C" void* malloc(unsigned int);
extern "C" void free(void*);
void* operator new(size_t size){
return malloc(size);
}
//第二个参数必须存在
void operator delete(void* p,size_t size){
free(p);
}
void* operator new[](size_t size){
return malloc(size);
}
//删除不是对象的数组
void operator delete[](void* p){
free(p);
}
//删除对象数组
void operator delete[](void* p,size_t size){
free(p);
}
//test.cpp
#include <stdio.h>
#include "xixi.h"
class HelloWorld{
int m_a;
public:
HelloWorld(int a);
~HelloWorld();
};
HelloWorld::HelloWorld(int a){
m_a = a;
printf("HelloWorld %d\n",a);
}
HelloWorld::~HelloWorld(){
printf("~HelloWorld %d\n",m_a);
}
HelloWorld Hw1(1);
HelloWorld Hw2(2);
int main(int argc,char** argv){
printf("main\n");
xixishow();
return 0;
}
//xixi.h
#ifndef XIXI_H
#define XIXI_H
class Person{
int m_age;
public:
Person(int age);
~Person();
void showage();
};
extern Person xixip;
extern void xixishow();
#endif
//xixi.cpp
#include "xixi.h"
#include <stdio.h>
Person::Person(int age){
m_age = age;
printf("Person %d\n",age);
}
Person::~Person(){
printf("~Person %d\n",m_age);
}
void Person::showage(){
printf("age: %d\n",m_age);
}
Person xixip1(1);
Person xixip2(2);
void xixishow(){
xixip1.showage();
}
g++ -c test.cpp -o test.o
objdump -d test.o
g++ -c xixi.cpp -o xixi.o
objdump -d xixi.o
int __cxa_atexit(void (*func) (void *), void * arg, void * dso_handle);
void __do_global_ctors_aux(void){
/* Call constructor functions. */
unsigned long nptrs = (unsigned long) __CTOR_LIST__[0];
unsigned i;
for ( i = nptrs; i >= 1; i--)
{
__CTOR_LIST__[i]();
}
}
//crtbegin.cpp
#ifndef WIN32
typedef void (*ctor_func)(void);
//当前新版本的glibc,如2.27版本,会放在`.init_array`,同时兼容`.ctors`段
ctor_func ctors_begin[1] __attribute__ ((section(".init_array"))) = {
(ctor_func)-1
};
void run_hooks(){
const ctor_func* list = ctors_begin;
while ((int)*++list != -1){
(**list)();
}
}
#endif
//crtend.cpp
#ifndef WIN32
typedef void (*ctor_func)(void);
//当前新版本的glibc,如2.27版本,会放在`.init_array`,同时兼容`.ctors`段
ctor_func crt_end[1] __attribute__ ((section(".init_array"))) = {
(ctor_func)-1
};
#endif
//ctor.cpp
typedef void (*init_func)(void);
#ifdef WIN32
#pragma section(".CRT$XCA",long,read)
#pragma section(".CRT$XCZ",long,read)
__declspec(allocate(".CRT$XCA")) init_func ctors_begin[] = { 0 };
__declspec(allocate(".CRT$XCZ")) init_func ctors_end[] = { 0 };
extern "C" void do_global_ctors(){
init_func* p = ctors_begin;
while (p < ctors_end)
{
if (*p != 0)
{
(**p)();
}
++p;
}
}
#else
void run_hooks();
extern "C" void do_global_ctors(){
run_hooks();
}
#endif
#include <iostream>
class HelloWorld{
int m_a;
public:
HelloWorld(int a);
~HelloWorld();
};
HelloWorld::HelloWorld(int a){
m_a = a;
printf("HelloWorld %d\n",a);
}
HelloWorld::~HelloWorld(){
printf("~HelloWorld %d\n",m_a);
}
HelloWorld Hw1(1);
HelloWorld Hw2(2);
int main(int argc,char** argv){
printf("main\n");
return 0;
}
int atexit(void (*function)(void));
typedef void (*init_func)(void);
#pragma section(".CRT$XCA",long,read)
#pragma section(".CRT$XCZ",long,read)
__declspec(allocate(".CRT$XCA")) init_func ctors_begin[] = { 0 };
__declspec(allocate(".CRT$XCZ")) init_func ctors_end[] = { 0 };
void do_global_ctors(){
init_func * p = ctors_begin;
while (p < ctors_end)
{
if (*p != 0)
{
(**p)();
}
++p;
}
}
//ctor.cpp
typedef void (*init_func)(void);
#ifdef WIN32
#pragma section(".CRT$XCA",long,read)
#pragma section(".CRT$XCZ",long,read)
__declspec(allocate(".CRT$XCA")) init_func ctors_begin[] = { 0 };
__declspec(allocate(".CRT$XCZ")) init_func ctors_end[] = { 0 };
extern "C" void do_global_ctors(){
init_func* p = ctors_begin;
while (p < ctors_end)
{
if (*p != 0)
{
(**p)();
}
++p;
}
}
#else
void run_hooks();
extern "C" void do_global_ctors(){
run_hooks();
}
#endif
typedef void(*cxa_func_t)(void*);
typedef void (*atexit_func_t) (void);
int __cxa_atexit(cxa_func_t func,void* arg,void* unused);
int atexit(atexit_func_t);
typedef struct __func_node{
atexit_func_t func;
void* arg;
int is_cxa;
struct __func_node* next;
}func_node;
//atexit.c
#include "minicrt.h"
typedef struct __func_node{
atexit_func_t func;
void* arg;
int is_cxa;
struct __func_node* next;
}func_node;
static func_node* atexit_list = 0;
int register_atexit(atexit_func_t func,void* arg,int is_cxa){
func_node* node;
if (!func)
{
return -1;
}
node = (func_node*)malloc(sizeof(func_node));
if (node == 0)
{
return -1;
}
node->func = func;
node->arg = arg;
node->is_cxa = is_cxa;
node->next = atexit_list;
atexit_list = node;
return 0;
}
#ifndef WIN32
int __cxa_atexit(cxa_func_t func,void* arg,void* unused){
return register_atexit((atexit_func_t)func,arg,1);
}
#endif
int atexit(atexit_func_t func){
return register_atexit(func,0,0);
}
...完整代码请点击阅读原文查看
//entry.c
...
void mini_crt_entry(void){
...
if (mini_crt_heap_init() == -1)
{
crt_fatal_error("heap initialize failed");
}
if (mini_crt_io_init() == -1)
{
crt_fatal_error("IO initialize failed");
}
do_global_ctors();
ret = main(argc,argv);
exit(ret);
}
void exit(int exitCode){
mini_crt_call_exit_routine();
#ifdef WIN32
ExitProcess(exitCode);
#else
asm("movl %0,%%ebx \n"
"movl $1,%%eax \n"
"int $0x80 \n"
"hlt \n"
:
:"m"(exitCode)
:"%ebx");
#endif
}
cout作为ofstream的一个实例,它的输出文件是标准输出。
//string.cpp
#include "minicrt.h"
namespace std{
class string{
unsigned len;
char* pbuf;
public:
explicit string(const char* str);
string(const string&);
~string();
string& operator=(const string&);
string& operator=(const char* s);
const char& operator[](unsigned idx) const;
char& operator[](unsigned idx);
const char* c_str() const;
unsigned length() const;
unsigned size() const;
};
string::string(const char* str) :
len(0),pbuf(0){
*this = str;
}
string::string(const string& s) :
len(0),pbuf(0){
*this = s;
}
string::~string(){
if (pbuf != 0)
{
delete[] pbuf;
pbuf = 0;
}
}
...完整代码请点击阅读原文查看
cl /c /DWIN32 /GS- /utf-8 entry.c malloc.c printf.c stdio.c string.c atexit.c
cl /c /DWIN32 /GS- /GR- /utf-8 crtbegin.cpp crtend.cpp ctor.cpp new_delete.cpp iostream.cpp
lib entry.obj malloc.obj printf.obj stdio.obj string.obj ctor.obj new_delete.obj atexit.obj iostream.obj /OUT:minicrt.lib
//sysdep.cpp
extern "C"{
void* __dso_handle = 0;
}
gcc -c -m32 -fno-builtin -nostdlib -fno-stack-protector entry.c malloc.c stdio.c string.c printf.c atexit.c
g++ -c -m32 -nostdinc++ -fno-rtti -fno-exceptions -fno-builtin -nostdlib -fno-stack-protector crtbegin.cpp crtend.cpp ctor.cpp new_delete.cpp sysdep.cpp iostream.cpp
ar -rs minicrt.a malloc.o printf.o stdio.o string.o ctor.o atexit.o iostream.o new_delete.o sysdep.o
-fno-rtti的作用与cl的/GR-作用一样,用于关闭RTTI。
-fno-exceptions的作用用于关闭异常支持,否则GCC会产生异常支持代码,可能导致链接错误。
-m32是指生成32位的中间目标文件,因为我的实验环境是64位的,而实现的运行库是32位的
cl /c /DWIN32 /GR- /utf-8 test.cpp
link test.obj minicrt.lib kernel32.lib /NODEFAULTLIB /DEBUG /entry:mini_crt_entry
g++ -c -m32 -nostdinc++ -fno-rtti -fno-exceptions -fno-builtin -nostdlib -fno-stack-protector test.cpp
ld -static -m elf_i386 -e mini_crt_entry entry.o crtbegin.o test.o minicrt.a crtend.o -o test
六、小结
七、问题解答
//newtest.cpp
#include "iostream"
#include "string"
using namespace std;
int main(int argc,char* argv[]){
string* msg = new string("Hello World");
cout << *msg << endl;
delete msg;
return 0;
}
//test.cpp
#include "iostream"
#include "string"
class Person{
private:
int age;
char* name;
public:
Person(){
printf("Person\n");
}
~Person(){
printf("~Person\n");
}
};
int main(int argc,char* argv[]){
Person* arr = new Person[2];
return 0;
}
C运行库库编译命令
gcc -c -fno-builtin -nostdlib -fno-stack-protector -m32 entry.c malloc.c stdio.c string.c printf.c && ar -rs minicrt.a malloc.o printf.o stdio.o string.o && gcc -c -ggdb -fno-builtin -nostdlib -fno-stack-protector -m32 test.c && ld -static -m elf_i386 -e mini_crt_entry entry.o test.o minicrt.a -o test
cl /c /DWIN32 /utf-8 /GS- entry.c malloc.c printf.c stdio.c string.c && lib entry.obj malloc.obj printf.obj stdio.obj string.obj /OUT:minicrt.lib && cl /c /DWIN32 /utf-8 test.c && link test.obj minicrt.lib kernel32.lib /NODEFAULTLIB /DEBUG /entry:mini_crt_entry
———————————————————————————————————————————————————————
C++运行库库编译命令
cl /c /DWIN32 /GS- /utf-8 entry.c malloc.c printf.c stdio.c string.c atexit.c && cl /c /DWIN32 /GS- /GR- /utf-8 crtbegin.cpp crtend.cpp ctor.cpp new_delete.cpp iostream.cpp && lib entry.obj malloc.obj printf.obj stdio.obj string.obj ctor.obj new_delete.obj atexit.obj iostream.obj /OUT:minicrt.lib && cl /c /DWIN32 /GR- /utf-8 test.cpp && link test.obj minicrt.lib kernel32.lib /NODEFAULTLIB /DEBUG /entry:mini_crt_entry
gcc -c -m32 -fno-builtin -nostdlib -fno-stack-protector entry.c malloc.c stdio.c string.c printf.c atexit.c && g++ -c -m32 -nostdinc++ -fno-rtti -fno-exceptions -fno-builtin -nostdlib -fno-stack-protector crtbegin.cpp crtend.cpp ctor.cpp new_delete.cpp sysdep.cpp iostream.cpp && ar -rs minicrt.a malloc.o printf.o stdio.o string.o ctor.o atexit.o iostream.o new_delete.o sysdep.o && g++ -c -m32 -nostdinc++ -fno-rtti -fno-exceptions -fno-builtin -nostdlib -fno-stack-protector test.cpp && ld -static -m elf_i386 -e mini_crt_entry entry.o crtbegin.o test.o minicrt.a crtend.o -o test
看雪ID:genliese
https://bbs.pediy.com/user-home-825187.htm
# 往期推荐
球分享
球点赞
球在看
点击“阅读原文”,了解更多!