From 43e8a3bd3d063a2e37d06db4962e06ecfe985614 Mon Sep 17 00:00:00 2001
From: foreman
Date: Fri, 10 Jun 2016 13:23:51 -0400
Subject: [PATCH] P4 to Git Change 1278607 by smekhano@stas-rampitec-hsa on
2016/06/10 13:18:54
SWDEV-94189 - ORCA RT: do not use temp files
This is memfile implementation, an interface to plug into libelf and emulate files in memory w/o any IO.
If passed filename to open() is empty it will use in memory file, otherwise proxy it to the real file IO routine.
This allows RT not to use temp files. Next this interface will be plugged to the finalizer.
Testing: smoke, precheckin, conformance 2.0 reallyquick, test_compiler 1.2 with -legacy, test_compiler with -save-temps-all and -g -O0 -mem2reg=0
Reviewed by Evgeny Mankov
Affected files ...
... //depot/stg/opencl/drivers/opencl/compiler/lib/loaders/elf/elf.cpp#34 edit
... //depot/stg/opencl/drivers/opencl/compiler/lib/loaders/elf/elf.hpp#23 edit
... //depot/stg/opencl/drivers/opencl/compiler/lib/loaders/elf/elf_utils.cpp#2 edit
... //depot/stg/opencl/drivers/opencl/compiler/lib/loaders/elf/utils/libelf/_libelf_config.h#3 edit
... //depot/stg/opencl/drivers/opencl/compiler/lib/loaders/elf/utils/libelf/build/Makefile.libelf#5 edit
... //depot/stg/opencl/drivers/opencl/compiler/lib/loaders/elf/utils/libelf/elf_update.c#12 edit
... //depot/stg/opencl/drivers/opencl/compiler/lib/loaders/elf/utils/libelf/memfile.cpp#1 add
... //depot/stg/opencl/drivers/opencl/compiler/lib/loaders/elf/utils/libelf/memfile.h#1 add
---
rocclr/compiler/lib/loaders/elf/elf.cpp | 40 +--
rocclr/compiler/lib/loaders/elf/elf.hpp | 3 -
rocclr/compiler/lib/loaders/elf/elf_utils.cpp | 32 +-
.../loaders/elf/utils/libelf/_libelf_config.h | 45 +++
.../lib/loaders/elf/utils/libelf/elf_update.c | 8 +-
.../lib/loaders/elf/utils/libelf/memfile.cpp | 326 ++++++++++++++++++
.../lib/loaders/elf/utils/libelf/memfile.h | 30 ++
7 files changed, 426 insertions(+), 58 deletions(-)
create mode 100644 rocclr/compiler/lib/loaders/elf/utils/libelf/memfile.cpp
create mode 100644 rocclr/compiler/lib/loaders/elf/utils/libelf/memfile.h
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