Existe uma maneira de usar o gcc para converter C em MIPS?
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.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.
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.
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.
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
...
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
.
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
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.
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.