ARM assembler's syntax in clang

Hi,all. Since the recent clang(3.2) has an integrated assembler for ARM, but I can't find document about this assembler's syntax, such assembler's directive, pseudo-instruction, (I assumed it follows the ARM Unified Assembly Language in instructions), where can I get such information?

Thanks!
ashi

I don’t think there is such a document…

There isn’t a 1:1 compatibility assurance with any syntax, including the UAL and GAS, but there is good compatibility with most of them, focusing more on GAS than any other, though recent changes are making it more in sync with the UAL (as is happening on GAS, too).

I think the recommendation is to try it on, throw code that works on other (OSS) ARM assemblers and report any mismatch. We really need some more real world testing, as we’re considering turning the integrated assembler by default on ARM, so your input is greatly appreciated.

cheers,
–renato

Thanks, Renato.
I’m actually porting a project which is based on GAS to iOS platform. I’ll report my result.

Best regards!
ashi

Hi,all,
I find clang’s integrated-as changes fast, My code which can’t be compiled by llvm3.1 tool-chain can be compiled by llvm3.2 tool-chain now. However, there are still existing link-errors.

My develop environment is:
Apple LLVM version 4.2 (clang-425.0.24) (based on LLVM 3.2svn)
Target: x86_64-apple-darwin12.2.1
Thread model: posix

the code is attached, I get this error (there is no such error under gcc tool-chain):

Undefined symbols for architecture armv7:
“_add_gas”, referenced from:
_main in main_ios_clang.o
ld: symbol(s) not found for architecture armv7
clang: error: linker command failed with exit code 1 (use -v to see invocation)

I find after add ‘_’ to add_gas label in iosasm_clang.s(change all add_gas to _add_gas) will get rid of this error, but this will raise error(can’t find symbol ‘add_gas’ when linking) in gcc tool chain. I don’t know whether it’s llvm’s feature or not. Thanks for any help!

=============file: main.c===========================================

#include <stdio.h>

extern void add_gas(int* dst,
int* src1,
int* src2);

int main(int argc, char **argv)
{
int a = 10;
int b = 10;
int c = 0;
add_gas(&c, &a, &b);
printf("\nafter call add_gas, c=%d
(should be 20)\n", c);

return 0;
}

=============file: iosasm_clang.s=====================================

/* this code follows ios’ as syntax

  • comment test
    */

.text
.globl add_gas
.align 4

add_gas:
/* add src1 and src2, result is return to dst

  • r0: *dst
  • r1: *src1
  • r2: *src2
    */
    push {r4, r5}
    ldr r3, [r1]
    ldr r4, [r2]
    add r5, r3, r4
    str r5, [r0]
    pop {r4, r5}
    bx lr
    ===========end=============================================

Best regards,
ashi

Apple requires a leading _ for all external symbols. So "works as
expected".

Joerg

Apple requires a leading _ for all external symbols. So “works as
expected”.
Thanks.

Do you have any advice to make the code work both under Apple and GNU gcc?

Best regards,
ashi

Do you have any advice to make the code work both under Apple and GNU gcc?

The leading underscore for external symbols is standard, if that’s what you’re referring to. http://en.m.wikipedia.org/wiki/Underscore#Origins_in_identifiers

But it’s unreasonable that if I declare a function ‘foo()’, then I have to implement ‘_foo()’ in assembly, doesn’t it?

Best regards,
ashi

So it turns out that I was wrong. It, in fact, is not standard. But regardless, you can use asm to specify the exact name. Eg.

extern int func() asm(“func”);

You can read more here: http://stackoverflow.com/questions/1034852/adding-leading-underscores-to-assembly-symbols-with-gcc-on-win32
Despite the title of the thread, the solution is compiler and system independent.

Thanks, Tyler. It works!

You were correct the first time. That post is talking about a Windows target. Ashi is working on iOS. Underscores are normal and expected. Using an “asm” name on the symbol is a horrible hack. Adding the underscore to the name in the .s file is the correct solution.

-Jim

Hi, Jim,
Why “asm” name is a horrible hack? Do you have any suggestion for cross-platform support of my ARM assembly code?

Thanks!
ashi

Hi,all,
I’ve some problem when using clang compile my ARM assembly code:

1 .qn directive
In GAS, .qn directive is used to create typed and/or indexed register aliases for use in Advanced SIMD Extension (Neon) instructions.(http://sourceware.org/binutils/docs/as/ARM-Directives.html#ARM-Directives)
But clang’s integrated-as seems have different syntax, for example, my code:

input .qn Q6.F32

Clang would give error: unexpected token in argument list

2 .unreq
Clang doesn’t recognize .unreq, my code is as below:

px .req r0
.unreq px
px .req r1

clang give error: redefinition of ‘px’ does not match original.

3 .end
clang also doesn’t recognize .end directive

all my code is compiled by: clang -arch armv7 -v -integrated-as -g -mcpu=cortex-a9 -mfpu=neon -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.1.sdk/

my clang version is: Apple LLVM version 4.2 (clang-425.0.24) (based on LLVM 3.2svn)

BTW, could any tell me which files implement integrated-as in clang source code, I think it may also help me by looking the source code(I’ve tried ‘grep’, but with no success.)

Great Thanks!

ashi

Hi, all. Another problem in ARM assembly: I use LDR to load an external symbol :

LDR R7,=DataTable

But clang gives error: unexpected token in operand to the ‘=’,
Then I change the code to:

LDR R7,=DataTable

The error becomes: unsupported relocation on symbol. How can I get around this in clang?

Thanks in advance!

Hi, all. The previous post have a typo:

problem in ARM assembly: I use LDR to load an external symbol :

LDR R7,=DataTable

But clang gives error: unexpected token in operand to the ‘=’,
Then I change the code to:

LDR R7,DataTable

The error becomes: unsupported relocation on symbol. How can I get around this in clang? My problem is actually how to load external symbol in Clang’s integrated-as? I’ve tried to learn some trivial c code’s assembly output, but find there are many linker related symbol and really confusing.

Thanks in advance!

Hi Ashi,

Your first LDR is a pseudoinstruction that is supported by some tools (gas and armasm, at least), but not by LLVM. Roughly speaking, it turns into a PC-relative load from a literal pool.

To do what you’re trying to achieve you can write your own literal pool in your assembly. You can see some examples of this sort of thing at https://github.com/tianocore/edk2/blob/master/ArmPkg/Include/AsmMacroIoLib.h.

Regards,

Bernie

Hi, Bernie, Thanks for your reply!
However, I still have problem by following edk2’s code, my test code is attached, what I want to do is build it as a dynamic lib. But I get error from ld:
ld: illegal text-relocation to _data_table in table.o from foo in use_table.o for architecture armv7

Do you have any suggestion to solve this? Thanks!

//==begin table.c==
int data_table[] = {0xff, 0xff};
//==end table.c==

//==begin use_table.s ==
.text
.syntax unified
.align 4
.global foo
.thumb
.thumb_func

foo:
PUSH {lr}
@LDR r0,[PC,#2]
.long _data_table
POP {pc}
//==end use_table.s==

//==begin Makefile==
CC = /Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang
CFLAG = -arch armv7 -mcpu=cortex-a9 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPh
oneOS.platform/Developer/SDKs/iPhoneOS6.1.sdk

all:libtest.dylib

libtest.dylib:table.o use_table.o
$(CC) -v -dynamiclib $(CFLAG) $^ -o $@
table.o:table.c
$(CC) -c $(CFLAG) $^ -o $@
use_table.o:use_table.s
$(CC) -c -integrated-as $(CFLAG) $^ -o $@
clean:
rm *.o libtest.dylib test
//==end Makefile==

Cheers,
Ashi

Not sure, but I would try:

  1. Are the objects being linked in the right order?

  2. Is the symbol name _data_table correct?

  3. You may need to explicitly tell your use_table.s file about the existence of data_table. In armasm I would have an ‘import’ statement to achieve this, not sure about clang/gas.

You also need to return from foo before you execute ‘.long _data_table’. And be warned that the PC doesn’t point at the next instruction when you use it like this - I believe you don’t need to modify it at all if you swap the pop and the .long.

Hi Ashi,

ld: illegal text-relocation to _data_table in table.o from foo in
use_table.o for architecture armv7

It looks like you're using iOS. I'm not familiar with the exact
workings of that platform, but I think a similar message would occur
in ELF-land.

If iOS *is* comparable, your issue is that symbols in dynamically
loaded objects can't (usually) be referenced directly because the code
section (and any embedded litpools) need to be identical no matter
where everything is loaded in memory. This is most of the point of
.dylib files: the instructions only have to exist once in memory and
can be shared. If the bytes would be different for each user that's
not possible -- the linker spots places where that happens and gives
an error.

My advice would be to compile a .c file (with "-S" to view the
assembly) which makes accesses like you're trying to do and copy its
code. There's no shame in it: I had a good idea of what ELF did but
still got the syntactic details wrong when I tried to write similar
code off the top of my head.

In this case, for example, I'd compile the C code (with "-fPIC" in
principle, though it seems to make no difference here. Actually, I'm
rather disturbed that you're trying to compile the C part of a .dylib
without "-fPIC". In the Linux world that's a no-no. Could be valid for
iOS, but I'd suggest you make sure if you don't know):

extern int data_table[];

int *wheres_data_table(void) {
    return &data_table[0];
}

(N.b. "armv7" uses a movw/movt pair which is perfectly valid. If you
want to see how to do it using litpools, you need to compile for
"armv6" which doesn't have those instructions).

Cheers.

Tim.

And be warned that the PC doesn't point at the next instruction when you

use it like this - I believe you don't need to modify it at all if you swap
the pop and the .long.
Bernie, is it related to ARM pipeline? I'm interesting in this, is there
any other additional information?

Hi Ashi,

> ld: illegal text-relocation to _data_table in table.o from foo in
> use_table.o for architecture armv7

It looks like you're using iOS. I'm not familiar with the exact
workings of that platform, but I think a similar message would occur
in ELF-land.

If iOS *is* comparable, your issue is that symbols in dynamically
loaded objects can't (usually) be referenced directly because the code
section (and any embedded litpools) need to be identical no matter
where everything is loaded in memory. This is most of the point of
.dylib files: the instructions only have to exist once in memory and
can be shared. If the bytes would be different for each user that's
not possible -- the linker spots places where that happens and gives
an error.

My advice would be to compile a .c file (with "-S" to view the
assembly) which makes accesses like you're trying to do and copy its
code. There's no shame in it: I had a good idea of what ELF did but
still got the syntactic details wrong when I tried to write similar
code off the top of my head.

In this case, for example, I'd compile the C code (with "-fPIC" in
principle, though it seems to make no difference here. Actually, I'm
rather disturbed that you're trying to compile the C part of a .dylib
without "-fPIC". In the Linux world that's a no-no. Could be valid for
iOS, but I'd suggest you make sure if you don't know):

extern int data_table[];

int *wheres_data_table(void) {
    return &data_table[0];
}

(N.b. "armv7" uses a movw/movt pair which is perfectly valid. If you
want to see how to do it using litpools, you need to compile for
"armv6" which doesn't have those instructions).

Cheers.

Tim.

Thanks for all your great reply! Finally, I got it work by several ways,
compiler's assembly output would help a lot(thanks Tim) and a linker
option:-Wl,-read_only_relocs,suppress would also help.
And here is a similar problem under powerPC :
http://lists.apple.com/archives/unix-porting/2008/Jan/msg00027.html

here is my summary:
*** problem ***
LDR Rx, =Label is not supported under Clang

*** solution ***
replace LDR pseudo-instruction by manually loading Label. 2 methods are
used, they are shown in use_table_m1.s and use_table_m2.s respectively.
There are 7 targets in my Makefile, include several different option
test(details are all in Makefile).
Test environment is Xcode4.6. The test_d_m1_1 can't be generated due to
illegal text-relocation error and others can be generated, they are 3
dynamic targets and 3 static targets, the test_s_m1_2 have a warning due to
-mdynamic-no-pic option. however I haven't test them on iOS device, I'm not
sure whether the "-Wl,-read_only_relocs,suppress" option would really work.

/* ==begin table.c== */
int data_table[] = {0xff, 0xff};
/* ==end table.c== */

/* ==begin use_table_m1.s==
* use table by LDR
*/
    .text
    .syntax unified
    .align 4
    .global foo
    .thumb
    .thumb_func

foo:
    LDR r0,[PC,#4]
    BX lr
    .long _data_table
/* ==end use_table_m1.s== */

/* ==begin use_table_m2.s==
* use table by code from compiler's assembly out put
*/
    .text
    .syntax unified
    .align 4
    .global foo
    .thumb
    .thumb_func

foo:
    /* these lines are from compiler's assembly output($(CC) -S):
     * extern int data_table[];
     * int *wheres_data_table(void) {
     * return &data_table[0];
     * }
     */
    movw r1, :lower16:(L_data_table$non_lazy_ptr-(LPC0_0+4))
    movt r1, :upper16:(L_data_table$non_lazy_ptr-(LPC0_0+4))
LPC0_0:
    add r1, pc
    ldr r1, [r1]
    bx lr

    .section __DATA,__nl_symbol_ptr,non_lazy_symbol_pointers
    .align 2
L_data_table$non_lazy_ptr:
    .indirect_symbol _data_table
    .long 0

    .subsections_via_symbols
/* ==end use_table_m2.s== */

/* ==begin test.c ==*/
extern int data_table[];
int main(void)
{
  int a = data_table[0];
  return 0;
}
/* ==end test.c ==*/

/* ==Makefile== */

CC = /Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang
AR = /Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ar
CFLAG = -fPIC -Wall -arch armv7 -mcpu=cortex-a9 -isysroot
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.1.sdk

all:dynamic static

dynamic:test_d_m1_1 test_d_m1_2 test_d_m2_1 test_d_m2_2

static:test_s_m1_1 test_s_m1_2 test_s_m2_1

test_d_m1_1:test.c libtest_m1_1.dylib
    $(CC) $(CFLAG) test.c ./libtest_m1_1.dylib -o $@

test_d_m1_2:test.c libtest_m1_2.dylib
    $(CC) $(CFLAG) test.c ./libtest_m1_2.dylib -o $@

test_d_m2_1:test.c libtest_m2_2.dylib
    $(CC) $(CFLAG) test.c ./libtest_m2_2.dylib -o $@

test_d_m2_2:test.c libtest_m2_2.dylib
    $(CC) $(CFLAG) test.c ./libtest_m2_2.dylib -o $@

test_s_m1_1:test.c libtest_m1_1.a
    $(CC) $(CFLAG) $^ -o $@

test_s_m1_2:test.c libtest_m1_1.a
    $(CC) $(CFLAG) -mdynamic-no-pic $^ -o $@

test_s_m2_1:test.o libtest_m2_1.a
    $(CC) $(CFLAG) $^ -o $@

libtest_m1_1.dylib:table.o use_table_m1.o
    $(CC) -dynamiclib $(CFLAG) $^ -o $@

libtest_m1_2.dylib:table.o use_table_m1.o
    $(CC) -dynamiclib -Wl,-read_only_relocs,suppress $(CFLAG) $^ -o $@

libtest_m2_1.dylib:table.o use_table_m2.o
    $(CC) -dynamiclib $(CFLAG) $^ -o $@

libtest_m2_2.dylib:table.o use_table_m2.o
    $(CC) -dynamiclib -Wl,-read_only_relocs,suppress $(CFLAG) $^ -o $@

libtest_m1_1.a:table.o use_table_m1.o
    $(AR) rcs $@ $^

libtest_m2_1.a:table.o use_table_m2.o
    $(AR) rcs $@ $^

table.o:table.c
    $(CC) -c $(CFLAG) $^ -o $@

test.o:test.c
    $(CC) -c $(CFLAG) $^ -o $@

use_table_m1.o:use_table_m1.s
    $(CC) -c -integrated-as $(CFLAG) $^ -o $@

use_table_m2.o:use_table_m2.s
    $(CC) -c -integrated-as $(CFLAG) $^ -o $@

clean:
    rm -f *.o libtest* test_d_m* *~ test_s_m*

/* == end Makefile == */

(all of these files are also available at
http://dl.dropbox.com/u/13855163/ill_text_relocation_test.tar.gz)

Best Regards,
Ashi