0

I'm attempting to put together some relatively simple code that uses two functions, fact and exp. However, whenever I try to branch to either of them, I get an error that reads: undefined reference to 'fact' and undefined reference to 'exp'. I tried adding .global fact and .global exp to the top of the file, but that didn't help. Here's my code:

.text
.global main
.extern printf

main:
    ldr x2,=x // load 'x' -> x value
    ldr d2,[x2]
    ldr x2,=n  // load 'n' -> stopping point
    ldr x3,[x2]
    mov x2,#1 // set i/exp value to 1
    scvtf d1,x2  // default d1 (return value) to 1.0
loop:
    subs xzr, x3, x2
    ble done
    sub sp, sp, #16
    str x2,[sp] // save the value of x2 first
    sub x7, x2, #1

    bl fact

    ldr x2,[sp]   // get original x2 value back
    add sp, sp, #16
    mov x5, #0
    fmov d4, d2

.func fact
    mul x2, x2, x7
    sub x7, x7, #1
    cbnz x7,fact
    mov x4, x2
    br x30
.endfunc

.func exp
    fmul d4, d4, d4
    add x5, x5, #1
    cmp x5, x2

    bl exp

    br x30
.endfunc

done:
    // done

.data
    n:
    .quad 5
    x:
    .double 1.45
.end
  • What assembler are you using? I suspect that `.func` doesn't do what you think it does. – Nate Eldredge Dec 10 '20 at 20:30
  • In particular, if it's the GNU assembler, `.func` and `.endfunc` don't generate any code or labels, only debug info. You should just put a label `fact:` at the start of your function, and skip the `.func/.endfunc` unless you really know what you're doing as far as debug info. – Nate Eldredge Dec 10 '20 at 20:32
  • By the way, I believe that in ARM64, one should normally use `ret` instead of `br x30` to return from a subroutine. Unlike on ARM32, they're actually different encodings, and I think `ret` is better for the branch predictor. – Nate Eldredge Dec 10 '20 at 20:35
  • @NateEldredge Understood, thanks. – TheFiveHundredYears Dec 10 '20 at 20:36
  • Oh, and your `bl exp` within `exp` will create an infinite loop. I think perhaps you meant `b.lt`. – Nate Eldredge Dec 10 '20 at 20:38
  • @NateEldredge Yep, I meant blt. The code as a whole is still very much under construction. – TheFiveHundredYears Dec 10 '20 at 20:40

1 Answers1

2

In the GNU assembler, .func and .endfunc only serve to emit debugging info. They don't take the place of actually defining a label. (Nor do they emit any prologue or epilogue code, which might have been your next guess.)

So you should simply write, as for your other entry points:

fact:
    mul x2, x2, x7
    // ...

You might as well omit .func/.endfunc unless you are going to also produce proper debugging info for the rest of your code, which is usually not worth the trouble for handwritten assembly.

Nate Eldredge
  • 48,811
  • 6
  • 54
  • 82