void PrintLabel( const char *labelName, const char *format, va_list *args ) { Str *label = StrNew( labelName ); Str *formatString = StrNew( format ); Str *messageString = StrConcat( label, formatString ); Print( messageString->value, args ); StrDel( label ); StrDel( formatString ); StrDel( messageString ); }
bool ParseInstString(XEDPARSE* Parse, Inst* Instruction) { // Copy a buffer to edit char buf[XEDPARSE_MAXBUFSIZE]; strcpy(buf, Parse->instr); // Find near/far modifiers Instruction->Near = StrDel(buf, "near", ' '); Instruction->Far = StrDel(buf, "far", ' '); Instruction->Short = StrDel(buf, "short", ' '); // Limit the number of possible modifiers to 1 at a time if(((int)Instruction->Near + (int)Instruction->Far + (int)Instruction->Short) > 1) { strcpy(Parse->error, "Instruction cannot have multiple modifiers (short, near, far)"); return false; } // Parse into tokens char tokens[8][64]; memset(tokens, 0, sizeof(tokens)); int tokenIndex = 0; int tokenCount = InstructionToTokens(buf, tokens); if(tokenCount <= 0) { strcpy(Parse->error, "Malformed or invalid instruction"); return false; } // Prefix Instruction->Prefix = PrefixFromString(tokens[tokenIndex]); if(Instruction->Prefix != PREFIX_NONE) tokenIndex++; // Mnemonic strcpy(Instruction->Mnemonic, tokens[tokenIndex++]); // Operands for(int i = tokenIndex; i < tokenCount; i++) { if(!AnalyzeOperand(Parse, tokens[i], &Instruction->Operands[Instruction->OperandCount++])) return false; } if(Instruction->OperandCount > 4) { strcpy(Parse->error, "Instruction has more than 4 operands"); return false; } // Verify and translate the mnemonic this time Instruction->Class = str2xed_iclass_enum_t(MnemonicInstToXed(Parse, Instruction)); if(Instruction->Class == XED_ICLASS_INVALID) { sprintf(Parse->error, "Unknown instruction mnemonic '%s'", Instruction->Mnemonic); return false; } return true; }
bool HandleMemoryOperand(XEDPARSE* Parse, const char* Value, InstOperand* Operand) { // Copy the prefix into a buffer char prefix[64]; strcpy(prefix, Value); *strchr(prefix, '[') = '\0'; // Copy the calculation into a buffer (strrchr is intentional) char calc[64]; if(strrchr(Value, '[') > strrchr(Value, ']')) { // Someone tried using a closing bracket before the opening strcpy(Parse->error, "Invalid memory bracket open/close pair"); return false; } strcpy(calc, strrchr(Value, '[') + 1); *strchr(calc, ']') = '\0'; // Gather any information & check the prefix validity if(strlen(prefix) > 0) { // Prefix must be lowercase _strlwr(prefix); // Remove 'ptr' if it exists and remove colons StrDel(prefix, "ptr", '\0'); StrDel(prefix, ":", '\0'); // Check if the segment can be used size_t len = strlen(prefix); if(len >= 2) { // Move backwards in order to get the segment (SIZE-SEG[CALC]) char* segPtr = (prefix + (len - 2)); // See if the segment is actually valid REG segment = RegFromString(segPtr); if(segment != REG_INVALID) { // Set the new segment Operand->Segment = segment; // End the string here *segPtr = '\0'; } } // Determine the prefix size Operand->Size = OpsizeFromString(prefix); // If the size is UNSET and there's still chars left in the string, // it is an invalid identifier if(Operand->Size == SIZE_UNSET && strlen(prefix) > 0) { sprintf(Parse->error, "Unknown identifier in '%s'", Value); return false; } // Update the effective operand size for Xed Operand->XedEOSZ = OpsizeToEosz(Operand->Size); } // Begin determining the calculation // [Base + (Index * Scale) + Displacement] -- IN ANY ORDER if(strlen(calc) <= 0) { strcpy(Parse->error, "Invalid memory calculation"); return false; } char temp[32]; char* ptr = calc; char* base = temp; bool mulFlag = false; for(;; ptr++) { *base = '\0'; switch(*ptr) { case '\0': case '+': case '-': if(mulFlag) SetMemoryIndexOrScale(Parse, temp, Operand); else SetMemoryDisplacementOrBase(Parse, temp, Operand); base = temp; mulFlag = false; if(*ptr == '-') *base++ = '-'; break; case '*': SetMemoryIndexOrScale(Parse, temp, Operand); base = temp; mulFlag = true; break; default: *base++ = *ptr; break; } if(*ptr == '\0') break; } // Fix up the operand segment if(Operand->Segment == REG_INVALID) { if((Operand->Mem.BaseVal == REG_ESP || Operand->Mem.BaseVal == REG_EBP) && !Parse->x64) { // If the segment isn't set and the base is ESP or EBP, // auto-set the segment to SS Operand->Segment = REG_SS; } else { // Default to DS // 64-bit also doesn't have true segments except for FS/GS/DS Operand->Segment = REG_DS; } } if(Operand->Mem.Disp) { // If the base isn't set, the displacement must be at least 32 bits if(!Operand->Mem.Base) Operand->Mem.DispWidth = max(Operand->Mem.DispWidth, SIZE_DWORD); // Use RIP-relative addressing per default when on x64 and when the displacement is set // and when the segment is SEG_DS if(Parse->x64 && Operand->Segment == REG_DS) { if(!Operand->Mem.Base && !Operand->Mem.Index && !Operand->Mem.Scale) { // If a 32-bit address was given, don't apply RIP-relative addressing if(true || Operand->Mem.DispWidth != SIZE_DWORD) //removed this because rip-relative instructions are smaller { LONGLONG newDisp = TranslateRelativeCip(Parse, Operand->Mem.DispVal, true); ULONGLONG masked = newDisp & 0xFFFFFFFF00000000; // Check if the mask fits into a 32-bit variable (taking sign-extension into account) if(masked == 0 || masked == 0xFFFFFFFF00000000) { Operand->Mem.DispVal = newDisp; Operand->Mem.DispWidth = SIZE_DWORD; Operand->Mem.Base = true; Operand->Mem.BaseVal = REG_RIP; Operand->Mem.ImplicitRip = true; } else Operand->Mem.DispWidth = SIZE_QWORD; } } } } else if(!Operand->Mem.Base && Operand->Mem.Index && Operand->Mem.Scale) { // Handle when only an index register and scale are set // Ex: MOV EAX, [ECX * 8] Operand->Mem.Disp = true; Operand->Mem.DispVal = 0; Operand->Mem.DispWidth = SIZE_DWORD; } return true; }