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>
12f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines#include <mcld/Support/SystemUtils.h>
13affc150dc44fab1911775a49636d0ce85333b634Zonr Chang#include <cstdlib>
14affc150dc44fab1911775a49636d0ce85333b634Zonr Chang#include <unistd.h>
15affc150dc44fab1911775a49636d0ce85333b634Zonr Chang
16affc150dc44fab1911775a49636d0ce85333b634Zonr Changusing namespace mcld;
17affc150dc44fab1911775a49636d0ce85333b634Zonr Chang
18affc150dc44fab1911775a49636d0ce85333b634Zonr Chang//===----------------------------------------------------------------------===//
19affc150dc44fab1911775a49636d0ce85333b634Zonr Chang// constant data
20f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines//===----------------------------------------------------------------------===//
21f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hinesstatic const int PageSize = mcld::sys::GetPageSize();
22affc150dc44fab1911775a49636d0ce85333b634Zonr Chang
23affc150dc44fab1911775a49636d0ce85333b634Zonr Chang//===----------------------------------------------------------------------===//
24affc150dc44fab1911775a49636d0ce85333b634Zonr Chang// Non-member functions
2522add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao//===----------------------------------------------------------------------===//
26affc150dc44fab1911775a49636d0ce85333b634Zonr Chang//
27affc150dc44fab1911775a49636d0ce85333b634Zonr Chang// low address      A page             high address
28affc150dc44fab1911775a49636d0ce85333b634Zonr Chang// |--------------------|------------------|
29affc150dc44fab1911775a49636d0ce85333b634Zonr Chang// ^ page_offset        ^ pFileOffset      ^ page_boundary
3022add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao//
31affc150dc44fab1911775a49636d0ce85333b634Zonr Chang// Given a file offset, return the page offset.
32affc150dc44fab1911775a49636d0ce85333b634Zonr Chang// return the first page boundary \b before pFileOffset
33affc150dc44fab1911775a49636d0ce85333b634Zonr Changinline static off_t page_offset(off_t pFileOffset)
34affc150dc44fab1911775a49636d0ce85333b634Zonr Chang{ return pFileOffset & ~ (PageSize - 1); }
35affc150dc44fab1911775a49636d0ce85333b634Zonr Chang
36affc150dc44fab1911775a49636d0ce85333b634Zonr Chang// page_boundary - Given a file size, return the size to read integral pages.
37affc150dc44fab1911775a49636d0ce85333b634Zonr Chang// return the first page boundary \b after pFileOffset
38affc150dc44fab1911775a49636d0ce85333b634Zonr Changinline static off_t page_boundary(off_t pFileOffset)
39affc150dc44fab1911775a49636d0ce85333b634Zonr Chang{ return (pFileOffset + (PageSize - 1)) & ~ (PageSize - 1); }
40affc150dc44fab1911775a49636d0ce85333b634Zonr Chang
41affc150dc44fab1911775a49636d0ce85333b634Zonr Changinline static Space::Type policy(off_t pOffset, size_t pLength)
42affc150dc44fab1911775a49636d0ce85333b634Zonr Chang{
43f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines#if defined(MCLD_ON_WIN32)
44f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  return Space::ALLOCATED_ARRAY;
45f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines#endif
46affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  const size_t threshold = (PageSize*3)/4; // 3/4 page size in Linux
47affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  if (pLength < threshold)
48affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    return Space::ALLOCATED_ARRAY;
49affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  else
50affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    return Space::MMAPED;
51affc150dc44fab1911775a49636d0ce85333b634Zonr Chang}
52affc150dc44fab1911775a49636d0ce85333b634Zonr Chang
53affc150dc44fab1911775a49636d0ce85333b634Zonr Chang//===----------------------------------------------------------------------===//
54affc150dc44fab1911775a49636d0ce85333b634Zonr Chang// Space
5522add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao//===----------------------------------------------------------------------===//
56affc150dc44fab1911775a49636d0ce85333b634Zonr ChangSpace::Space()
57affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  : m_Data(NULL), m_StartOffset(0), m_Size(0),
58affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    m_RegionCount(0), m_Type(UNALLOCATED) {
59affc150dc44fab1911775a49636d0ce85333b634Zonr Chang}
60affc150dc44fab1911775a49636d0ce85333b634Zonr Chang
61affc150dc44fab1911775a49636d0ce85333b634Zonr ChangSpace::Space(Space::Type pType, void* pMemBuffer, size_t pSize)
62affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  : m_Data(static_cast<Address>(pMemBuffer)), m_StartOffset(0), m_Size(pSize),
63affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    m_RegionCount(0), m_Type(pType)
64affc150dc44fab1911775a49636d0ce85333b634Zonr Chang{
65affc150dc44fab1911775a49636d0ce85333b634Zonr Chang}
66affc150dc44fab1911775a49636d0ce85333b634Zonr Chang
67affc150dc44fab1911775a49636d0ce85333b634Zonr ChangSpace::~Space()
68affc150dc44fab1911775a49636d0ce85333b634Zonr Chang{
69affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  // do nothing. m_Data is deleted by @ref releaseSpace
70affc150dc44fab1911775a49636d0ce85333b634Zonr Chang}
71affc150dc44fab1911775a49636d0ce85333b634Zonr Chang
7222add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei LiaoSpace* Space::Create(void* pMemBuffer, size_t pSize)
7322add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao{
7422add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  Space* result = new Space(EXTERNAL, pMemBuffer, pSize);
7522add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  return result;
7622add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao}
7722add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
7822add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei LiaoSpace* Space::Create(FileHandle& pHandler, size_t pStart, size_t pSize)
79affc150dc44fab1911775a49636d0ce85333b634Zonr Chang{
80affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  Type type;
8122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  void* memory = NULL;
82affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  Space* result = NULL;
83f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines  size_t start = 0, size = 0, total_offset = 0;
84affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  switch(type = policy(pStart, pSize)) {
85affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    case ALLOCATED_ARRAY: {
86affc150dc44fab1911775a49636d0ce85333b634Zonr Chang      // adjust total_offset, start and size
87affc150dc44fab1911775a49636d0ce85333b634Zonr Chang      total_offset = pStart + pSize;
88affc150dc44fab1911775a49636d0ce85333b634Zonr Chang      start = pStart;
89affc150dc44fab1911775a49636d0ce85333b634Zonr Chang      if (total_offset > pHandler.size()) {
90affc150dc44fab1911775a49636d0ce85333b634Zonr Chang        if (pHandler.isWritable()) {
91affc150dc44fab1911775a49636d0ce85333b634Zonr Chang          size = pSize;
92affc150dc44fab1911775a49636d0ce85333b634Zonr Chang          pHandler.truncate(total_offset);
93affc150dc44fab1911775a49636d0ce85333b634Zonr Chang        }
94f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines        else if (pHandler.size() > start) {
95f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines          // not writable -> shrink the size
96affc150dc44fab1911775a49636d0ce85333b634Zonr Chang          size = pHandler.size() - start;
97f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines        }
98affc150dc44fab1911775a49636d0ce85333b634Zonr Chang        else {
99affc150dc44fab1911775a49636d0ce85333b634Zonr Chang          // create a space out of a read-only file.
100affc150dc44fab1911775a49636d0ce85333b634Zonr Chang          fatal(diag::err_cannot_read_small_file) << pHandler.path()
101affc150dc44fab1911775a49636d0ce85333b634Zonr Chang                                                  << pHandler.size()
102affc150dc44fab1911775a49636d0ce85333b634Zonr Chang                                                  << start << size;
103affc150dc44fab1911775a49636d0ce85333b634Zonr Chang        }
104affc150dc44fab1911775a49636d0ce85333b634Zonr Chang      }
105f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      else {
106f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines        // within the space.
107affc150dc44fab1911775a49636d0ce85333b634Zonr Chang        size = pSize;
108f7ac0f19a1c8d0ad14bcf6456ce368b830fea886Stephen Hines      }
109affc150dc44fab1911775a49636d0ce85333b634Zonr Chang
110affc150dc44fab1911775a49636d0ce85333b634Zonr Chang      // malloc
111affc150dc44fab1911775a49636d0ce85333b634Zonr Chang      memory = (void*)malloc(size);
112affc150dc44fab1911775a49636d0ce85333b634Zonr Chang      if (!pHandler.read(memory, start, size))
113affc150dc44fab1911775a49636d0ce85333b634Zonr Chang        error(diag::err_cannot_read_file) << pHandler.path() << start << size;
114affc150dc44fab1911775a49636d0ce85333b634Zonr Chang
115affc150dc44fab1911775a49636d0ce85333b634Zonr Chang      break;
116affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    }
117affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    case MMAPED: {
118affc150dc44fab1911775a49636d0ce85333b634Zonr Chang      // adjust total_offset, start and size
119affc150dc44fab1911775a49636d0ce85333b634Zonr Chang      total_offset = page_boundary(pStart + pSize);
120affc150dc44fab1911775a49636d0ce85333b634Zonr Chang      start = page_offset(pStart);
121affc150dc44fab1911775a49636d0ce85333b634Zonr Chang      if (total_offset > pHandler.size()) {
122affc150dc44fab1911775a49636d0ce85333b634Zonr Chang        if (pHandler.isWritable()) {
123affc150dc44fab1911775a49636d0ce85333b634Zonr Chang          size = page_boundary((pStart - start) + pSize);
124affc150dc44fab1911775a49636d0ce85333b634Zonr Chang          pHandler.truncate(total_offset);
125affc150dc44fab1911775a49636d0ce85333b634Zonr Chang        }
126affc150dc44fab1911775a49636d0ce85333b634Zonr Chang        else if (pHandler.size() > start)
127affc150dc44fab1911775a49636d0ce85333b634Zonr Chang          size = pHandler.size() - start;
128affc150dc44fab1911775a49636d0ce85333b634Zonr Chang        else {
129affc150dc44fab1911775a49636d0ce85333b634Zonr Chang          // create a space out of a read-only file.
130affc150dc44fab1911775a49636d0ce85333b634Zonr Chang          fatal(diag::err_cannot_read_small_file) << pHandler.path()
131affc150dc44fab1911775a49636d0ce85333b634Zonr Chang                                                  << pHandler.size()
132affc150dc44fab1911775a49636d0ce85333b634Zonr Chang                                                  << start << size;
133affc150dc44fab1911775a49636d0ce85333b634Zonr Chang        }
134affc150dc44fab1911775a49636d0ce85333b634Zonr Chang      }
135affc150dc44fab1911775a49636d0ce85333b634Zonr Chang      else
136affc150dc44fab1911775a49636d0ce85333b634Zonr Chang        size = page_boundary((pStart - start) + pSize);
137affc150dc44fab1911775a49636d0ce85333b634Zonr Chang
138affc150dc44fab1911775a49636d0ce85333b634Zonr Chang      // mmap
139affc150dc44fab1911775a49636d0ce85333b634Zonr Chang      if (!pHandler.mmap(memory, start, size))
140affc150dc44fab1911775a49636d0ce85333b634Zonr Chang        error(diag::err_cannot_mmap_file) << pHandler.path() << start << size;
141affc150dc44fab1911775a49636d0ce85333b634Zonr Chang
142affc150dc44fab1911775a49636d0ce85333b634Zonr Chang      break;
143affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    }
144affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    default:
145affc150dc44fab1911775a49636d0ce85333b634Zonr Chang      break;
146affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  } // end of switch
147affc150dc44fab1911775a49636d0ce85333b634Zonr Chang
148affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  result = new Space(type, memory, size);
149affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  result->setStart(start);
150affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  return result;
151affc150dc44fab1911775a49636d0ce85333b634Zonr Chang}
152affc150dc44fab1911775a49636d0ce85333b634Zonr Chang
15322add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liaovoid Space::Destroy(Space*& pSpace)
15422add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao{
15522add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  delete pSpace;
15622add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao  pSpace = NULL;
15722add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao}
15822add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao
15922add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liaovoid Space::Release(Space* pSpace, FileHandle& pHandler)
160affc150dc44fab1911775a49636d0ce85333b634Zonr Chang{
161affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  if (NULL == pSpace)
162affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    return;
163affc150dc44fab1911775a49636d0ce85333b634Zonr Chang
164affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  switch(pSpace->type()) {
165affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    case ALLOCATED_ARRAY:
166affc150dc44fab1911775a49636d0ce85333b634Zonr Chang      free(pSpace->memory());
167affc150dc44fab1911775a49636d0ce85333b634Zonr Chang      break;
168affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    case MMAPED:
169affc150dc44fab1911775a49636d0ce85333b634Zonr Chang      if (!pHandler.munmap(pSpace->memory(), pSpace->size()))
170affc150dc44fab1911775a49636d0ce85333b634Zonr Chang        error(diag::err_cannot_munmap_file) << pHandler.path();
171affc150dc44fab1911775a49636d0ce85333b634Zonr Chang      break;
172affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    default: // external and unallocated memory buffers
173affc150dc44fab1911775a49636d0ce85333b634Zonr Chang      break;
174affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  } // end of switch
175affc150dc44fab1911775a49636d0ce85333b634Zonr Chang}
176affc150dc44fab1911775a49636d0ce85333b634Zonr Chang
17722add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liaovoid Space::Sync(Space* pSpace, FileHandle& pHandler)
178affc150dc44fab1911775a49636d0ce85333b634Zonr Chang{
179affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  if (NULL == pSpace || !pHandler.isWritable())
180affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    return;
181affc150dc44fab1911775a49636d0ce85333b634Zonr Chang
182affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  switch(pSpace->type()) {
183affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    case Space::ALLOCATED_ARRAY: {
184affc150dc44fab1911775a49636d0ce85333b634Zonr Chang      if (!pHandler.write(pSpace->memory(),
185affc150dc44fab1911775a49636d0ce85333b634Zonr Chang                          pSpace->start(),
186affc150dc44fab1911775a49636d0ce85333b634Zonr Chang                          pSpace->size())) {
187affc150dc44fab1911775a49636d0ce85333b634Zonr Chang        error(diag::err_cannot_write_file) << pHandler.path()
188affc150dc44fab1911775a49636d0ce85333b634Zonr Chang                                           << pSpace->start()
189affc150dc44fab1911775a49636d0ce85333b634Zonr Chang                                           << pSpace->size();
190affc150dc44fab1911775a49636d0ce85333b634Zonr Chang      }
191affc150dc44fab1911775a49636d0ce85333b634Zonr Chang      return;
192affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    }
193affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    case Space::MMAPED:
194affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    default: {
195affc150dc44fab1911775a49636d0ce85333b634Zonr Chang      // system will eventually write bakc the memory after
196affc150dc44fab1911775a49636d0ce85333b634Zonr Chang      // calling ::munmap
197affc150dc44fab1911775a49636d0ce85333b634Zonr Chang      return;
198affc150dc44fab1911775a49636d0ce85333b634Zonr Chang    }
199affc150dc44fab1911775a49636d0ce85333b634Zonr Chang  } // end of switch
200affc150dc44fab1911775a49636d0ce85333b634Zonr Chang}
201affc150dc44fab1911775a49636d0ce85333b634Zonr Chang
202