Existe uma maneira de usar o gcc para converter C em MIPS?

Eu completei uma conversão de C para MIPS para uma classe, e quero verificá-la contra a montagem. Ouvi dizer que há uma maneira de configurar o gcc para que ele possa converter o código C para a arquitetura MIPS em vez da arquitetura x86 (Meu Computador usuários um processador Intel i5) e imprime a saída.

ao executar o terminal no Ubuntu (que vem com o gcc), qual o comando que uso para configurar o gcc para converter para MIPS? Há alguma coisa que eu preciso instalar como então?

editar: Deixe-me esclarecer. Por favor, leia isto. Eu não estou procurando por qual compilador usar, ou pessoas dizendo " Bem você poderia cruzar compilar, mas em vez disso você deve usar essa outra coisa que não tem instruções sobre como configurar."

Se vais postar isso, pelo menos dá-me instruções. O GCC veio com o Ubuntu. Eu não tenho experiência em como instalar Compiladores e não é fácil encontrar tutoriais on-line para qualquer outra coisa que não GCC. Então há o caso de também preciso de saber da compilação cruzada. Obrigado.

Author: Peter Cordes, 2010-11-14

7 answers

O GCC Pode produzir código de montagem para um grande número de arquitecturas, incluindo MIPS. Mas que Arquitetura um determinado alvo de instância GCC é decidido quando o próprio GCC é compilado. O binário pré-compilado que você vai encontrar em um sistema Ubuntu sabe sobre x86 (possivelmente ambos modos 32-bit e 64-bit), mas não MIPS.

O GCC com uma arquitectura-alvo distinta da arquitectura na qual o próprio GCC estará a correr é conhecido por preparar uma compilação cruzada toolchain . Isto é realizável, mas requer bastante leitura de documentação e paciência; você normalmente precisa primeiro construir um cross-assembler e cross-linker (GNU binutils), em seguida, construir o cross-GCC em si.

Recomendo a utilização de buildroot . Este é um conjunto de scripts e makefiles projetado para ajudar com a produção de um conjunto completo de ferramentas de compilação cruzada e utilitários. No final do dia, você terá um SO completo e ferramentas de desenvolvimento para um sistema alvo. Presente inclui o compilador que procura.

Outra solução completamente diferente é usar QEMU . Este é um emulador para vários processadores e sistemas, incluindo sistemas MIPS. Você pode usá-lo para executar uma máquina virtual com um processador MIPS, e, dentro dessa máquina, instalar um sistema operacional para MIPS, por exemplo, Debian, uma distribuição de Linux. Desta forma, você obter um nativo GCC (um GCC executando em um sistema MIPS e produzindo código para MIPS).

A maneira QEMU pode ser um pouco mais simples; usar cross-compilation requer alguma compreensão de alguns detalhes peludos. De qualquer forma, você vai precisar de cerca de 1 GB de espaço em disco livre.

 31
Author: Thomas Pornin, 2010-11-14 15:31:55
Não é uma coisa de configuração, precisas de uma versão do GCC que compile para MIPS. Isto requer uma construção GCC especial e é bastante peludo para configurar (o edifício GCC não é para os fracos de coração).

Eu recomendaria usar LCC para isto. É muito mais fácil fazer compilação cruzada com LCC do que com GCC, e construir LCC é uma questão de segundos em máquinas atuais.

 6
Author: Fabian Giesen, 2010-11-14 00:18:07

Você deve instalar um compilador cruzado dos repositórios Ubuntu. Existem quatro GCC MIPS C cross-compilers fornecidos nos repositórios. Escolha de acordo com suas necessidades:

  • 32 bits big-endian.
  • gcc-mipsel-linux-gnu - 32-bit little-endian.
  • 64 bits big-endian.
  • gcc-mips64el-linux-gnuabi64 - 64-bit little-endian.

(Nota para os utilizadores Debian: se normalmente quiser instalar os seus compiladores regulares usando o pacote build-essential, Você seria interessado em saber da existência de crossbuild-essential-mips, crossbuild-essential-mipsel e crossbuild-essential-mips64el)

Nos seguintes exemplos, eu vou assumir que você escolheu a versão little-endian de 32 bits (sudo apt-get install gcc-mipsel-linux-gnu). Os comandos para outras versões MIPS são semelhantes.

Para lidar com MIPS em vez da arquitectura nativa do seu sistema, use o comando mipsel-linux-gnu-gcc Em vez de gcc. Por exemplo, mipsel-linux-gnu-gcc -fverbose-asm -S myprog.c produz um ficheiro myprog.s que contém o conjunto MIPS.

Outra maneira de ver o conjunto MIPS: ficheiro do objecto myprog.o que contém informação de depuração. Em seguida, veja a desmontagem do arquivo do objeto usando mipsel-linux-gnu-objdump -d -S myprog.o. Por exemplo, se myprog.c é isto:
#include <stdio.h>

int main()
{
    int a = 1;
    int b = 2;
    printf("The answer is: %d\n", a + b);
    return 0;
}

E se for compilado usando mipsel-linux-gnu-gcc -g -c myprog.c, então {[17] } mostrará algo assim:

myprog.o:     file format elf32-tradlittlemips


Disassembly of section .text:

00000000 <main>:
#include <stdio.h>

int main() {
   0:   27bdffd8    addiu   sp,sp,-40
   4:   afbf0024    sw  ra,36(sp)
   8:   afbe0020    sw  s8,32(sp)
   c:   03a0f025    move    s8,sp
  10:   3c1c0000    lui gp,0x0
  14:   279c0000    addiu   gp,gp,0
  18:   afbc0010    sw  gp,16(sp)
    int a = 1;
  1c:   24020001    li  v0,1
  20:   afc20018    sw  v0,24(s8)
    int b = 2;
  24:   24020002    li  v0,2
  28:   afc2001c    sw  v0,28(s8)
    printf("The answer is: %d\n", a + b);
  2c:   8fc30018    lw  v1,24(s8)
  30:   8fc2001c    lw  v0,28(s8)
  34:   00621021    addu    v0,v1,v0
  38:   00402825    move    a1,v0
  3c:   3c020000    lui v0,0x0
  40:   24440000    addiu   a0,v0,0
  44:   8f820000    lw  v0,0(gp)
  48:   0040c825    move    t9,v0
  4c:   0320f809    jalr    t9
  50:   00000000    nop
  54:   8fdc0010    lw  gp,16(s8)
    return 0;
  58:   00001025    move    v0,zero
}
  5c:   03c0e825    move    sp,s8
  60:   8fbf0024    lw  ra,36(sp)
  64:   8fbe0020    lw  s8,32(sp)
  68:   27bd0028    addiu   sp,sp,40
  6c:   03e00008    jr  ra
  70:   00000000    nop
    ...
 4
Author: Flux, 2019-10-05 05:43:29

Você teria que baixar o código para binutils e GCC-core e compilar com algo como {[[0]}. Você pode precisar escolher um alvo MIPS específico. Então você poderia usar mips-gcc -S.

 2
Author: Ben Jackson, 2010-11-14 00:17:47

Você pode cruzar o GCC de modo que ele gera código MIPS em vez de x86. É uma boa experiência de aprendizagem.

Se quiser resultados rápidos, também poderá obter um GCC pré-construído com suporte para MIPS. Um deles é o porta-ferramentas do CodeSourcery Lite. É gratuito, vem para um monte de arquiteturas (incluindo MIPS) e eles têm pronto para usar binários para Linux e Windows.

Http://www.codesourcery.com/sgpp/lite/mips/portal/subscription?@template=lite

 2
Author: Nils Pipenbrinck, 2010-11-14 05:54:55

Você deve compilar a sua própria versão do gcc que é capaz de compilar de forma cruzada. Claro que isto não é fácil, por isso podes procurar uma abordagem diferente.. por exemplo este SDK.

 1
Author: Jack, 2010-11-14 00:19:40

Para um uso único para um pequeno programa ou funções de casal, você não precisa instalar nada localmente.

Usa o site do compilador explorer do Matt Godbolt, https://godbolt.org/, que tem GCC e clang para várias ISAs, incluindo MIPS e x86-64, e alguns outros compiladores.

Note que o compilador explorer por directivas de filtros por omissão para que você possa apenas ver as instruções, deixando de fora coisas como alinhamento, secções, .globl, e assim por diante. (Para função sem dados globais / estáticos, isso é realmente bom, especialmente quando você só quer usar um compilador para fazer um exemplo para você. A secção por omissão é .text de qualquer forma, se não usar quaisquer directivas.)


A maioria das pessoas que querem MIPS asm para trabalhos de casa estão usando SPIM ou MARS, geralmente sem slots de atraso de branch. (Ao contrário dos MIPS reais, então você precisa ajustar o compilador para Não tirar vantagem da próxima instrução depois de um branch correr incondicionalmente, mesmo quando está ocupado.) Para o GCC, a opção é -fno-delayed-branch - que irá preencher todos os espaços de atraso com um NOP, de modo que o código ainda será executado em um MIPS real. Você pode apenas remover manualmente todos os PoPs.

Pode haver outros ajustes necessários, como Marte pode exigir que você use {[[6]} em vez de j $31, Tweak mips-GCC output to work with MARS . E é claro que o código I / O terá de ser implementado usando As chamadas do sistema de brinquedos de Marte , não jal chamadas para funções de biblioteca padrão como printf ou std::ostream::operator<<. Você pode compilar (e ajustar à mão) asm para manipular dados, como multiplicar inteiros ou somar ou reverter um array, no entanto.

Infelizmente o GCC não tem a opção de usar nomes de registo como $a0 Em vez de $r. Para PowerPC há -mregnames para usar r1 em vez de 1, mas nenhuma opção semelhante para MIPS usar nomes reg "mais simbólicos".

int maybe_square(int num) {
    if (num>0)
        return num;
    return num * num;
}

Em Godbolt com GCC 5.4 -xc -O3 -march=mips32r2 -Wall -fverbose-asm -fno-delayed-branch

-xc compila como C, Não c++, Porque eu acho que é mais conveniente do que rodar entre as linguagens C E C++ no dropdown e fazer com que o site apague o meu código-fonte.

-fverbose-asm comenta o asm com nomes de variáveis C para o destino e fontes. (Em código otimizado que é muitas vezes um temporário inventado, mas nem sempre.)

-O3 activa a optimização completa, porque o modo de depuração por omissão -O0 é uma confusão horrível para os humanos lerem. Use sempre pelo menos -Og se quiser ver o código à mão e ver como implementa a fonte. Como remover o "ruído" da saída do conjunto GCC/clang?. Você também pode usar -fno-unroll-loops, e -fno-tree-vectorize se compilar para um ISA com instruções SIMD.

Isto usa mul em vez dos MIPS clássicos mult + mflo, graças à opção -march= para dizer ao GCC que estamos a compilar para um MIPS ISA posterior, não seja qual for a linha de base padrão. (Talvez MIPS I aka R2000, -march=mips1)

Ver também a secção do manual do GCC sobre o alvo MIPS opções.

# gcc 5.4 -O3
square:
        blez    $4,$L5
        nop
        move    $2,$4    # D.1492, num         # retval = num
        j       $31                            # jr $ra  = return
        nop

$L5:
        mul     $2,$4,$4   # D.1492, num, num   # retval = num * num
        j       $31                             # jr $ra  = return
        nop

Ou com clang, use {[29] } para lhe dizer para compilar os MIPS. Você pode fazer isto no seu ambiente de trabalho; ao contrário do GCC, o clang é normalmente construído com vários back-ends activos.

Da mesma ligação de Godbolt, clang 10.1 -xc -O3 -target mips -Wall -fverbose-asm -fomit-frame-pointer. O alvo padrão é aparentemente MIPS32 ou algo assim para clang. Além disso, clang é o padrão para permitir ponteiros de quadro para MIPS, tornando o asm barulhento.

Note que escolheu fazer asm branchless, fazendo if-conversion em um condicional-mover para selecionar entre a entrada original e o resultado mul. Infelizmente clang não suporta -fno-delayed-branch; talvez tenha outro nome para a mesma opção, ou talvez não haja esperança.

maybe_square:
        slti    $1, $4, 1
        addiu   $2, $zero, 1
        movn    $2, $4, $1            # conditional move based on $1
        jr      $ra
        mul     $2, $2, $4            # in the branch delay slot

Neste caso podemos simplesmente colocar o mul antes do jr, mas em outros casos a conversão para o ASM de atraso sem ramificações não é totalmente trivial. por exemplo, branch on a loop counter before decrementing it can't be undone by put the decrement first; that would change the significado.


Nomes de Registo:

Os compiladores usam números de registo, sem se preocuparem com nomes. Para uso humano, você muitas vezes vai querer traduzir de volta. Muitos lugares on-line têm MIPS register tables que mostram como $4..$ 7 são $ a0..$ a3, $8 .. $ 15 são $ t0 .. $t7, etc. Por exemplo este aqui.

 0
Author: Peter Cordes, 2020-08-19 07:04:58