Skip to content

C variables representation in assembly(gcc -S)

In this article I'll try to find out what C vars(symbols) are in the assembly generated by gcc -S.

vars-section.c
#include <stdio.h>
#include <string.h>

int i;
short j = 2;
long k = 0;

static int l;
static short m = 5;
static long n = 0;

char *str1 = "hello";
static char *str2 = "world";

void func()
{
    static long o;
    static short p = 3;
    static int q = 0;

    int r = 4;
    int ia[4] = {2,0,4,8};
    int s = 5;
    int t;
    char ca[] = "hello";

    printf("func global static: ijk = %ld\n", i+j+k);
    printf("func locals: r+s=%d, ia[3]=%d, ca=%s\n", r+s, ia[3], ca);
    printf("func local static: o++=%ld, ++p=%hd, q++=%d\n", o++, ++p, q++);
}

int main(int argc, char* argv[])
{
    static short u;
    static int v = 3;
    static long w = 0;

    for (int i=0; i<3; i++)
    {
        func();
    }

    long lmn = l+m+n;
    printf("lmn = %ld\n", lmn);

    long uvw = u+v+w;
    printf("uvw = %ld\n", uvw);

    printf("strlen(%s) = %zu; strlen(%s) = %zu\n", str1, strlen(str1), str2, strlen(str2));

    // Writing to read-only memory(.rodata) will raise segmentation fault(SIGSEGV) exception.
    // char *ptr = str1;
    // char *ptr = str2;
    // *ptr = 'T';
    // printf("ptr = %s\n", ptr);

    return 0;
}

On Raspiberry PI 3 Model B/aarch64/ubuntu, compile with gcc to produce assembly code:

-S: Stop after the stage of compilation proper; do not assemble.
The output is in the form of an assembler code file for each non-assembler input file specified.
By default, the assembler file name for a source file is made by replacing the suffix ‘.c’, ‘.i’, etc., with ‘.s’.
-fverbose-asm: Put extra commentary information in the generated assembly code to make it more readable.

# output -o vars-section.s
$ gcc vars-section.c -S -fverbose-asm

asm#

# gcc vars-section.c -S -fverbose-asm -o -
$ cat vars-section.s
cat vars-section.s
    .arch armv8-a
    .file   "vars-section.c"
// GNU C17 (Ubuntu 11.4.0-1ubuntu1~22.04) version 11.4.0 (aarch64-linux-gnu)
//  compiled by GNU C version 11.4.0, GMP version 6.2.1, MPFR version 4.1.0, MPC version 1.2.1, isl version isl-0.24-GMP

// GGC heuristics: --param ggc-min-expand=91 --param ggc-min-heapsize=115876
// options passed: -mlittle-endian -mabi=lp64 -fasynchronous-unwind-tables -fstack-protector-strong -fstack-clash-protection
    .text
    .global i
    .bss
    .align  2
    .type   i, %object
    .size   i, 4
i:
    .zero   4
    .global j
    .data
    .align  1
    .type   j, %object
    .size   j, 2
j:
    .hword  2
    .global k
    .bss
    .align  3
    .type   k, %object
    .size   k, 8
k:
    .zero   8
    .local  l
    .comm   l,4,4
    .data
    .align  1
    .type   m, %object
    .size   m, 2
m:
    .hword  5
    .local  n
    .comm   n,8,8
    .global str1
    .section    .rodata
    .align  3
.LC0:
    .string "hello"
    .section    .data.rel.local,"aw"
    .align  3
    .type   str1, %object
    .size   str1, 8
str1:
    .xword  .LC0
    .section    .rodata
    .align  3
.LC1:
    .string "world"
    .section    .data.rel.local
    .align  3
    .type   str2, %object
    .size   str2, 8
str2:
    .xword  .LC1
    .section    .rodata
    .align  3
.LC2:
    .string "func global static: ijk = %ld\n"
    .align  3
.LC3:
    .string "func locals: r+s=%d, ia[3]=%d, ca=%s\n"
    .align  3
.LC4:
    .string "func local static: o++=%ld, ++p=%hd, q++=%d\n"
    .text
    .align  2
    .global func
    .type   func, %function
func:
.LFB0:
    .cfi_startproc
    stp x29, x30, [sp, -64]!    //,,,
    .cfi_def_cfa_offset 64
    .cfi_offset 29, -64
    .cfi_offset 30, -56
    mov x29, sp //,
// vars-section.c:16: {
    adrp    x0, :got:__stack_chk_guard  // tmp112,
    ldr x0, [x0, #:got_lo12:__stack_chk_guard]  // tmp111, tmp112,
    ldr x1, [x0]    // tmp154,
    str x1, [sp, 56]    // tmp154, D.4466
    mov x1, 0   // tmp154
// vars-section.c:21:     int r = 4;
    mov w0, 4   // tmp113,
    str w0, [sp, 24]    // tmp113, r
// vars-section.c:22:     int ia[4] = {2,0,4,8};
    mov w0, 2   // tmp114,
    str w0, [sp, 32]    // tmp114, ia[0]
    str wzr, [sp, 36]   //, ia[1]
    mov w0, 4   // tmp115,
    str w0, [sp, 40]    // tmp115, ia[2]
    mov w0, 8   // tmp116,
    str w0, [sp, 44]    // tmp116, ia[3]
// vars-section.c:23:     int s = 5;
    mov w0, 5   // tmp117,
    str w0, [sp, 28]    // tmp117, s
// vars-section.c:25:     char ca[] = "hello";
    adrp    x0, .LC0    // tmp119,
    add x1, x0, :lo12:.LC0  // tmp118, tmp119,
    add x0, sp, 48  // tmp120,,
    ldr w2, [x1]    // tmp122,
    str w2, [x0]    // tmp122, ca
    ldrh    w1, [x1, 4] // tmp123,
    strh    w1, [x0, 4] // tmp123, ca
// vars-section.c:27:     printf("func global static: ijk = %ld\n", i+j+k);
    adrp    x0, j   // tmp125,
    add x0, x0, :lo12:j // tmp124, tmp125,
    ldrsh   w0, [x0]    // j.0_1, j
    mov w1, w0  // _2, j.0_1
    adrp    x0, i   // tmp127,
    add x0, x0, :lo12:i // tmp126, tmp127,
    ldr w0, [x0]    // i.1_3, i
    add w0, w1, w0  // _4, _2, i.1_3
    sxtw    x1, w0  // _5, _4
// vars-section.c:27:     printf("func global static: ijk = %ld\n", i+j+k);
    adrp    x0, k   // tmp129,
    add x0, x0, :lo12:k // tmp128, tmp129,
    ldr x0, [x0]    // k.2_6, k
    add x0, x1, x0  // _7, _5, k.2_6
    mov x1, x0  //, _7
    adrp    x0, .LC2    // tmp130,
    add x0, x0, :lo12:.LC2  //, tmp130,
    bl  printf      //
// vars-section.c:28:     printf("func locals: r+s=%d, ia[3]=%d, ca=%s\n", r+s, ia[3], ca);
    ldr w1, [sp, 24]    // tmp131, r
    ldr w0, [sp, 28]    // tmp132, s
    add w0, w1, w0  // _8, tmp131, tmp132
    ldr w1, [sp, 44]    // _9, ia[3]
    add x2, sp, 48  // tmp133,,
    mov x3, x2  //, tmp133
    mov w2, w1  //, _9
    mov w1, w0  //, _8
    adrp    x0, .LC3    // tmp134,
    add x0, x0, :lo12:.LC3  //, tmp134,
    bl  printf      //
// vars-section.c:29:     printf("func local static: o++=%ld, ++p=%hd, q++=%d\n", o++, ++p, q++);
    adrp    x0, o.5 // tmp136,
    add x0, x0, :lo12:o.5   // tmp135, tmp136,
    ldr x0, [x0]    // o.3_10, o
    add x2, x0, 1   // _12, o.3_10,
    adrp    x1, o.5 // tmp138,
    add x1, x1, :lo12:o.5   // tmp137, tmp138,
    str x2, [x1]    // _12, o
// vars-section.c:29:     printf("func local static: o++=%ld, ++p=%hd, q++=%d\n", o++, ++p, q++);
    adrp    x1, p.4 // tmp140,
    add x1, x1, :lo12:p.4   // tmp139, tmp140,
    ldrsh   w1, [x1]    // p.5_13, p
    and w1, w1, 65535   // p.6_14, p.5_13
    add w1, w1, 1   // tmp141, p.6_14,
    and w1, w1, 65535   // _15, tmp141
    sxth    w2, w1  // _16, _15
// vars-section.c:29:     printf("func local static: o++=%ld, ++p=%hd, q++=%d\n", o++, ++p, q++);
    adrp    x1, p.4 // tmp143,
    add x1, x1, :lo12:p.4   // tmp142, tmp143,
    strh    w2, [x1]    // tmp144, p
// vars-section.c:29:     printf("func local static: o++=%ld, ++p=%hd, q++=%d\n", o++, ++p, q++);
    adrp    x1, p.4 // tmp146,
    add x1, x1, :lo12:p.4   // tmp145, tmp146,
    ldrsh   w1, [x1]    // p.7_17, p
// vars-section.c:29:     printf("func local static: o++=%ld, ++p=%hd, q++=%d\n", o++, ++p, q++);
    mov w4, w1  // _18, p.7_17
    adrp    x1, q.3 // tmp148,
    add x1, x1, :lo12:q.3   // tmp147, tmp148,
    ldr w1, [x1]    // q.8_19, q
    add w3, w1, 1   // _21, q.8_19,
    adrp    x2, q.3 // tmp150,
    add x2, x2, :lo12:q.3   // tmp149, tmp150,
    str w3, [x2]    // _21, q
    mov w3, w1  //, q.8_19
    mov w2, w4  //, _18
    mov x1, x0  //, o.3_10
    adrp    x0, .LC4    // tmp151,
    add x0, x0, :lo12:.LC4  //, tmp151,
    bl  printf      //
// vars-section.c:30: }
    nop 
    adrp    x0, :got:__stack_chk_guard  // tmp153,
    ldr x0, [x0, #:got_lo12:__stack_chk_guard]  // tmp152, tmp153,
    ldr x2, [sp, 56]    // tmp155, D.4466
    ldr x1, [x0]    // tmp156,
    subs    x2, x2, x1  // tmp155, tmp156
    mov x1, 0   // tmp156
    beq .L2     //,
    bl  __stack_chk_fail        //
.L2:
    ldp x29, x30, [sp], 64  //,,,
    .cfi_restore 30
    .cfi_restore 29
    .cfi_def_cfa_offset 0
    ret 
    .cfi_endproc
.LFE0:
    .size   func, .-func
    .section    .rodata
    .align  3
.LC5:
    .string "lmn = %ld\n"
    .align  3
.LC6:
    .string "uvw = %ld\n"
    .align  3
.LC7:
    .string "strlen(%s) = %zu; strlen(%s) = %zu\n"
    .text
    .align  2
    .global main
    .type   main, %function
main:
.LFB1:
    .cfi_startproc
    stp x29, x30, [sp, -80]!    //,,,
    .cfi_def_cfa_offset 80
    .cfi_offset 29, -80
    .cfi_offset 30, -72
    mov x29, sp //,
    stp x19, x20, [sp, 16]  //,,
    str x21, [sp, 32]   //,
    .cfi_offset 19, -64
    .cfi_offset 20, -56
    .cfi_offset 21, -48
// vars-section.c:38:     for (int i=0; i<3; i++)
    str wzr, [sp, 60]   //, i
// vars-section.c:38:     for (int i=0; i<3; i++)
    b   .L4     //
.L5:
// vars-section.c:40:         func();
    bl  func        //
// vars-section.c:38:     for (int i=0; i<3; i++)
    ldr w0, [sp, 60]    // tmp113, i
    add w0, w0, 1   // tmp112, tmp113,
    str w0, [sp, 60]    // tmp112, i
.L4:
// vars-section.c:38:     for (int i=0; i<3; i++)
    ldr w0, [sp, 60]    // tmp114, i
    cmp w0, 2   // tmp114,
    ble .L5     //,
// vars-section.c:43:     long lmn = l+m+n;
    adrp    x0, m   // tmp116,
    add x0, x0, :lo12:m // tmp115, tmp116,
    ldrsh   w0, [x0]    // m.10_1, m
    mov w1, w0  // _2, m.10_1
    adrp    x0, l   // tmp118,
    add x0, x0, :lo12:l // tmp117, tmp118,
    ldr w0, [x0]    // l.11_3, l
    add w0, w1, w0  // _4, _2, l.11_3
    sxtw    x1, w0  // _5, _4
// vars-section.c:43:     long lmn = l+m+n;
    adrp    x0, n   // tmp120,
    add x0, x0, :lo12:n // tmp119, tmp120,
    ldr x0, [x0]    // n.12_6, n
// vars-section.c:43:     long lmn = l+m+n;
    add x0, x1, x0  // tmp121, _5, n.12_6
    str x0, [sp, 64]    // tmp121, lmn
// vars-section.c:44:     printf("lmn = %ld\n", lmn);
    ldr x1, [sp, 64]    //, lmn
    adrp    x0, .LC5    // tmp122,
    add x0, x0, :lo12:.LC5  //, tmp122,
    bl  printf      //
// vars-section.c:46:     long uvw = u+v+w;
    adrp    x0, u.2 // tmp124,
    add x0, x0, :lo12:u.2   // tmp123, tmp124,
    ldrsh   w0, [x0]    // u.13_7, u
    mov w1, w0  // _8, u.13_7
    adrp    x0, v.1 // tmp126,
    add x0, x0, :lo12:v.1   // tmp125, tmp126,
    ldr w0, [x0]    // v.14_9, v
    add w0, w1, w0  // _10, _8, v.14_9
    sxtw    x1, w0  // _11, _10
// vars-section.c:46:     long uvw = u+v+w;
    adrp    x0, w.0 // tmp128,
    add x0, x0, :lo12:w.0   // tmp127, tmp128,
    ldr x0, [x0]    // w.15_12, w
// vars-section.c:46:     long uvw = u+v+w;
    add x0, x1, x0  // tmp129, _11, w.15_12
    str x0, [sp, 72]    // tmp129, uvw
// vars-section.c:47:     printf("uvw = %ld\n", uvw);
    ldr x1, [sp, 72]    //, uvw
    adrp    x0, .LC6    // tmp130,
    add x0, x0, :lo12:.LC6  //, tmp130,
    bl  printf      //
// vars-section.c:49:     printf("strlen(%s) = %zu; strlen(%s) = %zu\n", str1, strlen(str1), str2, strlen(str2));
    adrp    x0, str1    // tmp132,
    add x0, x0, :lo12:str1  // tmp131, tmp132,
    ldr x19, [x0]   // str1.16_13, str1
    adrp    x0, str1    // tmp134,
    add x0, x0, :lo12:str1  // tmp133, tmp134,
    ldr x0, [x0]    // str1.17_14, str1
    bl  strlen      //
    mov x21, x0 // _15,
    adrp    x0, str2    // tmp136,
    add x0, x0, :lo12:str2  // tmp135, tmp136,
    ldr x20, [x0]   // str2.18_16, str2
    adrp    x0, str2    // tmp138,
    add x0, x0, :lo12:str2  // tmp137, tmp138,
    ldr x0, [x0]    // str2.19_17, str2
    bl  strlen      //
    mov x4, x0  //, _18
    mov x3, x20 //, str2.18_16
    mov x2, x21 //, _15
    mov x1, x19 //, str1.16_13
    adrp    x0, .LC7    // tmp139,
    add x0, x0, :lo12:.LC7  //, tmp139,
    bl  printf      //
// vars-section.c:57:     return 0;
    mov w0, 0   // _28,
// vars-section.c:58: }
    ldp x19, x20, [sp, 16]  //,,
    ldr x21, [sp, 32]   //,
    ldp x29, x30, [sp], 80  //,,,
    .cfi_restore 30
    .cfi_restore 29
    .cfi_restore 21
    .cfi_restore 19
    .cfi_restore 20
    .cfi_def_cfa_offset 0
    ret 
    .cfi_endproc
.LFE1:
    .size   main, .-main
    .local  o.5
    .comm   o.5,8,8
    .data
    .align  1
    .type   p.4, %object
    .size   p.4, 2
p.4:
    .hword  3
    .local  q.3
    .comm   q.3,4,4
    .local  u.2
    .comm   u.2,2,2
    .align  2
    .type   v.1, %object
    .size   v.1, 4
v.1:
    .word   3
    .local  w.0
    .comm   w.0,8,8
    .ident  "GCC: (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0"
    .section    .note.GNU-stack,"",@progbits

vars#

Refer to GNU Assembler Directives:

.type name,type_description: sets the type of a symbol name to be either a function or an object. Valid values for type_desription in GNU AArch64 assembly include:

  • %function : The symbol is a function name.
  • %object : The symbol is a data object.
  • %common : The symbol is a common (shared) object.

int i#

Uninitialized global int i will be initialized with 0 and placed in the .bss section:

  • .type = %object: data object
  • .size = 4 Byte
  • .align = 2 => 2^2: 4 Byte
    .global i
    .bss
    .align  2
    .type   i, %object
    .size   i, 4
i:
    .zero   4

short j = 2#

Initialized global short j = 2; is placed in the .data section:

  • .type = %object: data object
  • .size = 2 Byte
  • .align = 1 => 2^1: 2 Byte
    .global j
    .data
    .align  1
    .type   j, %object
    .size   j, 2
j:
    .hword  2

long k = 0#

Initialized global long k = 0; is placed in the .bss section:

  • .type = %object: data object
  • .size = 8 Byte
  • .align = 3 => 2^3: 8 Byte
    .global k
    .bss
    .align  3
    .type   k, %object
    .size   k, 8
k:
    .zero   8

static int l#

Uninitialized local static int l;:

    .local  l
    .comm   l,4,4

At this momoent, l is labelled as .comm which means it's a tentative definition.

Tentative, Induced, External

Modern C | 13 Storage

Tentative indicates that a definition is implied only if there is no other definition with an initializer.
Induced indicates that the linkage is internal if another declaration with internal linkage has been met prior to that declaration;
otherwise, it is external.

The compiler will not allocate any space for l yet. The two "4"s at the end mean that if space is allocated for l in the future, the size of l will be 4 bytes and the address of l should be 4-byte aligned.

static short m = 5#

Initialized static short m = 5; is placed in the .data section:

  • .type = %object: data object
  • .size = 2 Byte
  • .align = 1 => 2^1: 2 Byte
    .data
    .align  1
    .type   m, %object
    .size   m, 2
m:
    .hword  5

static long n = 0#

Uninitialized local static long n = 0;:

    .local  n
    .comm   n,8,8

Why initialized n is also labelled as .comm as uninitialized l?

char *str1#

Initialized global char *str1 = "hello"; is placed in the .rodata section, alias to label .LC0:

  • .align = 3 => 2^3: 8 Byte under aarch64/LP64
    .global str1
    .section    .rodata
    .align  3
.LC0:
    .string "hello"

    .section    .data.rel.local,"aw"
    .align  3
    .type   str1, %object
    .size   str1, 8
str1:
    .xword  .LC0

static char *str2#

Initialized static char *str2 = "world"; is also placed in the .rodata section, alias to label .LC1:

  • .align = 3 => 2^3: 8 Byte under aarch64/LP64
    .section    .rodata
    .align  3
.LC1:
    .string "world"

    .section    .data.rel.local
    .align  3
    .type   str2, %object
    .size   str2, 8
str2:
    .xword  .LC1

printf in func()#

format#

The format string of printf() in func() are placed in the .rodata section, labelled as .LC2 and .LC3:

  • .align = 3 => 2^3: 8 Byte under aarch64/LP64
    .section    .rodata

    .align  3
.LC2:
    .string "func global static: ijk = %ld\n"

    .align  3
.LC3:
    .string "func locals: r+s=%d, ia[3]=%d, ca=%s\n"

    .align  3
.LC4:
    .string "func local static: o++=%ld, ++p=%hd, q++=%d\n"

printf 1#

printf("func global static: ijk = %ld\n", i+j+k);

  1. load j to W1:

    • line 113~114: after ADRP and ADD, X0 holds address of short j.
    • line 115: LDRSH(Load Register Signed Halfword) loads a halfword(16-bits) from address X0 and sign extends the result to 32 bits, writes the result to W0.
    • line 116: w1=w0, W1 stores j, vacate W0 for other use.
  2. load i to W0:

    • line 117~118: after ADRP and ADD, X0 holds address of int i.
    • line 119: w0=[x0] => W0=i;
  3. calc j+i and store to X1:

    • line 120: w0=w1+w0 => W0=j+i;
    • line 121: SXTW(Sign Extend Word) W0 to X1(64-bits), vacate W0.
  4. load k to X0:

    • line 123~124: after ADRP and ADD, X0 holds address of long k.
    • line 125: x0=[x0] => X0=k;
  5. calc (j+i)+k and store to X1:

    • line 126: x0=x1+x0 => X0=(j+i)+k;
    • line 127: x1=x0, X1 stores i+j+k, vacate X0.
  6. line 128~129: X0 holds the format placeholder of printf -- .LC2.

printf 2#

Look at char ca[] = "hello";, array name ca will decays to a pointer.

ca is a local auto variable on the stack. As its value is equal to global string str1, it's optimized to point to the same copy. So it stores the address of str1(alias to .LC0).

printf("func locals: r+s=%d, ia[3]=%d, ca=%s\n", r+s, ia[3], ca);

  1. line 105~106, after ADRP and ADD, X1 holds address of label .LC0
  2. line 107: x0=sp+48, auto var in stack for ca(type of char *)
  3. line 108: w2=[x1], W2 holds address of .LC0
  4. line 109: [x0]=w2, ca holds the address of (points to) .LC0
  5. line 110~111: ldrh w1, [x1, 4]; strh w1, [x0, 4]; ?
  6. line 136~137: x2=sp+48; x3=x2 => X3=sp+48 which stores ca.
  7. line 140~141: X0 holds the format placeholder of printf -- .LC3.

printf 3(o,p,q)#

Local static o and q are labelled as .comm at the moment; Initialized p is placed in the .data section.

They're suffixed o.5, p.4, q.3 to avoid conflicting with same-named outer-scope vars.

    // static long o;
    .local  o.5
    .comm   o.5,8,8

    // static short p = 3;
    .data
    .align  1
    .type   p.4, %object
    .size   p.4, 2
p.4:
    .hword  3

    // static int q = 0;
    .local  q.3
    .comm   q.3,4,4

printf("func local static: o++=%ld, ++p=%hd, q++=%d\n", o++, ++p, q++);

  1. o++

    • line 144~145: x0=&o(load o)
    • line 146: x0=o.5
    • line 147: x2=x0+1 => x2 = o.5+1(auto increment)
    • line 148~149: x1=&o(reload o)
    • line 150: o.5=x2 => update o.5+1 to o.5
    • line 178: x1=x0(X1 for printf o++=%ld) output original o
  2. ++p

    • line 152~153: x1=&p(load p)
    • line 154: LDRSH(Load Register Signed Halfword) loads a halfword(16-bits) from address X1 and sign extends the result to 32 bits, writes the result to W1.
    • line 155: w1 = w1 & 0x0000ffff, clear high 16-bits, leave low 16-bits (represent short value).
    • line 156: w1 = w1+1(auto increment)
    • line 157: w1 = w1 & 0x0000ffff, clear high 16-bits, leave low 16-bits (represent short value).
    • line 158: SXTH(Sign Extend Halfword) W1 to W2, vacate W1.
    • line 160~161: x1=&p(reload p)
    • line 162: STRH(Store Register Halfword) W2 to [X1] => update p.4+1 to p.4
    • line 164~165: x1=&p(reload latest p)
    • line 166: LDRSH(Load Register Signed Halfword) loads a halfword(16-bits) from address X1 and sign extends the result to 32 bits, writes the result to W1.
    • line 168,177: w4=w1; w2=w4(W2 for printf ++p=%hd)
  3. q++(almost the same as o++)

    • line 169~170: x1=&q(load q)
    • line 171: w1=q.3
    • line 172: w3=w1+1 => w3 = q.3+1(auto increment)
    • line 173~174: x2=&q(reload q)
    • line 175: q.3=w3 => update q.3+1 to q.3
    • line 176: w3=w1(W3 for printf q++=%d) output original q
  4. line 179~180: X0 holds the format placeholder of printf -- .LC4.

printf in main()#

format#

The format string of printf() in main() are also placed in the .rodata section, labelled as .LC5, .LC6 and .LC7:

    .section    .rodata

    .align  3
.LC5:
    .string "lmn = %ld\n"

    .align  3
.LC6:
    .string "uvw = %ld\n"

    .align  3
.LC7:
    .string "strlen(%s) = %zu; strlen(%s) = %zu\n"

printf 1#

long lmn = l+m+n; printf("lmn = %ld\n", lmn);

  1. line 245~146: x0=&m(load m)
  2. line 247: LDRSH(Load Register Signed Halfword) loads a halfword(16-bits) from address X0 and sign extends the result to 32 bits, writes the result to W0
  3. line 248: w1=w0, vacate W0
  4. line 249~250: x0=&l(load l)
  5. line 251: w0=[x0]
  6. line 252: w0=w1+w0 => W0=m+l
  7. line 253: SXTW(Sign Extend Word) W0 to X1(64-bits), vacate W0.
  8. line 255~256: x0=&n(load n)
  9. line 257: x0=[x0]
  10. line 259: x0=x1+x0 => X0=(m+l)+n
  11. line 260: [sp+64]=x0 => store (m+l)+n to sp+64(auto var lmn in stack)
  12. line 262: x1=[sp+64] => load lmn to X1(for printf lmn = %ld)
  13. line 263~264: X0 holds the format placeholder of printf -- .LC5.

printf 2(u+v+w)#

Local static u and w are labelled as .comm at the moment; Initialized v is placed in the .data section.

They're suffixed u.0, v.1, w.2 to avoid conflicting with same-named outer-scope vars.

    .data

    // static long w = 0;
    .local  w.2
    .comm   w.2,8,8

    // static int v = 3;
    .align  2
    .type   v.1, %object
    .size   v.1, 4
v.1:
    .word   3

    // static short u;
    .local  u.0
    .comm   u.0,2,2

long uvw = u+v+w; printf("uvw = %ld\n", uvw);

  1. line 267~268: x0=&u(load u)
  2. line 269: LDRSH(Load Register Signed Halfword) loads a halfword(16-bits) from address X0 and sign extends the result to 32 bits, writes the result to W0
  3. line 270: w1=w0, vacate W0
  4. line 271~272: x0=&v(load v)
  5. line 273: w0=[x0]
  6. line 274: w0=w1+w0 => W0=u+v
  7. line 275: SXTW(Sign Extend Word) W0 to X1(64-bits), vacate W0.
  8. line 277~278: x0=&w(load w)
  9. line 279: x0=[x0]
  10. line 281: x0=x1+x0 => X0=(u+v)+w
  11. line 282: [sp+72]=x0 => store (u+v)+w to sp+72(auto var uvw in stack)
  12. line 284: x1=[sp+72] => load uvw to X1(for printf uvw = %ld)
  13. line 285~286: X0 holds the format placeholder of printf -- .LC6.

printf 3#

printf("strlen(%s) = %zu; strlen(%s) = %zu\n", str1, strlen(str1), str2, strlen(str2));

  1. line 289~290: x0=&str1(load str1)
  2. line 291: x19=[x0]
  3. line 292~293: x0=&str1(reload str1)
  4. line 294: x0=[x0] (param for strlen)
  5. line 295~296: x21=strlen(str1)
  6. line 297~298: x0=&str2(load str2)
  7. line 299: x20=[x0]
  8. line 300~301: x0=&str2(reload str2)
  9. line 302: x0=[x0] (param for strlen)
  10. line 303~304: x4=strlen(str2)
  11. line 305: x3=x20=&str2
  12. line 306: x2=x21=strlen(str1)
  13. line 307: x1=x19=&str1
  14. line 308~309: X0 holds the format placeholder of printf -- .LC7.

Comments