/* output import stubs for exported entry points that link to external symbols */ static void output_external_link_imports( DLLSPEC *spec ) { unsigned int i, pos; if (!ext_link_imports.count) return; /* nothing to do */ sort_names( &ext_link_imports ); /* get rid of duplicate names */ for (i = 1; i < ext_link_imports.count; i++) { if (!strcmp( ext_link_imports.names[i-1], ext_link_imports.names[i] )) remove_name( &ext_link_imports, i-- ); } output( "\n/* external link thunks */\n\n" ); output( "\t.data\n" ); output( "\t.align %d\n", get_alignment(get_ptr_size()) ); output( ".L__wine_spec_external_links:\n" ); for (i = 0; i < ext_link_imports.count; i++) output( "\t%s %s\n", get_asm_ptr_keyword(), asm_name(ext_link_imports.names[i]) ); output( "\n\t.text\n" ); output( "\t.align %d\n", get_alignment(get_ptr_size()) ); output( "%s:\n", asm_name("__wine_spec_external_link_thunks") ); for (i = pos = 0; i < ext_link_imports.count; i++) { char *buffer = strmake( "__wine_spec_ext_link_%s", ext_link_imports.names[i] ); output_import_thunk( buffer, ".L__wine_spec_external_links", pos ); free( buffer ); pos += get_ptr_size(); } output_function_size( "__wine_spec_external_link_thunks" ); }
/******************************************************************* * output_asm_constructor * * Output code for calling a dll constructor. */ static void output_asm_constructor( const char *constructor ) { if (target_platform == PLATFORM_APPLE) { /* Mach-O doesn't have an init section */ output( "\n\t.mod_init_func\n" ); output( "\t.align %d\n", get_alignment(get_ptr_size()) ); output( "\t%s %s\n", get_asm_ptr_keyword(), asm_name(constructor) ); } else { switch(target_cpu) { case CPU_x86: case CPU_x86_64: // output( "\n\t.section \".init\",\"ax\"\n" ); output( "\n\t.section .init,\"ax\"\n" ); output( "\tcall %s\n", asm_name(constructor) ); break; case CPU_ARM: output( "\n\t.section \".text\",\"ax\"\n" ); output( "\tblx %s\n", asm_name(constructor) ); break; case CPU_ARM64: case CPU_POWERPC: output( "\n\t.section \".init\",\"ax\"\n" ); output( "\tbl %s\n", asm_name(constructor) ); break; } } }
/******************************************************************* * output_asm_constructor * * Output code for calling a dll constructor. */ static void output_asm_constructor( const char *constructor ) { if (target_platform == PLATFORM_APPLE) { /* Mach-O doesn't have an init section */ output( "\n\t.mod_init_func\n" ); output( "\t.align %d\n", get_alignment(4) ); output( "\t.long %s\n", asm_name(constructor) ); } else { output( "\n\t.section \".init\",\"ax\"\n" ); switch(target_cpu) { case CPU_x86: case CPU_x86_64: output( "\tcall %s\n", asm_name(constructor) ); break; case CPU_SPARC: output( "\tcall %s\n", asm_name(constructor) ); output( "\tnop\n" ); break; case CPU_ARM: case CPU_POWERPC: output( "\tbl %s\n", asm_name(constructor) ); break; } } }
static void gl_update_input_size(gl_t *gl, unsigned width, unsigned height, unsigned pitch) { // Res change. Need to clear out texture. if ((width != gl->last_width[gl->tex_index] || height != gl->last_height[gl->tex_index]) && gl->empty_buf) { gl->last_width[gl->tex_index] = width; gl->last_height[gl->tex_index] = height; glPixelStorei(GL_UNPACK_ALIGNMENT, get_alignment(pitch)); glPixelStorei(GL_UNPACK_ROW_LENGTH, gl->tex_w); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, gl->tex_w, gl->tex_h, gl->texture_type, gl->texture_fmt, gl->empty_buf); GLfloat xamt = (GLfloat)width / gl->tex_w; GLfloat yamt = (GLfloat)height / gl->tex_h; set_texture_coords(gl->tex_coords, xamt, yamt); } // We might have used different texture coordinates last frame. Edge case if resolution changes very rapidly. else if (width != gl->last_width[(gl->tex_index - 1) & TEXTURES_MASK] || height != gl->last_height[(gl->tex_index - 1) & TEXTURES_MASK]) { GLfloat xamt = (GLfloat)width / gl->tex_w; GLfloat yamt = (GLfloat)height / gl->tex_h; set_texture_coords(gl->tex_coords, xamt, yamt); } }
static bool pack_align(lima_symbol_t* symbol, void* data) { align_pack_state_t* state = (align_pack_state_t*) data; unsigned alignment = get_alignment(symbol); state->pos = ALIGN(state->pos, alignment); symbol->offset = state->pos; if (symbol->type == lima_symbol_struct) { unsigned old_pos = state->pos; state->pos = 0; for (unsigned i = 0; i < symbol->num_children; i++) { if (!pack_align(symbol->children[i], data)) return false; } state->pos = ALIGN(state->pos, alignment); symbol->stride = state->pos; state->pos = old_pos; } else symbol->stride = sizes[symbol->type]; unsigned array_elems = symbol->array_elems ? symbol->array_elems : 1; state->pos += symbol->stride * array_elems; return true; }
// Old style "blitting", so we can render all the fonts in one go. // TODO: Is it possible that fonts could overlap if we blit without alpha blending? static void blit_fonts(gl_t *gl, const struct font_output *head, const struct font_rect *geom) { // Clear out earlier fonts. glPixelStorei(GL_UNPACK_ALIGNMENT, 8); glPixelStorei(GL_UNPACK_ROW_LENGTH, gl->font_tex_w); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, gl->font_tex_w, gl->font_tex_h, GL_LUMINANCE, GL_UNSIGNED_BYTE, gl->font_tex_empty_buf); while (head) { // head has top-left oriented coords. int x = head->off_x - geom->x; int y = head->off_y - geom->y; y = gl->font_tex_h - head->height - y - 1; glPixelStorei(GL_UNPACK_ALIGNMENT, get_alignment(head->pitch)); glPixelStorei(GL_UNPACK_ROW_LENGTH, head->pitch); glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, head->width, head->height, GL_LUMINANCE, GL_UNSIGNED_BYTE, head->output); head = head->next; } }
CL_CollisionOutline CL_CollisionOutline::clone() const { CL_CollisionOutline copy; copy.impl->contours.clear(); copy.impl->contours.reserve(impl->contours.size()); for (size_t i = 0; i < impl->contours.size(); i++) copy.impl->contours.push_back(impl->contours[i].clone()); copy.impl->do_inside_test = get_inside_test(); copy.impl->width = get_width(); copy.impl->height = get_height(); copy.impl->position = get_translation(); copy.impl->scale_factor = get_scale(); copy.impl->angle = get_angle(); copy.impl->minimum_enclosing_disc = get_minimum_enclosing_disc(); bool points, normals, metadata, pendepths; get_collision_info_state(points,normals,metadata,pendepths); copy.enable_collision_info(points,normals,metadata,pendepths); CL_Origin origin; float x, y; get_alignment(origin,x,y); copy.impl->translation_origin = origin; copy.impl->translation_offset.x = x; copy.impl->translation_offset.y = y; get_rotation_hotspot(origin,x,y); copy.impl->rotation_origin = origin; copy.impl->rotation_hotspot.x = x; copy.impl->rotation_hotspot.y = y; return copy; }
/* output the import thunks of a Win32 module */ static void output_immediate_import_thunks(void) { int i, j, pos; int nb_imm = nb_imports - nb_delayed; static const char import_thunks[] = "__wine_spec_import_thunks"; if (!nb_imm) return; output( "\n/* immediate import thunks */\n\n" ); output( "\t.text\n" ); output( "\t.align %d\n", get_alignment(8) ); output( "%s:\n", asm_name(import_thunks)); for (i = pos = 0; i < nb_imports; i++) { if (dll_imports[i]->delay) continue; for (j = 0; j < dll_imports[i]->nb_imports; j++, pos += get_ptr_size()) { ORDDEF *odp = dll_imports[i]->imports[j]; output_import_thunk( odp->name ? odp->name : odp->export_name, ".L__wine_spec_import_data_ptrs", pos ); } pos += get_ptr_size(); } output_function_size( import_thunks ); }
/* output a single import thunk */ static void output_import_thunk( const char *name, const char *table, int pos ) { output( "\n\t.align %d\n", get_alignment(4) ); output( "\t%s\n", func_declaration(name) ); output( "%s\n", asm_globl(name) ); output_cfi( ".cfi_startproc" ); switch(target_cpu) { case CPU_x86: if (!UsePIC) { output( "\tjmp *(%s+%d)\n", table, pos ); } else { output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") ); output( "1:\tjmp *%s+%d-1b(%%eax)\n", table, pos ); } break; case CPU_x86_64: output( "\tjmpq *%s+%d(%%rip)\n", table, pos ); break; case CPU_ARM: output( "\tldr IP,1f\n"); output( "\tldr PC,[PC,IP]\n" ); output( "1:\t.long %s+%u-(1b+4)\n", table, pos ); break; case CPU_ARM64: output( "\tadr x9, 1f\n" ); output( "\tldur x9, [x9, #0]\n" ); if (pos & 0xf000) output( "\tadd x9, x9, #%u\n", pos & 0xf000 ); if (pos & 0x0f00) output( "\tadd x9, x9, #%u\n", pos & 0x0f00 ); if (pos & 0x00f0) output( "\tadd x9, x9, #%u\n", pos & 0x00f0 ); if (pos & 0x000f) output( "\tadd x9, x9, #%u\n", pos & 0x000f ); output( "\tldur x9, [x9, #0]\n" ); output( "\tbr x9\n" ); output( "1:\t.quad %s\n", table ); break; case CPU_POWERPC: output( "\tmr %s, %s\n", ppc_reg(0), ppc_reg(31) ); if (target_platform == PLATFORM_APPLE) { output( "\tlis %s, ha16(%s+%d+32768)\n", ppc_reg(31), table, pos ); output( "\tla %s, lo16(%s+%d)(%s)\n", ppc_reg(31), table, pos, ppc_reg(31) ); } else { output( "\tlis %s, (%s+%d+32768)@h\n", ppc_reg(31), table, pos ); output( "\tla %s, (%s+%d)@l(%s)\n", ppc_reg(31), table, pos, ppc_reg(31) ); } output( "\tlwz %s, 0(%s)\n", ppc_reg(31), ppc_reg(31) ); output( "\tmtctr %s\n", ppc_reg(31) ); output( "\tmr %s, %s\n", ppc_reg(31), ppc_reg(0) ); output( "\tbctr\n" ); break; } output_cfi( ".cfi_endproc" ); output_function_size( name ); }
void* VariableBlockHeap::alloc( size_t size, Align align, const char* name, int lineNum ) { // Ensure that the low level heap is valid before the allocation #ifdef _DEBUG this->lowLevelHeap.CheckValidity(); GameAssert( this->heapInfo.currNumAlloc + 1 == this->lowLevelHeap.CountAllocations() ); #endif unsigned int alignment = get_alignment( align ); unsigned int alignedSize = size + sizeof( TrackingBlock ) + alignment - 1; void* ptr = this->lowLevelHeap.Allocate( alignedSize ); TrackingBlock* block = new(ptr) TrackingBlock( name, lineNum ); block->allocIndex = ++this->mem->memInfo.currAllocIndex; block->allocSize = alignedSize; block->gNext = this->mem->globalTrackingBlockHead; if( this->mem->globalTrackingBlockHead != 0 ) this->mem->globalTrackingBlockHead->gPrev = block; this->mem->globalTrackingBlockHead = block; block->hNext = this->trackingBlockHead; if( this->trackingBlockHead != 0 ) this->trackingBlockHead->hPrev = block; this->trackingBlockHead = block; this->heapInfo.currNumAlloc++; this->heapInfo.peakNumAlloc = max( this->heapInfo.currNumAlloc, this->heapInfo.peakNumAlloc ); this->heapInfo.currBytesUsed += alignedSize; this->heapInfo.peakBytesUsed = max( this->heapInfo.currBytesUsed, this->heapInfo.peakBytesUsed ); this->heapInfo.currBytesFree -= alignedSize; // Have we exceeded the amount of memory specified for heap size? GameAssert( ( this->heapInfo.totalHeapSize - sizeof( VariableBlockHeap ) ) >= this->heapInfo.currBytesUsed ); this->mem->memInfo.currBytesUsed += alignedSize; this->mem->memInfo.peakBytesUsed = max( this->mem->memInfo.currBytesUsed, this->mem->memInfo.peakBytesUsed ); this->mem->memInfo.currNumAlloc++; this->mem->memInfo.peakNumAlloc = max( this->mem->memInfo.peakNumAlloc, this->mem->memInfo.currNumAlloc ); void* p = block + 1; void* alignedAddr = (void*) ( ( (unsigned int) p + alignment - 1 ) & ~( alignment - 1 ) ); TrackingBlock** topPtr = (TrackingBlock**) ( (size_t) alignedAddr - sizeof( TrackingBlock* ) ); *topPtr = block; // Make sure the low level heap is valid after the allocation #ifdef _DEBUG this->lowLevelHeap.CheckValidity(); GameAssert( this->heapInfo.currNumAlloc + 1 == this->lowLevelHeap.CountAllocations() ); #endif return alignedAddr; }
/******************************************************************* * BuildRelays16 * * Build all the 16-bit relay callbacks */ void BuildRelays16(void) { if (target_cpu != CPU_x86) { output( "/* File not used with this architecture. Do not edit! */\n\n" ); return; } /* File header */ output( "/* File generated automatically. Do not edit! */\n\n" ); output( "\t.text\n" ); output( "%s:\n\n", asm_name("__wine_spec_thunk_text_16") ); output( "%s\n", asm_globl("__wine_call16_start") ); /* Standard CallFrom16 routine */ BuildCallFrom16Core( FALSE, FALSE ); /* Register CallFrom16 routine */ BuildCallFrom16Core( TRUE, FALSE ); /* C16ThkSL CallFrom16 routine */ BuildCallFrom16Core( FALSE, TRUE ); /* Standard CallTo16 routine */ BuildCallTo16Core( 0 ); /* Register CallTo16 routine */ BuildCallTo16Core( 1 ); /* Standard CallTo16 return stub */ BuildRet16Func(); /* CBClientThunkSL routine */ BuildCallTo32CBClient( FALSE ); /* CBClientThunkSLEx routine */ BuildCallTo32CBClient( TRUE ); /* Pending DPMI events check stub */ BuildPendingEventCheck(); output( "%s\n", asm_globl("__wine_call16_end") ); output_function_size( "__wine_spec_thunk_text_16" ); /* Declare the return address and data selector variables */ output( "\n\t.data\n\t.align %d\n", get_alignment(4) ); output( "%s\n\t.long 0\n", asm_globl("CallTo16_DataSelector") ); output( "%s\n\t.long 0\n", asm_globl("CallTo16_TebSelector") ); if (UsePIC) output( "wine_ldt_copy_ptr:\t.long %s\n", asm_name("wine_ldt_copy") ); output_gnu_stack_note(); }
static PyObject *ffi_alignof(FFIObject *self, PyObject *arg) { int align; CTypeDescrObject *ct = _ffi_type(self, arg, ACCEPT_ALL); if (ct == NULL) return NULL; align = get_alignment(ct); if (align < 0) return NULL; return PyInt_FromLong(align); }
ssize_t write_blockwise(int fd, void *orig_buf, size_t count) { void *hangover_buf, *hangover_buf_base = NULL; void *buf, *buf_base = NULL; int r, hangover, solid, bsize, alignment; ssize_t ret = -1; if ((bsize = sector_size(fd)) < 0) return bsize; hangover = count % bsize; solid = count - hangover; alignment = get_alignment(fd); if ((long)orig_buf & (alignment - 1)) { buf = aligned_malloc(&buf_base, count, alignment); if (!buf) goto out; memcpy(buf, orig_buf, count); } else buf = orig_buf; r = write(fd, buf, solid); if (r < 0 || r != solid) goto out; if (hangover) { hangover_buf = aligned_malloc(&hangover_buf_base, bsize, alignment); if (!hangover_buf) goto out; r = read(fd, hangover_buf, bsize); if (r < 0 || r != bsize) goto out; r = lseek(fd, -bsize, SEEK_CUR); if (r < 0) goto out; memcpy(hangover_buf, (char*)buf + solid, hangover); r = write(fd, hangover_buf, bsize); if (r < 0 || r != bsize) goto out; } ret = count; out: free(hangover_buf_base); if (buf != orig_buf) free(buf_base); return ret; }
/* output the get_pc thunk if needed */ void output_get_pc_thunk(void) { if (target_cpu != CPU_x86) return; if (!UsePIC) return; output( "\n\t.text\n" ); output( "\t.align %d\n", get_alignment(4) ); output( "\t%s\n", func_declaration("__wine_spec_get_pc_thunk_eax") ); output( "%s:\n", asm_name("__wine_spec_get_pc_thunk_eax") ); output_cfi( ".cfi_startproc" ); output( "\tmovl (%%esp),%%eax\n" ); output( "\tret\n" ); output_cfi( ".cfi_endproc" ); output_function_size( "__wine_spec_get_pc_thunk_eax" ); }
static void function_header( FILE *outfile, const char *name ) { fprintf( outfile, "\n\t.align %d\n", get_alignment(4) ); #ifdef USE_STABS fprintf( outfile, "\t.stabs \"%s:F1\",36,0,0," PREFIX "%s\n", name, name); #endif #ifdef TYPE_ASM_SUPPORTED fprintf( outfile, "\t.type " PREFIX "%s,@function\n", name ); #elif defined(NEED_TYPE_IN_DEF) fprintf( outfile, "\t.def " PREFIX "%s; .scl 2; .type 32; .endef\n", name ); #endif fprintf( outfile, "\t.globl " PREFIX "%s\n", name ); fprintf( outfile, PREFIX "%s:\n", name ); }
/* * Combines llseek with blockwise write. write_blockwise can already deal with short writes * but we also need a function to deal with short writes at the start. But this information * is implicitly included in the read/write offset, which can not be set to non-aligned * boundaries. Hence, we combine llseek with write. */ ssize_t write_lseek_blockwise(int fd, char *buf, size_t count, off_t offset) { char *frontPadBuf; void *frontPadBuf_base = NULL; int r, bsize, frontHang; size_t innerCount = 0; ssize_t ret = -1; if ((bsize = sector_size(fd)) < 0) return bsize; frontHang = offset % bsize; if (lseek(fd, offset - frontHang, SEEK_SET) < 0) goto out; if (frontHang) { frontPadBuf = aligned_malloc(&frontPadBuf_base, bsize, get_alignment(fd)); if (!frontPadBuf) goto out; r = read(fd, frontPadBuf, bsize); if (r < 0 || r != bsize) goto out; innerCount = bsize - frontHang; if (innerCount > count) innerCount = count; memcpy(frontPadBuf + frontHang, buf, innerCount); if (lseek(fd, offset - frontHang, SEEK_SET) < 0) goto out; r = write(fd, frontPadBuf, bsize); if (r < 0 || r != bsize) goto out; buf += innerCount; count -= innerCount; } ret = count ? write_blockwise(fd, buf, count) : 0; if (ret >= 0) ret += innerCount; out: free(frontPadBuf_base); return ret; }
void CreatureType::make_creature(Creature& cr) const { cr.type_idname=idname_; cr.align=get_alignment(); cr.age=age_.roll(); cr.juice=juice_.roll(); cr.gender_liberal=cr.gender_conservative=roll_gender(); cr.infiltration=roll_infiltration(); cr.money=money_.roll(); strcpy(cr.name,get_encounter_name()); for(int i=0; i<SKILLNUM; i++) cr.set_skill(i,skills_[i].roll()); give_armor(cr); give_weapon(cr); }
/******************************************************************* * BuildRet16Func * * Build the return code for 16-bit callbacks */ static void BuildRet16Func( FILE *outfile ) { /* * Note: This must reside in the .data section to allow * run-time relocation of the SYSLEVEL_Win16CurrentTeb symbol */ function_header( outfile, "CallTo16_Ret" ); /* Save %esp into %esi */ fprintf( outfile, "\tmovl %%esp,%%esi\n" ); /* Restore 32-bit segment registers */ fprintf( outfile, "\t.byte 0x2e\n\tmovl " PREFIX "CallTo16_DataSelector-" PREFIX "Call16_Ret_Start,%%edi\n" ); #ifdef __svr4__ fprintf( outfile, "\tdata16\n"); #endif fprintf( outfile, "\tmovw %%di,%%ds\n" ); #ifdef __svr4__ fprintf( outfile, "\tdata16\n"); #endif fprintf( outfile, "\tmovw %%di,%%es\n" ); fprintf( outfile, "\tmovw " PREFIX "SYSLEVEL_Win16CurrentTeb,%%fs\n" ); /* Restore the 32-bit stack */ #ifdef __svr4__ fprintf( outfile, "\tdata16\n"); #endif fprintf( outfile, "\tmovw %%di,%%ss\n" ); fprintf( outfile, "\t.byte 0x64\n\tmovl (%d),%%esp\n", STACKOFFSET ); fprintf( outfile, "\t.byte 0x64\n\tpopl (%d)\n", STACKOFFSET ); /* Return to caller */ fprintf( outfile, "\tlret\n" ); /* Declare the return address and data selector variables */ fprintf( outfile, "\n\t.align %d\n", get_alignment(4) ); fprintf( outfile, "\t.globl " PREFIX "CallTo16_DataSelector\n" ); fprintf( outfile, PREFIX "CallTo16_DataSelector:\t.long 0\n" ); fprintf( outfile, "\t.globl " PREFIX "CallTo16_RetAddr\n" ); fprintf( outfile, PREFIX "CallTo16_RetAddr:\t.long 0\n" ); fprintf( outfile, "\t.globl " PREFIX "SYSLEVEL_Win16CurrentTeb\n" ); fprintf( outfile, PREFIX "SYSLEVEL_Win16CurrentTeb:\t.long 0\n" ); }
static bool gl_read_viewport(void *data, uint8_t *buffer) { (void)data; GLint vp[4]; glGetIntegerv(GL_VIEWPORT, vp); glPixelStorei(GL_PACK_ALIGNMENT, get_alignment(vp[2])); glPixelStorei(GL_PACK_ROW_LENGTH, vp[2]); glReadPixels(vp[0], vp[1], vp[2], vp[3], GL_BGR, GL_UNSIGNED_BYTE, buffer); return true; }
static unsigned get_alignment(lima_symbol_t* symbol) { if (symbol->type == lima_symbol_struct) { unsigned alignment = 1; for (unsigned i = 0; i < symbol->num_children; i++) { unsigned new_alignment = get_alignment(symbol->children[i]); if (new_alignment > alignment) alignment = new_alignment; } return alignment; } return alignments[symbol->type]; }
void output_get_pc_thunk (FILE *outfile) { #ifndef __i386__ return; #else if (!UsePIC) return; fprintf( outfile, "asm(\"\\n\\t.text\\n\"\n" ); fprintf( outfile, "\"\\t.align %d\\n\"\n", get_alignment(4) ); output_function_name (outfile, "__wine_spec_get_pc_thunk_eax"); fprintf( outfile, "\"%s:\\n\"\n", __ASM_NAME("__wine_spec_get_pc_thunk_eax") ); fprintf( outfile, "\"\\tpopl %%eax\\n\"\n" ); fprintf( outfile, "\"\\tpushl %%eax\\n\"\n" ); fprintf( outfile, "\"\\tret\\n\"\n" ); fprintf( outfile, ");\n"); #endif }
/******************************************************************* * output_asm_relays16 * * Build all the 16-bit relay callbacks */ void output_asm_relays16(void) { /* File header */ output( "\t.text\n" ); output( "%s:\n\n", asm_name("__wine_spec_thunk_text_16") ); output( "%s\n", asm_globl("__wine_call16_start") ); /* Standard CallFrom16 routine */ BuildCallFrom16Core( 0, 0 ); /* Register CallFrom16 routine */ BuildCallFrom16Core( 1, 0 ); /* C16ThkSL CallFrom16 routine */ BuildCallFrom16Core( 0, 1 ); /* Standard CallTo16 routine */ BuildCallTo16Core( 0 ); /* Register CallTo16 routine */ BuildCallTo16Core( 1 ); /* Standard CallTo16 return stub */ BuildRet16Func(); /* CBClientThunkSL routine */ BuildCallTo32CBClient( 0 ); /* CBClientThunkSLEx routine */ BuildCallTo32CBClient( 1 ); output( "%s\n", asm_globl("__wine_call16_end") ); output_function_size( "__wine_spec_thunk_text_16" ); /* Declare the return address and data selector variables */ output( "\n\t.data\n\t.align %d\n", get_alignment(4) ); output( "%s\n\t.long 0\n", asm_globl("CallTo16_DataSelector") ); output( "%s\n\t.long 0\n", asm_globl("CallTo16_TebSelector") ); }
void *bus_devmem_access(uint32_t base, uint32_t mlen, int *fd) { *fd = open("/dev/mem", O_RDWR); if(*fd == -1) { perror("open(/dev/mem)"); return NULL; } uint32_t aligned_base = base - get_alignment(base); // Get number of pages for mmap pagenum = mlen / getpagesize(); pagenum += (mlen % getpagesize() == 0) ? 0: 1; void *m = mmap(NULL, pagenum * getpagesize(), PROT_READ | PROT_WRITE, MAP_SHARED, *fd, aligned_base); if(m == NULL) { perror("mmap(NULL, pagenum * getpagesize(), PROT_READ | PROT_WRITE, MAP_SHARED, fd, aligned_base)"); close(*fd); return NULL; } return m; }
void TextWidget::redraw() { Image& target=get_redraw_target(); target.fill(m_BGColor); Rect rect=get_rect(); const xstring& text = get_text(); str_vec lines(1, text); Rect bounds=m_Font->get_bounds(text); if (bounds.get_width() > rect.get_width()) { break_text_lines(m_Font, text, rect.get_width(),lines); bounds = Rect(0, 0, 0, 0); for (auto& line : lines) { Rect b = m_Font->get_bounds(line); bounds.right = Max(bounds.right, b.get_width()); bounds.bottom += b.get_height(); } } Point d(rect.get_width()-bounds.get_width(),rect.get_height()-bounds.get_height()); if ((get_alignment() & ALIGN_HCENTER)==ALIGN_HCENTER) bounds.offset(Point(d.x/2,0)); else if ((get_alignment() & ALIGN_RIGHT)==ALIGN_RIGHT) bounds.offset(Point(d.x,0)); if ((get_alignment() & ALIGN_VCENTER)==ALIGN_VCENTER) bounds.offset(Point(0,d.y/2)); else if ((get_alignment() & ALIGN_BOTTOM)==ALIGN_BOTTOM) bounds.offset(Point(0,d.y)); int x = bounds.left, y = bounds.top; for (auto& line : lines) { Rect line_bounds = m_Font->get_bounds(line); int dx = 0; if ((get_alignment() & ALIGN_HCENTER) == ALIGN_HCENTER) dx = (bounds.get_width() - line_bounds.get_width()) / 2; else if ((get_alignment() & ALIGN_RIGHT) == ALIGN_RIGHT) dx = (bounds.get_width() - line_bounds.get_width()); m_Font->draw(target, Point(x + dx, y), line, m_Color); y += line_bounds.get_height(); } }
/* output the delayed import thunks of a Win32 module */ static void output_delayed_import_thunks( const DLLSPEC *spec ) { int i, idx, j, pos, extra_stack_storage = 0; static const char delayed_import_loaders[] = "__wine_spec_delayed_import_loaders"; static const char delayed_import_thunks[] = "__wine_spec_delayed_import_thunks"; if (!nb_delayed) return; output( "\n/* delayed import thunks */\n\n" ); output( "\t.text\n" ); output( "\t.align %d\n", get_alignment(8) ); output( "%s:\n", asm_name(delayed_import_loaders)); output( "\t%s\n", func_declaration("__wine_delay_load_asm") ); output( "%s:\n", asm_name("__wine_delay_load_asm") ); output_cfi( ".cfi_startproc" ); switch(target_cpu) { case CPU_x86: output( "\tpushl %%ecx\n" ); output_cfi( ".cfi_adjust_cfa_offset 4" ); output( "\tpushl %%edx\n" ); output_cfi( ".cfi_adjust_cfa_offset 4" ); output( "\tpushl %%eax\n" ); output_cfi( ".cfi_adjust_cfa_offset 4" ); output( "\tcall %s\n", asm_name("__wine_spec_delay_load") ); output_cfi( ".cfi_adjust_cfa_offset -4" ); output( "\tpopl %%edx\n" ); output_cfi( ".cfi_adjust_cfa_offset -4" ); output( "\tpopl %%ecx\n" ); output_cfi( ".cfi_adjust_cfa_offset -4" ); output( "\tjmp *%%eax\n" ); break; case CPU_x86_64: output( "\tsubq $88,%%rsp\n" ); output_cfi( ".cfi_adjust_cfa_offset 88" ); output( "\tmovq %%rdx,80(%%rsp)\n" ); output( "\tmovq %%rcx,72(%%rsp)\n" ); output( "\tmovq %%r8,64(%%rsp)\n" ); output( "\tmovq %%r9,56(%%rsp)\n" ); output( "\tmovq %%r10,48(%%rsp)\n" ); output( "\tmovq %%r11,40(%%rsp)\n" ); output( "\tmovq %%rax,%%rcx\n" ); output( "\tcall %s\n", asm_name("__wine_spec_delay_load") ); output( "\tmovq 40(%%rsp),%%r11\n" ); output( "\tmovq 48(%%rsp),%%r10\n" ); output( "\tmovq 56(%%rsp),%%r9\n" ); output( "\tmovq 64(%%rsp),%%r8\n" ); output( "\tmovq 72(%%rsp),%%rcx\n" ); output( "\tmovq 80(%%rsp),%%rdx\n" ); output( "\taddq $88,%%rsp\n" ); output_cfi( ".cfi_adjust_cfa_offset -88" ); output( "\tjmp *%%rax\n" ); break; case CPU_SPARC: output( "\tsave %%sp, -96, %%sp\n" ); output( "\tcall %s\n", asm_name("__wine_spec_delay_load") ); output( "\tmov %%g1, %%o0\n" ); output( "\tjmp %%o0\n" ); output( "\trestore\n" ); break; case CPU_ARM: output( "\tstmfd SP!, {r4-r10,FP,LR}\n" ); output( "\tmov LR,PC\n"); output( "\tadd LR,LR,#8\n"); output( "\tldr PC,[PC,#-4]\n"); output( "\t.long %s\n", asm_name("__wine_spec_delay_load") ); output( "\tmov IP,r0\n"); output( "\tldmfd SP!, {r4-r10,FP,LR}\n" ); output( "\tldmfd SP!, {r0-r3}\n" ); output( "\tmov PC,IP\n"); break; case CPU_ARM64: output( "\tstp x29, x30, [sp,#-16]!\n" ); output( "\tmov x29, sp\n" ); output( "\tadr x9, 1f\n" ); output( "\tldur x9, [x9, #0]\n" ); output( "\tblr x9\n" ); output( "\tmov x9, x0\n" ); output( "\tldp x29, x30, [sp],#16\n" ); output( "\tldp x0, x1, [sp,#16]\n" ); output( "\tldp x2, x3, [sp,#32]\n" ); output( "\tldp x4, x5, [sp,#48]\n" ); output( "\tldp x6, x7, [sp],#80\n" ); output( "\tbr x9\n" ); /* or "ret x9" */ output( "1:\t.quad %s\n", asm_name("__wine_spec_delay_load") ); break; case CPU_POWERPC: if (target_platform == PLATFORM_APPLE) extra_stack_storage = 56; /* Save all callee saved registers into a stackframe. */ output( "\tstwu %s, -%d(%s)\n",ppc_reg(1), 48+extra_stack_storage, ppc_reg(1)); output( "\tstw %s, %d(%s)\n", ppc_reg(3), 4+extra_stack_storage, ppc_reg(1)); output( "\tstw %s, %d(%s)\n", ppc_reg(4), 8+extra_stack_storage, ppc_reg(1)); output( "\tstw %s, %d(%s)\n", ppc_reg(5), 12+extra_stack_storage, ppc_reg(1)); output( "\tstw %s, %d(%s)\n", ppc_reg(6), 16+extra_stack_storage, ppc_reg(1)); output( "\tstw %s, %d(%s)\n", ppc_reg(7), 20+extra_stack_storage, ppc_reg(1)); output( "\tstw %s, %d(%s)\n", ppc_reg(8), 24+extra_stack_storage, ppc_reg(1)); output( "\tstw %s, %d(%s)\n", ppc_reg(9), 28+extra_stack_storage, ppc_reg(1)); output( "\tstw %s, %d(%s)\n", ppc_reg(10),32+extra_stack_storage, ppc_reg(1)); output( "\tstw %s, %d(%s)\n", ppc_reg(11),36+extra_stack_storage, ppc_reg(1)); output( "\tstw %s, %d(%s)\n", ppc_reg(12),40+extra_stack_storage, ppc_reg(1)); /* r0 -> r3 (arg1) */ output( "\tmr %s, %s\n", ppc_reg(3), ppc_reg(0)); /* save return address */ output( "\tmflr %s\n", ppc_reg(0)); output( "\tstw %s, %d(%s)\n", ppc_reg(0), 44+extra_stack_storage, ppc_reg(1)); /* Call the __wine_delay_load function, arg1 is arg1. */ output( "\tbl %s\n", asm_name("__wine_spec_delay_load") ); /* Load return value from call into ctr register */ output( "\tmtctr %s\n", ppc_reg(3)); /* restore all saved registers and drop stackframe. */ output( "\tlwz %s, %d(%s)\n", ppc_reg(3), 4+extra_stack_storage, ppc_reg(1)); output( "\tlwz %s, %d(%s)\n", ppc_reg(4), 8+extra_stack_storage, ppc_reg(1)); output( "\tlwz %s, %d(%s)\n", ppc_reg(5), 12+extra_stack_storage, ppc_reg(1)); output( "\tlwz %s, %d(%s)\n", ppc_reg(6), 16+extra_stack_storage, ppc_reg(1)); output( "\tlwz %s, %d(%s)\n", ppc_reg(7), 20+extra_stack_storage, ppc_reg(1)); output( "\tlwz %s, %d(%s)\n", ppc_reg(8), 24+extra_stack_storage, ppc_reg(1)); output( "\tlwz %s, %d(%s)\n", ppc_reg(9), 28+extra_stack_storage, ppc_reg(1)); output( "\tlwz %s, %d(%s)\n", ppc_reg(10),32+extra_stack_storage, ppc_reg(1)); output( "\tlwz %s, %d(%s)\n", ppc_reg(11),36+extra_stack_storage, ppc_reg(1)); output( "\tlwz %s, %d(%s)\n", ppc_reg(12),40+extra_stack_storage, ppc_reg(1)); /* Load return value from call into return register */ output( "\tlwz %s, %d(%s)\n", ppc_reg(0), 44+extra_stack_storage, ppc_reg(1)); output( "\tmtlr %s\n", ppc_reg(0)); output( "\taddi %s, %s, %d\n", ppc_reg(1), ppc_reg(1), 48+extra_stack_storage); /* branch to ctr register. */ output( "\tbctr\n"); break; } output_cfi( ".cfi_endproc" ); output_function_size( "__wine_delay_load_asm" ); output( "\n" ); for (i = idx = 0; i < nb_imports; i++) { if (!dll_imports[i]->delay) continue; for (j = 0; j < dll_imports[i]->nb_imports; j++) { ORDDEF *odp = dll_imports[i]->imports[j]; const char *name = odp->name ? odp->name : odp->export_name; output( ".L__wine_delay_imp_%d_%s:\n", i, name ); output_cfi( ".cfi_startproc" ); switch(target_cpu) { case CPU_x86: output( "\tmovl $%d, %%eax\n", (idx << 16) | j ); output( "\tjmp %s\n", asm_name("__wine_delay_load_asm") ); break; case CPU_x86_64: output( "\tmovq $%d,%%rax\n", (idx << 16) | j ); output( "\tjmp %s\n", asm_name("__wine_delay_load_asm") ); break; case CPU_SPARC: output( "\tset %d, %%g1\n", (idx << 16) | j ); output( "\tb,a %s\n", asm_name("__wine_delay_load_asm") ); output( "\tnop\n" ); break; case CPU_ARM: output( "\tstmfd SP!, {r0-r3}\n" ); output( "\tmov r0, #%d\n", idx ); output( "\tmov r1, #16384\n" ); output( "\tmul r1, r0, r1\n" ); output( "\tmov r0, r1\n" ); output( "\tmov r1, #4\n" ); output( "\tmul r1, r0, r1\n" ); output( "\tmov r0, r1\n" ); output( "\tadd r0, #%d\n", j ); output( "\tldr PC,[PC,#-4]\n"); output( "\t.long %s\n", asm_name("__wine_delay_load_asm") ); break; case CPU_ARM64: output( "\tstp x6, x7, [sp,#-80]!\n" ); output( "\tstp x4, x5, [sp,#48]\n" ); output( "\tstp x2, x3, [sp,#32]\n" ); output( "\tstp x0, x1, [sp,#16]\n" ); output( "\tmov x0, #%d\n", idx ); output( "\tmov x1, #16384\n" ); output( "\tmul x1, x0, x1\n" ); output( "\tmov x0, x1\n" ); output( "\tmov x1, #4\n" ); output( "\tmul x1, x0, x1\n" ); output( "\tmov x0, x1\n" ); output( "\tadd x0, x0, #%d\n", j ); output( "\tadr x9, 1f\n" ); output( "\tldur x9, [x9, #0]\n" ); output( "\tbr x9\n" ); output( "1:\t.quad %s\n", asm_name("__wine_delay_load_asm") ); break; case CPU_POWERPC: switch(target_platform) { case PLATFORM_APPLE: /* On Darwin we can use r0 and r2 */ /* Upper part in r2 */ output( "\tlis %s, %d\n", ppc_reg(2), idx); /* Lower part + r2 -> r0, Note we can't use r0 directly */ output( "\taddi %s, %s, %d\n", ppc_reg(0), ppc_reg(2), j); output( "\tb %s\n", asm_name("__wine_delay_load_asm") ); break; default: /* On linux we can't use r2 since r2 is not a scratch register (hold the TOC) */ /* Save r13 on the stack */ output( "\taddi %s, %s, -0x4\n", ppc_reg(1), ppc_reg(1)); output( "\tstw %s, 0(%s)\n", ppc_reg(13), ppc_reg(1)); /* Upper part in r13 */ output( "\tlis %s, %d\n", ppc_reg(13), idx); /* Lower part + r13 -> r0, Note we can't use r0 directly */ output( "\taddi %s, %s, %d\n", ppc_reg(0), ppc_reg(13), j); /* Restore r13 */ output( "\tstw %s, 0(%s)\n", ppc_reg(13), ppc_reg(1)); output( "\taddic %s, %s, 0x4\n", ppc_reg(1), ppc_reg(1)); output( "\tb %s\n", asm_name("__wine_delay_load_asm") ); break; } break; } output_cfi( ".cfi_endproc" ); } idx++; } output_function_size( delayed_import_loaders ); output( "\n\t.align %d\n", get_alignment(get_ptr_size()) ); output( "%s:\n", asm_name(delayed_import_thunks)); for (i = pos = 0; i < nb_imports; i++) { if (!dll_imports[i]->delay) continue; for (j = 0; j < dll_imports[i]->nb_imports; j++, pos += get_ptr_size()) { ORDDEF *odp = dll_imports[i]->imports[j]; output_import_thunk( odp->name ? odp->name : odp->export_name, ".L__wine_delay_IAT", pos ); } } output_function_size( delayed_import_thunks ); }
/* output the delayed import table of a Win32 module */ static void output_delayed_imports( const DLLSPEC *spec ) { int i, j, mod; if (!nb_delayed) return; output( "\n/* delayed imports */\n\n" ); output( "\t.data\n" ); output( "\t.align %d\n", get_alignment(get_ptr_size()) ); output( "%s\n", asm_globl("__wine_spec_delay_imports") ); /* list of dlls */ for (i = j = mod = 0; i < nb_imports; i++) { if (!dll_imports[i]->delay) continue; output( "\t%s 0\n", get_asm_ptr_keyword() ); /* grAttrs */ output( "\t%s .L__wine_delay_name_%d\n", /* szName */ get_asm_ptr_keyword(), i ); output( "\t%s .L__wine_delay_modules+%d\n", /* phmod */ get_asm_ptr_keyword(), mod * get_ptr_size() ); output( "\t%s .L__wine_delay_IAT+%d\n", /* pIAT */ get_asm_ptr_keyword(), j * get_ptr_size() ); output( "\t%s .L__wine_delay_INT+%d\n", /* pINT */ get_asm_ptr_keyword(), j * get_ptr_size() ); output( "\t%s 0\n", get_asm_ptr_keyword() ); /* pBoundIAT */ output( "\t%s 0\n", get_asm_ptr_keyword() ); /* pUnloadIAT */ output( "\t%s 0\n", get_asm_ptr_keyword() ); /* dwTimeStamp */ j += dll_imports[i]->nb_imports; mod++; } output( "\t%s 0\n", get_asm_ptr_keyword() ); /* grAttrs */ output( "\t%s 0\n", get_asm_ptr_keyword() ); /* szName */ output( "\t%s 0\n", get_asm_ptr_keyword() ); /* phmod */ output( "\t%s 0\n", get_asm_ptr_keyword() ); /* pIAT */ output( "\t%s 0\n", get_asm_ptr_keyword() ); /* pINT */ output( "\t%s 0\n", get_asm_ptr_keyword() ); /* pBoundIAT */ output( "\t%s 0\n", get_asm_ptr_keyword() ); /* pUnloadIAT */ output( "\t%s 0\n", get_asm_ptr_keyword() ); /* dwTimeStamp */ output( "\n.L__wine_delay_IAT:\n" ); for (i = 0; i < nb_imports; i++) { if (!dll_imports[i]->delay) continue; for (j = 0; j < dll_imports[i]->nb_imports; j++) { ORDDEF *odp = dll_imports[i]->imports[j]; const char *name = odp->name ? odp->name : odp->export_name; output( "\t%s .L__wine_delay_imp_%d_%s\n", get_asm_ptr_keyword(), i, name ); } } output( "\n.L__wine_delay_INT:\n" ); for (i = 0; i < nb_imports; i++) { if (!dll_imports[i]->delay) continue; for (j = 0; j < dll_imports[i]->nb_imports; j++) { ORDDEF *odp = dll_imports[i]->imports[j]; if (!odp->name) output( "\t%s %d\n", get_asm_ptr_keyword(), odp->ordinal ); else output( "\t%s .L__wine_delay_data_%d_%s\n", get_asm_ptr_keyword(), i, odp->name ); } } output( "\n.L__wine_delay_modules:\n" ); for (i = 0; i < nb_imports; i++) { if (dll_imports[i]->delay) output( "\t%s 0\n", get_asm_ptr_keyword() ); } for (i = 0; i < nb_imports; i++) { if (!dll_imports[i]->delay) continue; output( ".L__wine_delay_name_%d:\n", i ); output( "\t%s \"%s\"\n", get_asm_string_keyword(), dll_imports[i]->spec->file_name ); } for (i = 0; i < nb_imports; i++) { if (!dll_imports[i]->delay) continue; for (j = 0; j < dll_imports[i]->nb_imports; j++) { ORDDEF *odp = dll_imports[i]->imports[j]; if (!odp->name) continue; output( ".L__wine_delay_data_%d_%s:\n", i, odp->name ); output( "\t%s \"%s\"\n", get_asm_string_keyword(), odp->name ); } } output_function_size( "__wine_spec_delay_imports" ); }
/* output the import table of a Win32 module */ static void output_immediate_imports(void) { int i, j; const char *dll_name; if (nb_imports == nb_delayed) return; /* no immediate imports */ /* main import header */ output( "\n/* import table */\n" ); output( "\n\t.data\n" ); output( "\t.align %d\n", get_alignment(4) ); output( ".L__wine_spec_imports:\n" ); /* list of dlls */ for (i = j = 0; i < nb_imports; i++) { if (dll_imports[i]->delay) continue; dll_name = make_c_identifier( dll_imports[i]->spec->file_name ); output( "\t.long .L__wine_spec_import_data_names+%d-.L__wine_spec_rva_base\n", /* OriginalFirstThunk */ j * get_ptr_size() ); output( "\t.long 0\n" ); /* TimeDateStamp */ output( "\t.long 0\n" ); /* ForwarderChain */ output( "\t.long .L__wine_spec_import_name_%s-.L__wine_spec_rva_base\n", /* Name */ dll_name ); output( "\t.long .L__wine_spec_import_data_ptrs+%d-.L__wine_spec_rva_base\n", /* FirstThunk */ j * get_ptr_size() ); j += dll_imports[i]->nb_imports + 1; } output( "\t.long 0\n" ); /* OriginalFirstThunk */ output( "\t.long 0\n" ); /* TimeDateStamp */ output( "\t.long 0\n" ); /* ForwarderChain */ output( "\t.long 0\n" ); /* Name */ output( "\t.long 0\n" ); /* FirstThunk */ output( "\n\t.align %d\n", get_alignment(get_ptr_size()) ); output( ".L__wine_spec_import_data_names:\n" ); for (i = 0; i < nb_imports; i++) { if (dll_imports[i]->delay) continue; dll_name = make_c_identifier( dll_imports[i]->spec->file_name ); for (j = 0; j < dll_imports[i]->nb_imports; j++) { ORDDEF *odp = dll_imports[i]->imports[j]; if (!(odp->flags & FLAG_NONAME)) output( "\t%s .L__wine_spec_import_data_%s_%s-.L__wine_spec_rva_base\n", get_asm_ptr_keyword(), dll_name, odp->name ); else { if (get_ptr_size() == 8) output( "\t.quad 0x800000000000%04x\n", odp->ordinal ); else output( "\t.long 0x8000%04x\n", odp->ordinal ); } } output( "\t%s 0\n", get_asm_ptr_keyword() ); } output( ".L__wine_spec_import_data_ptrs:\n" ); for (i = 0; i < nb_imports; i++) { if (dll_imports[i]->delay) continue; for (j = 0; j < dll_imports[i]->nb_imports; j++) output( "\t%s 0\n", get_asm_ptr_keyword() ); output( "\t%s 0\n", get_asm_ptr_keyword() ); } output( ".L__wine_spec_imports_end:\n" ); for (i = 0; i < nb_imports; i++) { if (dll_imports[i]->delay) continue; dll_name = make_c_identifier( dll_imports[i]->spec->file_name ); for (j = 0; j < dll_imports[i]->nb_imports; j++) { ORDDEF *odp = dll_imports[i]->imports[j]; if (!(odp->flags & FLAG_NONAME)) { output( "\t.align %d\n", get_alignment(2) ); output( ".L__wine_spec_import_data_%s_%s:\n", dll_name, odp->name ); output( "\t%s %d\n", get_asm_short_keyword(), odp->ordinal ); output( "\t%s \"%s\"\n", get_asm_string_keyword(), odp->name ); } } } for (i = 0; i < nb_imports; i++) { if (dll_imports[i]->delay) continue; dll_name = make_c_identifier( dll_imports[i]->spec->file_name ); output( ".L__wine_spec_import_name_%s:\n\t%s \"%s\"\n", dll_name, get_asm_string_keyword(), dll_imports[i]->spec->file_name ); } }
/* output a single import thunk */ static void output_import_thunk( const char *name, const char *table, int pos ) { output( "\n\t.align %d\n", get_alignment(4) ); output( "\t%s\n", func_declaration(name) ); output( "%s\n", asm_globl(name) ); output_cfi( ".cfi_startproc" ); switch(target_cpu) { case CPU_x86: if (!UsePIC) { output( "\tjmp *(%s+%d)\n", table, pos ); } else { output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") ); output( "1:\tjmp *%s+%d-1b(%%eax)\n", table, pos ); } break; case CPU_x86_64: output( "\tjmpq *%s+%d(%%rip)\n", table, pos ); break; case CPU_SPARC: if ( !UsePIC ) { output( "\tsethi %%hi(%s+%d), %%g1\n", table, pos ); output( "\tld [%%g1+%%lo(%s+%d)], %%g1\n", table, pos ); output( "\tjmp %%g1\n" ); output( "\tnop\n" ); } else { /* Hmpf. Stupid sparc assembler always interprets global variable names as GOT offsets, so we have to do it the long way ... */ output( "\tsave %%sp, -96, %%sp\n" ); output( "0:\tcall 1f\n" ); output( "\tnop\n" ); output( "1:\tsethi %%hi(%s+%d-0b), %%g1\n", table, pos ); output( "\tor %%g1, %%lo(%s+%d-0b), %%g1\n", table, pos ); output( "\tld [%%g1+%%o7], %%g1\n" ); output( "\tjmp %%g1\n" ); output( "\trestore\n" ); } break; case CPU_ARM: output( "\tldr IP,[PC,#0]\n"); output( "\tldr PC,[IP,#%d]\n", pos); output( "\t.long %s\n", table ); break; case CPU_ARM64: output( "\tadr x9, 1f\n" ); output( "\tldur x9, [x9, #0]\n" ); if (pos & 0xf000) output( "\tadd x9, x9, #%u\n", pos & 0xf000 ); if (pos & 0x0f00) output( "\tadd x9, x9, #%u\n", pos & 0x0f00 ); if (pos & 0x00f0) output( "\tadd x9, x9, #%u\n", pos & 0x00f0 ); if (pos & 0x000f) output( "\tadd x9, x9, #%u\n", pos & 0x000f ); output( "\tldur x9, [x9, #0]\n" ); output( "\tbr x9\n" ); output( "1:\t.quad %s\n", table ); break; case CPU_POWERPC: output( "\tmr %s, %s\n", ppc_reg(0), ppc_reg(31) ); if (target_platform == PLATFORM_APPLE) { output( "\tlis %s, ha16(%s+%d+32768)\n", ppc_reg(31), table, pos ); output( "\tla %s, lo16(%s+%d)(%s)\n", ppc_reg(31), table, pos, ppc_reg(31) ); } else { output( "\tlis %s, (%s+%d+32768)@h\n", ppc_reg(31), table, pos ); output( "\tla %s, (%s+%d)@l(%s)\n", ppc_reg(31), table, pos, ppc_reg(31) ); } output( "\tlwz %s, 0(%s)\n", ppc_reg(31), ppc_reg(31) ); output( "\tmtctr %s\n", ppc_reg(31) ); output( "\tmr %s, %s\n", ppc_reg(31), ppc_reg(0) ); output( "\tbctr\n" ); break; } output_cfi( ".cfi_endproc" ); output_function_size( name ); }
/* output the resource definitions */ void output_resources( DLLSPEC *spec ) { int k, nb_id_types; unsigned int i, n; struct res_tree *tree; struct res_type *type; struct res_name *name; const struct resource *res; if (!spec->nb_resources) return; tree = build_resource_tree( spec, NULL ); /* output the resource directories */ output( "\n/* resources */\n\n" ); output( "\t.data\n" ); output( "\t.align %d\n", get_alignment(get_ptr_size()) ); output( ".L__wine_spec_resources:\n" ); for (i = nb_id_types = 0, type = tree->types; i < tree->nb_types; i++, type++) if (!type->type->str) nb_id_types++; output_res_dir( tree->nb_types - nb_id_types, nb_id_types ); /* dump the type directory */ for (i = 0, type = tree->types; i < tree->nb_types; i++, type++) output( "\t.long 0x%08x,0x%08x\n", type->name_offset, type->dir_offset | 0x80000000 ); /* dump the names and languages directories */ for (i = 0, type = tree->types; i < tree->nb_types; i++, type++) { output_res_dir( type->nb_names - type->nb_id_names, type->nb_id_names ); for (n = 0, name = type->names; n < type->nb_names; n++, name++) output( "\t.long 0x%08x,0x%08x\n", name->name_offset, name->dir_offset | 0x80000000 ); for (n = 0, name = type->names; n < type->nb_names; n++, name++) { output_res_dir( 0, name->nb_languages ); for (k = 0, res = name->res; k < name->nb_languages; k++, res++) output( "\t.long 0x%08x,0x%08x\n", res->lang, res->data_offset ); } } /* dump the resource data entries */ for (i = 0, res = spec->resources; i < spec->nb_resources; i++, res++) output( "\t.long .L__wine_spec_res_%d-.L__wine_spec_rva_base,%u,0,0\n", i, (res->data_size + 3) & ~3 ); /* dump the name strings */ for (i = 0, type = tree->types; i < tree->nb_types; i++, type++) { if (type->type->str) output_string( type->type->str ); for (n = 0, name = type->names; n < type->nb_names; n++, name++) if (name->name->str) output_string( name->name->str ); } /* resource data */ for (i = 0, res = spec->resources; i < spec->nb_resources; i++, res++) { output( "\n\t.align %d\n", get_alignment(get_ptr_size()) ); output( ".L__wine_spec_res_%d:\n", i ); dump_res_data( res ); } output( ".L__wine_spec_resources_end:\n" ); output( "\t.byte 0\n" ); free_resource_tree( tree ); }
/******************************************************************* * output_stubs * * Output the functions for stub entry points */ void output_stubs( DLLSPEC *spec ) { const char *name, *exp_name; int i, count; if (!has_stubs( spec )) return; output( "\n/* stub functions */\n\n" ); output( "\t.text\n" ); for (i = count = 0; i < spec->nb_entry_points; i++) { ORDDEF *odp = &spec->entry_points[i]; if (odp->type != TYPE_STUB) continue; name = get_stub_name( odp, spec ); exp_name = odp->name ? odp->name : odp->export_name; output( "\t.align %d\n", get_alignment(4) ); output( "\t%s\n", func_declaration(name) ); output( "%s:\n", asm_name(name) ); output_cfi( ".cfi_startproc" ); switch (target_cpu) { case CPU_x86: /* flesh out the stub a bit to make safedisc happy */ output(" \tnop\n" ); output(" \tnop\n" ); output(" \tnop\n" ); output(" \tnop\n" ); output(" \tnop\n" ); output(" \tnop\n" ); output(" \tnop\n" ); output(" \tnop\n" ); output(" \tnop\n" ); output( "\tsubl $12,%%esp\n" ); output_cfi( ".cfi_adjust_cfa_offset 12" ); if (UsePIC) { output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") ); output( "1:" ); if (exp_name) { output( "\tleal .L%s_string-1b(%%eax),%%ecx\n", name ); output( "\tmovl %%ecx,4(%%esp)\n" ); count++; } else output( "\tmovl $%d,4(%%esp)\n", odp->ordinal ); output( "\tleal .L__wine_spec_file_name-1b(%%eax),%%ecx\n" ); output( "\tmovl %%ecx,(%%esp)\n" ); } else { if (exp_name) { output( "\tmovl $.L%s_string,4(%%esp)\n", name ); count++; } else output( "\tmovl $%d,4(%%esp)\n", odp->ordinal ); output( "\tmovl $.L__wine_spec_file_name,(%%esp)\n" ); } output( "\tcall %s\n", asm_name("__wine_spec_unimplemented_stub") ); break; case CPU_x86_64: output( "\tsubq $8,%%rsp\n" ); output_cfi( ".cfi_adjust_cfa_offset 8" ); output( "\tleaq .L__wine_spec_file_name(%%rip),%%rdi\n" ); if (exp_name) { output( "leaq .L%s_string(%%rip),%%rsi\n", name ); count++; } else output( "\tmovq $%d,%%rsi\n", odp->ordinal ); output( "\tcall %s\n", asm_name("__wine_spec_unimplemented_stub") ); break; case CPU_ARM: output( "\tldr r0,[PC,#0]\n"); output( "\tmov PC,PC\n"); output( "\t.long .L__wine_spec_file_name\n" ); output( "\tldr r1,[PC,#0]\n"); output( "\tmov PC,PC\n"); if (exp_name) { output( "\t.long .L%s_string\n", name ); count++; } else output( "\t.long %d\n", odp->ordinal ); output( "\tbl %s\n", asm_name("__wine_spec_unimplemented_stub") ); break; default: assert(0); } output_cfi( ".cfi_endproc" ); output_function_size( name ); } if (count) { output( "\t%s\n", get_asm_string_section() ); for (i = 0; i < spec->nb_entry_points; i++) { ORDDEF *odp = &spec->entry_points[i]; if (odp->type != TYPE_STUB) continue; exp_name = odp->name ? odp->name : odp->export_name; if (exp_name) { name = get_stub_name( odp, spec ); output( ".L%s_string:\n", name ); output( "\t%s \"%s\"\n", get_asm_string_keyword(), exp_name ); } } } }