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