Why does clang insert a giant block of padding in the middle of my function? How do I prevent this?

Why does clang insert a giant block of padding in the middle of my function? How do I prevent this?

I am attempting to write a bare-metal armv7a kernel from scratch. When compiling my implementation of printf, the resulting binary contains a massive block of andmi instructions:

$ arm-none-eabi-objdump  --disassembler-color=extended --visualize-jumps=color -Dx cmake-build-debug-arm32/leg.elf | less -R
4000874c <printf>:
4000874c:       ,----------------------> e24dd00c       sub     sp, sp, #12
40008750:       |                        e92d4ff0       push    {r4, r5, r6, r7, r8, r9, sl, fp, lr}
40008754:       |                        e28db01c       add     fp, sp, #28
40008758:       |                        e24dd028       sub     sp, sp, #40     @ 0x28
4000875c:       |                        e1a07000       mov     r7, r0
40008760:       |                        e58b1008       str     r1, [fp, #8]
40008764:       |                        e58b200c       str     r2, [fp, #12]
40008768:       |                        e58b3010       str     r3, [fp, #16]
4000876c:       |                        e28b0008       add     r0, fp, #8
40008770:       |                        e58d0004       str     r0, [sp, #4]
40008774:       |                        e3a06000       mov     r6, #0
40008778:       |                        e28d8008       add     r8, sp, #8
4000877c:       |                        e30991eb       movw    r9, #37355      @ 0x91eb
40008780:       |                        e3449000       movt    r9, #16384      @ 0x4000
40008784:       |        ,-------------> e1a04007       mov     r4, r7
40008788:       |        |               e4d40001       ldrb    r0, [r4], #1
4000878c:       |        |               e3500025       cmp     r0, #37 @ 0x25
40008790:       |        |           ,-- 0a000005       beq     400087ac <printf+0x60>
40008794:       |        |           |   e3500000       cmp     r0, #0
40008798:       |  ,-----|-----------|-- 0a000110       beq     40008be0 <printf+0x494>
4000879c:       |  |     |           |   eb000257       bl      40009100 <putchar>
400087a0:       |  |     |           |   e2866001       add     r6, r6, #1
400087a4:       |  |     |           |   e1a07004       mov     r7, r4
400087a8:       |  |     +-----------|-- eafffff5       b       40008784 <printf+0x38>
400087ac:       |  |     |           '-> e5d75001       ldrb    r5, [r7, #1]
400087b0:       |  |     |               e2450025       sub     r0, r5, #37     @ 0x25
400087b4:       |  |     |               e3500053       cmp     r0, #83 @ 0x53
400087b8:       |  |  ,--|-------------- 8a0000fa       bhi     40008ba8 <printf+0x45c>
400087bc:       |  |  |  |               e28f1000       add     r1, pc, #0
400087c0:       |  |  |  |               e791f100       ldr     pc, [r1, r0, lsl #2]
400087c4:       |  |  |  |               40008aa4       andmi   r8, r0, r4, lsr #21
400087c8:       |  |  |  |               40008ba8       andmi   r8, r0, r8, lsr #23
400087cc:       |  |  |  |               40008ba8       andmi   r8, r0, r8, lsr #23
400087d0:       |  |  |  |               40008ba8       andmi   r8, r0, r8, lsr #23
400087d4:       |  |  |  |               40008ba8       andmi   r8, r0, r8, lsr #23
400087d8:       |  |  |  |               40008ba8       andmi   r8, r0, r8, lsr #23
400087dc:       |  |  |  |               40008ba8       andmi   r8, r0, r8, lsr #23
400087e0:       |  |  |  |               40008ba8       andmi   r8, r0, r8, lsr #23
400087e4:       |  |  |  |               40008ba8       andmi   r8, r0, r8, lsr #23
400087e8:       |  |  |  |               40008ba8       andmi   r8, r0, r8, lsr #23
...
...
40008904:       |  |  |  |               4000895c       andmi   r8, r0, ip, asr r9
40008908:       |  |  |  |               40008ba8       andmi   r8, r0, r8, lsr #23
4000890c:       |  |  |  |               40008ba8       andmi   r8, r0, r8, lsr #23
40008910:       |  |  |  |               400089bc                       @ <UNDEFINED> instruction: 0x400089bc
40008914:       |  |  |  |               e59d0004       ldr     r0, [sp, #4]
40008918:       |  |  |  |               e2801004       add     r1, r0, #4
4000891c:       |  |  |  |               e58d1004       str     r1, [sp, #4]
40008920:       |  |  |  |               e5900000       ldr     r0, [r0]
40008924:       |  |  |  |               e28d5008       add     r5, sp, #8
40008928:       |  |  |  |               e1a01005       mov     r1, r5

I have tried several combinations of compiler flags, including optimizing for size or enabling/disabling features, but nothing seems to affect this. I did notice that the encoding of the pad instructions looks suspiciously similar to the current program address, but I don't really know what to do with that.

The permalink to the source that generates this binary is below. My compiler options can be found in the root CMakeLists.txt.
https://github.com/romirk/leg/blob/aabad666439dbd6be0eda4862cdee9a90e8a8245/src/stdio.c#L63

Any help diagnosing this is very appreciated. Thanks!

Answer

It is a jump table. The instructions that use it are immediately before it. add r1, pc, #0 loads a starting address for the table, and ldr pc, [r1, r0, lsl #2] loads the element at offset r0*4 in the table into the program counter.

Enjoyed this question?

Check out more content on our blog or follow us on social media.

Browse more questions