Winston
Winston

Reputation: 13

Tell the compiler to translate a certain instruction differently?

I'm using armcc and arm-gcc for compiling my project for an ARM968 processor.
When returning form a function call, the returning instruction is as follows:

Pop {ri-rj, pc}

All the pushed registers are popped in the same instruction. I want to change the instruction above into something like this:

Pop {ri-rj}
Pop {pc}

Can I instruct the assembler or the compiler to adhere to the rule above in any of the ARM tool chains when using Pop?

Upvotes: 1

Views: 184

Answers (2)

Notlikethat
Notlikethat

Reputation: 20924

Depending on the exact nature of the problem, and whether you're critically dependent on a handful of newer instructions, another possibility might be to compile for ARMv4T. Prior to ARMv5T, ldm into the PC was not interworking, so the compiler won't emit that form of return instruction for a v4T target. For some simple test code, compiling with -march=armv5t generates a stack frame thus:

   8:   e92d4070        push    {r4, r5, r6, lr}
...
  4c:   d8bd8070        pople   {r4, r5, r6, pc}

whereas compiling the same thing with -march=armv4t uses the same prologue but with an indirect return sequence (the above was a conditional return from inside a loop, now it's also moved out to the end of the function):

  48:   da000006        ble     68 <func+0x68>
...
  68:   e8bd4070        pop     {r4, r5, r6, lr}
  6c:   e12fff1e        bx      lr

Of course, whether that has the same effect as the two separate pops depends on what the underlying bug in the system is - if it's something like the timing between the data fetches of the ldm and the instruction fetches of the jump itself, then this might be sufficiently equivalent; it could conceivably be something quite different, like a broken memory system truncating AHB bursts above a certain size, so it's the number of registers transferred in a single ldm that's the issue, but in that case I'd also expect to see problems with things like memcpy which aren't so easily fixed.

Upvotes: 4

Stian Skjelstad
Stian Skjelstad

Reputation: 2335

you can tell gcc to stop processing after it has generated the assembler. The you can edit the assembler files manually or by using sed. Then you pass the assembler file to as from binutils to assemble it into an object file.

$ cat test.c
#include <stdio.h>

int main(int argc, char *argv[])
{
        printf ("hello world\n");

        return 0;
}
$ gcc test.c -o test.s -S
cat test.s
        .file   "test.c"
        .section        .rodata
.LC0:
        .string "hello world"
        .text
        .globl  main
        .type   main, @function
main:
.LFB0:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        subq    $16, %rsp
        movl    %edi, -4(%rbp)
        movq    %rsi, -16(%rbp)
        movl    $.LC0, %edi
        call    puts
        movl    $0, %eax
        leave
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE0:
        .size   main, .-main
        .ident  "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.1) 4.8.4"
        .section        .note.GNU-stack,"",@progbits
$ as test.s -o test.o

Upvotes: 0

Related Questions