1

I am trying to follow an example that I found on a blog.

It doesn't seem that androideabi can call printf directly on assembler code level (maybe I am missing a flag when I compile?).

I am running with these commands:

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'

I get an undefined reference from the assembly code.

This would be neat if it actually pulled off. I am of course open to alternative solution if anyone wants to share their awesome knowledge of low level programming!

Any tips for this problem? Code is below:

.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
mins
  • 6,478
  • 12
  • 56
  • 75
Khiem-Kim Ho Xuan
  • 1,301
  • 1
  • 22
  • 45
  • The linker isn't psychic - you need to give it a library with `printf` in. When going directly to the assembler and linker rather than via a compiler, expect to have to do all the things that a compiler would (normally) automatically do for you. – Notlikethat Apr 23 '15 at 17:35
  • Try using gcc directly rather than as, ld combination. With sysroot specified it should work but of course that doesn't mean your code is correct. – auselen Apr 23 '15 at 17:44
  • tried it with : arm-linux-androideabi-gcc-4.9 -fPIE -pie --sysroot $env:SYSROOT -s -o fib fib.o I got; WARNING: linker: ./fib has text relocations. This is wasting memory and prevents security hardening. Please fix. 4613732 – Khiem-Kim Ho Xuan Apr 23 '15 at 17:57
  • I meant use gcc to .s -> executable. It might fix that warning. If not assembly is not following best practices and that's a different question. – auselen Apr 23 '15 at 18:13
  • possible duplicate of [What is an undefined reference/unresolved external symbol error and how do I fix it?](http://stackoverflow.com/questions/12573816/what-is-an-undefined-reference-unresolved-external-symbol-error-and-how-do-i-fix) – Notlikethat Apr 23 '15 at 21:04
  • @Notlikethat, no, not a duplicate of that. This is highly specific to an unusual build process and concerns a function in the C library which in most cases would be *automatically* linked by a toolchain. – Chris Stratton Apr 23 '15 at 21:32
  • @Chris what's unusual about assembling some source and linking it? I can trivially reproduce this with my x86 machine's native binutils as well as all the arm and aarch64 cross-toolchains I have installed; Unless you _tell the linker_ to look in `libc.so` for `printf`, it won't. Not using the C compiler means having to do what the C compiler does in the same situation, i.e. specify the necessary libraries, hence the "Failure to link against appropriate libraries/object files or compile implementation files" answer there is entirely appropriate. – Notlikethat Apr 23 '15 at 21:47
  • It's precisely the difference between "Failure to link against appropriate libraries/object files or compile implementation files" vs "Not using the C compiler means having to do what the C compiler does in the same situation, i.e. specify the necessary libraries" which makes that *not* a duplicate. The former may provide a hint that might ultimately lead to *discovery* of a solution, but the latter *is* an answer to *this* question. – Chris Stratton Apr 23 '15 at 22:02
  • Ah, I see what you mean. And all this time I'd missed that the purported "canonical" question about link errors isn't actually about invoking a linker, only using a compiler as one. That gap is far too easy to bridge unconsciously... :( – Notlikethat Apr 23 '15 at 22:27
  • @jww The commands are all there in the question already. (And it can easily be solved by adding `-lc` to the `ld` command line, or by switching to doing the linking by using the `gcc` frontend.) – mstorsjo Apr 24 '15 at 05:52
  • @mstorsjo - indeed, the close was retracted. – jww Apr 24 '15 at 05:57

2 Answers2

3

You need to link to the C runtime library aka libc, in order to get printf. Either you can add -lc at the end of your linking command, or use the gcc frontend instead of using ld directly.

I.e., either do this:

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

Or this:

arm-linux-androideabi-gcc --sysroot $env:SYSROOT -Wl,-s -o fib fib.o
mstorsjo
  • 12,983
  • 2
  • 39
  • 62
  • Unfortunately, I still get the undefined reference. – Khiem-Kim Ho Xuan Apr 24 '15 at 06:33
  • Are you sure the sysroot environment variable is used correctly? I'm not sure what you try to do with `$env:SYSROOT` in your original post, try doing `--sysroot $SYSROOT` instead, where `$SYSROOT` is an environment variable pointing to e.g. `android-ndk/platforms/android-3/arch-arm`. – mstorsjo Apr 24 '15 at 06:38
  • Yeah I am pointing to that one with SYSROOT and I am running in Windows with powershell, so that is why I had $env:SYSROOT – Khiem-Kim Ho Xuan Apr 24 '15 at 06:41
  • Ok, I see. Is the sysroot path set in the right format? I.e. if you try to compile a C source file with `arm-linux-androideabi-gcc -c test.c --sysroot $env:SYSROOT`, where `test.c` contains e.g. `#include `, does it work? I think the path on windows should be in normal windows style, but I'm not sure if it should be forward or backwards slashes. You can try both, and with and without a `c:` prefix. IIRC the normal NDK tools aren't built on cygwin at least, so it shouldn't be a fully unix/cygwin path (any longer - it used to be like that). – mstorsjo Apr 24 '15 at 06:45
  • yeah that did work-. not sure why it would not work when I do code assembly though. An alternative solution would be to return the value from the assembly code. But not sure why it would not be possible to link the stdiolibrary in assembly. – Khiem-Kim Ho Xuan Apr 24 '15 at 06:52
  • It should work just fine - it works for me; I tested your code, and got the same error message originally, until I added `-lc`. Did you try doing the linking with the `gcc` frontend instead of with `ld`, in case it does the path mangling differently? – mstorsjo Apr 24 '15 at 06:53
  • I did get alot of errors then. but are you running the command on Windows Powershell or Cygwin? – Khiem-Kim Ho Xuan Apr 24 '15 at 06:56
  • I originally just tried on OS X, but now I tested on windows as well, in cmd and in powershell. It worked just fine there when I spelled out the sysroot path manually without trying to expand it via some variable (I'm not familiar enough with powershell), something like `arm-linux-androideabi-ld --sysroot \path\to\android-ndk\platforms\android-3\arch-arm -o fib fib.o -lc` worked just fine. – mstorsjo Apr 24 '15 at 07:14
  • @Khiem-KimHoXuan If my memory doesn't fool me, sysroot path should be absolute. – auselen Apr 24 '15 at 07:17
  • @Khiem-KimHoXuan I'm not really sure what's the problem? Is using gcc OK and ld is a problem? or you can't get gcc make an executable out of assembly? if gcc works try verbose, it will show which dirs are used when compiling, linking etc. – auselen Apr 24 '15 at 07:28
  • seems it works compiling now. But another problem is that when I try to compile on my phone it says: "linker: ./fib has text relocations. This is wasting memory and prevents security hardening. Please fix. 4613732". fml :( – Khiem-Kim Ho Xuan Apr 24 '15 at 07:53
  • Getting rid of text relocations requires writing PIC assembly, which is a bit harder. IIRC this is only required for executables since Android 5.0. For your case, you can change `ldr r0, =sumstring` into something like this: `ldr r0, .Lpicsumstring \n .Lpic0: \n add r0, pc` and then at the end of the function: `.Lpicsumstring: \n .word .Lpicsumstring - (.Lpic0+8)` (literal newlines since this doesn't fit into comments - this really is a separate question). – mstorsjo Apr 24 '15 at 08:15
  • @Khiem-KimHoXuan again relocation stuff is a different question, you should accept answer and post a new one about it. that might attract a nice answer if you can ask it in a good way. – auselen Apr 24 '15 at 09:11
  • thanks @auselen ;) I will ask another that links to another problem that occured :D – Khiem-Kim Ho Xuan Apr 24 '15 at 09:14
0

use gcc -o fib fib.o instead of ld -o fib fib.o

Yehor Androsov
  • 4,885
  • 2
  • 23
  • 40
Hassan Maher
  • 73
  • 1
  • 3