Ir para conteúdo

fredericopissarra

Membros
  • Postagens

    425
  • Registro em

  • Última visita

  • Dias Ganhos

    163

fredericopissarra venceu a última vez em Junho 27

fredericopissarra tinha o conteúdo mais apreciado!

Últimos Visitantes

O bloco dos últimos visitantes está desativado e não está sendo visualizado por outros usuários.

Conquistas de fredericopissarra

317

Reputação

  1. Ou use a SysV ABI: ;██████████████████████████████████████ ; ; test.asm ; ; $ nasm -felf64 -o test.o test.asm ; $ ld -s -o test test.o ; ;██████████████████████████████████████ bits 64 default rel ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ ; section read-only ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ section .rodata msg: db `Hello, world!\n` msglength equ $ - msg ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ ; section de código ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ section .text global _start _start: mov eax,1 ; sys_write mov edi,eax ; stdout lea rsi,[msg] ; Endereçamento relativo ao RIP. mov edx,msglength ; Tamanho do buffer. syscall mov eax,60 ; sys_exit xor edi,edi ; errorcode=0 syscall []s Fred
  2. Um jeito mais fácil que ainda tem um problema: #include <stdio.h> int main( void ) { char buffer[128]; // um tamanho grande, arbitrário. puts( "Digite alguns números e <enter>" ); while ( fgets( buffer, sizeof buffer, stdin ) ) { // Atenção: `long int`, no Windows, é o mesmo que `int`. long long int n; if ( sscanf( buffer, " %lld", &n ) != 1 ) break; printf( "read: %lld\n", n ); } } Uma versão melhor: #include <stdio.h> #include <stdlib.h> #include <string.h> int main( void ) { char buffer[128]; // um tamanho grande, arbitrário. puts( "Digite alguns números e <enter>" ); while ( fgets( buffer, sizeof buffer, stdin ) ) { // Atenção: `long int`, no Windows, é o mesmo que `int`. long long int n; char *p; p = buffer + strspn( buffer, " \f\n\r\t\v" ); errno = 0; n = strtoll( p, NULL, 10 ); if ( errno ) { fputs( "ERRO convertendo string.\n", stderr ); continue; } printf( "read: %lld\n", n ); } } []s Fred
  3. No caso a implicação não é importate, dado que printf() sempre converte argumentos float para double. O formato %f é double, para o printf() -- que é uma função "intrínseca". Isso é diferente no scanf(), onde %f é float, %lf é double e %Lf, long double. Ali, também, a divisão por 2.0 resultará em double, mas o arredondamento terá que ser feito na conversão para float, o que será a mesma coisa que dividir por 2.0f (visto que a divisão por 2 apenas mudará o fator de escala). E, uma vez que o printf() está restringindo a "precisão" para 2 "casas decimais", tanto faz ser float ou double. A perda de 29 bits de precisão do double para o float, aqui, não faz diferença. EU faria a conta de maneira diferente: emed = ((double)qmin + qmax)/2; Por quê double? Porque a precisão de um int é de 31 bits e double tem precisão de 53 bits. Essa expressão evitaria um possível overflow na soma e, como o resultado dela é double, o literal 2 também é convertido para double, deixando a conversão final para float. []s Fred
  4. Well... UMA opção é usar o scanf(), como o povo te disse, mas há um detalhe: A função usa o stream stdin e os buffers de streams de entrada não podem ser "descartados" com fflush(). A função scanf() "varre" (scans) o stream em busca do formato informado. Uma vez que o formato foi completado, os dados são colocados nos ponteiros informados e o restante do buffer é mantido no stream. Por exemplo, isso pode ser problemático: int op; do { scanf( "%c", &op ); } while ( op != '0' ); O loop acima será executado DUAS vezes se op for igual a zero na primeira "varrida"... Ele será o valor digitado na primeira vez e '\n' na segunda (porque scanf deixará o '\n' no buffer do stream ao converter o caracter inicial. OBS: O formato %c exige um ponteiro para int, não para char! Geralmente o pessoal contorna isso adicionando um espaço no início do formato: scanf( " %c", &op ). Isso porque scanf() usa a função isspace() para ignorar "espaços", nesse caso. OUTRA solução mais "esperta" é usar a função fgets(), com um buffer de tamanho máximo conhecido: char buffer[11]; // 11 chars suporta valores de 9 algarismos + 1 '\n' e mais o '\0' final. char *p ... fgets( buffer, sizeof buffer, stdin ); buffer[sizeof buffer - 1] = '\0'; // para ter certeza que sempre tenhamos uma string. p = buffer + strspn( buffer, " \t\n\r" ); // ignora espaços, tabs, '\n' ou '\r' inciais, se houverem. op = atoi( p ); // lembrando que op será zero se a string não puder ser convertida. Com isso você garante que o buffer estará sempre vazio na próxima leitura (desde que buffer seja grande o suficiente para caber toda a "linha" lida) - omiti o teste do retorno de fgets() ai em cima por simplicidade - é bom testar se ele retorna ou não NULL. atoi() pode ser substituída por strtol() para maior controle de erros.
  5. Tá com cara de ser um hash (SHA-1? SHA-256?), tendo strings mostradas em um charset diferente do original (possivelmente UTF-8 ao invés de WINDOWS-1252). Se for o caso, não dá para "decriptografar"...
  6. Os dados empilhados (pushed ou "empurrados" para a pilha) ficam lá até que sejam sobrescritos. A pilha do sistema é um espaço temporário de armazenamento.
  7. Coisas como: section .bss var: resd 1 section .text ... mov eax,[var] Aqui var é um offset no endereço efetivo [var]. Como o NASM está usando um endereçamento não relativo a RIP o linker precisará colocar um fixup, uma entrada de relocação. Um jeito de evitar isso no modo x86-64 é usando mov eax,[rel val], dizendo ao NASM que o offset é relativo a RIP. Mas é melhor dizer a ele que TODOS os endereços desse tipo são relativos a RIP via diretiva default rel. A vantagem do modo x86-64 e os endereços relativos a RIP é que bem menos entradas na tabela de relocação são necessárias no executável final... Note que endereços relativos a RIP têm apenas o offset, nunca outro registrador... Algo como [rax+4] ou [rbx+4*rax+4] não são relativos a RIP. Com relação ao mov ebx,[eax], note que no modo x86-64 os endereços têm sempre 64 bits de tamanho. Ao usar [eax] você está, explicitamente, extirpando os 32 bits superiores de um endereço. Endereços devem usar registradores R??, assim, o correto ali seria mov ebx,[rax]. Note que, aqui, RBX será inicializado e os 32 bits superiores serão, automaticamente, zerados, tornando o xor rbx,rbx anterior desnecessário. Além disso, ao usar EAX num endereço efetivo o NASM é obrigado e acrescentar um prefixo 0x67 na sua instrução. Evite usar endereços de 32 bits num código de 64. Mesmo que não seja para endereços... Por exemplo, suponha que eu queira multiplicar EAX (de 32 bits) por 5. Isso pode ser facilmente feito com lea eax,[rax+4*rax]. Note que o destino é EAX, mas o endereço efetivo é RAX+4*RAX. O endereço efetivo é calculado em 64 bits (como deve ser), mas a atribuição final estirpará os 32 bits superiores (e os zerará). PS: Yep... multiplicar EAX por 10 é tão simples quanto: lea eax,[rax+4*rax] ; ou '5*rax', o NASM entende que isso é 'rax+4*rax' add eax,eax Desde que estejamos trabalhando com valores sem sinal.
  8. Entendi que a intenção é ofuscar o código ao máximo, mas, mesmo assim, acho que têm algumas coisas que podem ser melhoradas: Em primeiro lugar, se for criar sessões que não sejam "de sistema" como ".bss" (e não ".BSS"), ".data", ".rdata" e ".text", não use o "." inicial. Sessões que não sejam "de sistema" não deveriam ter esse "." inicial. Constantes, ou seja, valores em memória que não serão modificados no decorrer do código, deveriam estar na sessão ".rdata" e não em ".data". Se for usar estruturas (struc) e blocos de dados inicializados com essas estruturas, os elementos não especificados são, automaticamente, inicializados com zeros. Por exemplo, o label ctx poderia ser definido como: ; Coloque em .bss para não colocar dados da imagem binária do executável final. ; O loader automaticamente zera toda a sessão .bss. section .bss ctx: istruc CONTEXT ; Aqui, TODOS os membros serão zerados. iend A mesma coisa (zerar automaticamente) acontece com "variáveis" comuns... Por exemplo: section .bss ; De novo, colocando em .bss para evitar fazer uma grande imagem binária... ; addressAlloc times 8 dq 0 ; TamArqProgram times 8 dq 0 ; TamArqTarget times 8 dq 0 ; Serão zerados, automaticamente. addressAlloc: resq 8 TamArqProgram: resq 8 TamArqTarget: resq 8 Para zerar um registrador R?? qualquer não é necessário usar R?? na instrução, mas apenas a versão E??. Como em: xor edx, edx ; Zera todo o RDX (sem o prefixo REX). A mesma coisa acontece se tivermos que inicializar um registrador com valores menores que 2³²-1: mov eax,1 ; Opcode: B8 01 00 00 00 mov rax,1 ; Opcode: 48 B8 01 00 00 00 00 00 00 00 O NASM tende a otimizar isso, nesse caso específico, mas é bom sempre usar E?? ao invés de R??, se for o caso. Um endereço efetivo (no formato [offset]), numa instrução, é ABSOLUTO e exige um fixup para relocação. No entanto, no modo x86-64, temos endereçamentos relativos ao registrador RIP, que elimina a relocação. Adicione a diretiva default rel no seu código. Evite recarregar o mesmo dado mais de uma vez, como em: mov rcx,[alloc] mov rax,[alloc] Mesmo que: mov rcx,[alloc] mov rax,rcx Insira uma dependência no stream das instruções (a inicialização de RAX depende de RCX)... Isso ainda é mais rápido (e menor) que DOIS acessos à memória. Pra quê tanta manipulação da pilha se funções da Win32 API para x86-64 tendem a NÃO usar a pilha para receber argumentos? Tenha em mente, também, que RBX, RBP e de R12 até R15 são preservados pela função chamada (no caso da Win32 API) e suas funções deveriam preservá-las também... Lembre-se que todo endereço efetivo no modo x86-64 é de 64 bits. Essas instruções estão erradas: xor rbx,rbx ; Pra quê? mov ebx,[eax] ; RBX inteiro é inicializado e EAX está errado aqui. Chamadas indiretas, como em call r12, sofrem do problema de branch misprediction de forma muito mais fácil do que uma chamada direta. O processador mantém a estatística das chamadas... se a chamada anterior for "para frente" e R12 aponta "para trás", alguns ciclos de penalidade serão usados para recarregar o cache L1I... []s Fred
  9. NIST não é o "Departamento de Segurança Interna dos Estados Unidos". É o "INMETRO" deles: NIST: National Institute of Standards and Technology. NSA: National Security Agency
  10. Depende do que você quer fazer, é claro, mas eu sugeriria, se for o caso de ter uma única interface, que 3 funções fossem criadas. Por exemplo: enum kind_e { PRODUCT, CONSUMER }; _Bool saveProduct( Product *p ) { ... } _Bool saveConsumer( Consumer *p ) { ... } _Bool save( void *p, enum kind_e kind ) { switch ( kind ) { case PRODUCT: return saveProduct( p ); case CONSUMER: return saveConsumer( p ); } return 0; }
  11. Não está perfeito e nem mesmo sei se está "certo"... O detalhe é que entrada formatada por std::basic_istream não funciona como um scanf, você é quem tem que verificar o formato. Eis um exemplo rápido pra sua avaliação: #include <cstdlib> #include <iostream> #include <string> #include <sstream> #include <iomanip> #include <exception> struct horario { int hora; int minuto; // Só para garantir valores válidos. horario ( int h = 0, int m = 0 ) : hora ( h ), minuto ( m ) {} bool operator<( const horario& ); // Crie o seu operador - aqui para retornar um horario como diferença. }; bool horario::operator<( const horario& rhs ) { int m = hora*60 + minuto; return m < ( rhs.hora*60 + rhs.minuto ); } static std::ostream& operator<<( std::ostream& os, const horario& h ) { std::stringstream ss; ss << std::setw(2) << std::setfill('0') << h.hora << ':' << h.minuto; os << ss.str(); return os; } static std::istream& operator>>( std::istream& is, horario& h ) { std::string s; std::string::size_type n; is >> s; n = s.find( ':' ); if ( n == std::string::npos ) throw std::range_error( "Invalid format" ); h.hora = std::stoi( s.substr( 0, n ) ); h.minuto = std::stoi( s.substr( n + 1 ) ); // Porque 60 no limite superior? Porque leap seconds devem ser considerados em horários! if ( h.minuto < 0 || h.minuto > 60 ) throw std::range_error( "Invalid format" ); return is; } // Escolhi que o operator -, quando usando duas referências a horario, deve retornar uma string. static std::string operator-( const horario& lhs, const horario& rhs ) { int h, m; static const char *sigs[2] = { "", "-" }; bool negative = false; h = lhs.hora - rhs.hora; m = lhs.minuto - rhs.minuto; m += 60*h; if ( m < 0 ) negative = true; h = abs( m / 60 ); m = abs( m % 60 ); std::stringstream ss; ss << sigs[negative] << std::setw(2) << std::setfill('0') << h << ':' << m; return ss.str(); } int main() { horario h1, h2; std::cin >> h1; std::cin >> h2; if ( h2 < h1 ) { std::cerr << "Primeiro horário precisa ser menor ou igual ao segundo.\n"; return 1; } std::cout << "Diferença: " << h2 - h1 << '\n'; return 0; } []s Fred
  12. Se esses 16 bytes forem 1 bloco do AES-128, sem a chave é virtualmente impossível obter o dado original.
  13. Prestar um cadinho de atenção as aulas e deixar de simplesmente "copiar" ajudaria um bocado.
  14. Qualquer coisa pode acontecer, inclusive um segmentation fault. ISO 9899 7.21.5.2 § 2: If stream points to an output stream or an update stream in which the most recent operation was not input, the fflush function causes any unwritten data for that stream to be delivered to the host environment to be written to the file; otherwise, the behavior is undefined.
×
×
  • Criar Novo...