1

I'm new to assembly and I'm using IA32 architecture. I'm trying code a .s function that produces the following operation: C + A - D + B

  • A is an 8-bit variable
  • B is a 16-bit variable
  • C and D are both 32-bit variables

The function should return a 64-bit value that must be printed in C and I can't figure this out.

I am trying this and it works for the tests of positive numbers, but when I'm working with negative numbers it doesn't work and I can't figure out the reason.

My function sum_and_subtract.s:

.section .data

.global A
.global B
.global C
.global D

.section .text
.global sum_and_subtract

# short sum_and_subtract(void)

sum_and_subtract:

#prologue 
    pushl %ebp 
    movl %esp, %ebp
    
    pushl %ebx
    
#body of the function

    movl $0, %eax # clear eax   
    movl C, %eax
    movl $0, %ecx
    movb A, %cl
    
    addl %ecx, %eax
    movl $0, %edx
    movl D, %edx
    subl %edx, %eax
    movl $0, %ebx
    movw B, %bx
    addl %ebx, %eax
        
    movl $0, %edx
    adcl $0, %edx
    
    cdq
#epilogue

fim:

    popl %ebx
    
    movl %ebp, %esp
    popl %ebp
    ret

An correct example is:

  • A = 0, B = 1, C = 0, D = 0; Expected = 1 -> Result = 1 and It works for this example

The error appears when:

  • A = 0, B = 0, C = 0, D = 1; Expected = -1 -> Result = 256

After seeing your comments I forgot to write my main code where I print my long long result.

main.c :

#include <stdio.h>
#include "sum_and_subtract.h"   

char A = 0;
short B = 0;
long C = 0;
long D = 1;

int main(void) {
    
    printf("A = %d\n", A);
    printf("B = %hd\n", B);
    printf("C = %ld\n", C);
    printf("D = %ld\n", D);

    long long result = sum_and_subtract();
    
    printf("Result = %lld\n", result);
    
    return 0;

}

Here it is.

I have this other file sum_and_subtract.h

long long sum_and_subtract(void);
  • The code is not correct, but it should still work for the test case you showed. You are likely printing the value wrong, as `-1` is `255` when printed as unsigned byte. Even so, you should not get `256` though. – Jester Nov 02 '20 at 23:17
  • can you explain what `print` means. How function should return 64 bit value and what print in C means – 0___________ Nov 02 '20 at 23:23
  • @Jester return value is 64 bits so -1 wil be 0xffffffffffffffff which is much more than 255 :) – 0___________ Nov 02 '20 at 23:24
  • 2
    Can you create a [mcve]? This is missing the actual definition and initialization of the variables `A,B,C,D`, as well as the code that calls `sum_and_subtract` and outputs the result. – Nate Eldredge Nov 02 '20 at 23:28
  • @P__JsupportswomeninPoland I know, but if it's printed wrong as just an unsigned byte, it will be shown as `255`. – Jester Nov 02 '20 at 23:46
  • @Jester I don't see any printing there, but maybe I am blind – 0___________ Nov 03 '20 at 00:00
  • 1
    There is none. My point is, José did not show the code that prints it so maybe **that** is wrong. Because the code as shown does return `-1`. Or maybe it's not printed but passed to `exit()` which truncates to 8 bits typically and the shell prints stuff as unsigned. – Jester Nov 03 '20 at 00:13
  • So your variables are all signed? And you need to widen to avoid possible overflow by widening to 64-bit *before* summing? Or can you do a 32-bit sum and then just `cdq` like you're doing? It's pointless to use `cdq` after using `adc` or `setc` to set EDX to 0 or 1; `cdq` overwrites that. First figure out exactly what math on what types you want to implement. – Peter Cordes Nov 03 '20 at 00:58
  • I already edited my question. I think the main code is correct. Maybe is missing something in my `.c` code – José Soares Nov 03 '20 at 13:48
  • @PeterCordes They are all signed but I really don't know the difference between signed and unsigned. The function has to return a 64-bit value. What's the better way to do it? My teacher told me to use `cdq` but I don't see a way to use it. – José Soares Nov 03 '20 at 13:53
  • What is in `sum_and_subtract.h`? Assuming `extern long long sum_and_subtract();` the code prints `-1` as expected. – Jester Nov 03 '20 at 14:03
  • @Jester I edited again. – José Soares Nov 03 '20 at 14:10
  • The problem is: I have the following test: A = 5000, B = -5000, C = -1 and D = 1 that should return 10000 but doesn't. – José Soares Nov 03 '20 at 14:11
  • 1
    So why did you ask about a totally different test case? Also `A` is a `char` it can not be `5000`. You are not sign extending `A` or `B`. – Jester Nov 03 '20 at 14:14
  • Because that test was wrong too. But now it only doesn't work for that test and I can't figure why. How can I sign estend A or B? – José Soares Nov 03 '20 at 14:31
  • 1
    Instead of `movb A, %cl` do `movsbl A, %ecx` and instead of `movw B, %bx` do `movswl B, %ebx`. You can remove the zeroing. See also the answer below. – Jester Nov 03 '20 at 14:39
  • The answer below is for 64-bit code. I'm in 32-bit code. – José Soares Nov 03 '20 at 14:41
  • That is hardly relevant to the sign extension. – Jester Nov 03 '20 at 14:42
  • The same instructions work in 32-bit mode, just using `A` instead of `A(%rip)`. It's correct if you want to do 32-bit wrapping math, and *then* sign-extend that possibly-wrapped result to 64-bit, like you were trying to do in the question. (Except cdq aka AT&T `cltd` not x86-64 only `cltq` (aka Intel `cdqe`)) – Peter Cordes Nov 03 '20 at 23:36

1 Answers1

0

I would follow the C compiler:

doit:
        movsbl  A(%rip), %eax
        movswl  B(%rip), %edx
        addl    C(%rip), %eax
        subl    D(%rip), %eax
        addl    %edx, %eax
        cltq
        ret
        movsx   eax, BYTE PTR A[rip]
        movsx   edx, WORD PTR B[rip]
        add     eax, DWORD PTR C[rip]
        sub     eax, DWORD PTR D[rip]
        add     eax, edx
        cdqe
        ret

It "prints" -1

It is rather a comment so do not UV. Feel free to DV

The complete code with print: https://godbolt.org/z/3a9YMo

And with the printing code: https://godbolt.org/z/KT8YWT

0___________
  • 60,014
  • 4
  • 34
  • 74
  • 2
    That's 64-bit code. The OP is clearly writing 32-bit code (note the `popl %ebp`), so you should use `-m32`. Also, this doesn't avoid overflow of the 32-bit sum before you sign-extend to 64-bit. So right idea to ask a compiler, but you didn't ask it the right thing. :P – Peter Cordes Nov 03 '20 at 00:54