mirror of
https://gitlab.winehq.org/wine/wine.git
synced 2024-11-19 17:06:04 -07:00
server: Assign a system-wide mapping address for dynamic base modules.
This commit is contained in:
parent
4847c1d8e4
commit
efd03f40e6
10 changed files with 200 additions and 9 deletions
|
@ -2936,7 +2936,7 @@ static NTSTATUS map_image_view( struct file_view **view_ret, pe_image_info_t *im
|
|||
ULONG_PTR limit_low, ULONG_PTR limit_high, ULONG alloc_type )
|
||||
{
|
||||
unsigned int vprot = SEC_IMAGE | SEC_FILE | VPROT_COMMITTED | VPROT_READ | VPROT_EXEC | VPROT_WRITECOPY;
|
||||
void *base = wine_server_get_ptr( image_info->base );
|
||||
void *base;
|
||||
NTSTATUS status;
|
||||
ULONG_PTR start, end;
|
||||
BOOL top_down = (image_info->image_charact & IMAGE_FILE_DLL) &&
|
||||
|
@ -2947,9 +2947,18 @@ static NTSTATUS map_image_view( struct file_view **view_ret, pe_image_info_t *im
|
|||
|
||||
/* first try the specified base */
|
||||
|
||||
if (base && (ULONG_PTR)base == image_info->base)
|
||||
if (image_info->map_addr)
|
||||
{
|
||||
base = wine_server_get_ptr( image_info->map_addr );
|
||||
if ((ULONG_PTR)base != image_info->map_addr) base = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
base = wine_server_get_ptr( image_info->base );
|
||||
if ((ULONG_PTR)base != image_info->base) base = NULL;
|
||||
}
|
||||
if (base)
|
||||
{
|
||||
if (top_down) alloc_type |= MEM_TOP_DOWN;
|
||||
status = map_view( view_ret, base, size, alloc_type, vprot, limit_low, limit_high, 0 );
|
||||
if (!status) return status;
|
||||
}
|
||||
|
@ -3005,6 +3014,18 @@ static NTSTATUS virtual_map_image( HANDLE mapping, void **addr_ptr, SIZE_T *size
|
|||
return status;
|
||||
}
|
||||
|
||||
if (!image_info->map_addr &&
|
||||
(image_info->image_charact & IMAGE_FILE_DLL) &&
|
||||
(image_info->image_flags & IMAGE_FLAGS_ImageDynamicallyRelocated))
|
||||
{
|
||||
SERVER_START_REQ( get_image_map_address )
|
||||
{
|
||||
req->handle = wine_server_obj_handle( mapping );
|
||||
if (!wine_server_call( req )) image_info->map_addr = reply->addr;
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
}
|
||||
|
||||
server_enter_uninterrupted_section( &virtual_mutex, &sigset );
|
||||
|
||||
status = map_image_view( &view, image_info, size, limit_low, limit_high, alloc_type );
|
||||
|
|
|
@ -827,6 +827,7 @@ typedef union
|
|||
typedef struct
|
||||
{
|
||||
client_ptr_t base;
|
||||
client_ptr_t map_addr;
|
||||
mem_size_t stack_size;
|
||||
mem_size_t stack_commit;
|
||||
unsigned int entry_point;
|
||||
|
@ -1997,6 +1998,19 @@ struct get_mapping_info_reply
|
|||
|
||||
|
||||
|
||||
struct get_image_map_address_request
|
||||
{
|
||||
struct request_header __header;
|
||||
obj_handle_t handle;
|
||||
};
|
||||
struct get_image_map_address_reply
|
||||
{
|
||||
struct reply_header __header;
|
||||
client_ptr_t addr;
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct map_view_request
|
||||
{
|
||||
struct request_header __header;
|
||||
|
@ -5687,6 +5701,7 @@ enum request
|
|||
REQ_create_mapping,
|
||||
REQ_open_mapping,
|
||||
REQ_get_mapping_info,
|
||||
REQ_get_image_map_address,
|
||||
REQ_map_view,
|
||||
REQ_map_image_view,
|
||||
REQ_map_builtin_view,
|
||||
|
@ -5977,6 +5992,7 @@ union generic_request
|
|||
struct create_mapping_request create_mapping_request;
|
||||
struct open_mapping_request open_mapping_request;
|
||||
struct get_mapping_info_request get_mapping_info_request;
|
||||
struct get_image_map_address_request get_image_map_address_request;
|
||||
struct map_view_request map_view_request;
|
||||
struct map_image_view_request map_image_view_request;
|
||||
struct map_builtin_view_request map_builtin_view_request;
|
||||
|
@ -6265,6 +6281,7 @@ union generic_reply
|
|||
struct create_mapping_reply create_mapping_reply;
|
||||
struct open_mapping_reply open_mapping_reply;
|
||||
struct get_mapping_info_reply get_mapping_info_reply;
|
||||
struct get_image_map_address_reply get_image_map_address_reply;
|
||||
struct map_view_reply map_view_reply;
|
||||
struct map_image_view_reply map_image_view_reply;
|
||||
struct map_builtin_view_reply map_builtin_view_reply;
|
||||
|
@ -6487,7 +6504,7 @@ union generic_reply
|
|||
|
||||
/* ### protocol_version begin ### */
|
||||
|
||||
#define SERVER_PROTOCOL_VERSION 783
|
||||
#define SERVER_PROTOCOL_VERSION 784
|
||||
|
||||
/* ### protocol_version end ### */
|
||||
|
||||
|
|
21
server/fd.c
21
server/fd.c
|
@ -136,6 +136,8 @@ struct fd
|
|||
struct closed_fd *closed; /* structure to store the unix fd at destroy time */
|
||||
struct object *user; /* object using this file descriptor */
|
||||
struct list locks; /* list of locks on this fd */
|
||||
client_ptr_t map_addr; /* default mapping address for PE files */
|
||||
mem_size_t map_size; /* mapping size for PE files */
|
||||
unsigned int access; /* file access (FILE_READ_DATA etc.) */
|
||||
unsigned int options; /* file options (FILE_DELETE_ON_CLOSE, FILE_SYNCHRONOUS...) */
|
||||
unsigned int sharing; /* file sharing mode */
|
||||
|
@ -1547,6 +1549,7 @@ static void fd_destroy( struct object *obj )
|
|||
free_async_queue( &fd->write_q );
|
||||
free_async_queue( &fd->wait_q );
|
||||
|
||||
if (fd->map_addr) free_map_addr( fd->map_addr, fd->map_size );
|
||||
if (fd->completion) release_object( fd->completion );
|
||||
remove_fd_locks( fd );
|
||||
list_remove( &fd->inode_entry );
|
||||
|
@ -1665,6 +1668,8 @@ static struct fd *alloc_fd_object(void)
|
|||
fd->user = NULL;
|
||||
fd->inode = NULL;
|
||||
fd->closed = NULL;
|
||||
fd->map_addr = 0;
|
||||
fd->map_size = 0;
|
||||
fd->access = 0;
|
||||
fd->options = 0;
|
||||
fd->sharing = 0;
|
||||
|
@ -1703,6 +1708,8 @@ struct fd *alloc_pseudo_fd( const struct fd_ops *fd_user_ops, struct object *use
|
|||
fd->user = user;
|
||||
fd->inode = NULL;
|
||||
fd->closed = NULL;
|
||||
fd->map_addr = 0;
|
||||
fd->map_size = 0;
|
||||
fd->access = 0;
|
||||
fd->options = options;
|
||||
fd->sharing = 0;
|
||||
|
@ -2095,6 +2102,20 @@ int get_unix_fd( struct fd *fd )
|
|||
return fd->unix_fd;
|
||||
}
|
||||
|
||||
/* retrieve the suggested mapping address for the fd */
|
||||
client_ptr_t get_fd_map_address( struct fd *fd )
|
||||
{
|
||||
return fd->map_addr;
|
||||
}
|
||||
|
||||
/* set the suggested mapping address for the fd */
|
||||
void set_fd_map_address( struct fd *fd, client_ptr_t addr, mem_size_t size )
|
||||
{
|
||||
assert( !fd->map_addr );
|
||||
fd->map_addr = addr;
|
||||
fd->map_size = size;
|
||||
}
|
||||
|
||||
/* check if two file descriptors point to the same file */
|
||||
int is_same_file_fd( struct fd *fd1, struct fd *fd2 )
|
||||
{
|
||||
|
|
|
@ -94,6 +94,8 @@ extern unsigned int get_fd_options( struct fd *fd );
|
|||
extern unsigned int get_fd_comp_flags( struct fd *fd );
|
||||
extern int is_fd_overlapped( struct fd *fd );
|
||||
extern int get_unix_fd( struct fd *fd );
|
||||
extern client_ptr_t get_fd_map_address( struct fd *fd );
|
||||
extern void set_fd_map_address( struct fd *fd, client_ptr_t addr, mem_size_t size );
|
||||
extern int is_same_file_fd( struct fd *fd1, struct fd *fd2 );
|
||||
extern int is_fd_removable( struct fd *fd );
|
||||
extern int check_fd_events( struct fd *fd, int events );
|
||||
|
@ -172,7 +174,9 @@ extern int is_file_executable( const char *name );
|
|||
|
||||
struct memory_view;
|
||||
|
||||
extern void init_memory(void);
|
||||
extern int grow_file( int unix_fd, file_pos_t new_size );
|
||||
extern void free_map_addr( client_ptr_t base, mem_size_t size );
|
||||
extern struct memory_view *find_mapped_view( struct process *process, client_ptr_t base );
|
||||
extern struct memory_view *get_exe_view( struct process *process );
|
||||
extern struct file *get_view_file( const struct memory_view *view, unsigned int access, unsigned int sharing );
|
||||
|
|
|
@ -232,6 +232,7 @@ int main( int argc, char *argv[] )
|
|||
if (debug_level) fprintf( stderr, "wineserver: starting (pid=%ld)\n", (long) getpid() );
|
||||
set_current_time();
|
||||
init_signals();
|
||||
init_memory();
|
||||
init_directories( load_intl_file() );
|
||||
init_registry();
|
||||
main_loop();
|
||||
|
|
105
server/mapping.c
105
server/mapping.c
|
@ -208,10 +208,31 @@ static const struct fd_ops mapping_fd_ops =
|
|||
default_fd_reselect_async /* reselect_async */
|
||||
};
|
||||
|
||||
/* free address ranges for PE image mappings */
|
||||
struct addr_range
|
||||
{
|
||||
unsigned int count;
|
||||
unsigned int size;
|
||||
struct
|
||||
{
|
||||
client_ptr_t base;
|
||||
mem_size_t size;
|
||||
} *free;
|
||||
};
|
||||
|
||||
static size_t page_mask;
|
||||
static const mem_size_t granularity_mask = 0xffff;
|
||||
static struct addr_range ranges32;
|
||||
static struct addr_range ranges64;
|
||||
|
||||
#define ROUND_SIZE(size) (((size) + page_mask) & ~page_mask)
|
||||
|
||||
void init_memory(void)
|
||||
{
|
||||
page_mask = sysconf( _SC_PAGESIZE ) - 1;
|
||||
free_map_addr( 0x60000000, 0x1c000000 );
|
||||
free_map_addr( 0x600000000000, 0x100000000000 );
|
||||
}
|
||||
|
||||
static void ranges_dump( struct object *obj, int verbose )
|
||||
{
|
||||
|
@ -826,6 +847,7 @@ static unsigned int get_image_params( struct mapping *mapping, file_pos_t file_s
|
|||
return STATUS_INVALID_IMAGE_FORMAT;
|
||||
}
|
||||
|
||||
mapping->image.map_addr = get_fd_map_address( mapping->fd );
|
||||
mapping->image.image_charact = nt.FileHeader.Characteristics;
|
||||
mapping->image.machine = nt.FileHeader.Machine;
|
||||
mapping->image.dbg_offset = nt.FileHeader.PointerToSymbolTable;
|
||||
|
@ -919,8 +941,6 @@ static struct mapping *create_mapping( struct object *root, const struct unicode
|
|||
int unix_fd;
|
||||
struct stat st;
|
||||
|
||||
if (!page_mask) page_mask = sysconf( _SC_PAGESIZE ) - 1;
|
||||
|
||||
if (!(mapping = create_named_object( root, &mapping_ops, name, attr, sd )))
|
||||
return NULL;
|
||||
if (get_error() == STATUS_OBJECT_NAME_EXISTS)
|
||||
|
@ -1137,9 +1157,70 @@ static enum server_fd_type mapping_get_fd_type( struct fd *fd )
|
|||
return FD_TYPE_FILE;
|
||||
}
|
||||
|
||||
/* assign a mapping address to a PE image mapping */
|
||||
static client_ptr_t assign_map_address( struct mapping *mapping )
|
||||
{
|
||||
unsigned int i;
|
||||
client_ptr_t ret;
|
||||
struct addr_range *range = (mapping->image.base >> 32) ? &ranges64 : &ranges32;
|
||||
mem_size_t size = (mapping->size + granularity_mask) & ~granularity_mask;
|
||||
|
||||
if (!(mapping->image.image_charact & IMAGE_FILE_DLL)) return 0;
|
||||
|
||||
if ((ret = get_fd_map_address( mapping->fd ))) return ret;
|
||||
|
||||
for (i = 0; i < range->count; i++)
|
||||
{
|
||||
if (range->free[i].size < size) continue;
|
||||
range->free[i].size -= size;
|
||||
ret = range->free[i].base + range->free[i].size;
|
||||
set_fd_map_address( mapping->fd, ret, size );
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* free a PE mapping address range when the last mapping is closed */
|
||||
void free_map_addr( client_ptr_t base, mem_size_t size )
|
||||
{
|
||||
unsigned int i;
|
||||
client_ptr_t end = base + size;
|
||||
struct addr_range *range = (base >> 32) ? &ranges64 : &ranges32;
|
||||
|
||||
for (i = 0; i < range->count; i++)
|
||||
{
|
||||
if (range->free[i].base > end) continue;
|
||||
if (range->free[i].base + range->free[i].size < base) break;
|
||||
if (range->free[i].base == end)
|
||||
{
|
||||
if (i + 1 < range->count && range->free[i + 1].base + range->free[i + 1].size == base)
|
||||
{
|
||||
size += range->free[i].size;
|
||||
range->count--;
|
||||
memmove( &range->free[i], &range->free[i + 1], (range->count - i) * sizeof(*range->free) );
|
||||
}
|
||||
else range->free[i].base = base;
|
||||
}
|
||||
range->free[i].size += size;
|
||||
return;
|
||||
}
|
||||
|
||||
if (range->count == range->size)
|
||||
{
|
||||
unsigned int new_size = max( 256, range->size * 2 );
|
||||
void *new_free = realloc( range->free, new_size * sizeof(*range->free) );
|
||||
if (!new_free) return;
|
||||
range->size = new_size;
|
||||
range->free = new_free;
|
||||
}
|
||||
memmove( &range->free[i + 1], &range->free[i], (range->count - i) * sizeof(*range->free) );
|
||||
range->free[i].base = base;
|
||||
range->free[i].size = size;
|
||||
range->count++;
|
||||
}
|
||||
|
||||
int get_page_size(void)
|
||||
{
|
||||
if (!page_mask) page_mask = sysconf( _SC_PAGESIZE ) - 1;
|
||||
return page_mask + 1;
|
||||
}
|
||||
|
||||
|
@ -1233,6 +1314,24 @@ DECL_HANDLER(get_mapping_info)
|
|||
release_object( mapping );
|
||||
}
|
||||
|
||||
/* get the address to use to map an image mapping */
|
||||
DECL_HANDLER(get_image_map_address)
|
||||
{
|
||||
struct mapping *mapping;
|
||||
|
||||
if (!(mapping = get_mapping_obj( current->process, req->handle, SECTION_MAP_READ ))) return;
|
||||
|
||||
if ((mapping->flags & SEC_IMAGE) &&
|
||||
(mapping->image.image_flags & IMAGE_FLAGS_ImageDynamicallyRelocated))
|
||||
{
|
||||
if (!mapping->image.map_addr) mapping->image.map_addr = assign_map_address( mapping );
|
||||
reply->addr = mapping->image.map_addr;
|
||||
}
|
||||
else set_error( STATUS_INVALID_PARAMETER );
|
||||
|
||||
release_object( mapping );
|
||||
}
|
||||
|
||||
/* add a memory view in the current process */
|
||||
DECL_HANDLER(map_view)
|
||||
{
|
||||
|
|
|
@ -843,6 +843,7 @@ typedef union
|
|||
typedef struct
|
||||
{
|
||||
client_ptr_t base;
|
||||
client_ptr_t map_addr;
|
||||
mem_size_t stack_size;
|
||||
mem_size_t stack_commit;
|
||||
unsigned int entry_point;
|
||||
|
@ -1612,6 +1613,14 @@ enum server_fd_type
|
|||
@END
|
||||
|
||||
|
||||
/* Get the address to use to map an image mapping */
|
||||
@REQ(get_image_map_address)
|
||||
obj_handle_t handle; /* handle to the mapping */
|
||||
@REPLY
|
||||
client_ptr_t addr; /* map address */
|
||||
@END
|
||||
|
||||
|
||||
/* Add a memory view in the current process */
|
||||
@REQ(map_view)
|
||||
obj_handle_t mapping; /* file mapping handle */
|
||||
|
|
|
@ -184,6 +184,7 @@ DECL_HANDLER(read_change);
|
|||
DECL_HANDLER(create_mapping);
|
||||
DECL_HANDLER(open_mapping);
|
||||
DECL_HANDLER(get_mapping_info);
|
||||
DECL_HANDLER(get_image_map_address);
|
||||
DECL_HANDLER(map_view);
|
||||
DECL_HANDLER(map_image_view);
|
||||
DECL_HANDLER(map_builtin_view);
|
||||
|
@ -473,6 +474,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
|
|||
(req_handler)req_create_mapping,
|
||||
(req_handler)req_open_mapping,
|
||||
(req_handler)req_get_mapping_info,
|
||||
(req_handler)req_get_image_map_address,
|
||||
(req_handler)req_map_view,
|
||||
(req_handler)req_map_image_view,
|
||||
(req_handler)req_map_builtin_view,
|
||||
|
@ -717,7 +719,7 @@ C_ASSERT( sizeof(mem_size_t) == 8 );
|
|||
C_ASSERT( sizeof(message_data_t) == 56 );
|
||||
C_ASSERT( sizeof(mod_handle_t) == 8 );
|
||||
C_ASSERT( sizeof(obj_handle_t) == 4 );
|
||||
C_ASSERT( sizeof(pe_image_info_t) == 80 );
|
||||
C_ASSERT( sizeof(pe_image_info_t) == 88 );
|
||||
C_ASSERT( sizeof(process_id_t) == 4 );
|
||||
C_ASSERT( sizeof(property_data_t) == 16 );
|
||||
C_ASSERT( sizeof(rectangle_t) == 16 );
|
||||
|
@ -1143,6 +1145,10 @@ C_ASSERT( FIELD_OFFSET(struct get_mapping_info_reply, flags) == 16 );
|
|||
C_ASSERT( FIELD_OFFSET(struct get_mapping_info_reply, shared_file) == 20 );
|
||||
C_ASSERT( FIELD_OFFSET(struct get_mapping_info_reply, total) == 24 );
|
||||
C_ASSERT( sizeof(struct get_mapping_info_reply) == 32 );
|
||||
C_ASSERT( FIELD_OFFSET(struct get_image_map_address_request, handle) == 12 );
|
||||
C_ASSERT( sizeof(struct get_image_map_address_request) == 16 );
|
||||
C_ASSERT( FIELD_OFFSET(struct get_image_map_address_reply, addr) == 8 );
|
||||
C_ASSERT( sizeof(struct get_image_map_address_reply) == 16 );
|
||||
C_ASSERT( FIELD_OFFSET(struct map_view_request, mapping) == 12 );
|
||||
C_ASSERT( FIELD_OFFSET(struct map_view_request, access) == 16 );
|
||||
C_ASSERT( FIELD_OFFSET(struct map_view_request, base) == 24 );
|
||||
|
|
|
@ -2199,6 +2199,16 @@ static void dump_get_mapping_info_reply( const struct get_mapping_info_reply *re
|
|||
dump_varargs_unicode_str( ", name=", cur_size );
|
||||
}
|
||||
|
||||
static void dump_get_image_map_address_request( const struct get_image_map_address_request *req )
|
||||
{
|
||||
fprintf( stderr, " handle=%04x", req->handle );
|
||||
}
|
||||
|
||||
static void dump_get_image_map_address_reply( const struct get_image_map_address_reply *req )
|
||||
{
|
||||
dump_uint64( " addr=", &req->addr );
|
||||
}
|
||||
|
||||
static void dump_map_view_request( const struct map_view_request *req )
|
||||
{
|
||||
fprintf( stderr, " mapping=%04x", req->mapping );
|
||||
|
@ -4662,6 +4672,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
|
|||
(dump_func)dump_create_mapping_request,
|
||||
(dump_func)dump_open_mapping_request,
|
||||
(dump_func)dump_get_mapping_info_request,
|
||||
(dump_func)dump_get_image_map_address_request,
|
||||
(dump_func)dump_map_view_request,
|
||||
(dump_func)dump_map_image_view_request,
|
||||
(dump_func)dump_map_builtin_view_request,
|
||||
|
@ -4948,6 +4959,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
|
|||
(dump_func)dump_create_mapping_reply,
|
||||
(dump_func)dump_open_mapping_reply,
|
||||
(dump_func)dump_get_mapping_info_reply,
|
||||
(dump_func)dump_get_image_map_address_reply,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
|
@ -5234,6 +5246,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
|
|||
"create_mapping",
|
||||
"open_mapping",
|
||||
"get_mapping_info",
|
||||
"get_image_map_address",
|
||||
"map_view",
|
||||
"map_image_view",
|
||||
"map_builtin_view",
|
||||
|
|
|
@ -58,7 +58,7 @@ my %formats =
|
|||
"cursor_pos_t" => [ 24, 8 ],
|
||||
"debug_event_t" => [ 160, 8 ],
|
||||
"message_data_t" => [ 56, 8 ],
|
||||
"pe_image_info_t" => [ 80, 8 ],
|
||||
"pe_image_info_t" => [ 88, 8 ],
|
||||
"property_data_t" => [ 16, 8 ],
|
||||
"select_op_t" => [ 264, 8 ],
|
||||
"startup_info_t" => [ 96, 4 ],
|
||||
|
|
Loading…
Reference in a new issue