Hi,
Apologies if this is just me being dumb!
Either I’m going mad or alloca doesn’t work in a way that makes sense to me on the AVR back end?
I have some code that creates a load of alloca instructions. The program hung and when I stepped through in AVR-gdb I found it seemed to be creating stack corruption.
The IR…
define protected i32 @main(i32 %0, i8** nocapture readnone %1) local_unnamed_addr addrspace(1) #0 !dbg !31 {
%3 = tail call swiftcc addrspace(1) %swift.metadata_response @"$ss11_ArrayIndexVMa"(i16 0) #6, !dbg !43
%4 = extractvalue %swift.metadata_response %3, 0, !dbg !43
%5 = getelementptr inbounds %swift.type, %swift.type* %4, i16 -1, !dbg !43
%6 = bitcast %swift.type* %5 to i8***, !dbg !43
%7 = load i8**, i8*** %6, align 2, !dbg !43, !invariant.load !2, !dereferenceable !65
%8 = getelementptr inbounds i8*, i8** %7, i16 8, !dbg !43
%9 = bitcast i8** %8 to i16*, !dbg !43
%10 = load i16, i16* %9, align 2, !dbg !43, !invariant.load !2
%11 = alloca i8, i16 %10, align 16, !dbg !43
call addrspace(1) void @llvm.lifetime.start.p0i8(i64 -1, i8* nonnull %11), !dbg !43
%12 = bitcast i8* %11 to %swift.opaque*, !dbg !43
%13 = alloca i8, i16 %10, align 16, !dbg !66
call addrspace(1) void @llvm.lifetime.start.p0i8(i64 -1, i8* nonnull %13), !dbg !66
%14 = bitcast i8* %13 to %swift.opaque*, !dbg !66
etc etc something like 20 times
when I looked at the assembly lowered from one of the alloca instructions I saw this (as an example)…
360: 2d b7 in r18, 0x3d ; 61
362: 3e b7 in r19, 0x3e ; 62
364: 28 1b sub r18, r24
366: 39 0b sbc r19, r25
368: 20 7f andi r18, 0xF0 ; 240
36a: 49 01 movw r8, r18
36c: 0f b6 in r0, 0x3f ; 63
36e: f8 94 cli
370: 3e bf out 0x3e, r19 ; 62
372: 0f be out 0x3f, r0 ; 63
374: 2d bf out 0x3d, r18 ; 61
…basically repeated again and again. Obviously there’s an inefficiency with repeatedly loading and saving the SP. But the issue is it seems to me like it’s off by one? Say the stack pointer starts at 0x8FF, each time you PUSH, the SP will store the value in RAM at the location of SP (0x8FF), then decrement SP (0x8FE).
The alloca decrements SP by a chunk to create a stack allocation, say 16 bytes, then saves a pointer for use later (in this case the pointer is saved in r8/r9). My issue with this is the above code saves a pointer to the current SP, which is after the end of the stack. I think it should be saving a pointer to SP+1 should it not?
The stack corruption happens in my code later when a subroutine is called, pushing the return address onto the stack, then in the subroutine, data is stored at the address returned by one of these faulty alloca instructions. And as a result the return address is partly corrupted, when the subroutine hits RET it jumps back to the wrong place and chaos ensues!
What’s strange to me, this is coming from llvm head from the end of August and I would expect everyone to be going crazy if alloca was genuinely broken like this? Am I doing something silly?
Thanks for any advice and help.
Carl