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