Jump to content
unc4nny

Duvida no video sobre CRC do Fernando

 Read less than a minute

Recommended Posts

Posted (edited)
 Read less than a minute

Oi.
Me pediram pra formular minha duvida melhor no video que o Fernando fez de CRC.

Bixo, eu achava que entendia de C, mas o jeito que esse CRC funciona me bugou um pouquinho. Depois de pensar um pouco eu ate  consigo ver oq esta acontecendo, mas eu nao sei se eh isso que esta acontecendo

 

bool checa(char *nome, int serial) {
	int serial_correto = 0;

	while (*nome)
		serial_correto += *nome++;

	return (serial == serial_correto);
}

int main(void) {
	char nome[50];
	int serial;
	uint32_t crc = crc32((unsigned char *)checa, 63);

O unico jeito que eu vejo de isso funcionar do jeito que parece que esta funcionando eh se ele pegar todos os bytes que representam essa funcao:

000000000000129b <checa>:
    129b:        55                                          push   rbp
    129c:        48 89 e5                             mov    rbp,rsp
    129f:         48 89 7d e8                      mov    QWORD PTR [rbp-0x18],rdi
    12a3:        89 75 e4                             mov    DWORD PTR [rbp-0x1c],esi
    12a6:        c7 45 fc 00 00 00 00    mov    DWORD PTR [rbp-0x4],0x0
    12ad:        eb 15                                   jmp    12c4 <checa+0x29>
    12af:         48 8b 45 e8                     mov    rax,QWORD PTR [rbp-0x18]
    12b3:        48 8d 50 01                      lea    rdx,[rax+0x1]
    12b7:        48 89 55 e8                     mov    QWORD PTR [rbp-0x18],rdx
    12bb:        0f b6 00                            movzx  eax,BYTE PTR [rax]
    12be:        0f be c0                            movsx  eax,al
    12c1:         01 45 fc                             add    DWORD PTR [rbp-0x4],eax
    12c4:        48 8b 45 e8             	    mov    rax,QWORD PTR [rbp-0x18]
    12c8:        0f b6 00                           movzx  eax,BYTE PTR [rax]
    12cb:        84 c0                                 test   al,al
    12cd:        75 e0                                 jne    12af <checa+0x14>
    12cf:         8b 45 e4                          mov    eax,DWORD PTR [rbp-0x1c]
    12d2:        3b 45 fc                           cmp    eax,DWORD PTR [rbp-0x4]
    12d5:        0f 94 c0                           sete   al
    12d8:        5d                                      pop    rbp
    12d9:        c3                                      ret    

0x55, 0x48, 0x89, 0xe5... etc, castar para char*, e fazer o calculo. Eh assim que funciona mesmo? Se eu estiver errado (O que eh bem provavel kkk) alguem me ajuda ai!
Obg desde ja!

Edited by unc4nny

Share this post


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

Man eu acho que é exatamente assim, até mesmo se tu olhar o codigo de "crc32.c"...

u_int32_t chksum_crc32 (unsigned char *block, unsigned int length){
   register unsigned long crc;
   unsigned long i;

   crc = 0xFFFFFFFF;
   for (i = 0; i < length; i++)
   {
                                                                                               // incremento
                                                                                                  // vvvvvv
      crc = ((crc >> 8) & 0x00FFFFFF) ^ crc_tab[(crc ^ *block++) & 0xFF];
   }
   return (crc ^ 0xFFFFFFFF);
}

u_int32_t crc32(unsigned char *block, unsigned int length){
	if(!initialized){
		chksum_crc32gentab();
		initialized = 1;
	}

	return chksum_crc32(block, length);
}


Já da pra perceber que o nome da variavel na "crc32" é "length"(suspeito...), além disso o "for" na  "chksum_crc32" realmente "passa" length vezes, incrementando "block"(o address da funcao) cada vez que "passa".

Mas assim, não sou especialista.
 

  • Curtir 1

Share this post


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

Prefira sempre compilar seus códigos com a opção -O2 (pelo menos). Isso criará código mais "enxuto". A função checa(), por exemplo, ficará assim:
 

; Entrada: RDI = nome, ESI = serial
; Saída AL (0 = false, 1 = true).
checa:
	movsx	eax, BYTE PTR [rdi]   ; Lê o primeiro byte.

	xor	edx, edx              ; edx = serialcorreto = 0

	test	al, al                ; fim de string?
	je	.endOfString       ; sim, salta para a comparação.

.loop:
	add	rdi, 1                  ; aponta para o próximo byte
	add	edx, eax                         ; acumula o checksum.
	movsx	eax, BYTE PTR [rdi]   ; lê o próximo byte.
	test	al, al                          ; fim de string?
	jne	.loop                              ; não, volta ao loop.

.endOfString:
	cmp	esi, edx         ; serial == serialcorreto?
	sete	al                    ; ajusta AL.
	ret

No entanto, não entendi qual é a dúvida, especificamente...

  • Curtir 2

Share this post


Link to post
Share on other sites
Posted (edited)
 Read less than a minute
1 hour ago, fredericopissarra said:

No entanto, não entendi qual é a dúvida, especificamente...

Opa, foi mal.Minha duvida eh, como que funciona o casting da funcao para uma string? Isso parece meio esoterico, pelo menos na minha cabeca ashduiahsduih

Edited by unc4nny

Share this post


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

Bom, o jeito que eu entendo os casts é simplesmente um modo de interpretar os bytes dentro daquele endereço.


No código la o cara usa um char justamente pra poder acessar byte por byte, lembrando que na aritimética de ponteiro quando uma soma é feita, na verdade estamos somando n+(sizeof(elemento)). Acho que o @fredericopissarra deve saber explicar melhor.
 

Fiz um programinha aqui:

#include<stdio.h>
#include<stdlib.h>

int main(void){
	FILE *fd = fopen("number","r");

	unsigned long int li;
	fread(&li, sizeof(li), 1, fd);

	// os tamanhos so pra ajudar
	//printf("char: %zu\n", sizeof(char));
	//printf("short: %zu\n", sizeof(short));
	//printf("int: %zu\n", sizeof(int));
	//printf("%zu\n", sizeof(long int));

	// aqui vem os casts
	printf("%hhu\n",(unsigned char) li );
	printf("%hu\n",(unsigned short) li );
	printf("%u\n",(unsigned int) li );
	printf("long value: %ld\n",li );


	return 0;
}

number:

[mario@zrmt forum]$ hd number
00000000  01 01 00 01 00 00 00 01                           |........|
00000008

quando executado:

[mario@zrmt forum]$ ./cast
1
257
16777473
72057594054705409

O char vai interpretar o primeiro byte, o short os dois primeiros, o int os quatro e o long todos os oito.

Mas tambem posso estar terrivelmente errado.

  • Curtir 1

Share this post


Link to post
Share on other sites
 Read less than a minute
7 minutes ago, Marioh said:

Bom, o jeito que eu entendo os casts é simplesmente um modo de interpretar os bytes dentro daquele endereço.

Faz sentido mano. Deu pra dar uma esclarecida agora, brigadao cara

Share this post


Link to post
Share on other sites
 Read 1 minute
8 horas atrás, unc4nny disse:

...Minha duvida eh, como que funciona o casting da funcao para uma string?...

De novo, a dúvida ainda está confusa... "casting de função para string"? Em primeiro lugar, não existem "strings" em C (mas sim arrays de chars,  onde o último char é um '\0')... Em segundo lugar, o identificador de uma função é um ponteiro, bem como o identificador de um array é convertido para um ponteiro.

No seu exemplo, eu suponho que a função crc32() tenha o protótipo:

uint32_t crc32( unsigned char *ptr, size_t size );

Quando o argumento ptr poderia ser, muito bem, definido como um ponteiro para void e, neste caso, qualquer casting de ponteiro na passagem deste argumento para a função seria supérfluo (void * aponta para qualquer coisa).

Este é o mesmo caso de chamadas à função malloc(), por exemplo:

char *p;

p = malloc( 16 );  // aloca 16 bytes e devolve o ponteiro.

Casting aqui é desnecessário porque malloc() tem o protótipo:

void *malloc( size_t size );

Como o @Marioh disse ai em cima, casting é uma maneira de reinterpretar um tipo. Por exemplo:

int x = 1, y = 2;
float z;

// O casting aqui é "obrigatório" porque senão a divisão será feita
// com INTEIROS, resultando num INTEIRO que depois será convertido para
// float... Com o casting, a divisão será entre valores em PONTO FLUTUANTE.
z = (float) x / y;  // z = 0.5;

z = x / y;   // isso resulta em 0.0!

Casting pode ser usado para forçar a barra da atualização de um ponteiro também:

char *p;
...
// inicializa p em algum lugar...
...
*(int *)p++ = 1;  // aqui p[0]=1, p[1] até p[3]=0 (little endian).
// mas, p será avançado em 4 posições... (sizeof(int)).

Quando fazemos a conversão de tipos de menor precisão para maior, não precisamos de castring também. A promoção de tipos funciona direitinho... Para fazer a "demoção" de tipos o castring pode ser necessário para evitar avisos do compilador:

char a;
int b = 10;

a = (char)b;  // casting para evitar (?) warnings... nem sempre evita!
b = a;  // castring desnecessário.

Agora... no seu exemplo, você está passando um ponteiro para uma função (checa) para a função crc32(). O que é válido, mas LER a memória onde a função foi codificada é um "comportamento indefinido" (undefined behavior) - escrever nessa memória, provavelmente causará um SEGMENTATION FAULT - um erro.

Note que, no seu caso, o identificador checa equivale ao ponteiro:

_Bool (*checa)( char *, int );

Se seu crc32() for definido como:

uint32_t crc32( unsigned char *, size_t );

Então o pontiero terá que sofrer casting para evitar avisos... Note que isso pode não funcionar em todas as plataformas. Algumas assumem ponteiros para região de código com tamanho diferente da ponteiros para região de dados... Outras não permitem isso...

  • Curtir 1
  • l33t 1

Share this post


Link to post
Share on other sites
Posted (edited)
 Read less than a minute

PS: "CAST" é uma daquelas palavras em inglês difíceis de fixar... "CAST" significa elenco (teatro), mas também "jogar" (como em "cast a spell" ou "jogar um feitiço"). Mas, também é o nome que se dá ao suporte usado quando quebramos um braço ou uma perna (um "molde")... Esse último parece ser o neologismo para "casting", no contexto de C...

Edited by fredericopissarra
  • Curtir 1

Share this post


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

Então o pontiero terá que sofrer casting para evitar avisos... Note que isso pode não funcionar em todas as plataformas. Algumas assumem ponteiros para região de código com tamanho diferente da ponteiros para região de dados... Outras não permitem isso...

@fredericopissarra Uma duvida, a arquitetura de harvard seria assim?

  • Curtir 1

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.


  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...