0

I am learning how to combine assembly code with C program. Here is a short example of my program:

int umult_ok_asm(unsigned long x, unsigned long y, unsigned long *dest);
// x in %rdi, y in %rsi, dest in %rdx.

The function is to compute the product of arguments x and y and store the result in the memory location specified by arguments dest. As return values, they should return 0 when the multiplication overflows, requiring more than 64 bits to represent the true product, and 1 when it does not. Next, I give the complete code.

Part 1,Complete C code:

// file "c_code.c"

#include <stdio.h>
#include <limits.h>

int umult_ok_asm(unsigned long, unsigned long, unsigned long *);

int main(){
    unsigned long var;
    int t = umult_ok_asm(ULONG_MAX, 2, &var2);
    printf("asm: %d\n", t);
}

Part 2, Complete Assembly code:

# file "assembly_code.s"
.globl  umult_ok_asm

umult_ok_asm:
movq    %rdx, %rcx      # line 4, save copy of dest
movq    %rsi, %rax
mulq    %rdi
movq    %rax, (%rcx)    # line 7, Store product at dest
setae   %al
movzbl  %al, %eax
ret

my compilation command:

linux> gcc -o c_code.c assembly_code.s

They work fine and I got 0 as return value. BUT!

But I can’t figure out why I can’t delete the 4th line of assembly code and replace the 7th line with movq %rax, (%rdx). My modified Example:

# file "assembly_code.s"
.globl  umult_ok_asm

umult_ok_asm:
# movq    %rdx, %rcx      # Deleted code line 4
movq    %rsi, %rax
mulq    %rdi
# movq  %rax, (%rcx)     # Deleted code line 7
movq    %rax, (%rdx)     # Inserted new code, use (%rdx) store product.
setae   %al
movzbl  %al, %eax
ret

The above code will cause compilation errors:

Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)
(gdb)Program received signal SIGSEGV, Segmentation fault. 

Why I can't store product directly at dest (%rdx)? I have to do copy dest(%rdx) to dest(%rcx)? Is there any special reason?

My code reference source: http://csapp.cs.cmu.edu/3e/waside/waside-embedded-asm.pdf

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Ray Cao
  • 71
  • 6
  • 2
    You're using `mul` (to get flags set according to unsigned, not signed, overflow of the low half). But `mul` only has a widening form that actually writes the high half to RDX. Otherwise you'd just use `imul %rdi, %rsi` instead of copying either operand. If the function took the pointer arg first, you wouldn't have this problem. – Peter Cordes Jun 25 '21 at 04:34
  • 2
    https://www.felixcloutier.com/x86/mul: Unsigned multiply (`RDX:RAX ← RAX ∗ r/m64`). See that about RDX? – Nate Eldredge Jun 25 '21 at 04:39
  • Thanks to @Peter Cordes. I figured it out now. With the ```mulq``` instruction, the other argument to the multiplication must be in register %rax, and the product is sotred in registers %rdx (high-order 8 bytes) and %rax (low-order 8 bytes). – Ray Cao Jun 25 '21 at 04:46

0 Answers0