IF and ELSE IF statements in MASM x86 - masm

Basically, I try to translate this simple if else statement in C++ into MASM:
int i = 90;
if (i <100 and i >= 90)
cout <<" You got an A for this course!" <<endl;
else if(i >= 80)
cout <<"You got a B for this course! " <<endl;
else if (i >= 70)
cout <<"You got a C for this course! "<<endl;
else
cout <<"You fail this course! "<<endl;
So here is that I have in MASM using Irvine library:
.data
T dword 75
prompt6 byte "You got an A for this course! ",0
prompt7 byte "You got a B for this course! ",0
prompt8 byte "You got a C for this course! ",0
prompt9 byte "You have failed this course! ",0
.code
main PROC
call grading
exit
main ENDP
grading PROC
cmp T, 100
jle A
cmp T,90
jl B
cmp T,80
jl D
jmp fail
A:
cmp T,90
jge gradeA
gradeA:
mov edx, offset prompt6
call WriteString
jmp L1
B:
cmp T,80
jge gradeB
D:
cmp T,70
jge gradeC
gradeC:
mov edx,offset prompt8
call WriteString
jmp L1
gradeB:
mov edx, offset prompt7
call WriteString
jmp L1
fail:
mov edx, offset prompt9
call WriteString
jmp L1
L1:
ret
grading ENDP
END main
The problem I ran into was that the result for the program in MASM always showing "You got an A for this course!" no matter how I change T. I was wondering where is the problem in the MASM program and how I should I go about fixing it so that it will show the correct result based on T.

Related

What is the decompiled (C) code construct of this assembly x86 code?

This code compares every char of a string (located at ebp+arg_0) with different constants (ASCII chars) like 'I', 'o' and 'S'. I guess, based on other code parts, this code is originally written in C.
This compare-code-part looks very inefficient to. My question, how do you think this code will look in C? What code construct was used originally? my thoughts so far
It's not a for loop. Because i don't see any upward jump and stop-condition.
It's not a while/case/switch code construct
My best guess is that this are a lot of consecutive if/else statements.
Can you help?
Yes it's part of a challenge, i already have the flag/solution, no worries about that. Just trying to better understand the code.
It's not a for loop. Because i don't see any upward jump and stop-condition.
Correct.
It's not a while/case/switch code constuct
It can't be, it compares different indicies of the array.
My best guess is that this are a lot of consecutive if/elses. Can you help?
Looks like it could be this code:
void f(const char* arg_0) {
if(arg_0[4] == 'I' && arg_0[5] == 'o' && arg_0[6] == 'S') {
printf("Gratz man :)");
exit(0); //noreturn, hence your control flow ends here in the assembly
}
puts("Wrong password"); // Or `printf("Wrong password\n");` which gets optimized to `puts`
// leave, retn
}
This is how gcc compiles it without optimizations:
.LC0:
.string "Gratz man :)"
.LC1:
.string "Wrong password"
f(char const*):
push ebp
mov ebp, esp
sub esp, 8
mov eax, DWORD PTR [ebp+8]
add eax, 4
movzx eax, BYTE PTR [eax]
cmp al, 73
jne .L2
mov eax, DWORD PTR [ebp+8]
add eax, 5
movzx eax, BYTE PTR [eax]
cmp al, 111
jne .L2
mov eax, DWORD PTR [ebp+8]
add eax, 6
movzx eax, BYTE PTR [eax]
cmp al, 83
jne .L2
sub esp, 12
push OFFSET FLAT:.LC0
call printf
add esp, 16
sub esp, 12
push 0
call exit
.L2:
sub esp, 12
push OFFSET FLAT:.LC1
call puts
add esp, 16
nop
leave
ret
Looks very similar to your disassembled code.
This compare-code-part looks very inefficient
Looks like it was compiled without optimizations. With optimizations enabled, gcc compiled the code to:
.LC0:
.string "Gratz man :)"
.LC1:
.string "Wrong password"
f(char const*):
sub esp, 12
mov eax, DWORD PTR [esp+16]
cmp BYTE PTR [eax+4], 73
jne .L2
cmp BYTE PTR [eax+5], 111
je .L5
.L2:
mov DWORD PTR [esp+16], OFFSET FLAT:.LC1
add esp, 12
jmp puts
.L5:
cmp BYTE PTR [eax+6], 83
jne .L2
sub esp, 12
push OFFSET FLAT:.LC0
call printf
mov DWORD PTR [esp], 0
call exit
Not sure why gcc decided to jump down and back up again instead of a straight line of jnes. Also, the ret is gone, your printf got tail-call-optimized, i.e. a jmp printf istead of a call printf followed by a ret.
The first argument (arg_0) is a pointer to the given password string, e.g., const char *arg_0. This pointer (the address of the first character) is loaded into the eax register (mov eax, [ebp+arg_0]), and then the index of the current character is added to advance it to that index (add eax, 4 etc.). The single byte at that address is then loaded into eax (movzx eax, byte ptr [eax]).
Then that byte/character is compared against the correct one (cmp eax, 'I', etc). If the result is not zero (i.e., if they are not equal), the program jumps to the "Wrong password" branch (jnz - jump if not zero), otherwise it continues on to the next comparison (and ultimately success).
The nearest direct C equivalent would therefore be something like:
void check(const char *arg_0) {
// presumably comparisons 0-3 are omitted
if (arg_0[4] != 'I') goto fail;
if (arg_0[5] != 'o') goto fail;
if (arg_0[6] != 'S') goto fail;
printf("Gratz man :)");
exit(0);
fail:
puts("Wrong password");
}
(Of course the actual C code is unlikely to have looked like this, since the goto fail arrangement is not typical.)

abnormal program termination turbo c

I am trying to run an combined code of C that calling assembly procedure, and I get abnormal program termination message.
Its very simple code, the assembly procedure scans a number and return the result to c.
;main code
#include<stdio.h>
extern long getPnum();
int main()
{
long x;
x = getPnum();
printf("%d", x);
return 0;
}
;getPNum
.MODEL SMALL
.STACK 100H
.DATA
NUM DD 0
.CODE
.386
PUBLIC _getPnum
_getPnum PROC NEAR
PUSH BP
MOV BP,SP
PUSH EAX
PUSH EBX
PUSH ECX
MOV EBX,10
SCAN:
MOV EAX,NUM
MUL EBX
MOV ECX,EAX
XOR EAX,EAX
MOV AH,1
INT 21H
CMP AL,13
JE NEXT
SUB AL,'0'
MOV AH,0
ADD ECX,EAX
MOV NUM,ECX
JMP SCAN
NEXT:
MOV AX,WORD PTR NUM
MOV DX,WORD PTR NUM+2
ADD SP,14
RET
_getPnum ENDP
END
I changed the %d to ld%, and now I get another error: Dimdie error
It's very strange when I run the DEBUGER I return the number through AX DX,and X gets the wrong value
debugger
result scrren
I Changed
ADD SP,14
RET
to
ADD SP,12
POP BP
RET
and now I don't get any errors, but the printed value is incorrect, despite that the returned value trough DX:AX is correct
BP must be restored when you leave the procedure.
Change
ADD SP,14
RET
to
ADD SP,12
POP BP
RET
Better is:
MOV SP, BP
POP BP
RET
BTW: Why do you push a bunch of registers which you don't restore at the end of the function?

Perfect number C-NASM program not working?

so basically the program prints the factors of a number and checks if the inputted number is a perfect number. However, all the program does is ask for the input and then crashes. I assume that it has an endless loop somewhere in the .asm file. What could be the problem? Any and all suggestions/replies is appreciated. :)
C program:
#include <stdio.h>
extern int factors(int a);
int main()
{
int a1, x;
ag: printf("Enter a number: ");
scanf("%d", &a1);
if(a1 >= 65536)
{
printf("Invalid number, Enter again\n");
goto ag;
}
x = factors(a1);
if(x == 1)
printf("%d is a perfect number\n", a1);
else
printf("%d is not a perfect number", a1);
getchar();
return 0;
}
NASM program:
segment .text
global _factors
_factors:
push ebp ; create stack frame
mov ebp, esp ; save stack
mov eax, [ebp + 8] ; first parameter
mov ebx, 00000001 ; initialize ebx to 1. ebx is the countere
mov ecx, eax ; more eax to ecx in order to preserve the number
agn:
cmp ebx, ecx ; check if the counter is equal to the number
je done
mov eax, ecx
xor dx, dx
div bx
inc ebx
cmp dx, 0
jne agn
mov word [fact], ax
lea dx, [fact]
mov ah, 09h
int 21h
jmp agn
done:
leave
ret
section .data
fact times 5 db "$"
sum times 5 db "$"

NASM Assembly mathematical logic

I have a program in assembly for the Linux terminal that's supposed to work through a series of mathematical manipulations, compare the final value to 20, and then using if logic, report <, > or = relationship. Code is:
segment .data
out_less db "Z is less than 20.", 10, 0
out_greater db "Z is greater than 20.", 10, 0
out_equal db "Z is equal to 20.", 10, 0
segment .bss
segment .text
global main
extern printf
main:
mov eax, 10
mov ebx, 12
mov ecx, eax
add ecx, ebx ;set c (ecx reserved)
mov eax, 3
mov ebx, ecx
sub ebx, eax ;set f (ebx reserved)
mov eax, 12
mul ecx
add ecx, 10 ;(a+b*c) (ecx reserved)
mov eax, 6
mul ebx
mov eax, 3
sub eax, ebx
mov ebx, eax ;(d-e*f) (ebx reserved) reassign to ebx to free eax
mov eax, ecx
div ebx
add ecx, 1 ;(a+b*c)/(d-e*f) + 1
cmp ecx, 20
jl less
jg greater
je equal
mov eax, 0
ret
less:
push out_less
call printf
jmp end
greater:
push out_greater
call printf
jmp end
equal:
push out_equal
call printf
jmp end
end:
mov eax, 0
ret
Commands for compiling in terminal using nasm and gcc:
nasm -f elf iftest.asm
gcc -o iftest iftest.o
./iftest
Equivalent C code would be:
main() {
int a, b, c, d, e, f, z;
a = 10;
b = 12;
c = a + b;
d = 3;
e = 6;
f = c - d;
z = ((a + b*c) / (d - e*f)) + 1;
if (z < 20) {
printf("Z (%d) is less than 20.\n", z);
}
else if (z > 20) {
printf("Z is greater than 20.\n");
}
else {
printf("Z is equal to 20.\n");
}
}
The current output is incorrect. The C code will report that z = -1, and therefore less than 20, but the assembly code outputs Z is greater than 20. I've tried printing out the final value, but I run into this issue where printing the value somehow changes it. I've checked and rechecked the math logic and I can't see why it shouldn't give the correct value, unless I'm using the math operators incorrectly. Any and all help is appreciated.
I think the problem is here:
div ebx
add ecx, 1 ;(a+b*c)/(d-e*f) + 1
The result of the div instruction is not in ecx.

Assembly Return int to C function segfaults

I am finishing up an assembly program that replaces characters in a string with a given replacement character. The assembly code calls C functions and the assembly program itself is called from main in my .c file. However, when trying to finish and return a final int value FROM the assembly program TO C, I get segfaults. My .asm file is as follows:
; File: strrepl.asm
; Implements a C function with the prototype:
;
; int strrepl(char *str, int c, int (* isinsubset) (int c) ) ;
;
;
; Result: chars in string are replaced with the replacement character and string is returned.
SECTION .text
global strrepl
_strrepl: nop
strrepl:
push ebp ; set up stack frame
mov ebp, esp
push esi ; save registers
push ebx
xor eax, eax
mov ecx, [ebp + 8] ;load string (char array) into ecx
jecxz end ;jump if [ecx] is zero
mov al, [ebp + 12] ;move the replacement character into esi
mov edx, [ebp + 16] ;move function pointer into edx
firstLoop:
xor eax, eax
mov edi, [ecx]
cmp edi, 0
jz end
mov edi, ecx ; save array
movzx eax, byte [ecx] ;load single byte into eax
push eax ; parameter for (*isinsubset)
mov edx, [ebp + 16]
call edx ; execute (*isinsubset)
mov ecx, edi ; restore array
cmp eax, 0
jne secondLoop
add esp, 4 ; "pop off" the parameter
mov ebx, eax ; store return value
add ecx, 1
jmp firstLoop
secondLoop:
mov eax, [ebp+12]
mov [ecx], al
mov edx, [ebp+16]
add esp, 4
mov ebx, eax
add ecx, 1
jmp firstLoop
end:
pop ebx ; restore registers
pop esi
mov esp, ebp ; take down stack frame
pop ebp
mov eax, 9
push eax ;test
ret
and my c file is:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
//display *((char *) $edi)
// These functions will be implemented in assembly:
//
int strrepl(char *str, int c, int (* isinsubset) (int c) ) ;
int isvowel (int c) {
if (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u')
return 1 ;
if (c == 'A' || c == 'E' || c == 'I' || c == 'O' || c == 'U')
return 1 ;
return 0 ;
}
int main(){
char *str1;
int r;
str1 = strdup("ABC 123 779 Hello World") ;
r = strrepl(str1, '#', &isdigit) ;
printf("str1 = \"%s\"\n", str1) ;
printf("%d chararcters were replaced\n", r) ;
free(str1) ;
return 0;
}
In my assembly code, you can see in end
mov eax, 9
push eax
I am simply trying to return the value 9 to the value "r" which is an int in the C file. This is just a test to see if I can return an int back to r in the c file. Eventually I will be returning the number of characters that were replaced back to r. However, I need to figure out why the following code above is segfaulting. Any ideas?
mov eax, 9
push eax ; NOT a good idea
ret
That is a big mistake. It's going to return based on the lowest thing on the stack and you've just pushed something on to the stack that's almost certainly not a valid return address.
Most functions return a code by simply placing it into eax (this depends on calling convention of course but that's a pretty common one), there's generally no need to push it on to the stack, and certainly plenty of downside to doing so.
Return values are normally stored in EAX on X86 32 bit machines. So your pushing it on the stack after storing it in EAX is wrong, because the function it is returning to will try to use what is in EAX as a value for IP (instruction pointer)
Ret with no argument pops the return address off of the stack and jumps to it.
source

Resources