0


I want to generate assembly code from a function call like : (* 2 3).
it worked for the example of : (+ 7 3) like this :

 .text
.globl _main
.globl main
_main:
main:
push $7
push $3
pop %rax
add %rax,(%rsp)
call print_word_dec
push $10
call putchar
mov $0, %rax

and when I want to apply that to multiplication :

.text
 .globl _main
 .globl main
_main:
main:
 push $2
 push $3
 pop %rbx
 imulq %rbx
 call print_word_dec
 push $10
 call putchar
 mov $0, %rax
 ret

I always get the same result : 2 (the first operand) like if the multiplication didn't work.

I did some research and understood that a function is using the register rax for stocking the return value.

So in the multiplication example : it stocks 2 and 3 in rax register, when I call pop %rbx, it moves 3 to %rbx and it multiply %rbx with what's on %rax so it should be 6.

I think I misunderstood something.

Thanks for the help

PS: the functions putchar and print_word_dec are utilities and they are already tested

balimaco00
  • 85
  • 1
  • 11
  • 2
    let's assume you have two values already on stack: `pop rax` `imulq (%rsp), %rax` `mov %rax,(%rsp)` ? (didn't test it and I hate AT&T syntax, so for example I'm not sure about arguments of `imul`, the point is to use the truncating variant discarding upper 64b automatically and storing result only into `rax`, not modifying `rdx` (`imul rax,[rsp]` in Intel syntax)). That will set the stack to have only 1 value, equal to truncated result of `imul`. – Ped7g Feb 15 '18 at 02:46
  • 2
    And in the multiplication example you don't set `rax` to anything. Why do you even guess what is happening, simply use debugger to see yourself. – Ped7g Feb 15 '18 at 02:48
  • thank you so much ! it worked. I am using only unit test xD I will use a debugger, do you suggest an interesting one with values of each register ? – balimaco00 Feb 15 '18 at 02:58
  • 1
    uh... any reasonable one must give you tools to check any register and memory, so you can see whole machine state (actually under modern OS you can't escape from user land into kernel space just-so, so the kernel land features are off limit in ordinary setup, but as long as long as you are concerned about ordinary application code development, any decent debugger should do). I'm using edb-debugger compiled from sources from github (linux 64b OS). Not sure about options on different OSs, but anything from GNU family should have `gdb`, plus you may try some UI extensions for it. – Ped7g Feb 15 '18 at 03:09
  • 2
    Unit tests are good to *detect* failure, but once you know there's a failure, use a debugger to figure out why in cases when it isn't already obvious. – Peter Cordes Feb 15 '18 at 03:19
  • 1
    BTW, the 2 and 3 operand forms of `imul` are more efficient than one-operand `imul` (1 uop vs. 2 or 3 uops: http://agner.org/optimize/). e.g. `mov $2, %ecx` / `imul $3, %ecx, %eax`. Or better: `mov $3, %eax` / `add %eax,%eax`. Or at least `shl $1, %eax`, if you don't want a separate peephole optimization for multiplying by exactly 2, vs. for multiplying by an arbitrary power of 2. See also https://stackoverflow.com/questions/46480579/how-to-multiply-a-register-by-37-using-only-2-consecutive-leal-instructions-in-x and https://stackoverflow.com/questions/20150703/ – Peter Cordes Feb 15 '18 at 03:22

0 Answers0