
Esta história é sobre uma abordagem não padrão para o desenvolvimento de aplicativos Android. Uma coisa é instalar o Android Studio e escrever "Olá, Mundo" em Java ou Kotlin. Mas mostrarei como a mesma tarefa pode ser realizada de maneira diferente.
Lembramos que: para todos os leitores de "Habr" - um desconto de 10.000 rublos ao se inscrever em qualquer curso Skillbox usando o código promocional "Habr".
A Skillbox recomenda: O curso educacional on-line "Profissão Java-developer" .
Como meu smartphone funciona com o sistema operacional Android?
Primeiro, um pouco de fundo. Uma noite, uma amiga chamada Ariella me ligou. Ela me perguntou: “Ouça, como meu smartphone funciona? O que tem dentro? Como a energia elétrica e as unidades e zeros comuns fazem tudo funcionar? ”
Minha amiga não é uma noob em desenvolvimento, ela criou vários projetos no Arduino, que consistiam em software e hardware. Talvez por isso ela quisesse saber mais. Consegui responder com a ajuda do conhecimento obtido em um dos cursos de ciência da computação da universidade.
Depois, trabalhamos algumas semanas juntos, pois Ariella queria descobrir como os tijolos da tecnologia eletrônica funcionam, isto é, elementos semicondutores, incluindo transistores. Em seguida, subimos para um nível mais alto: mostrei a ela como criar portas lógicas, por exemplo, NAND (AND lógico) e NOR (OR lógico) usando uma combinação específica de transistores.
Investigamos elementos lógicos de diferentes tipos, combinando-os para realizar cálculos (por exemplo, adicionando dois números binários) e células de memória (gatilhos). Quando tudo ficou claro, eles começaram a desenvolver um processador simples (imaginário), no qual havia dois registros de uso geral e duas instruções simples (adicionando esses registros). Até escrevemos um programa simples que multiplica esses dois números.
A propósito, se você estiver interessado neste tópico, leia as instruções para criar um computador de 8 bits a partir do zero. Explica quase tudo, desde o básico. Eu gostaria de ler mais cedo!
Olá Android!
Depois de concluir todas as etapas do estudo, pareceu-me que Ariella tinha conhecimento suficiente para entender como o processador do smartphone funciona. Seu smartphone é o Galaxy S6 Edge, cuja base é a arquitetura ARM (como, de fato, com a maioria dos smartphones). Decidimos escrever um aplicativo "Olá, Mundo" para Android, mas em linguagem assembly.
.text .globl _start _start: mov %r0, $1 // file descriptor number 1 (stdout) ldr %r1, =message mov %r2, $message_len mov %r7, $4 // syscall 4 (write) swi $0 mov %r0, $0 // exit status 0 (ok) mov %r7, $1 // syscall 1 (exit) swi $0 .data message: .ascii "Hello, World\n" message_len = . - message
Se você nunca encontrou o código do assembler, esse bloco pode assustá-lo. Mas tudo bem, vamos analisar o código juntos.
Portanto, nosso programa consiste em duas partes. O primeiro é um texto com instruções de código de máquina e o segundo são variáveis, linhas e outras informações (começando na linha 15). A seção .text geralmente é somente leitura e .data também é gravável.
Na linha 2, definimos uma função global chamada _start. É o ponto de entrada para o aplicativo. O sistema operacional começa a executar o código a partir deste ponto. A definição da função é declarada na linha 4.
Além disso, a função faz mais duas coisas. Nas linhas 5 a 9, a mensagem é exibida na tela e nas linhas 11 a 13, o programa termina. Mesmo se você excluir as linhas 11–13, o programa emitirá nossa linha “Hello, World” e sairá. No entanto, a saída não estará correta, porque o programa terminará com um erro. Sem as linhas 11 a 13, o aplicativo tentará executar uma instrução inválida.
A impressão é exibida usando a função do sistema "Chamada do sistema" do sistema operacional. No aplicativo, chamamos a função write (). Nós o indicamos quando carregamos o valor 4 no registro do processador com o nome r7 (linha 8). Em seguida, a instrução swi $ = 0 (linha 9) é executada, onde há uma transição diretamente para o kernel do Linux, que é a base do Android.
Quanto aos parâmetros para a chamada do sistema, eles são transmitidos por outros registradores. Por exemplo, r0 mostra o número do descritor de arquivo que precisamos imprimir. Colocamos o valor 1 lá (linha 5), indicando a saída padrão (stdout), ou seja, a saída na tela.
r1 indica o endereço de memória dos dados que queremos escrever, então apenas carregamos o endereço da string "Olá, Mundo" (linha 6) nessa área, e o registro r2 mostra quantos bytes queremos escrever. Em nosso programa, é definido como message_len (linha 7), calculado na linha 18 usando uma sintaxe especial: o símbolo do ponto indica o endereço de memória atual. Por esse motivo. - message indica o endereço de memória atual menos o endereço de mensagem. Bem, como declaramos message_len imediatamente após a mensagem, tudo isso é calculado como o tamanho da mensagem.
Se você escrever o código para as linhas 5 a 9 usando C, obtém o seguinte:
#define message "Hello, World\n" write(1, message, strlen(message));
Desligar o programa é um pouco mais fácil. Para fazer isso, simplesmente registramos o código de saída no registrador r0 (linha 11), após o qual adicionamos o valor 1, que é o número da chamada de função do sistema exit (), a r7 (linha 12) e depois chamamos o kernel novamente (linha 13).
Uma lista completa das chamadas do sistema Android e seus números podem ser encontrados no
código- fonte
do sistema operacional . Há também uma implementação de
write () e
exit () que chamam as funções correspondentes do sistema.
Montando o programa
Para compilar nosso projeto, você precisará do Android NDK (Native Development Kit). Ele contém um conjunto de compiladores e ferramentas de construção para a plataforma ARM. Você pode baixá-lo no site oficial, instalá-lo, por exemplo, através do Android Studio.

Após a instalação do NDK, precisamos do arquivo arm-linux-androideabi-as, este é o assembler para o ARM. Se você fez o download via Android Studio, procure-o na pasta Android SDK. Geralmente sua localização é
ndk-bundle \ toolchains \ arm-linux-androideabi-4.9 \ prebuilt \ windows-x86_64 \ bin.Depois que o assembler for encontrado, salve o que está escrito em um arquivo chamado hello.s e execute o seguinte comando para convertê-lo em código de máquina:
arm-linux-androideabi-as -o hello.o hello.sEsta operação cria um arquivo de objeto ELF chamado hello.o. Para convertê-lo em um arquivo binário que possa funcionar no seu dispositivo, chame o vinculador:
arm-linux-androideabi-ld -o Olá, olá.oAgora, temos um arquivo hello que contém um programa pronto para uso.
Inicie o aplicativo no seu dispositivo
Aplicativos Android geralmente são distribuídos no formato .apk. Esse é um tipo especial de arquivo compactado que inclui classes Java (sim, você pode escrever com C / C ++, mas Java deve ser o ponto de entrada).
Para evitar problemas ao iniciar o aplicativo, adb foi usado no exemplo, o que nos permitiu copiá-lo para a pasta temporária do nosso dispositivo Android. Depois disso, lançamos o shell adb para iniciar o aplicativo e avaliar o resultado:
adb push hello / data / local / tmp / hello
shell adb chmod + x / data / local / tmp / helloE, finalmente, execute o aplicativo:
shell adb / data / local / tmp / helloO que você escreve?
Agora você tem um ambiente de trabalho semelhante ao que Ariella tinha. Ela passou vários dias estudando o montador do ARM, depois apresentou um projeto simples - este é o jogo Sven Boom (uma variação do Fizz Buzz originalmente de Israel). Os jogadores contam por sua vez e cada vez que o número é dividido por 7 ou contém o número 7, eles devem dizer "boom" (daí o nome do jogo).
Vale a pena notar que o programa do jogo não é uma tarefa tão fácil. Ariella escreveu um método inteiro que exibe números, um dígito de cada vez. Como ela escreveu tudo no assembler sem chamar as funções padrão da biblioteca C, levou vários dias para resolver.
O primeiro programa Ariella para Adnroid está disponível
aqui . A propósito, alguns identificadores de código no aplicativo são na verdade palavras hebraicas (por exemplo, _sifra_ahrona).
Escrever um aplicativo Android no assembler é uma boa maneira de conhecer melhor a arquitetura do ARM e também entender melhor a cozinha interna do gadget que você usa diariamente. Sugiro que você faça isso de perto e tente criar um pequeno aplicativo montador para o seu dispositivo. Poderia ser um jogo simples ou outra coisa.
A Skillbox recomenda: