Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

278
Vistas
¿Cómo funciona este programa C sin libc?

Encontré un servidor HTTP mínimo que está escrito sin libc: https://github.com/Francesco149/nolibc-httpd

Puedo ver que las funciones básicas de manejo de cadenas están definidas, lo que lleva a la llamada al sistema de write :

 #define fprint(fd, s) write(fd, s, strlen(s)) #define fprintn(fd, s, n) write(fd, s, n) #define fprintl(fd, s) fprintn(fd, s, sizeof(s) - 1) #define fprintln(fd, s) fprintl(fd, s "\n") #define print(s) fprint(1, s) #define printn(s, n) fprintn(1, s, n) #define printl(s) fprintl(1, s) #define println(s) fprintln(1, s)

Y las llamadas al sistema básicas se declaran en el archivo C:

 size_t read(int fd, void *buf, size_t nbyte); ssize_t write(int fd, const void *buf, size_t nbyte); int open(const char *path, int flags); int close(int fd); int socket(int domain, int type, int protocol); int accept(int socket, sockaddr_in_t *restrict address, socklen_t *restrict address_len); int shutdown(int socket, int how); int bind(int socket, const sockaddr_in_t *address, socklen_t address_len); int listen(int socket, int backlog); int setsockopt(int socket, int level, int option_name, const void *option_value, socklen_t option_len); int fork(); void exit(int status);

Así que supongo que la magia ocurre en start.S , que contiene _start y una forma especial de codificar llamadas al sistema creando etiquetas globales que fallan y acumulando valores en r9 para ahorrar bytes:

 .intel_syntax noprefix /* functions: rdi, rsi, rdx, rcx, r8, r9 */ /* syscalls: rdi, rsi, rdx, r10, r8, r9 */ /* ^^^ */ /* stack grows from a high address to a low address */ #define c(x, n) \ .global x; \ x:; \ add r9,n c(exit, 3) /* 60 */ c(fork, 3) /* 57 */ c(setsockopt, 4) /* 54 */ c(listen, 1) /* 50 */ c(bind, 1) /* 49 */ c(shutdown, 5) /* 48 */ c(accept, 2) /* 43 */ c(socket, 38) /* 41 */ c(close, 1) /* 03 */ c(open, 1) /* 02 */ c(write, 1) /* 01 */ .global read /* 00 */ read: mov r10,rcx mov rax,r9 xor r9,r9 syscall ret .global _start _start: xor rbp,rbp xor r9,r9 pop rdi /* argc */ mov rsi,rsp /* argv */ call main call exit

¿Es correcto este entendimiento? GCC usa los símbolos definidos en start.S para las llamadas al sistema, luego el programa se inicia en _start y llama a main desde el archivo C.

Además, ¿cómo funciona el binario personalizado httpd.asm separado? ¿Solo ensamblaje optimizado a mano que combina la fuente C y el ensamblaje de inicio?

over 4 years ago · Santiago Trujillo
1 Respuestas
Responde la pregunta

0

Tienes mucha razón sobre lo que está pasando. Muy interesante, nunca había visto algo así antes. Pero básicamente como dijiste, cada vez que llama a la etiqueta, como dijiste, r9 sigue sumando hasta que llega a read , cuyo número de llamada al sistema es 0. Es por eso que el orden es bastante inteligente. Suponiendo que r9 es 0 antes de que se llame a read (la propia etiqueta de read pone a cero r9 antes de llamar a la llamada al sistema correcta), no es necesario agregar porque r9 ya tiene el número de llamada al sistema correcto que se necesita. El número de llamada al sistema de write es 1, por lo que solo debe agregarse 1 desde 0, que se muestra en la llamada de macro. El número de llamada al sistema de open es 2, por lo que primero se agrega 1 en la etiqueta open , luego nuevamente 1 en la etiqueta de write y luego el número de llamada al sistema correcto se coloca en rax en la etiqueta de read . Y así. Los registros de parámetros como rdi , rsi , rdx , etc. tampoco se tocan, por lo que básicamente actúa como una llamada de función normal.

Además, ¿cómo funciona el binario personalizado httpd.asm separado? ¿Solo ensamblaje optimizado a mano que combina la fuente C y el ensamblaje de inicio?

Supongo que estás hablando de este archivo . No estoy seguro exactamente de lo que está pasando aquí, pero parece que se está creando manualmente un archivo ELF, probablemente para reducir aún más el tamaño.

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda