server: Assign a system-wide mapping address for dynamic base modules.

This commit is contained in:
Alexandre Julliard 2023-10-05 10:41:47 +02:00
parent 4847c1d8e4
commit efd03f40e6
10 changed files with 200 additions and 9 deletions

View file

@ -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 );

View file

@ -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 ### */

View file

@ -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 )
{

View file

@ -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 );

View file

@ -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();

View file

@ -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)
{

View file

@ -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 */

View file

@ -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 );

View file

@ -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",

View file

@ -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 ],