[读书笔记]程序员的自我修养 chp13 一个简单的CRT 运行库实现

来源:互联网 发布:中国网络空间安全协会 编辑:程序博客网 时间:2024/05/30 19:33

0. 前言

  1. 目标:实现一个小型的 CRT 运行库
  2. 本质: 利用系统提供的api接口, 实现一个通用的 CRT 函数接口, 使得 C 语言程序可以自由的运行在各个不同的系统上
  3. 项目工程地址: https://github.com/zhyh2010/miniCRT

1. 遇到的一些问题

  1. windows.h 不包含路径集
    这里写图片描述
    解决方法:
    http://www.unjeep.com/q/869954156.htm

    先执行C:/Program Files/Microsoft Visual Studio 9.0/Common7/Tools/vsvars32.bat
    再cl task.cpp

  2. 命令行使用
    参考文章: http://www.360doc.com/content/10/0228/10/111369_17077729.shtml

@REM @Author: anchen@REM @Date:   2016-12-21 16:38:42@REM @Last Modified by:   anchen@REM Modified time: 2016-12-22 15:57:18@echo offif "%1%"=="genlib" goto genlibif "%1%"=="test" goto testif "%1%"=="clean" goto clean:help    echo "Usage: make [genlib | test]"    goto end:genlib    call vsvars32    cl /c /DWIN32 /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    goto end:test    call vsvars32    cl /c /DWIN32 test.c    link test.obj minicrt.lib kernel32.lib /NODEFAULTLIB /entry:mini_crt_entry    test arg1 arg2 123    goto end:clean    echo "cleaning project"    for %%i in (*.obj, *.lib, *.txt) do del /f /q %%i    goto end:end

2. 实现

我们的这个CRT 本质上只是实现一些非常简单的功能, 命令行参数解析与设置, 字符串打印, 堆内存分配,文件读写 etc

2.1 入口函数

  1. 程序运行的起点并不是main, 而是由运行库提供的入口函数, 主要负责:
    1. 准备程序运行环境以及初始化运行库
    2. 调用 main 函数执行程序主体
    3. 清理程序运行后的各种资源
  2. code
#include "minicrt.h"#ifdef WIN32#include <Windows.h>#endifextern int main(int argc, char * argv[]);void exit(int);static void crt_fatal_error(const char * msg){    // printf("fatal error: %s", msg);    exit(1);}void mini_crt_entry(void){    int ret;#ifdef WIN32    int flag = 0;    int argc = 0;    char * argv[16];    char * cl = GetCommandLineA();    printf("origin commandline: %s\n", cl);    // parse the parameters    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++;                //printf("%d %s\n", argc - 1, argv[argc - 1]);            }            *cl = '\0';        }        cl++;    }#else    int argc;    char ** argv;    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);#endif    if (!mini_crt_heap_init())        crt_fatal_error("heap initialize failed");    if (!mini_crt_io_init())        crt_fatal_error("IO initialize failed");    ret = main(argc, argv);    exit(ret);}void exit(int exitCode){    // min_crt_call_exit_routine();#ifdef WIN32    ExitProcess(exitCode);#else    asm("movl %0, %%ebx \n\t"        "movl $1, %%eax \n\t"        "int $0x80      \n\t"        "hlt            \n\t"::"m"(exitCode));#endif}

2.1 堆的实现

  1. 堆的实现:
    1. 使用空闲链表算法作为基础
    2. 堆大小固定为 32MB
    3. 需要特别注意,* 堆释放的时候, 如果有相连的空闲内存, 应该进行内存的合并处理操作 *
  2. 相关代码:
#include "minicrt.h"typedef struct _heap_header{    enum {        HEAP_BLOCK_FREE = 0xABABABAB,        HEAP_BLOCK_USED = 0xCDCDCDCD,    } type;    unsigned size;    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;    header->type = HEAP_BLOCK_FREE;    if (header->prev != NULL && header->prev->type == HEAP_BLOCK_FREE){        // merge        header->prev->next = header->next;        if (header->next != NULL)            header->next->prev = header->prev;        header->prev->size += header->size;        header = header->prev;    }    if (header->next != NULL && header->next->type == HEAP_BLOCK_FREE){        // merge        header->size += header->next->size;        header->next = header->next->next;    }}void * malloc(unsigned size){    heap_header * header;    if (size == 0)        return NULL;    header = list_head;    while (header != 0){        if (header->type == HEAP_BLOCK_USED){            header = header->next;            continue;        }        if (header->size > size + HEADER_SIZE &&             header->size <= size + HEADER_SIZE * 2){            header->type = HEAP_BLOCK_USED;        }        if (header->size > size + HEADER_SIZE * 2){            // split            heap_header * next = (heap_header *)ADDR_ADD(header, size + HEADER_SIZE);            next->prev = header;            next->next = header->next;            next->type = HEAP_BLOCK_FREE;            next->size = header->size - (size - HEADER_SIZE);            header->next = next;            header->size = size + HEADER_SIZE;            header->type = HEAP_BLOCK_USED;            return ADDR_ADD(header, HEADER_SIZE);        }        header = header->next;    }    return NULL;}#ifndef WIN32// Linux brk system callstatic int brk(void * end_data_segment){    int ret = 0;    // brk system call number : 45    // in /usr/include/asm-i386/unistd.h:    // #define __NR_brk 45    asm("movl $45, %%eax    \n\t"        "movl %1, %%ebx     \n\t"        "int $0x80          \n\t"        "movl %%eax, %0     \n\t"        : "=r"(ret): "m"(end_data_segment));}#endif#ifdef WIN32#include <windows.h>#endifint mini_crt_heap_init(){    void * base = NULL;    heap_header * header = NULL;    // 32 MB heap size    unsigned heap_size = 1024 * 1024 * 32;#ifdef WIN32    base = VirtualAlloc(0, heap_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);    if (base == NULL)        return 0;#else    base = (void *)brk(0);    void * end = ADDR_ADD(base, heap_size);    end = (void *)brk(end);    if (!end)        return 0;#endif    header = (heap_header *) base;    header->size = heap_size;    header->type = HEAP_BLOCK_FREE;    header->next = NULL;    header->prev = NULL;    list_head = header;    return 1;}

2.3 格式化字符串操作

  1. 实现一个printf 操作, 本质上就是变长参数的函数的处理
  2. code
#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, 1, len, stream) != len)        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>#endifint vfprintf(FILE * stream, const char * format, va_list arglist){    int translating = 0;    int ret = 0;    const char * p = 0;    for (p = format; *p != '\0'; ++p){        switch (*p){            case '%':                if (!translating)                    translating = 1;                else{                    if (fputc('%', stream) < 0)                        return EOF;                    ++ret;                    translating = 0;                }                break;            case 'd':                if (translating){                    char buf[16];                    translating = 0;                    itoa(va_arg(arglist, int), buf, 10);                    if (fputs(buf, stream) < 0)                        return EOF;                    ret += strlen(buf);                }                else if (fputc('d', stream) < 0)                    return EOF;                else                    ++ret;                break;            case 's':                if (translating){                    const char * str = va_arg(arglist, const char *);                    translating = 0;                    if (fputs(str, stream) < 0)                        return EOF;                    ret += strlen(str);                }                else if (fputc('s', stream) < 0)                    return EOF;                else                    ++ret;                break;            default:                if (translating)                    translating = 0;                if (fputc(*p, stream) < 0)                    return EOF;                else                    ++ret;                break;        }    }    return ret;}int printf(const char * format, ...){    va_list(arglist);    va_start(arglist, format);    return vfprintf(stdout, format, arglist);}int fprintf(FILE * stream, const char * format, ...){    va_list(arglist);    va_start(arglist, format);    return vfprintf(stream, format, arglist);}
0 0
原创粉丝点击