Exemplos do uso syscalls (x86) do Linux

Hoje tive uma idéia ao ler um artigo intitulado How Compiling Works no qual o autor descreve em linhas gerais, mas de uma maneira interessante, o processo de compilação de um código escrito em C (abordando  o processo de linkagem com as bibliotecas) tomando como exemplo a função printf. Resolvi fazer uma brincadeira, mostrando como isso pode ser realmente implementado na prática, usando chamadas de sistema (syscalls) do Linux, de modo que não seja necessário usar a implementação disponível na glibc.

Começando com um exemplo simples, bem parecido com que todo mundo que um dia pensou em programar já viu.  A diferença que a função printf será modificada para receber apenas caracteres (não variáveis) e a quantidade.

#include "stdio.h"
int main() {

	printf("Hello, world!\n",15);
	return 0;
}

Reparem que o cabeçalho está entre aspas, indicando ao compilador que vamos usar uma implementação particular e não a implementação da glibc, no meu caso os arquivos

  • /usr/include/stdio.h (protótipo)
  • /usr/lib/libc.so  (implementação)

Serão substituidos pelos arquivos stdio.h e stdio.c abaixo:

#ifndef STDIO_H_
#define STDIO_H_

int printf(char* texto, int tam);

#endif /* STDIO_H_ */

Agora que temos o protótipo da função printf() que é diferente da função printf() que conhecemos mas servirá para esse primeiro exemplo:

#include "stdio.h"

int printf(char* texto, int tam)

{
__asm__ ("movl $0x4,%%eax; \
          movl $0x1,%%ebx; \
          movl %0,%%ecx; \
          movl %1,%%edx; \
          int $0x80": : "g" (texto) , "g" (tam) );

  return 0;
}

Podemos incrementar um pouco mais do código em assembly, para não precisar estipular o número de caracteres.

__asm__ ("      xorl %%edx,%%edx; \
                xorl %%eax,%%eax; \

                movl %0,%%ecx; \
        loop:   movb (%%ecx,%%edx),%%al; \
                incl %%edx; \
                test %%al,%%al; \
                jnz loop; \
                decl %%edx; \

                movl $0x4,%%eax; \
                movl $0x1,%%ebx; \
                int $0x80": : "g" (texto));

Para fazer uma função equivalente ao printf() da glibc precisaríamos implementar o suporte a múltiplos argumentos e mais um monte de coisas🙂 Fiz um esboço de uma idéia do printf, mas ainda usando funções da glibc apenas implementando a syscall write.

#include <stdlib.h>
#include <stdarg.h>
#include <string.h>

#define _write(texto, d) 
__asm__ ("movl $0x4,%%eax; \
	  movl $0x1,%%ebx; \
	  movl %0,%%ecx; \
	  movl %1,%%edx; \

	  int $0x80": : "g" (texto) , "g" (d) );

int write(char *fmt, ...);

int main(){

	char *index=malloc(2);
	char *nome=malloc(20);

	strcpy(index,"19");
	strcpy(nome,"Escovando Bits !!!");

	write("blog: %s \nindex: %s\n",nome,index);

	return 0;
}

int write(char *fmt, ...) {

	char *s;
	va_list ap;
	register int d=0,tam;

	int size;

	va_start(ap, fmt );
	tam = strlen(fmt);

	for (d=0; d<tam; d++, *++fmt) {

		if (*fmt != '%' ) {

		_write(fmt,1);
		} else {

			switch (*++fmt) {
			case 's': {
				s = va_arg(ap, char *);

				size = strlen(s);
				_write(s,size);
			break;
			} // fim case
			} // fim switch

		} // fim else
	} // fim for

	va_end(ap);
	return(1);
}

Se analisarmos o código-fonte da glibc veremos que sua implementação é completamente diferente da proposta nesse post, por questões de portabilidade de hardware, segurança, elegância, desempenho, etc;  Um exemplo é a possiblidade de criar extensões para a função printf.

Bom, essa foi a primeira entrada do ano aqui no EscovandoBits,  mais novidades para os próximos dias, com a cobertura do Mauro sobre a Campus Party que acontece do dia 19 a 25 de Janeiro.

Uma resposta

  1. Na linha 6, executamos a função printf, que imprime na tela os parâmetros que lhe foram passados — no nosso exemplo, passamos a seqüência de caracteres “Olá, mundo!” como parâmetro. Essa é uma das funções definidas no arquivo stdio.h.

Deixe uma resposta

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s

%d blogueiros gostam disto: