/**************************************************************************** * * Open Watcom Project * * Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved. * * ======================================================================== * * This file contains Original Code and/or Modifications of Original * Code as defined in and that are subject to the Sybase Open Watcom * Public License version 1.0 (the 'License'). You may not use this file * except in compliance with the License. BY USING THIS FILE YOU AGREE TO * ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is * provided with the Original Code and Modifications, and is also * available at www.sybase.com/developer/opensource. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR * NON-INFRINGEMENT. Please see the License for the specific language * governing rights and limitations under the License. * * ======================================================================== * * Description: ALIGN, EVEN, ORG directives * ****************************************************************************/ #include "globals.h" #include "parser.h" #include "segment.h" #include "expreval.h" #include "types.h" #include "listing.h" #include "posndir.h" #include "fastpass.h" #include "fixup.h" #include "input.h" #include "myassert.h" static const uint_8 NopList16[] = { 3, /* objlen of first NOP pattern */ 0x2E, 0x8b, 0xc0, /* MOV AX,AX */ /* v2.11: Masm v6+ uses 8B CO; Masm v5 uses 87 DB (xchg bx, bx) */ //0x89, 0xc0, /* MOV AX,AX */ 0x8b, 0xc0, /* MOV AX,AX */ 0x90 /* NOP */ }; /* 32bit alignment fillers. For 5 bytes, Masm uses "add eax,dword ptr 0", which modifies the flags! */ static const uint_8 NopList32[] = { 7, 0x8d,0xa4,0x24,0,0,0,0, /* lea esp,[esp+00000000] */ 0x8d,0x80,0,0,0,0, /* lea eax,[eax+00000000] */ #if 0 0x8d,0x40,0x00, /* lea eax,[eax+00] */ 0x8b,0xc9, /* mov ecx,ecx */ #else 0x2e,0x8d,0x44,0x20,0x00, /* lea eax,cs:[eax+no_index_reg+00H] */ #endif 0x8d,0x44,0x20,0x00, /* lea eax,[eax+no_index_reg+00H] */ 0x8d,0x40,0x00, /* lea eax,[eax+00H] */ 0x8b,0xff, /* mov edi,edi */ 0x90 /* nop */ }; #if AMD64_SUPPORT static const uint_8 NopList64[] = { 7, 0x0f,0x1f,0x80,0,0,0,0, /* nop dword ptr [rax+0] */ 0x66,0x0f,0x1f,0x44,0,0, /* nop word ptr [rax+rax] */ 0x0f,0x1f,0x44,0,0, /* nop dword ptr [rax+rax] */ 0x0f,0x1f,0x40,0, /* nop dword ptr [rax] */ 0x0f,0x1f,0, /* nop dword ptr [rax] */ 0x66,0x90, /* xchg ax,ax */ 0x90, /* nop */ }; /* just use the 32bit nops for 64bit */ static const uint_8 * const NopLists[] = { NopList16, NopList32, NopList64 }; #else static const uint_8 * const NopLists[] = { NopList16, NopList32 }; #endif ret_code OrgDirective( int i, struct asm_tok tokenarray[] ) /*********************************************************/ { //struct asym *sym; //int_32 value = 0; struct expr opndx; DebugMsg1(("OrgDirective(%u) enter\n", i)); i++; /* v2.09: if -Zne is set, don't allow forward reference in ORG argument */ //if ( ( ERROR == EvalOperand( &i, tokenarray, Token_Count, &opndx, 0 ) ) ) if ( ( ERROR == EvalOperand( &i, tokenarray, Token_Count, &opndx, Options.strict_masm_compat ? EXPF_NOUNDEF : 0 ) ) ) return( ERROR ); if ( tokenarray[i].token != T_FINAL ) { return( EmitErr( SYNTAX_ERROR_EX, tokenarray[i].string_ptr ) ); } if ( CurrStruct ) { if ( opndx.kind == EXPR_CONST ) return( SetStructCurrentOffset( opndx.value ) ); } else { if( CurrSeg == NULL ) { return( EmitError( MUST_BE_IN_SEGMENT_BLOCK ) ); } #if FASTPASS if ( StoreState == FALSE ) FStoreLine(0); #endif /* v2.04: added */ if ( Parse_Pass == PASS_1 && CurrSeg->e.seginfo->FixupList.head ) CurrSeg->e.seginfo->FixupList.head->orgoccured = TRUE; if ( opndx.kind == EXPR_CONST ) return( SetCurrOffset( CurrSeg, opndx.value, FALSE, FALSE ) ); else if ( opndx.kind == EXPR_ADDR && opndx.indirect == FALSE ) return( SetCurrOffset( CurrSeg, opndx.sym->offset + opndx.value, FALSE, FALSE ) ); } return( EmitError( ORG_NEEDS_A_CONSTANT_OR_LOCAL_OFFSET ) ); } static void fill_in_objfile_space( unsigned size ) /************************************************/ { int i; int nop_type; /* emit - nothing ... for BSS - x'00' ... for DATA - nops ... for CODE */ /* v2.04: no output if nothing has been written yet */ if( CurrSeg->e.seginfo->written == FALSE ) { SetCurrOffset( CurrSeg, size, TRUE, TRUE ); } else if( CurrSeg->e.seginfo->segtype != SEGTYPE_CODE ) { FillDataBytes( 0x00, size ); /* just output nulls */ } else { /* output appropriate NOP type instructions to fill in the gap */ while( size > NopLists[ ModuleInfo.Ofssize ][0] ) { for( i = 1; i <= NopLists[ ModuleInfo.Ofssize ][0]; i++ ) { OutputByte( NopLists[ ModuleInfo.Ofssize ][i] ); } size -= NopLists[ ModuleInfo.Ofssize ][0]; } if( size == 0 ) return; i=1; /* here i is the index into the NOP table */ for( nop_type = NopLists[ ModuleInfo.Ofssize ][0]; nop_type > size ; nop_type-- ) { i+=nop_type; } /* i now is the index of the 1st part of the NOP that we want */ for( ; nop_type > 0; nop_type--,i++ ) { OutputByte( NopLists[ ModuleInfo.Ofssize ][i] ); } } } /* align current offset to value ( alignment is 2^value ) */ void AlignCurrOffset( int value ) /*******************************/ { int seg_align; int alignment = (1 << value); unsigned int CurrAddr; CurrAddr = GetCurrOffset(); seg_align = CurrAddr % alignment; if( seg_align ) { alignment -= seg_align; fill_in_objfile_space( alignment ); } } #define align_value opndx.value ret_code AlignDirective( int i, struct asm_tok tokenarray[] ) /***********************************************************/ { int seg_align; struct expr opndx; uint_32 CurrAddr; char buffer[32]; DebugMsg1(("AlignDirective enter\n")); switch( tokenarray[i].tokval ) { case T_ALIGN: i++; if ( EvalOperand( &i, tokenarray, Token_Count, &opndx, EXPF_NOUNDEF ) == ERROR ) return( ERROR ); if ( opndx.kind == EXPR_CONST ) { int_32 power; /* check that the parm is a power of 2 */ for( power = 1; power < align_value; power <<= 1 ); if( power != align_value ) { return( EmitErr( POWER_OF_2, align_value ) ); } } else if ( opndx.kind == EXPR_EMPTY ) { /* ALIGN without argument? */ /* v2.03: special STRUCT handling was missing */ if ( CurrStruct ) align_value = CurrStruct->e.structinfo->alignment; else align_value = GetCurrSegAlign(); } else { return( EmitError( CONSTANT_EXPECTED ) ); } break; case T_EVEN: align_value = 2; i++; break; } if ( tokenarray[i].token != T_FINAL ) { return( EmitErr( SYNTAX_ERROR_EX, tokenarray[i].string_ptr ) ); } /* ALIGN/EVEN inside a STRUCT definition? */ if ( CurrStruct ) return( AlignInStruct( align_value )); #if FASTPASS if ( StoreState == FALSE ) FStoreLine(0); #endif seg_align = GetCurrSegAlign(); /* # of bytes */ if( seg_align <= 0 ) { return( EmitError( MUST_BE_IN_SEGMENT_BLOCK ) ); } if( align_value > seg_align ) { if ( Parse_Pass == PASS_1 ) EmitWarn( 1, ALIGN_TOO_HIGH, myltoa( align_value, buffer, 10, FALSE, FALSE ) ); //return( ERROR ); /* v2.0: don't exit */ } /* v2.04: added, Skip backpatching after ALIGN occured */ if ( Parse_Pass == PASS_1 && CurrSeg && CurrSeg->e.seginfo->FixupList.head ) CurrSeg->e.seginfo->FixupList.head->orgoccured = TRUE; /* find out how many bytes past alignment we are & add the remainder */ /* store temp. value */ CurrAddr = GetCurrOffset(); seg_align = CurrAddr % align_value; if( seg_align ) { align_value -= seg_align; fill_in_objfile_space( align_value ); } if ( CurrFile[LST] ) { LstWrite( LSTTYPE_DATA, CurrAddr, NULL ); } DebugMsg1(("AlignDirective exit\n")); return( NOT_ERROR ); }