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