clang / LLVM ARM ABI, энергонезависимые регистры уничтожаются - PullRequest
2 голосов
/ 08 апреля 2020

Таким образом, пытаясь использовать clang / llvm в качестве кросс-компилятора для ARM cortex-m

Основываясь на / некоторых страницах LLVM, я создаю тест цепочки инструментов

rm -rf /opt/llvm/llvm10armv6m
rm -rf llvm-project
git clone https://github.com/llvm/llvm-project.git
cd llvm-project
git checkout llvmorg-10.0.0
mkdir build
cd build
cmake -DLLVM_ENABLE_PROJECTS='clang;lld' -DCMAKE_CROSSCOMPILING=True -DCMAKE_INSTALL_PREFIX=/opt/llvm/llvm10armv6m -DLLVM_DEFAULT_TARGET_TRIPLE=armv6m-none-eabi -DLLVM_TARGET_ARCH=ARM -DLLVM_TARGETS_TO_BUILD=ARM -G "Unix Makefiles" ../llvm
make -j 8
make -j 4
make
sudo make install

. . c

void fun ( unsigned int, unsigned int );
int test ( void )
{
    unsigned int ra;
    unsigned int rx;

    for(rx=0;;rx++)
    {
        ra=rx;
        ra|=((~rx)&0xFF)<<16;
        fun(0x12345678,ra);
    }
    return(0);
}

clang -Wall -O2 -nostdlib -ffreestanding -fomit-frame-pointer -c test.c -o test.o
arm-none-eabi-objdump -D test.o


Disassembly of section .text:

00000000 <test>:
   0:   20ff        movs    r0, #255    ; 0xff
   2:   0405        lsls    r5, r0, #16
   4:   2600        movs    r6, #0
   6:   4c06        ldr r4, [pc, #24]   ; (20 <test+0x20>)
   8:   4637        mov r7, r6
   a:   4629        mov r1, r5
   c:   43b1        bics    r1, r6
   e:   4339        orrs    r1, r7
  10:   4620        mov r0, r4
  12:   f7ff fffe   bl  0 <fun>
  16:   2001        movs    r0, #1
  18:   0400        lsls    r0, r0, #16
  1a:   1836        adds    r6, r6, r0
  1c:   1c7f        adds    r7, r7, #1
  1e:   e7f4        b.n a <test+0xa>
  20:   12345678    eorsne  r5, r4, #120, 12    ; 0x7800000

(вывод gnus намного лучше)

Проблема здесь в том, что оружие abi говорит не уничтожать r4 и выше, конечно, не r4 и r7, как здесь, также он не сохраняет регистр ссылки для возврата из этой функции (хотя я предполагаю, что он видит, что это бесконечный l oop и не возвращает (пожалуйста, не говорите мне, что я снова попал в ошибку lvm ​​бесконечный l oop)).

с указателем кадра это не становится лучше

00000000 <test>:
   0:   b580        push    {r7, lr}
   2:   af00        add r7, sp, #0
   4:   20ff        movs    r0, #255    ; 0xff
   6:   0405        lsls    r5, r0, #16
   8:   2400        movs    r4, #0
   a:   4626        mov r6, r4
   c:   4629        mov r1, r5
   e:   43a1        bics    r1, r4
  10:   4331        orrs    r1, r6
  12:   4804        ldr r0, [pc, #16]   ; (24 <test+0x24>)
  14:   f7ff fffe   bl  0 <fun>
  18:   2001        movs    r0, #1
  1a:   0400        lsls    r0, r0, #16
  1c:   1824        adds    r4, r4, r0
  1e:   1c76        adds    r6, r6, #1
  20:   e7f4        b.n c <test+0xc>
  22:   46c0        nop         ; (mov r8, r8)
  24:   12345678    eorsne  r5, r4, #120, 12    ; 0x7800000

, а сборка цепочки инструментов для

armv6m-none-gnueabi

не делает его лучше

, но если Я беру обобщенную c apt-gotten clang / llvm

clang -Wall -O2 -nostdlib -ffreestanding -fomit-frame-pointer -target armv6m-none-gnueabi -mthumb -mcpu=cortex-m0 -c test.c -o test.o
arm-none-eabi-objdump -D test.o

Disassembly of section .text:

00000000 <test>:
   0:   b5f0        push    {r4, r5, r6, r7, lr}
   2:   b081        sub sp, #4
   4:   20ff        movs    r0, #255    ; 0xff
   6:   0405        lsls    r5, r0, #16
   8:   2600        movs    r6, #0
   a:   4c06        ldr r4, [pc, #24]   ; (24 <test+0x24>)
   c:   4637        mov r7, r6
   e:   4629        mov r1, r5
  10:   43b1        bics    r1, r6
  12:   4339        orrs    r1, r7
  14:   4620        mov r0, r4
  16:   f7ff fffe   bl  0 <fun>
  1a:   2001        movs    r0, #1
  1c:   0400        lsls    r0, r0, #16
  1e:   1836        adds    r6, r6, r0
  20:   1c7f        adds    r7, r7, #1
  22:   e7f4        b.n e <test+0xe>
  24:   12345678    eorsne  r5, r4, #120, 12    ; 0x7800000

проблема исчезла.

Теперь да, на момент написания этой статьи встроенный v10 и apt-gotten один v6 (сборка v10, почему для сборки требуется целая вечность? ge?)

при использовании той же командной строки против встроенной без изменений проблема abi.

Теперь, если я не оптимизирую, возможно, это просто глупая удача:

00000000 <test>:
   0:   b580        push    {r7, lr}
   2:   b082        sub sp, #8
   4:   2000        movs    r0, #0
   6:   9000        str r0, [sp, #0]
   8:   e7ff        b.n a <test+0xa>
   a:   9800        ldr r0, [sp, #0]
   c:   9001        str r0, [sp, #4]
   e:   4668        mov r0, sp
  10:   7800        ldrb    r0, [r0, #0]
  12:   21ff        movs    r1, #255    ; 0xff
  14:   4048        eors    r0, r1
  16:   0400        lsls    r0, r0, #16
  18:   9901        ldr r1, [sp, #4]
  1a:   4301        orrs    r1, r0
  1c:   9101        str r1, [sp, #4]
  1e:   9901        ldr r1, [sp, #4]
  20:   4803        ldr r0, [pc, #12]   ; (30 <test+0x30>)
  22:   f7ff fffe   bl  0 <fun>
  26:   e7ff        b.n 28 <test+0x28>
  28:   9800        ldr r0, [sp, #0]
  2a:   1c40        adds    r0, r0, #1
  2c:   9000        str r0, [sp, #0]
  2e:   e7ec        b.n a <test+0xa>
  30:   12345678    eorsne  r5, r4, #120, 12    ; 0x7800000

Ссылки плохие в SO, поэтому

Как кросс-компилировать Clang / LLVM с использованием Clang / LLVM

Это название страницы, на которой есть информация, подобная этой

The CMake options you need to add are:

-DCMAKE_CROSSCOMPILING=True
-DCMAKE_INSTALL_PREFIX=<install-dir>
-DLLVM_TABLEGEN=<path-to-host-bin>/llvm-tblgen
-DCLANG_TABLEGEN=<path-to-host-bin>/clang-tblgen
-DLLVM_DEFAULT_TARGET_TRIPLE=arm-linux-gnueabihf
-DLLVM_TARGET_ARCH=ARM
-DLLVM_TARGETS_TO_BUILD=ARM

Я начал с тройки gnu, которую я использую в качестве упоминания на странице, но потом увидел, что llvm имеет суб-архитектуру, поэтому добавил, что изначально все выглядело хорошо, пока я не создал программу с несколькими строками в этом.

Я неправильно строю llvm? Или это просто бесконечная l oop вещь? (или другое ...)

РЕДАКТИРОВАТЬ обновленный скрипт сборки:

export THEPLACE=/opt/llvm/llvm10armv6m
export THETARGET=armv6m-none-eabi

rm -rf $THEPLACE
rm -rf llvm-project
git clone https://github.com/llvm/llvm-project.git
cd llvm-project
git checkout llvmorg-10.0.0
mkdir build
cd build
cmake \
-DLLVM_ENABLE_PROJECTS='clang;lld' \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_CROSSCOMPILING=True \
-DCMAKE_INSTALL_PREFIX=$THEPLACE \
-DLLVM_DEFAULT_TARGET_TRIPLE=$THETARGET \
-DLLVM_TARGET_ARCH=ARM \
-DLLVM_TARGETS_TO_BUILD=ARM \
-G "Unix Makefiles" \
../llvm

make -j 8
make -j 4
make
sudo make install

материал tbl-gen явно не нужен. Теоретически, -G Unix Makefiles должен допускать параллельные сборки make-файлов, но у меня была проблема с этим. Одно или два места, где он работал, один, который не работал, и должен был бы бежать снова и снова или, в конце концов, поочередно. таким образом, в конце концов получается так.

При сборке Release бинарные файлы ЗНАЧИТЕЛЬНО меньше вместо десятков ГБ, это как 1.somethingGB для всей установки.

Я не думаю, что сборка происходит быстрее. По-прежнему на одном уровне со зданием g cc в 1990-х годах.

1 Ответ

2 голосов
/ 08 апреля 2020

Ответ довольно прост: ваша функция никогда не возвращается. Поэтому нет смысла сохранять / восстанавливать регистры, сохраненные вызываемыми пользователями.

Если вы измените свой источник, чтобы позволить прекращению функции, например:

void fun ( unsigned int, unsigned int );
unsigned bar();
int test ( void )
{
    unsigned int ra;
    unsigned int rx;

    for(rx=0;rx<bar();rx++)
    {
        ra=rx;
        ra|=((~rx)&0xFF)<<16;
        fun(0x12345678,ra);
    }
    return(0);
}

Все будет сохранено / восстановлено, как вы и ожидали.

PS: я бы не стал комментировать, является ли l oop бесконечным UB

PPS: вы, безусловно, захотите скомпилировать llvm / clang в режиме Release - двоичные файлы будут меньше, а время компоновки значительно сократится.

...