[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Issues with modifying pc in a sigaction handler

From: Devin Hussey
Subject: Issues with modifying pc in a sigaction handler
Date: Tue, 13 Apr 2021 18:03:52 -0400

In a toy project I was doing
(https://github.com/easyaspi314/ThumbGolf), I found that qemu will
incorrectly handle modifying pc in a handler.

Specifically, on platforms with instruction alignment requirements
(most notably ARM), if you set the pc to an odd address, QEMU will
start reading unaligned instructions.

Naturally, this is frustrating when dealing with ARM Thumb functions
which have the lowest bit set when referenced, as you must manually
clear the Thumb bit instead of it being implicit on hardware.

The following code exhibits this bug for ARM:

#include <signal.h>
#include <ucontext.h>
#include <stdio.h>

static void hello(void)

static void handler(int signo, siginfo_t *si, void *data)
    ucontext_t *uc = (ucontext_t *)data;
    // Effectively bl hello although we assume thumb state
    uc->uc_mcontext.arm_lr = uc->uc_mcontext.arm_pc + 2 | 1;
    uc->uc_mcontext.arm_pc = (unsigned long)&hello;

int main(void)
    // Set up the signal handler
    struct sigaction sa, osa;
    sa.sa_sigaction = handler;
    sigaction(SIGILL, &sa, &osa);
    sigaction(SIGTRAP, &sa, &osa);

    // Throw a SIGILL, which we do a runtime patch to call hello().
    // Make sure we mark the caller saved registers.
    __asm__ ("udf #0" ::: "r0", "r1", "r2", "r3", "r12", "lr", "memory");
    printf(" world!\n");
Compile with:
clang -O2 -march=armv7-a -mthumb file.c -static

(The same should happen with GCC).

On hardware (specifically, a Snapdragon 730g in Termux on Android 11),
the code prints "Hello, world!" and exits normally.

However, qemu-arm will get tripped up by the pc being odd, and execute this:

... snip
IN: main
0x00010288:  4c05       ldr      r4, [pc, #0x14]
0x0001028a:  de00       udf      #0

IN: handler
0x000102a4:  4804       ldr      r0, [pc, #0x10]
0x000102a6:  6dd1       ldr      r1, [r2, #0x5c]
0x000102a8:  4478       add      r0, pc
0x000102aa:  3102       adds     r1, #2
0x000102ac:  f041 0101  orr      r1, r1, #1
0x000102b0:  e9c2 1016  strd     r1, r0, [r2, #0x58]
0x000102b4:  4770       bx       lr

IN: __restore_rt
0x0004c36c:  e3a070ad  mov      r7, #0xad
0x0004c370:  ef000000  svc      #0

IN: hello
0x000102bd:  7848       ldrb     r0, [r1, #1]
0x000102bf:  0644       lsls     r4, r0, #0x19
0x000102c1:  5cf0       ldrb     r0, [r6, r3]
0x000102c3:  06bb       lsls     r3, r7, #0x1a
0x000102c5:  053e       lsls     r6, r7, #0x14
0x000102c7:  f000 89b5  beq.w    #0x90635

qemu: uncaught target signal 11 (Segmentation fault) - core dumped


Note the odd addresses in hello().

It should be interpreted as so, which happens when you manually clear
the Thumb bit:

0x000102b8:  4801       ldr      r0, [pc, #4]
                         0x000102ba:  4478       add      r0, pc
                                                  0x000102bc:  f006
bb5c  b.w      #0x16978 (printf)

reply via email to

[Prev in Thread] Current Thread [Next in Thread]