Ir para conteúdo

fredericopissarra

Membros
  • Total de itens

    10
  • Registro em

  • Última visita

Reputação

8 Neutral

2 Seguidores

  1. Código em ASM com gcc

    Duas dicas: Para obter um código mais "enxuto", use uma opção de otimização: Recomendo -O2, porque -O3 é mais agressiva e, às vezes, causa problemas (já tive experiência em que -O3 gerou código mais "lento"!). Use -masm=intel apenas para gerar o código equivalente em assembly, evite usá-lo quando seu código tiver assembly inline. Prefira o estilo AT&T, neste caso. O motivo é que alguns header files podem implementar funções com assembly inline usando o estilo AT&T (é o caso, por exemplo, do header cpuid.h - Veja a função __get_cpuid_max, por exemplo, em /usr/lib/gcc/x86_64-linux-gnu/5/include/cpuid.h).
  2. Endianness

    No GCC, se quiser testar pelo "endianess" para garantir que seu código funcionará corretamente (se tentar obter frações de dados maiores), pode usar: #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ ... #else ... #endif Essas são umas das muitas definições padrão do GCC, que podem ser vistas com: $ gcc -dM -E - < /dev/null | less []s Fred
  3. Ajuda com assembly

    Um artigo que escrevi em 2016 sobre uso de assembly para desenvolvimento de aplicações completas, para Windows: "A futilidade de programar para Windows diretamente em assembly"
  4. Ajuda com assembly

    Yep, pode-se usar a notação intel no GAS, mas não é o padrão. Sim, o NASM tem algumas pouquíssimas diferenças. Por exemplo, a pilha do fp87 não é nomeada st(n); mas st0, st1, ... st7. No mais, as instruções são as mesmas dos mnemônicos Intel. PS: MingW também tem um sistema de empacotamento, no caso do Windows, via MinGW32-setup.exe... mas eu recomento o uso do TDM-GCC para o ambiente Win64.
  5. Keygen genérico

    É apenas um hint. O compilador tenta, sempre que possível, manter variáveis locais automáticas em registradores (especialmente com otimizações ligadas).
  6. Ajuda com assembly

    Vejo algumas vantagens do NASM sobre o GAS: Sintaxe simplificada usando os mnemônicos oficiais da Intel, já que o GAS, por default, usa mnemônicos no estilo AT&T, onde algumas instruções foram renomeadas, como CWD, CWDE, CDQ. Ele também tem suporte melhor a códigos de 16 bits (8086) e otimizações para processadores específicos (diretiva CPU)... O NASM também suporta a geração de mais arquivos objeto do que o GAS... Em relação ao MASM, por exemplo, o NASM não possui diretivas ASSUME ou o esquisito "tipo PTR" ou "OFFSET", nem mesmo a dualidade do uso de ponteiros, como em: mov eax,var ; mesma coisa que 'mov eax,[var]' No NASM essas duas coisas são diferentes: mov eax,var ; Mesma coisa que 'mov eax,offset var', no MASM mov eax,[var] ; Mesma coisa que 'mov eax,var' ou 'mov eax,[var]', no MASM Ou seja, uma indireção deve ser cercada por [], senão estamos querendo saber o endereço do símbolo... símples e direto. Não há necessidade, também, da diretiva MODEL, já que as sessões (ou segmentos) são especificados diretamente e de forma simples (assim como no GAS). Ahhh... e MinGW não tem nada a ver com o Cygwin
  7. Keygen genérico

    Existe um problema em usar tipos menores que 'int', neste caso. Seu processador, por default, tenta lidar com tamanhos do tipo 'int' (dwords ou 32 bits). Usar 'char' ou 'short' implica em usar varáveis menores, mas o código tende a ficar maior, porque toda referência a arrays e ponteiros depende de manipulações de "endereços" e, esses, têm 32 ou 64 bites, dependendo da arquitetura. NESTE caso específico, com as otimizações ligadas, não faz muita diferença porque o loop tem número definido de iterações (10)... De qualquer maneira, é preferível usar como contadores o tipo 'int' ou o derivado não sinalizado. PS: Mesmo no modo x86-64 o tipo 'int' é preferível. Embora neste modo os endereços tenham 48 bits de tamanho e os registradores, 64, as instruções com menores opcodes continuam sendo aquelas que manipulam os GPRs (General Purpose Registers) de 32 bits. PS2: Se for o caso de não querer se preocupar com o tamanho e sempre usar um tamanho suficientemente grande para caber contagens usadas para endereçar arrays e bufffers, prefira usar size_t (definida em stddef.h e incluída em stdlib.h e stdio.h, bem como em outros headers da libc)...
  8. “Hello world” em nasm no Linux x86

    Notem que modifiquei o código original que postei, mostrando as chamadas SYSCALL... O NASM aceita o uso de delimitadores de string com "crases", que permite o uso de sequências de escape como \n, \r, \0, \t, ... Outra coisa... ao usar a diretiva "default rel", não precisa se preocupar com o uso do tipo de endereçamento relativo ao RIP, este torna-se o default.
  9. “Hello world” em nasm no Linux x86

    Eu mudaria pouca coisa: Mover valores imediatos para registradores de 32 bits automaticamente zera os 32 bits superiores; Por motivoo de clareza, usar LEA ao invés de MOV para inicializar registradores com ponteiros; Offsets relativos a RIP são menores que os tradicionais; Valores constantes, incluindo strings, deveriam ser colocados em .rodata, não .data. bits 64 default rel section .rodata ; Se usar 'crase' como delimitador de strings, ; pode usar sequências de escape! Aspas, simples ; ou duplas, não fazem isso no NASM. msg: db `Hello!\n` msg_len equ $ - msg section .text global _start _start: mov eax,1 ; syscall 1: write mov edi,eax ; STDOUT_FILENO lea rsi,[msg] ; offsets relativos a RIP são menores. mov edx,msg_len syscall mov eax,60 ; syscall 60: exit xor edi,edi syscall Assim as instruções ficam pequenas (apenas LEA, acima, tem o prefixo REX).
  10. Hello world em MASM no Windows

    Eis porque não gosto muito de criar aplicações diretamente em assembly: Praticamente não há vantagem alguma em fazê-lo. Experimente criar o mesmo programinha em C, compilá-lo e linká-lo extirpando os símbolos desnecessários e faça o mesmo com o seu código com o MASM. É possível que obtenha executáveis com o mesmíssimo tamanho. Outro detalhe é quanto à "versão" do Windows em uso... No Win64 a convenção de chamada é diferente, usando os registradores RCX, RDX, R8 e R9 para os 4 primeiros argumentos de uma chamada, ao invés da pilha (que é o padrao de cdecl e stdcall no modo i386 - ou Win32). Eis um código igual ao acima, para Win64, mas usando o NASM: bits 64 section .rodata msg: db "Hello!",0 caption: db "Hello Windows App",0 section .text ; Importado de user32.dll extern __imp_MessageBoxA global WinMain WinMain: sub rsp,40 ; Isso é necessário. ; Estranhamente é preciso avançar RSP ; por causa dos argumentos de WinMain e ; o endereço de retorno... senão dá crash! xor ecx,ecx ; hWnd = NULL lea rdx,[msg] ; msg ptr lea r8,[caption] ; caption ptr mov r9d,0x40 ; MB_OK | MB_ICONINFORMATION call [__imp_MessageBoxA] xor eax,eax ; return 0L; add rsp,40 ; Retorna a pilha para o lugar original. ret Note que MessageBoxA está sendo chamada indiretamente, via o ponteiro que é inicializado ao importar as bibliotecas libkernel32.a e libuser32.a (que contém código e links para late biding com as respectivas DLLs)... A macro "invoke" faz o que fiz acima (mas, no caso, usei a convenção para Win64). Para compilá-lo, usando o MinGW64 (no Linux), pode-se usar o seguinte Makefile: CC=x86_64-w64-mingw32-gcc hellowin.exe: hellowin.o $(CC) -Wl,--subsystem=windows -s -o $@ $^ -luser32 -lkernel32 hellowin.o: hellowin.asm nasm -fwin64 -o $@ $< Isso ai vai gerar um hellowin.exe com apenas 16 KiB (a mesma coisa que seria gerada com um arquivo em C) e funciona direitinho:
×