3

This is my assignment:

For each of these questions, you must write a C (not C++) program that contains three parts:

A. Some C code to read inputs (using scanf).

B. A segment of inline-assembler to do the computation.

C. Some C code to write the output (using printf).

  1. sign.c : reads a single integer, uses assembler to compute its sign (-1, 0, or 1), and outputs the sign. You will need opcodes jge and je.

I was able to do the first question (adding 2 integers, using those same 3 guidelines), but now I am stumped on this one.

I am able to get the first part of this particular question working (comparing eax and 0, then jumping to DoIF), but when I uncomment the other parts, the computation is messed up.

Thank you in advance for any help. It is greatly appreciated.

    #include "stdafx.h"


    int v; //integer to be read
    int sign; //sign

    int main()
    {
    printf("Enter an integer to compute its sign.\n");
    scanf_s("%d", &v); // this is how you read an int from the user

    //sign = -(v < 0); //C version
    __asm // tell MS Visual studio to start a block of assembler
    {

    mov eax, v // load x into A
    cmp eax, 0 // compare A with value 0
    je DoIF // if comparison was = 0, jmp to DoIF
    mov eax, 100
    mov sign, eax
    jmp done

    //mov eax, v; // load x into A
    //cmp eax, 1; // compare A with value 1
    //jge OtherIF; // if comparison was = 0, jmp to DoIF2
    //mov eax, 2;
    //mov sign, eax;
    //jmp done;

    //mov eax, v; // load x into A
    //cmp eax, -1; // compare A with value 1
    //jle NextIF; // if comparison was <= 0, jmp to DoIF3
    //mov eax, 100;
    //mov sign, eax;
    //jmp done;

    DoIF:
    mov eax, 0; // do y = 1
    mov sign, eax;

    /*OtherIF:
    mov eax, 1;
    mov sign, eax;*/

    /*NextIF:
    mov eax, -1;
    mov sign, eax;*/

    done:
    }
Jasen
  • 11,837
  • 2
  • 30
  • 48
user3313728
  • 127
  • 9

2 Answers2

1

Use jl(jump less) or jge(jump greater equal), if you have to jump if the result of comparison is less than 0:

int v; //integer to be read
int sign; //sign

printf("Enter an integer to compute its sign.\n");
scanf_s("%d", &v);

__asm 
{
    mov eax, v    // load x into A
    cmp eax, 0    // compare A with value 0
    je equal0     // if comparison was == 0 then jmp to equal0
    jge greater0  // if comparison was >= 0 then jmp to greater0
    mov eax, -1   // set eax to -1
    mov sign, eax // sign = -1
    jmp done
equal0:
    mov eax, 0    // set eax to 0
    mov sign, eax // sign = 0
    jmp done 
greater0:   
    mov eax,  1;  // set eax to 1 
    mov sign, eax // sign = 1
done:
}

printf("signe of %d is %d.\n", v, sign );
Rabbid76
  • 202,892
  • 27
  • 131
  • 174
  • Rabbid76, it won't let me tag you. The only problem with your answer is that I HAVE to use JGE as well as JE (otherwise your answer is fine). Can you help me with that? – user3313728 Jan 17 '16 at 16:06
1

Another way to do it, with fewer instructions (avoiding the unconditional branches):

    ;; Input in input_val.
    ;;  If it's already in a register, use test reg,reg instead of cmp
    xor    eax, eax
    cmp    input_val, 0
    je  .input_was_zero
    setg   al               ; eax = 0 (input_val<=0)  or  1 (input_val > 0)
    lea    eax, [eax*2 - 1] ; eax =-1 (0-1)           or  1 (2-1)
.input_was_zero:
    mov    [sign], eax      ; store eax somewhere since MSVC inline asm can't just tell the compiler that the result is live in eax

The key point is that you only need one test against zero. Checking two of the g, ge, e, le, or l conditions will gives you all three cases based on that one comparison.


This also avoids your silly mov reg, imm / mov [mem], reg sequence, (where you should have used mov [mem], imm, since having the value of sign in eax at the end of the inline asm does no good.) However, my code gets the values from setcc, rather than mov reg, imm anyway. (And of course zeroing a reg is done with xor, which avoids a slowdown when reading the full reg after using setg on the low byte.)

I was going to do a slightly more straightforward implementation with setg and then a conditional branch to skip over a mov eax, -1 or a dec or something, but then I noticed I could save even more instructions with lea to map (0,1) to (-1,1).

I also avoid loading input_val into a register, since cmp mem, imm works fine to get the flags set based on the comparison, and is more efficient than a separate load and test eax,eax.

Community
  • 1
  • 1
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847