Неопределенная ссылка на ‘function_name’ в сборке ARM

#assembly #arm #ds-5

#сборка #arm #ds-5

Вопрос:

Я пытаюсь собрать некоторый относительно простой код, который использует две функции, fact и exp . Однако всякий раз, когда я пытаюсь перейти к любому из них, я получаю сообщение об ошибке следующего содержания: undefined reference to 'fact' и undefined reference to 'exp' . Я попытался добавить .global fact и .global exp в начало файла, но это не помогло. Вот мой код:

 .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
 

Комментарии:

1. Какой ассемблер вы используете? Я подозреваю, что .func это не делает того, что вы думаете.

2. В частности, если это ассемблер GNU .func и .endfunc не генерирует никакого кода или меток, только отладочную информацию. Вы должны просто поставить метку fact: в начале своей функции и пропустить .func/.endfunc , если вы действительно не знаете, что вы делаете, что касается отладочной информации.

3. Кстати, я считаю, что в ARM64 обычно следует использовать ret вместо br x30 возврата из подпрограммы. В отличие от ARM32, на самом деле это разные кодировки, и я думаю ret , что это лучше для предсказателя ветвлений.

4. @NateEldredge понял, спасибо.

5. О, и ваш bl exp внутренний exp цикл создаст бесконечный цикл. Я думаю, возможно, вы имели в виду b.lt .

Ответ №1:

В ассемблере GNU .func и .endfunc служит только для передачи отладочной информации. Они не заменяют фактическое определение метки. (Они также не выдают никакого кода пролога или эпилога, что могло быть вашим следующим предположением.)

Поэтому вы должны просто написать, как и для других ваших точек входа:

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

Вы могли бы также опустить .func/.endfunc , если вы не собираетесь также создавать надлежащую информацию об отладке для остальной части вашего кода, что обычно не стоит проблем для рукописной сборки.