diff --git a/rocclr/compiler/lib/loaders/elf/elf.cpp b/rocclr/compiler/lib/loaders/elf/elf.cpp index 39d4fdf011..4bbd739672 100644 --- a/rocclr/compiler/lib/loaders/elf/elf.cpp +++ b/rocclr/compiler/lib/loaders/elf/elf.cpp @@ -194,7 +194,6 @@ OclElf::OclElf ( ) : _fd (-1), _fname (elfFileName), - _isTempFile(false), _e (0), _err (), _eclass (eclass), @@ -235,11 +234,10 @@ OclElf::~OclElf() if (_fd != -1) { xclose(_err, _fname, _fd); char* tname= const_cast(_fname); - if (_isTempFile) { + if (tname) { unlink(tname); - _isTempFile = false; - } free(tname); + } _fd = -1; _fname = NULL; @@ -284,25 +282,17 @@ OclElf::Init() // Create a temporary file if it is needed if (_elfCmd != ELF_C_READ) { - std::string tempFileName; - size_t sz; - if (_fname == NULL) { - tempFileName = amd::Os::getTempFileName(); - _fname = tempFileName.c_str(); - sz = tempFileName.size() + 1; - _isTempFile = true; - } - else { - sz = strlen(_fname) + 1; - } + if (_fname != NULL) { + size_t sz = strlen(_fname) + 1; - char* tname = (char*)xmalloc(_err, sz); - if (tname == 0) { - _err.xfail("OclElf::Init() failed to malloc()"); - return false; + char* tname = (char*)xmalloc(_err, sz); + if (tname == 0) { + _err.xfail("OclElf::Init() failed to malloc()"); + return false; + } + strcpy(tname, _fname); + _fname = static_cast(tname); } - strcpy(tname, _fname); - _fname = static_cast(tname); } if (elf_version(EV_CURRENT) == EV_NONE) { @@ -330,10 +320,8 @@ OclElf::Init() if ((_fd == -1) && (_rawElfBytes == NULL)) { // case 1: elf object is in file '_fname' - assert ((_fname != NULL) && "ELF file name should be provided"); - _fd = xopen(_err, _fname, oflag, pmode); - if (_fd < 0) { + if (_fd == -1) { _err.xfail("OclElf::Init(): Cannot Open File %s!", _fname); return false; } @@ -350,7 +338,7 @@ OclElf::Init() assert ((_fname == NULL) && "ELF file name should not be provided for a read only elf."); } else { _fd = xopen(_err, _fname, oflag, pmode); - if (_fd < 0) { + if (_fd == -1) { _err.xfail("OclElf::Init(): Cannot Open File %s!", _fname); return false; } @@ -1469,7 +1457,7 @@ OclElf::dumpImage(char** buff, size_t* len) return false; } - assert ((_fd > 0) && "_fd in Elf::dumpImage should be defined"); + assert ((_fd != -1) && "_fd in Elf::dumpImage should be defined"); // Now, write the ELF into the file if (elf_update(_e, ELF_C_WRITE) < 0) { diff --git a/rocclr/compiler/lib/loaders/elf/elf.hpp b/rocclr/compiler/lib/loaders/elf/elf.hpp index a72f6340b6..49c33fe583 100644 --- a/rocclr/compiler/lib/loaders/elf/elf.hpp +++ b/rocclr/compiler/lib/loaders/elf/elf.hpp @@ -134,9 +134,6 @@ private: // file name const char* _fname; - // Is the _fname temporary ? - bool _isTempFile; - // pointer to libelf structure ::Elf* _e; diff --git a/rocclr/compiler/lib/loaders/elf/elf_utils.cpp b/rocclr/compiler/lib/loaders/elf/elf_utils.cpp index d3ca6ce344..3303bed2cd 100644 --- a/rocclr/compiler/lib/loaders/elf/elf_utils.cpp +++ b/rocclr/compiler/lib/loaders/elf/elf_utils.cpp @@ -3,42 +3,24 @@ // #include "elf_utils.hpp" +#include "memfile.h" #include #include #include #include -#if defined(__GNUC__) -#include -#else -#include -#endif - - /* See elf_utils.hpp for descriptions about each functions */ namespace amd { -#if defined(_MSC_VER) - -#define ELF_OPEN _open -#define ELF_READ(f, b, l) _read((f), (b), (unsigned int)(l)) -#define ELF_WRITE _write -#define ELF_CLOSE _close -#define ELF_LSEEK _lseek - -#else - -#define ELF_OPEN open -#define ELF_READ(f, b, l) read((f), (b), (size_t)(l)) -#define ELF_WRITE write -#define ELF_CLOSE close -#define ELF_LSEEK lseek - -#endif +#define ELF_OPEN mem_open +#define ELF_READ(f, b, l) mem_read((f), (b), (unsigned int)(l)) +#define ELF_WRITE mem_write +#define ELF_CLOSE mem_close +#define ELF_LSEEK mem_lseek /* Save the error string in _lastErrMsg. If it is built without NDEBUG, the program @@ -81,7 +63,7 @@ void* xmalloc(OclElfErr& err, const size_t len) int xopen(OclElfErr& err, const char *fname, const int in_flags, const int perms) { const int retval = ELF_OPEN(fname, in_flags, perms); - if (retval < 0) { + if (retval == -1) { err.xfail("Failed to open '%s': %s", fname, strerror(errno)); return -1; } diff --git a/rocclr/compiler/lib/loaders/elf/utils/libelf/_libelf_config.h b/rocclr/compiler/lib/loaders/elf/utils/libelf/_libelf_config.h index d42216c37f..3116c59d7d 100644 --- a/rocclr/compiler/lib/loaders/elf/utils/libelf/_libelf_config.h +++ b/rocclr/compiler/lib/loaders/elf/utils/libelf/_libelf_config.h @@ -216,3 +216,48 @@ typedef struct { u_int32_t gh_shift2; /* Bloom filter shift count. */ } Elf_GNU_Hash_Header; #endif + +#if defined(USE_MEMFILE) +#include "memfile.h" + +#if !defined(read) +#define read(f, b, l) mem_read((f), (b), (l)) +#endif + +#if !defined(write) +#define write(f, b, l) mem_write((f), (b), (l)) +#endif + +#if !defined(lseek) +#define lseek(f, l, w) mem_lseek((f), (l), (w)) +#endif + +#if !defined(fstat) +#define fstat(f, b) mem_fstat((f), (struct stat*)(b)) +#endif + +#if !defined(_fstat64i32) +#define _fstat64i32(f, b) mem_fstat((f), (struct stat*)(b)) +#endif + +#if !defined(_fstat32i64) +#define _fstat32i64(f, b) mem_fstat((f), (struct stat*)(b)) +#endif + +#if !defined(_fstat32) +#define _fstat32(f, b) mem_fstat((f), (struct stat*)(b)) +#endif + +#if !defined(_fstat64) +#define _fstat64(f, b) mem_fstat((f), (struct stat*)(b)) +#endif + +#if !defined(ftruncate) +#define ftruncate(f, l) mem_ftruncate((f), (size_t)(l)) +#endif + +#if !defined(_chsize) +#define _chsize(f, l) mem_ftruncate((f), (size_t)(l)) +#endif + +#endif //USE_MEMFILE diff --git a/rocclr/compiler/lib/loaders/elf/utils/libelf/elf_update.c b/rocclr/compiler/lib/loaders/elf/utils/libelf/elf_update.c index 30709a9b8f..885c59d0af 100644 --- a/rocclr/compiler/lib/loaders/elf/utils/libelf/elf_update.c +++ b/rocclr/compiler/lib/loaders/elf/utils/libelf/elf_update.c @@ -1024,7 +1024,7 @@ _libelf_update_elf(Elf *e, off_t newsize, struct _Elf_Extent_List *extents) // memory and has a raw file and one that is based on a file // descriptor and does not have a raw_file. Both are equally // valid, so we don't special case here. - assert(e->e_cmd == ELF_C_RDWR || (e->e_cmd == ELF_C_WRITE && e->e_fd >= 0)); + assert(e->e_cmd == ELF_C_RDWR || (e->e_cmd == ELF_C_WRITE && e->e_fd != -1)); if ((newfile = e->e_mem.alloc((size_t) newsize)) == NULL) { LIBELF_SET_ERROR(RESOURCE, errno); @@ -1077,7 +1077,7 @@ _libelf_update_elf(Elf *e, off_t newsize, struct _Elf_Extent_List *extents) * For regular files, throw away existing file content and * unmap any existing mappings. */ - if ((e->e_flags & LIBELF_F_SPECIAL_FILE) == 0 && e->e_fd >= 0) { + if ((e->e_flags & LIBELF_F_SPECIAL_FILE) == 0 && e->e_fd != -1) { #if !defined(WIN32) #define FTRUNC(A, B) ftruncate(A, (off_t)B) #else @@ -1101,7 +1101,7 @@ _libelf_update_elf(Elf *e, off_t newsize, struct _Elf_Extent_List *extents) /* * Write out the new contents. */ - if (e->e_fd >= 0 && write(e->e_fd, newfile, (size_t) newsize) != newsize) { + if (e->e_fd != -1 && write(e->e_fd, newfile, (size_t) newsize) != newsize) { LIBELF_SET_ERROR(IO, errno); goto error; } @@ -1246,7 +1246,7 @@ elf_update(Elf *e, Elf_Cmd c) if (c == ELF_C_NULL) goto done; - if (c == ELF_C_WRITE && e->e_fd < 0) { + if (c == ELF_C_WRITE && e->e_fd == -1) { rc = (off_t) -1; LIBELF_SET_ERROR(SEQUENCE, 0); goto done; diff --git a/rocclr/compiler/lib/loaders/elf/utils/libelf/memfile.cpp b/rocclr/compiler/lib/loaders/elf/utils/libelf/memfile.cpp new file mode 100644 index 0000000000..cd434fe514 --- /dev/null +++ b/rocclr/compiler/lib/loaders/elf/utils/libelf/memfile.cpp @@ -0,0 +1,326 @@ +// +// Copyright (c) 2016 Advanced Micro Devices, Inc. All rights reserved. +// + +#include "memfile.h" +#include +#include +#include +#include +#include +#include + +#if defined(__GNUC__) +#include +#else +#include +#endif + +// Allocation granularity +#define ALLOC_G 512 +#define is_file(fd) ((fd) >= 0) + +#if defined(_MSC_VER) + +#define OPEN ::_open +#define READ(f, b, l) ::_read((f), (b), (unsigned int)(l)) +#define WRITE(f, b, l) ::_write((f), (b), (unsigned int)(l)) +#define CLOSE ::_close +#define LSEEK ::_lseek +#define FSTAT ::fstat +#define FTRUNC(f, l) ::_chsize((f), (long)(l)) + +#else + +#define OPEN ::open +#define READ(f, b, l) ::read((f), (b), (size_t)(l)) +#define WRITE ::write +#define CLOSE ::close +#define LSEEK ::lseek +#define FSTAT ::fstat +#define FTRUNC(f, l) ::ftruncate((f), (off_t)(l)) + +#endif + +namespace amd { + +// A structure which either maintains in memory file or uses a real file. +class memfile_t { +public: + memfile_t() : buf(nullptr), curp(nullptr), size(0) {} + + bool reserve(size_t new_size) { + if (!new_size) + new_size = 1; + new_size = (new_size + ALLOC_G - 1) & ~(ALLOC_G - 1); + size_t pos = tell(); + void *p = realloc(buf, new_size); + if (!p) + return false; + buf = p; + setpos(pos); + return true; + } + + bool open(int oflag, int pmode) + { + size = 0; + buf = curp = nullptr; + return reserve(1); + } + + off_t read(void *buffer, size_t count) + { + if (!buffer) { + errno = EINVAL; + return -1; + } + + size_t pos = tell(); + if (pos >= size) + return 0; + + size_t ret = size - pos; + ret = std::min(ret, count); + memcpy(buffer, curp, ret); + advance(ret); + return (off_t)ret; + } + + off_t write(const void *buffer, size_t count) + { + if (!buffer) { + errno = EINVAL; + return -1; + } + + size_t pos = tell(); + size_t new_size = std::max(pos + count, size); + if (new_size > size) { + if (!reserve(new_size)) + return -1; + if (pos > size) + memset((char*)buf + size, 0, pos - size); + size = new_size; + } + + memcpy(curp, buffer, count); + advance(count); + return (off_t)count; + } + + int close() { + if (is_open()) { + free(buf); + buf = nullptr; + size = 0; + return 0; + } + errno = EBADF; + return -1; + } + + off_t lseek(off_t offset, int origin) + { + switch (origin) { + default: + errno = EINVAL; + return -1; + case SEEK_SET: + break; + case SEEK_CUR: + offset += (off_t)tell(); + break; + case SEEK_END: + offset += (off_t)size; + break; + } + + if (offset < 0) { + errno = EOVERFLOW; + return -1; + } + + setpos((size_t)offset); + return offset; + } + + bool fstat(struct stat *buf) const + { + if (!is_open()) { + errno = EBADF; + return false; + } + + memset(buf, 0, sizeof(struct stat)); + buf->st_mode = S_IFREG; + buf->st_size = (off_t)size; + return true; + } + + bool ftruncate(size_t len) + { + if (len > size) { + size_t pos = tell(); + lseek(0, SEEK_END); + while(len--) + write("", 1u); + setpos(len); + } else { + reserve(len); + size = len; + } + return true; + } + + bool is_open() const { return buf != nullptr; } + size_t tell() const { return size_t((char*)curp - (char*)buf); } + +protected: + + void setpos(size_t new_pos) { curp = (char*)buf + new_pos; } + void advance(off_t offset) { curp = (char*)curp + offset; } + void advance(size_t offset) { curp = (char*)curp + offset; } + +private: + void* buf; + void* curp; + size_t size; +}; + +} // namespace amd + +using namespace amd; + +static std::vector Files; + +static size_t fd2idx(int fd) +{ + return (unsigned)-fd - 2; +} + +static int idx2fd(size_t idx) +{ + return -(int)idx - 2; +} + +static memfile_t* get_memfile(int fd) +{ + if (fd >= -1) { + errno = EBADF; + return nullptr; + } + + size_t fno = fd2idx(fd); + + if (fno >= Files.size()) { + errno = EBADF; + return nullptr; + } + + memfile_t &m = Files[fno]; + if (!m.is_open()) { + errno = EBADF; + return nullptr; + } + + return &m; +} + +// Acts the same as open(), but path can be NULL, which is a request for in memory file +int mem_open(const char *path, int oflag, int pmode) +{ + if (path && path[0]) // Filename provided, real file requested + return OPEN(path, oflag, pmode); + + memfile_t m; + if (!m.open(oflag, pmode)) + return -1; + + for (size_t i = 0; i < Files.size(); ++i) { + if (!Files[i].is_open()) { + Files[i] = m; + return idx2fd(i); + } + } + + Files.push_back(m); + return idx2fd(Files.size() - 1); +} + +off_t mem_read(int fd, void *buffer, size_t count) +{ + if (is_file(fd)) + return READ(fd, buffer, count); + + memfile_t *m = get_memfile(fd); + if (!m) + return -1; + + return m->read(buffer, count); +} + +off_t mem_write(int fd, const void *buffer, size_t count) +{ + if (is_file(fd)) + return WRITE(fd, buffer, count); + + memfile_t *m = get_memfile(fd); + if (!m) + return -1; + + return m->write(buffer, count); +} + +int mem_close(int fd) +{ + if (is_file(fd)) + return CLOSE(fd); + + memfile_t *m = get_memfile(fd); + if (!m) + return -1; + + int ret = m->close(); + + if ((size_t)fd == (Files.size() - 1)) + Files.pop_back(); + + return ret; +} + +off_t mem_lseek(int fd, off_t offset, int origin) +{ + if (is_file(fd)) + return LSEEK(fd, offset, origin); + + memfile_t *m = get_memfile(fd); + if (!m) + return -1; + + return m->lseek(offset, origin); +} + +int mem_fstat(int fd, struct stat *buf) +{ + if (is_file(fd)) + return FSTAT(fd, buf); + + memfile_t *m = get_memfile(fd); + if (!m) + return -1; + + return m->fstat(buf) ? 0 : -1; +} + +int mem_ftruncate(int fd, size_t len) +{ + if (is_file(fd)) + return FTRUNC(fd, len); + + memfile_t *m = get_memfile(fd); + if (!m) + return -1; + + return m->ftruncate(len) ? 0 : -1; +} diff --git a/rocclr/compiler/lib/loaders/elf/utils/libelf/memfile.h b/rocclr/compiler/lib/loaders/elf/utils/libelf/memfile.h new file mode 100644 index 0000000000..95f8851c12 --- /dev/null +++ b/rocclr/compiler/lib/loaders/elf/utils/libelf/memfile.h @@ -0,0 +1,30 @@ +// +// Copyright (c) 2016 Advanced Micro Devices, Inc. All rights reserved. +// + +#ifndef _MEMFILE_H +#define _MEMFILE_H + +#include +#if !defined(_MSC_VER) +#include +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +// Acts the same as open(), but path can be NULL, which is a request for in memory file +extern int mem_open(const char *path, int oflag, int pmode); +extern off_t mem_read(int fd, void *buffer, size_t count); +extern off_t mem_write(int fd, const void *buffer, size_t count); +extern int mem_close(int fd); +extern off_t mem_lseek(int fd, off_t offset, int origin); +extern int mem_fstat(int fd, struct stat *buf); +extern int mem_ftruncate(int fd, size_t len); + +#if defined(__cplusplus) +} +#endif + +#endif // !_MEMFILE_H