-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmalloc.c
136 lines (119 loc) · 3.29 KB
/
malloc.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
//malloc.c
#include "minicrt.h"
/******** Data struct of heap *********/
//
// | HEAP_BLOCK_FREE/ | SIZE |
// | HEAP_BLOCK_USED | |
// -----------------------------------------------
// | PTR NEXT | PTR PREV |
// | | |
// -----------------------------------------------
// | |
// | DATA |
// | |
//
typedef struct _heap_header
{
enum{
HEAP_BLOCK_FREE = 0xABABABAB, //magic number of free block
HEAP_BLOCK_USED = 0xCDCDCDCD, //magic number of used block
} type;
unsigned size; //block size including header
struct _header* next;
struct _header* prev;
}heap_header;
#define ADDR_AD(a,o) (((char *)(a)) + o) //get chunk pointer
#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); //get chunk pointer
if(header->type !=HEAP_BLOCK_USED) //Already freed
return;
head->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 = HEADER_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 = HEADER_BLOCK_USED;
return ADDR_ADD(header, HEADER_SIZE);
}
header = header->next;
}
return NULL;
}
#ifndef WIN32
//Linux brk system call
static 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));
}
#endif
#ifdef WIN32
#include <Windows.h>
#endif
int mini_crt_heap_init()
{
void* base = NULL;
heap_header* header = NULL;
// 32MB 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_header = header;
return 1;
}