0

I wrote this in C

int a;
int b[2] = {1, 2};

int main() { return a + b[1]; }
int func() { return a + b[0]; }

I used gcc -S and gcc -S -O1 to compiler it and output two assembly files named asm.s and asm-O1.s

There are two function in this code. Both of them use global variables a and b

here is the assembly code of asm.s

function func

func:
    @ args = 0, pretend = 0, frame = 0
    @ frame_needed = 1, uses_anonymous_args = 0
    @ link register save eliminated.
    str fp, [sp, #-4]!
    add fp, sp, #0
    ldr r3, .L7
    ldr r2, [r3]
    ldr r3, .L7+4
    ldr r3, [r3]
    add r3, r2, r3
    mov r0, r3
    add sp, fp, #0
    @ sp needed
    ldr fp, [sp], #4
    bx  lr
.L8:
    .align  2
.L7:
    .word   b
    .word   a
    .size   func, .-func
    .ident  "GCC: (Raspbian 8.3.0-6+rpi1) 8.3.0"
    .section    .note.GNU-stack,"",%progbits

function main

main:
    @ args = 0, pretend = 0, frame = 0
    @ frame_needed = 1, uses_anonymous_args = 0
    @ link register save eliminated.
    str fp, [sp, #-4]!
    add fp, sp, #0
    ldr r3, .L3
    ldr r2, [r3, #4]
    ldr r3, .L3+4
    ldr r3, [r3]
    add r3, r2, r3
    mov r0, r3
    add sp, fp, #0
    @ sp needed
    ldr fp, [sp], #4
    bx  lr
.L4:
    .align  2
.L3:
    .word   b
    .word   a
    .size   main, .-main
    .align  2
    .global func
    .syntax unified
    .arm
    .fpu vfp
    .type   func, %function

from the code we can see that function func puts the addr of a and b in the .L7 section and the function main puts the addr of a and b in the .L3 section

why ? for cache ?

and i have another question

here is the code of asm-O1.s

    .arch armv6
    .eabi_attribute 28, 1
    .eabi_attribute 20, 1
    .eabi_attribute 21, 1
    .eabi_attribute 23, 3
    .eabi_attribute 24, 1
    .eabi_attribute 25, 1
    .eabi_attribute 26, 2
    .eabi_attribute 30, 1
    .eabi_attribute 34, 1
    .eabi_attribute 18, 4
    .file   "global.c"
    .text
    .align  2
    .global main
    .arch armv6
    .syntax unified
    .arm
    .fpu vfp
    .type   main, %function
main:
    @ args = 0, pretend = 0, frame = 0
    @ frame_needed = 0, uses_anonymous_args = 0
    @ link register save eliminated.
    ldr r3, .L2
    ldr r0, [r3, #4]
    ldr r3, .L2+4
    ldr r3, [r3]
    add r0, r0, r3
    bx  lr
.L3:
    .align  2
.L2:
    .word   .LANCHOR0
    .word   a
    .size   main, .-main
    .align  2
    .global func
    .syntax unified
    .arm
    .fpu vfp
    .type   func, %function
func:
    @ args = 0, pretend = 0, frame = 0
    @ frame_needed = 0, uses_anonymous_args = 0
    @ link register save eliminated.
    ldr r3, .L5
    ldr r0, [r3]
    ldr r3, .L5+4
    ldr r3, [r3]
    add r0, r0, r3
    bx  lr
.L6:
    .align  2
.L5:
    .word   .LANCHOR0
    .word   a
    .size   func, .-func
    .global b
    .comm   a,4,4
    .data
    .align  2
    .set    .LANCHOR0,. + 0
    .type   b, %object
    .size   b, 8
b:
    .word   1
    .word   2
    .ident  "GCC: (Raspbian 8.3.0-6+rpi1) 8.3.0"
    .section    .note.GNU-stack,"",%progbits

in the section of function main

I can only see global variable a in .L2, why has b disappeared

marko
  • 9,029
  • 4
  • 30
  • 46
happy coding
  • 27
  • 1
  • 6
  • Compilers do PC-relative loads of 32-bit addresses from nearby literal pools because (without `movw/movk`) ARM would take even more than 2 instructions to generate a full 32-bit address in a register. [What does an equals sign = on the right side of a LDR instruction in ARM mean?](https://stackoverflow.com/q/37840754). I haven't looked at your code in detail to see what GCC is doing and whether it's optimizing one literal pool between functions, or if Godbolt is just filtering things out. – Peter Cordes May 31 '20 at 06:57
  • 2
    *why b disappeared* - it did not disappear, you just need to scroll further down, see (and use!) https://godbolt.org/z/xxj6Rs. Also, analysing UNoptimized output of gcc is generally a waste of time. Your *why ? for cache ?* question to the first part does not make sense - optimisation is OFF, so the compiler just produces something that works and that's it. – tum_ May 31 '20 at 07:49
  • 1
    @tum_: There is no `.word b` in that output, so in that respect it disappeared. There is a `.set .LANCHOR0,. + 0` before `b` is defined, so `.LANCHOR0` and `b` have the same address. Interestingly, if `b[]` is larger, we once again see a `.word b`. https://godbolt.org/z/cjrKG6. But yeah, this is all compiler internals / minutiae; it seems GCC is using separate literal pools for both functions, unfortunately. – Peter Cordes May 31 '20 at 08:29
  • @Peter Cordes what is `.LANCHOR0,. + 0` mean . been google for a long time , i did't see some doc about it – happy coding May 31 '20 at 08:39
  • 1
    See this [question](https://stackoverflow.com/q/55433736/6012693), I provided a link in one of the comments there. – tum_ May 31 '20 at 09:00
  • 1
    Terminology note: `.L2, .L3`, etc, are *labels*, not *sections*. They just mark particular locations in the code (typically so they can be used as branch targets); they aren't meant to break up the code into blocks, nor to describe how it should be laid out in memory (which is what sections do). – Nate Eldredge May 31 '20 at 16:48

0 Answers0