1.6 Using the integrated assembler

These examples show how to use the armclang integrated assembler to build an object from assembly source files, and how to call functions in this object from C/C++ source files.

The assembly source code

The assembly example is a single assembly source file, mystrcopy.s, containing a function to perform a simple string copy operation:

    .section   StringCopy, "ax"
    .balign    4

    .global    mystrcopy
    .type      mystrcopy, "function"
mystrcopy:
    ldrb       r2, [r1], #1
    strb       r2, [r0], #1
    cmp        r2, #0
    bne        mystrcopy
    bx         lr

The .section directive creates a new section in the object file named StringCopy. The characters in the string following the section name are the flags for this section. The a flag marks this section as allocatable. The x flag marks this section as executable.

The .balign directive aligns the subsequent code to a 4-byte boundary. The alignment is required for compliance with the ARM Application Procedure Call Standard (AAPCS).

The .global directive marks the symbol mystrcopy as a global symbol. This enables the symbol to be referenced by external files.

The .type directive sets the type of the symbol mystrcopy to function. This helps the linker use the proper linkage when the symbol is branched to from A32 or T32 code.

Assembling a source file

When assembling code, you must first decide which target the executable is to run on. The ‑‑target option determines which target state to compile for. This option is a mandatory option.

To assemble the above source file for an ARMv8-M Mainline target:

armclang ‑‑target=arm‑arm‑none‑eabi ‑c ‑march=armv8‑m.main mystrcopy.s

This command creates an object file, mystrcopy.o.

The ‑‑target option selects the target that you want to assemble for. In this example, there is no default target for ARM state, so you must specify either ‑march to target an architecture or ‑mcpu to target a processor. This example uses ‑march to target the ARMv8-M Mainline architecture. The integrated assembler accepts the same options for ‑‑target, ‑march, ‑mcpu, and ‑mfpu as the compiler.

Use ‑mcpu=list or ‑march=list to see all available options.

Examining the executable

You can use the fromelf tool to:

  • examine an assembled binary.
  • extract information about an assembled binary.
  • convert an assembled binary to another format.

For example, you can disassemble the code that is contained in the object file:

fromelf ‑‑text ‑c mystrcopy.o
	
	...
	** Section #3 'StringCopy' (SHT_PROGBITS) [SHF_ALLOC + SHF_EXECINSTR]
	    Size   : 14 bytes (alignment 4)
	    Address: 0x00000000
	
	    $t.0
	    mystrcopy
	        0x00000000:    f8112b01    ...+    LDRB     r2,[r1],#1
	        0x00000004:    f8002b01    ...+    STRB     r2,[r0],#1
	        0x00000008:    2a00        .*      CMP      r2,#0
	        0x0000000a:    d1f9        ..      BNE      mystrcopy ; 0x0
	        0x0000000c:    4770        pG      BX       lr
	...

The example shows the disassembly for the section StringCopy as created in the source file.

Note:

The code is marked as T32 by default because ARMv8-M Mainline does not support A32 code. For processors that support A32 and T32 code, you can explicitly mark the code as A32 or T32 by adding the GNU assembly .arm or .thumb directive, respectively, at the start of the source file.

Calling an assembly function from C/C++ code

It can be useful to write optimized functions in an assembly file and call them from C/C++ code. When doing so, ensure that the assembly function uses registers in compliance with the AAPCS.

The C example is a single C source file main.c, containing a call to the mystrcopy function to copy a string from one location to another:

const char *source = "String to copy.";
char *dest;

extern void mystrcopy(char *dest, const char *source);

int main(void) {
    mystrcopy(dest, source);
    return 0;
}

An extern function declaration has been added for the mystrcopy function. The return type and function parameters must be checked manually.

If you want to call the assembly function from a C++ source file, you must disable C++ name mangling by using extern "C" instead of extern. For the above example, use:

extern "C" void mystrcopy(char *dest, const char *source);

Compiling and linking the C source file

To compile the above source file for an ARMv8-M Mainline target:

armclang ‑‑target=arm‑arm‑none‑eabi ‑c ‑march=armv8‑m.main main.c

This command creates an object file, main.o.

To link the two object files main.o and mystrcopy.o and generate an executable image:

armlink main.o mystrcopy.o ‑o image.axf

This command creates an executable image file image.axf.

Non-ConfidentialPDF file icon PDF versionARM 100748_0607_00_en
Copyright © 2016, 2017 ARM Limited or its affiliates. All rights reserved.