diff options
Diffstat (limited to 'linkers/elftoolchain/libelf/mmap_win32.c')
-rw-r--r-- | linkers/elftoolchain/libelf/mmap_win32.c | 247 |
1 files changed, 247 insertions, 0 deletions
diff --git a/linkers/elftoolchain/libelf/mmap_win32.c b/linkers/elftoolchain/libelf/mmap_win32.c new file mode 100644 index 0000000..f801fc6 --- /dev/null +++ b/linkers/elftoolchain/libelf/mmap_win32.c @@ -0,0 +1,247 @@ +/*- + * Copyright (c) 2011 Chris Johns <chrisj@rtems.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Basic mmap/munmap set of functions that allows software that needs to use + * these functions to work without changing. Currently only the basic read + * has been tested. + * + * The basic was taken from the implementation in Python 3.x by Sam Rushing + * <rushing@nightmare.com>. + */ + +#ifndef __WIN32__ +#error "Wrong OS; only for WIN32" +#endif + +#include <errno.h> +#include <stdint.h> +#include <windows.h> + +/* + * Bring in the local mman.h header to make sure the interface is in sync. + */ +#include <sys/mman.h> + +/* + * The data for each map. Maintained as a list. If performance is important maybe + * some other container can be used. + */ +typedef struct mmap_data_s +{ + struct mmap_data_s* next; + void* data; + HANDLE file_handle; + HANDLE map_handle; + size_t size; + off_t offset; +} mmap_data; + +/* + * Head of the map list. + */ +static mmap_data* map_head; + +void* +mmap(void* addr, size_t len, int prot, int flags, int fd, off_t offset) +{ + mmap_data* map = NULL; + DWORD flProtect; + DWORD dwDesiredAccess; + HANDLE fh = 0; + DWORD dwErr = 0; + DWORD size_lo; + DWORD size_hi; + DWORD off_lo; + DWORD off_hi; + uint64_t size = 0; + + if ((fd == 0) || (fd == -1)) + return MAP_FAILED; + + /* + * Not implemented. Patches welcome. + */ + if (prot & PROT_EXEC) + return MAP_FAILED; + + /* + * Map the protection. + */ + if ((prot & PROT_READ) == PROT_READ) + { + flProtect = PAGE_READONLY; + dwDesiredAccess = FILE_MAP_READ; + } + if ((prot & PROT_WRITE) == PROT_WRITE) + { + flProtect = PAGE_WRITECOPY; + dwDesiredAccess = FILE_MAP_WRITE; + } + if ((prot & (PROT_READ | PROT_WRITE)) == (PROT_READ | PROT_WRITE)) + { + flProtect = PAGE_READWRITE; + dwDesiredAccess = FILE_MAP_WRITE; + } + + fh = (HANDLE) _get_osfhandle (fd); + if (fh == (HANDLE) -1) + return MAP_FAILED; + + /* + * Win9x appears to need us seeked to zero. + */ + lseek (fd, 0, SEEK_SET); + + /* + * Allocate the space to handle the mapping. + */ + map = malloc (sizeof (mmap_data)); + if (!map) + return MAP_FAILED; + + map->next = NULL; + map->data = NULL; + map->file_handle = fh; + map->map_handle = NULL; + map->offset = offset; + + if (len == 0) + { + DWORD low; + DWORD high; + + low = GetFileSize (fh, &high); + + /* + * Low might just happen to have the value INVALID_FILE_SIZE; so we need to + * check the last error also. + */ + if ((low == INVALID_FILE_SIZE) && (dwErr = GetLastError()) != NO_ERROR) + { + free (map); + return MAP_FAILED; + } + + size = (((uint64_t) high) << 32) + low; + + if (offset >= size) + { + free (map); + return MAP_FAILED; + } + + if (offset - size > (size_t) -1LL) + /* Map area too large to fit in memory */ + map->size = (size_t) -1; + else + map->size = (size_t) (size - offset); + } + else + { + map->size = len; + size = offset + len; + } + + size_hi = (DWORD)(size >> 32); + size_lo = (DWORD)(size & 0xFFFFFFFF); + off_hi = (DWORD)(0); + off_lo = (DWORD)(offset & 0xFFFFFFFF); + + /* + * For files, it would be sufficient to pass 0 as size. For anonymous maps, + * we have to pass the size explicitly. + */ + map->map_handle = CreateFileMapping (map->file_handle, + NULL, + flProtect, + size_hi, + size_lo, + NULL); + if (!map->map_handle) + { + free (map); + return MAP_FAILED; + } + + map->data = (char *) MapViewOfFileEx (map->map_handle, + dwDesiredAccess, + off_hi, + off_lo, + map->size, + addr); + if (!map->data) + { + CloseHandle (map->map_handle); + free (map); + return MAP_FAILED; + } + + /* + * Add to the list. + */ + map->next = map_head; + map_head = map; + + return map->data; +} + +int +munmap (void* addr, size_t len) +{ + mmap_data* map = map_head; + mmap_data** prev_next = &map_head; + + /* + * Find the map and remove from the list. + */ + while (map) + { + if (map->data == addr) + { + *prev_next = map->next; + break; + } + prev_next = &map->next; + map = map->next; + } + + if (!map) + { + errno = EINVAL; + return -1; + } + + if (map->data != NULL) + UnmapViewOfFile (map->data); + if (map->map_handle != NULL) + CloseHandle (map->map_handle); + + free (map); + + errno = 0; + return 0; +} |