Estou tentando montar e executar um Hello World
programa simples no meu telefone Android. Meu laptop host é um Ubuntu 22.04
sistema de 64 bits. Baixei android-ndk-r27c
e extraí para minha pasta Android onde meu SDK já residia.
Este é meu hello64bit.s tirado daqui e seu caminho é/home/developer/Android/android-ndk-r27c-linux/android-ndk-r27c/toolchains/llvm/prebuilt/linux-x86_64/bin
/* Data segment: define our message string and calculate its length. */
msg:
.ascii "Hello, ARM64!\n"
len = . - msg
.text
/* Our application's entry point. */
.globl _start
_start:
/* syscall write(int fd, const void *buf, size_t count) */
mov x0, #1 /* fd := STDOUT_FILENO */
ldr x1, =msg /* buf := msg */
ldr x2, =len /* count := len */
mov w8, #64 /* write is syscall #64 */
svc #0 /* invoke syscall */
/* syscall exit(int status) */
mov x0, #0 /* status := 0 */
mov w8, #93 /* exit is syscall #93 */
svc #0 /* invoke syscall */
Quando executo ./aarch64-linux-android27-clang -o hello64.o hello64bit.s
recebo o seguinte erro:
ld.lld: error: duplicate symbol: _start
>>> defined at crtbegin.c
>>> /home/developer/Android/android-ndk-r27c-linux/android-ndk-r27c/toolchains/llvm/prebuilt/linux-x86_64/bin/./../sysroot/usr/lib/aarch64-linux-android/27/crtbegin_dynamic.o:(_start)
>>> defined at /tmp/hello64bit-fb91b4.o:(.text+0x0)
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Quando altero o nome start
para start1
recebo um undefined main
erro:
ld.lld: error: undefined symbol: main
>>> referenced by crtbegin.c
>>> /home/developer/Android/android-ndk-r27c-linux/android-ndk-r27c/toolchains/llvm/prebuilt/linux-x86_64/bin/./../sysroot/usr/lib/aarch64-linux-android/27/crtbegin_dynamic.o:(_start_main)
O que estou fazendo errado?
Compile e vincule assim:
Explicação
Por que
-nostartfiles -nostdlib
?Você
hello64bit.s
é um pequeno programa autônomo cujo ponto de entrada (onde o sistema operacional o chama) é_start
._start
é o ponto de entrada padrão para qualquer programa, e sua definição padrão está contida no arquivo de objetocrtbegin_dynamic.o
que você vê mencionado noduplicate symbol
diagnóstico de erros.Esse arquivo contém o código de inicialização do tempo de execução C que executa as inicializações necessárias para executar um programa regular que depende da biblioteca de tempo de execução C. A
_start
função definida nesse arquivo executa esse código e, depois disso, chamamain
, a função raiz obrigatória do código do aplicativo de um programa C (ou C++) regular.O arquivo
crtbegin_dynamic.o
é vinculado a qualquer programa vinculado dinamicamente por padrão, partindo do princípio de que o programa é um programa regular, que definemain
, não define_start
e depende da biblioteca de tempo de execução C.Mas seu programa não é um regular. Você quer compilar e vincular sua própria definição da
_start
função, e essa definição é seu programa inteiro , que não depende da biblioteca de tempo de execução C.Então, por padrão, o vinculador vincula a
crtbegin_dynamic.o
definição da_start
função além da sua, e isso é um símbolo duplicado ou erro de definição múltipla.Você quer instruir o vinculador a não se preocupar em vincular o código de inicialização do tempo de execução C e a biblioteca de tempo de execução C.
-nostartfiles
diz a ele para não se preocupar em vincular o código de inicialização e-nostdlib
diz a ele para não se preocupar em vincular a biblioteca de tempo de execução C.Por que
-static
?.Sem ele, a ligação ainda falhará assim:
Isso ocorre porque seu assembly não é um código independente de posição (PIC), que deve estar em um executável vinculado dinamicamente independente de posição, que é o que o vinculador tenta criar por padrão. Você não pode seguir o conselho do vinculador -
recompile with -fPIC
- porque essa é uma opção de compilação que diz ao compilador para gerar código de assembly PIC , mas você não está usando o compilador para gerar o código de assembly. Você está fornecendo você mesmo, então caberia a você torná-lo PIC.Como este programa não é PIC, e acho que você não se importa, você pode direcionar o vinculador para não realizar uma vinculação dinâmica, que requer realocações, e apenas fazer uma vinculação estática, que não
-static
realiza isso.Por que
-o hell64
em vez de-o hello64.o
?hello64.o
denota um arquivo objeto (*.o
), ou seja, a saída do compilador/assembler, antes de ser vinculado a um programa. É isso que você obteria com:onde
-c
significa Apenas compilar/montar. Não vincular . Mas não é isso que você está fazendo. Você está montando o código e vinculando-o a um programa executável. Executáveis não têm extensões (exceto no Windows,*.exe
).