Jump to content
Sign in to follow this  
Lincoln Arantes

Assembly (iniciantes)

 Read less than a minute

Recommended Posts

 Read less than a minute

Vamos a pequena e importante dica!

Em algumas distribuições Linux já vem instalado o compilador Assembly, como no caso do Fedora 29, bastando apenas o usuário desenvolver seu código e compilar..

Nesse exemplo mando para você um código simples que fiz. Espero que goste!


===================================================

.section .data
    mensagem:
        .ascii "Lincoln Arantes\n"
.section .text
.globl _start
_start:
    movq  $1, %rax
    movq  $1, %rdi
    movq  $mensagem, %rsi
    movq  $15, %rdx
    syscall

    movq  $60, %rax
    movq  $0, %rdi
    syscall

==================================================

Desconsidere os sinais de = (igual)
Copie o código e salve com o nome hello.s

Depois abra o terminal do Linux na pasta onde você salvou o arquivo e compile usando cada linha e teclando [enter] no teclado.

#    as hello.s -o hello.o
#    ld -s hello.o -o hello.x

Pronto!

Para executar digite: ./hello.x

Autor: Lincoln César dos Reis Arantes (ADS - graduado)

E-mail: lincolnsetelagoas@yahoo.com.br

Share this post


Link to post
Share on other sites
 Read less than a minute

Algumas correções e dicas:
 

# test.S
#
#   $ as -o test.o test.S
#   $ ld -s -o test test.o

# Read Only data section
# Usada para conter contantes que nunca serão alteradas.
.section .rodata

# Label 'mensagem' com a mensagem.
# Note que criei o símbolo 'msg_len' que é calculado com o tamanho da mensagem.
# O símbolo especial '.' é o equivalente ao $, em outros assemblers.
mensagem: .ascii "Lincoln Arantes\n"
          .equ msg_len, . - mensagem

# Code section
.section .text

# O símbolo _start é usado pelo linker, automaticamente.
# pode-se usar outro, mas a opção -e deve ser usada na chamada do linker.
.globl _start
_start:
    ; Para criar instruções menores, inicializar registradores de 32 bits
    ; automaticamente zera os 32 bits superiores dos registradores extendidos.
    ; Por isso, coloquei 1 em %eax.
    ; Ainda, copiar %eax para %edi cria uma instrução ainda menor (e zerará os
    ; 32 bits superiores de %edi).
    movl  $1, %eax
    movl  %eax, %edi

    ; Usando o endereçamento relativo com RIP gera instruções menores... 
    leaq  mensagem(%rip),%rsi

    ; O símbolo msg_len é usado como constante, daí o $.
    movl  $msg_len, %edx

    ; Chama a systecall write().
    syscall

    ; Note que zerei %edi via XOR. Usando %edi para aproveitar o zero
    ; automático dos 32 bits superiores.
    movl  $60, %eax
    xorl  %edi,%edi

    ; Chama a syscall exit().
    syscall 

Outra coisa... Códigos-fonte em assembly, tipicamente têm extensão .S (maiúsculo)... a extensão .s (minúsculo) geralmente é usado para listagens geradas por outras ferramentas (gcc, por exemplo).

[]s
Fred

Share this post


Link to post
Share on other sites
 Read less than a minute

Observe... seu código (test), depois de compilado com o as, e o meu código (test2), abaixo. Repare que o fato de não usar uma constante calculada para o tamanho da string fez com que você pedisse ao write() para imprimir 1 caracter a menos (o '\n' não irá para stdout!).

Repare também que meu código tem 16 bytes a menos...

$ objdump -dM intel test | sed -nE '/_start/,$p'
00000000004000b0 <_start>:
  4000b0: 48 c7 c0 01 00 00 00  mov    rax,0x1
  4000b7: 48 c7 c7 01 00 00 00  mov    rdi,0x1
  4000be: 48 c7 c6 de 00 60 00  mov    rsi,0x6000de
  4000c5: 48 c7 c2 0f 00 00 00  mov    rdx,0xf
  4000cc: 0f 05                 syscall 
  4000ce: 48 c7 c0 3c 00 00 00  mov    rax,0x3c
  4000d5: 48 c7 c7 00 00 00 00  mov    rdi,0x0
  4000dc: 0f 05                 syscall 

$ objdump -dM intel test2 | sed -nE '/_start/,$p'
00000000004000b0 <_start>:
  4000b0: b8 01 00 00 00        mov    eax,0x1
  4000b5: 89 c7                 mov    edi,eax
  4000b7: 48 8d 35 10 00 20 00  lea    rsi,[rip+0x200010]        # 6000ce <mensagem>
  4000be: ba 10 00 00 00        mov    edx,0x10
  4000c3: 0f 05                 syscall 
  4000c5: b8 3c 00 00 00        mov    eax,0x3c
  4000ca: 31 ff                 xor    edi,edi
  4000cc: 0f 05                 syscall 

 

  • Curtir 1

Share this post


Link to post
Share on other sites
 Read less than a minute

Uma desvantagem de chamar código para processadores Intel de "Assembly" é que existem "Assemblies" diferentes para modos e processadores diferentes. Eis um código que faz a mesma coisa para o ARM (AArch32):

@ test.S

@ Compilar com:
@   as -o test.o test.S
@   ld -o test test.o

@ Note que tanto faz usar uma instrução ou outra para zerar um registrador:
@    mov r1, #0
@    eor r1, r1, r1
@ As instruções do ARM tem tamanho fixo de 32 bits!

@ Usando o cortex-a53 como plataforma base!
.cpu cortex-a53

.section .rodata

msg:  .ascii  "Hello!\n"
      .equ    msg_len, . - msg

.text

.globl _start
_start:
  mov   r7, #4        @ syscall_write (syscalls ids vão em R7).
  mov   r0, #1        @   fd = STDOUT
  ldr   r1, msgptr    @   ptr
  mov   r2, #msg_len  @   size
  swi   0             @ chama a syscall (o vetor 0 é a interface para syscalls!)

  mov   r7, #1        @ syscall_exit
  mov   r1, #0
  swi   0             @ chama a syscall.

@ No ARM a referência a um símbolo numa outra section
@ tem que ser feita de forma indireta?!

msgptr: .word msg

Dá pra notar que:

  • As instruções e os registradores são completamente diferentes;
  • As systemcalls são diferentes;
  • As regras para acesso a recursos em sections diferentes são... ora bolas... diferentes...

"Assembly" é a linguagem mnemônica de programação cujo alvo é um processador de tipo específico, operando em um modo específico. Por exemplo, se você fizer um código para Intel usando instruções como AAA, AAM, DAA, no modo IA-32 (i386), entre outras, elas não poderão ser compiladas para o mesmo processador trabalhando no modo IA-32e (x86-64). Essas instruções não existem no modo x86-64...

Escrever programas inteiros diretamente em Assembly (sempre para o processador específico), geralmente, não é uma boa ideia...

 

Edited by fredericopissarra

Share this post


Link to post
Share on other sites
 Read less than a minute

PS: Note que, no Linux, as syscalls têm, no máximo 7 argumentos... assim o ARM reserva R0-R6 para os argumentos e usa R7 como ID para a syscall, chamando a "interrupção" 0 como interface para as syscalls.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...