【问题标题】:Undefined reference to 'printf' in ARM assembler for AndroidAndroid ARM 汇编程序中对“printf”的未定义引用
【发布时间】:2015-04-23 17:26:13
【问题描述】:

我正在尝试遵循我在博客上找到的示例。

androideabi 似乎不能直接在汇编代码级别调用 printf (可能我在编译时遗漏了一个标志?)。

我正在使用这些命令运行:

arm-linux-androideabi-as -o fib.o fibonacci.s
arm-linux-androideabi-ld --sysroot $env:SYSROOT -s -o fib fib.o
fib.o(.text+0x8): error: undefined reference to 'printf'

我从汇编代码中得到一个未定义的引用。

如果它真的成功了,那就太好了。如果有人想分享他们对低级编程的真棒知识,我当然愿意接受替代解决方案!

对于这个问题有什么建议吗?代码如下:

.syntax unified

.equ maxfib,4000000

previous .req r4
current  .req r5
next     .req r6
sum      .req r7
max      .req r8
tmp      .req r9

.section .rodata
 .align 2
fibstring:
 .asciz "fib is %d\n"
sumstring:
 .asciz "%d\n"

len = . - sumstring
.text
 .align 2
 .global main
 .extern printf
 .type main, %function
main:
 stmfd sp!, {r4-r9, lr}
 ldr max,   =maxfib
 mov previous, 1
 mov current, 1
 mov sum, 0

loop:
 cmp current, max
 bgt last

 add next, current, previous

 movs tmp, current, lsr 1      @ set carry flag from lsr - for the odd-valued terms
                               @ we discard the result of the movs and are only interested
                               @ in the side effect of the lsr which pushes the lower bit
                               @ of current (1 for odd; 0 for even) into the carry flag
                               @ movs will update the status register (c.f. mov which will not)
 addcc sum, sum, current       @ we add current to the sum ONLY when cc (carry clear) is true
                               @ these are even-valued fibonacci terms

 mov previous, current
 mov current, next
 b loop

last:
 mov r1, sum
 ldr r0, =sumstring            @ store address of start of string to r0
 bl         printf

 mov r0, 0
 ldmfd sp!, {r4-r9, pc}
 mov r7, 1                     @ set r7 to 1 - the syscall for exit
 swi 0                         @ then invoke the syscall from linux

【问题讨论】:

  • 链接器不是通灵的——你需要给它一个带有printf的库。当直接进入汇编器和链接器而不是通过编译器时,预计必须做所有的事情编译器会(通常)自动为你做。
  • 尝试直接使用 gcc 而不是 as, ld 组合。指定 sysroot 后它应该可以工作,但当然这并不意味着您的代码是正确的。
  • 试过了:arm-linux-androideabi-gcc-4.9 -fPIE -pie --sysroot $env:SYSROOT -s -o fib fib.o 我得到了;警告:链接器:./fib 有文本重定位。这会浪费内存并防止安全加固。请修复。 4613732
  • 我的意思是使用 gcc 到 .s -> 可执行文件。它可能会修复该警告。如果不是组装,则不遵循最佳实践,那是另一个问题。

标签: android assembly android-ndk arm


【解决方案1】:

您需要链接到 C 运行时库(也称为 libc)才能获得 printf。您可以在链接命令的末尾添加-lc,或者使用gcc 前端而不是直接使用ld

即,要么这样做:

arm-linux-androideabi-ld --sysroot $env:SYSROOT -s -o fib fib.o -lc

或者这个:

arm-linux-androideabi-gcc --sysroot $env:SYSROOT -Wl,-s -o fib fib.o

【讨论】:

  • 不幸的是,我仍然得到未定义的引用。
  • 您确定 sysroot 环境变量使用正确吗?我不确定您在原始帖子中尝试使用$env:SYSROOT 做什么,请尝试使用--sysroot $SYSROOT 代替,其中$SYSROOT 是指向例如的环境变量。 android-ndk/platforms/android-3/arch-arm.
  • 是的,我用 SYSROOT 指向那个,我在 Windows 中使用 powershell 运行,所以这就是为什么我有 $env:SYSROOT
  • 好的,我明白了。 sysroot 路径是否以正确的格式设置? IE。如果您尝试使用 arm-linux-androideabi-gcc -c test.c --sysroot $env:SYSROOT 编译 C 源文件,其中 test.c 包含例如#include <stdio.h>,有用吗?我认为windows上的路径应该是普通的windows风格,但我不确定它应该是正斜杠还是反斜杠。您可以同时尝试,无论是否带有c: 前缀。 IIRC 正常的 NDK 工具至少不是基于 cygwin 构建的,因此它不应该是完全的 unix/cygwin 路径(不再是 - 它曾经是那样的)。
  • 是的,确实有效-。不知道为什么当我进行代码汇编时它不起作用。另一种解决方案是从汇编代码中返回值。但不确定为什么无法在程序集中链接标准库。
【解决方案2】:

使用gcc -o fib fib.o 而不是ld -o fib fib.o

【讨论】:

    猜你喜欢
    • 2016-03-26
    • 1970-01-01
    • 2013-01-27
    • 1970-01-01
    • 1970-01-01
    • 2019-05-05
    • 2013-10-21
    • 1970-01-01
    相关资源
    最近更新 更多