• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===- Space.cpp ----------------------------------------------------------===//
2 //
3 //                     The MCLinker Project
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 #include <mcld/Support/Space.h>
10 #include <mcld/Support/FileHandle.h>
11 #include <mcld/Support/MsgHandling.h>
12 #include <cstdlib>
13 #include <unistd.h>
14 
15 using namespace mcld;
16 
17 //===----------------------------------------------------------------------===//
18 // constant data
19 static const off_t PageSize = getpagesize();
20 
21 //===----------------------------------------------------------------------===//
22 // Non-member functions
23 //
24 // low address      A page             high address
25 // |--------------------|------------------|
26 // ^ page_offset        ^ pFileOffset      ^ page_boundary
27 
28 // Given a file offset, return the page offset.
29 // return the first page boundary \b before pFileOffset
page_offset(off_t pFileOffset)30 inline static off_t page_offset(off_t pFileOffset)
31 { return pFileOffset & ~ (PageSize - 1); }
32 
33 // page_boundary - Given a file size, return the size to read integral pages.
34 // return the first page boundary \b after pFileOffset
page_boundary(off_t pFileOffset)35 inline static off_t page_boundary(off_t pFileOffset)
36 { return (pFileOffset + (PageSize - 1)) & ~ (PageSize - 1); }
37 
policy(off_t pOffset,size_t pLength)38 inline static Space::Type policy(off_t pOffset, size_t pLength)
39 {
40   const size_t threshold = (PageSize*3)/4; // 3/4 page size in Linux
41   if (pLength < threshold)
42     return Space::ALLOCATED_ARRAY;
43   else
44     return Space::MMAPED;
45 }
46 
47 //===----------------------------------------------------------------------===//
48 // Space
Space()49 Space::Space()
50   : m_Data(NULL), m_StartOffset(0), m_Size(0),
51     m_RegionCount(0), m_Type(UNALLOCATED) {
52 }
53 
Space(Space::Type pType,void * pMemBuffer,size_t pSize)54 Space::Space(Space::Type pType, void* pMemBuffer, size_t pSize)
55   : m_Data(static_cast<Address>(pMemBuffer)), m_StartOffset(0), m_Size(pSize),
56     m_RegionCount(0), m_Type(pType)
57 {
58 }
59 
~Space()60 Space::~Space()
61 {
62   // do nothing. m_Data is deleted by @ref releaseSpace
63 }
64 
createSpace(FileHandle & pHandler,size_t pStart,size_t pSize)65 Space* Space::createSpace(FileHandle& pHandler,
66                           size_t pStart, size_t pSize)
67 {
68   Type type;
69   void* memory;
70   Space* result = NULL;
71   size_t start, size = 0, total_offset;
72   switch(type = policy(pStart, pSize)) {
73     case ALLOCATED_ARRAY: {
74       // adjust total_offset, start and size
75       total_offset = pStart + pSize;
76       start = pStart;
77       if (total_offset > pHandler.size()) {
78         if (pHandler.isWritable()) {
79           size = pSize;
80           pHandler.truncate(total_offset);
81         }
82         else if (pHandler.size() > start)
83           size = pHandler.size() - start;
84         else {
85           // create a space out of a read-only file.
86           fatal(diag::err_cannot_read_small_file) << pHandler.path()
87                                                   << pHandler.size()
88                                                   << start << size;
89         }
90       }
91       else
92         size = pSize;
93 
94       // malloc
95       memory = (void*)malloc(size);
96       if (!pHandler.read(memory, start, size))
97         error(diag::err_cannot_read_file) << pHandler.path() << start << size;
98 
99       break;
100     }
101     case MMAPED: {
102       // adjust total_offset, start and size
103       total_offset = page_boundary(pStart + pSize);
104       start = page_offset(pStart);
105       if (total_offset > pHandler.size()) {
106         if (pHandler.isWritable()) {
107           size = page_boundary((pStart - start) + pSize);
108           pHandler.truncate(total_offset);
109         }
110         else if (pHandler.size() > start)
111           size = pHandler.size() - start;
112         else {
113           // create a space out of a read-only file.
114           fatal(diag::err_cannot_read_small_file) << pHandler.path()
115                                                   << pHandler.size()
116                                                   << start << size;
117         }
118       }
119       else
120         size = page_boundary((pStart - start) + pSize);
121 
122       // mmap
123       if (!pHandler.mmap(memory, start, size))
124         error(diag::err_cannot_mmap_file) << pHandler.path() << start << size;
125 
126       break;
127     }
128     default:
129       break;
130   } // end of switch
131 
132   result = new Space(type, memory, size);
133   result->setStart(start);
134   return result;
135 }
136 
releaseSpace(Space * pSpace,FileHandle & pHandler)137 void Space::releaseSpace(Space* pSpace, FileHandle& pHandler)
138 {
139   if (NULL == pSpace)
140     return;
141 
142   switch(pSpace->type()) {
143     case ALLOCATED_ARRAY:
144       free(pSpace->memory());
145       break;
146     case MMAPED:
147       if (!pHandler.munmap(pSpace->memory(), pSpace->size()))
148         error(diag::err_cannot_munmap_file) << pHandler.path();
149       break;
150     default: // external and unallocated memory buffers
151       break;
152   } // end of switch
153 }
154 
syncSpace(Space * pSpace,FileHandle & pHandler)155 void Space::syncSpace(Space* pSpace, FileHandle& pHandler)
156 {
157   if (NULL == pSpace || !pHandler.isWritable())
158     return;
159 
160   switch(pSpace->type()) {
161     case Space::ALLOCATED_ARRAY: {
162       if (!pHandler.write(pSpace->memory(),
163                           pSpace->start(),
164                           pSpace->size())) {
165         error(diag::err_cannot_write_file) << pHandler.path()
166                                            << pSpace->start()
167                                            << pSpace->size();
168       }
169       return;
170     }
171     case Space::MMAPED:
172     default: {
173       // system will eventually write bakc the memory after
174       // calling ::munmap
175       return;
176     }
177   } // end of switch
178 }
179 
180