notas de estudio pila de red de Linux kernel (a) - Análisis glibc2.30 la llamada a la función socket

glibc \ sysdeps \ unix \ sysv \ linux \ socket.c

Este archivo define una función de socket

int
__socket (int fd, int type, int domain)
{
#ifdef __ASSUME_SOCKET_SYSCALL
  return INLINE_SYSCALL (socket, 3, fd, type, domain);
#else
  return SOCKETCALL (socket, fd, type, domain);
#endif
}
libc_hidden_def (__socket)
weak_alias (__socket, socket) //给__socket起了个别名 socket

En primer lugar damos un ejemplo llamadas de socket son:

socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

Linux pila de protocolos de red de BSD socket layer principio del todo parte del núcleo, por lo que la interfaz de programación de la red Linux casi nada se ha hecho en la capa de aplicación, por ejemplo, la toma de función se llama, sólo se glibc proporciona una interfaz para una llamada al sistema, cuanto más baja siga el paso socketcall macro definiciones para analizar el modo de funcionamiento (por supuesto en el mach del sistema, sockets llamadas y funciones de Linux gran diferencia en el funcionamiento del sistema, pero sólo se centran en el análisis de la pila de protocolos de red Linux)

\ Glibc \ sysdeps \ unix \ sysv \ linux \ socketcall.h

#define SOCKETCALL(name, args...)					\
  ({									\
    long int sc_ret = __SOCKETCALL (SOCKOP_##name, args);		\
    sc_ret;								\
  })

Encontraron en el bloque de código y llamar a otro __SOCKETCALL (SOCKOP _ ## nombre, args ) y vuelve sc_ret
continuar el seguimiento __SOCKETCALL encontrará una serie de definiciones que siguen

#define __SOCKETCALL_NARGS_X(a,b,c,d,e,f,g,h,n,...) n
#define __SOCKETCALL_NARGS(...) \
  __SOCKETCALL_NARGS_X (__VA_ARGS__,7,6,5,4,3,2,1,0,)
#define __SOCKETCALL_CONCAT_X(a,b)     a##b
#define __SOCKETCALL_CONCAT(a,b)       __SOCKETCALL_CONCAT_X (a, b)
#define __SOCKETCALL_DISP(b,...) \
  __SOCKETCALL_CONCAT (b,__SOCKETCALL_NARGS(__VA_ARGS__))(__VA_ARGS__)

#define __SOCKETCALL(...) __SOCKETCALL_DISP (__SOCKETCALL, __VA_ARGS__)

#define __SOCKETCALL1(name, a1) \
  INLINE_SYSCALL (socketcall, 2, name, \
     ((long int [1]) { (long int) (a1) }))
#define __SOCKETCALL2(name, a1, a2) \
  INLINE_SYSCALL (socketcall, 2, name, \
     ((long int [2]) { (long int) (a1), (long int) (a2) }))
#define __SOCKETCALL3(name, a1, a2, a3) \
  INLINE_SYSCALL (socketcall, 2, name, \
     ((long int [3]) { (long int) (a1), (long int) (a2), (long int) (a3) }))
#define __SOCKETCALL4(name, a1, a2, a3, a4) \
  INLINE_SYSCALL (socketcall, 2, name, \
     ((long int [4]) { (long int) (a1), (long int) (a2), (long int) (a3), \
                       (long int) (a4) }))
#define __SOCKETCALL5(name, a1, a2, a3, a4, a5) \
  INLINE_SYSCALL (socketcall, 2, name, \
     ((long int [5]) { (long int) (a1), (long int) (a2), (long int) (a3), \
                       (long int) (a4), (long int) (a5) }))
#define __SOCKETCALL6(name, a1, a2, a3, a4, a5, a6) \
  INLINE_SYSCALL (socketcall, 2, name, \
     ((long int [6]) { (long int) (a1), (long int) (a2), (long int) (a3), \
                       (long int) (a4), (long int) (a5), (long int) (a6) }))

所以翻译__SOCKETCALL (SOCKOP_ nombre #, args)可以得到:(按步骤)
1 .__ SOCKETCALL_DISP (__SOCKETCALL, SOCKOP__socket, args)
2 .__ SOCKETCALL_CONCAT (__SOCKETCALL, __ SOCKETCALL_NARGS (SOCKOP__socket, fd, tipo, dominio)) (SOCKOP # nombre, args)
3.翻译__SOCKETCALL_NARGS
__SOCKETCALL_CONCAT (__SOCKETCALL, __ SOCKETCALL_NARGS_X (SOCKOP__socket, fd, el tipo, de dominio, 7,6,5,4,3,2,1,0,)) (SOCKOP__socket, fd, tipo, dominio)
4.翻译__SOCKETCALL_NARGS_X
__SOCKETCALL_CONCAT (__SOCKETCALL, 3) (SOCKOP__socket, fd, tipo, dominio)
5 .__ SOCKETCALL_CONCAT_X (__SOCKETCALL, 3) (SOCKOP__socket, fd, tipo, dominio)
6.翻译__SOCKETCALL_CONCAT_X
__SOCKETCALL3 (SOCKOP_socket, fd, tipo, dominio)

Esta vez nuestro caso en nombre de la
toma de corriente (AF_INET, SOCK_STREAM, IPPROTO_TCP) ;
donde:

#define AF_INET PF_INET
#define PF_INET 2

enum __socket_type
{
	SOCK_STREAM = 1,
#define SOCK_STREAM SOCK_STREAM
	...
}

enum {
	IPPROTO_TCP = 6,
#define IPPROTO_TCP IPPROTO_TCP
	...
}

#define SOCKOP_socket 1

Estas definiciones son mejores no proporciona el código fuente para encontrar una ubicación

Finalmente obtenido
__SOCKETCALL3 (1,2,1,6)
y sustituyendo

#define __SOCKETCALL3(name, a1, a2, a3) \
  INLINE_SYSCALL (socketcall, 2, name, \
     ((long int [3]) { (long int) (a1), (long int) (a2), (long int) (a3) }))

Última traducción es:

INLINE_SYSCALL (socketcall, 2,1, ((long int [3]) {(int largo) (2), (int largo) (1), (long int) (6)}))

No se olvide de este paso es socketcall venimos, es decir:

int
__socket (int fd, int type, int domain)
{
#ifdef __ASSUME_SOCKET_SYSCALL
  return INLINE_SYSCALL (socket, 3, fd, type, domain);
#else
  return INLINE_SYSCALL(socketcall,2,1,((long int [3]){(long int)(2),(long int)(1),(long int)(6)}))
#endif
}

Ahora la toma de capa de aplicación a ser como
nosotros para el seguimiento INLINE_SYSCALL, a este paso, es casi más lejos de la llamada al sistema

glibc \ sysdeps \ unix \ sysv \ linux \ i386 \ sysdep.h

#undef INLINE_SYSCALL
#if IS_IN (libc)
# define INLINE_SYSCALL(name, nr, args...) \
  ({									      \
    unsigned int resultvar = INTERNAL_SYSCALL (name, , nr, args);	      \
    __glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (resultvar, ))		      \
    ? __syscall_error (-INTERNAL_SYSCALL_ERRNO (resultvar, ))		      \
    : (int) resultvar; })
#else
# define INLINE_SYSCALL(name, nr, args...) \
  ({									      \
    unsigned int resultvar = INTERNAL_SYSCALL (name, , nr, args);	      \
    if (__glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (resultvar, )))	      \
      {									      \
	__set_errno (INTERNAL_SYSCALL_ERRNO (resultvar, ));		      \
	resultvar = 0xffffffff;						      \
      }									      \
    (int) resultvar; })
#endif

Para #if SI_IN (libc)
La explicación oficial es la siguiente: para detectar qué componente se está compilando

Debido a que las dos definiciones no hay mucha diferencia, pero todos INTERNAL_SYSCALL prestado, y devuelve el valor de la definición de la macro
de manera que es de acuerdo con lo anterior macro para analizar

Ahora la capa de aplicación de socket un largo camino:

int
__socket (int fd, int type, int domain)
{
#ifdef __ASSUME_SOCKET_SYSCALL
  return INLINE_SYSCALL (socket, 3, fd, type, domain);
#else
  return INTERNAL_SYSCALL (socketcall, , 2, 1,((long int [3]){(long int)(2),(long int)(1),(long int)(6)}))#endif
}

análisis INTERNAL_SYSCALL

\ Glibc \ sysdeps \ unix \ sysv \ linux \ i386

#define INTERNAL_SYSCALL(name, err, nr, args...) \
  ({									      \
    register unsigned int resultvar;					      \
    INTERNAL_SYSCALL_MAIN_##nr (name, err, args);			      \
    (int) resultvar; })

Vamos a conservar el aspecto macro dentro de la primera traducción INTERNAL_SYSCALL_MAIN _ nr ## (nombre, err , args)
a saber:
INTERNAL_SYSCALL_MAIN_2 (socketcall, 1, ((long int [3]) {(long int) (2), (long int ) (1), (long int ) (6)})
para continuar:
#define INTERNAL_SYSCALL_MAIN_2 (nombre, ERR, args ...)
INTERNAL_SYSCALL_MAIN_INLINE (nombre, ERR, 2, args)
para dar:
INTERNAL_SYSCALL_MAIN_INLINE (el socketcall, 2 ,. 1, ((Long int) {(int largo) ( 2), (long int) (1), (long int) (6)}) [3]
lo que en este caso como bloque de función es:

({									      \
    register unsigned int resultvar;					      \
    INTERNAL_SYSCALL_MAIN_INLINE(socketcall,, 2, 1,((long int [3]){(long int)(2),(long int)(1),(long int)(6)});			      \
    (int) resultvar; })

Veamos ahora a ordenar:
ahora la capa de aplicación tanto tiempo:

int
__socket (int fd, int type, int domain)
{
#ifdef __ASSUME_SOCKET_SYSCALL
  return INLINE_SYSCALL (socket, 3, fd, type, domain);
#else
  register unsigned int resultvar;
  INTERNAL_SYSCALL_MAIN_INLINE(socketcall,, 2, 1,((long int [3]){(long int)(2),(long int)(1),(long int)(6)});
  return (int)resultvar;
#endif
}

Continuar analizando INTERNAL_SYSCALL_MAIN_INLINE:

\ Glibc \ sysdeps \ unix \ sysv \ linux \ i386 \ sysdep.h

#if I386_USE_SYSENTER
# ifdef OPTIMIZE_FOR_GCC_5
#  ifdef PIC
#   define INTERNAL_SYSCALL_MAIN_INLINE(name, err, nr, args...) \
    LOADREGS_##nr(args)							\
    asm volatile (							\
    "call *%%gs:%P2"							\
    : "=a" (resultvar)							\
    : "a" (__NR_##name), "i" (offsetof (tcbhead_t, sysinfo))		\
      ASMARGS_##nr(args) : "memory", "cc")
#   define INTERNAL_SYSCALL_NCS(name, err, nr, args...) \
  ({									\
    register unsigned int resultvar;					\
    LOADREGS_##nr(args)							\
    asm volatile (							\
    "call *%%gs:%P2"							\
    : "=a" (resultvar)							\
    : "a" (name), "i" (offsetof (tcbhead_t, sysinfo))			\
      ASMARGS_##nr(args) : "memory", "cc");				\
    (int) resultvar; })
#  else
#   define INTERNAL_SYSCALL_MAIN_INLINE(name, err, nr, args...) \
    LOADREGS_##nr(args)							\
    asm volatile (							\
    "call *_dl_sysinfo"							\
    : "=a" (resultvar)							\
    : "a" (__NR_##name) ASMARGS_##nr(args) : "memory", "cc")
#   define INTERNAL_SYSCALL_NCS(name, err, nr, args...) \
  ({									\
    register unsigned int resultvar;					\
    LOADREGS_##nr(args)							\
    asm volatile (							\
    "call *_dl_sysinfo"							\
    : "=a" (resultvar)							\
    : "a" (name) ASMARGS_##nr(args) : "memory", "cc");			\
    (int) resultvar; })
#  endif
# else /* GCC 5  */
#  ifdef PIC
#   define INTERNAL_SYSCALL_MAIN_INLINE(name, err, nr, args...) \
    EXTRAVAR_##nr							      \
    asm volatile (							      \
    LOADARGS_##nr							      \
    "movl %1, %%eax\n\t"						      \
    "call *%%gs:%P2\n\t"						      \
    RESTOREARGS_##nr							      \
    : "=a" (resultvar)							      \
    : "i" (__NR_##name), "i" (offsetof (tcbhead_t, sysinfo))		      \
      ASMFMT_##nr(args) : "memory", "cc")
#   define INTERNAL_SYSCALL_NCS(name, err, nr, args...) \
  ({									      \
    register unsigned int resultvar;					      \
    EXTRAVAR_##nr							      \
    asm volatile (							      \
    LOADARGS_##nr							      \
    "call *%%gs:%P2\n\t"						      \
    RESTOREARGS_##nr							      \
    : "=a" (resultvar)							      \
    : "0" (name), "i" (offsetof (tcbhead_t, sysinfo))			      \
      ASMFMT_##nr(args) : "memory", "cc");				      \
    (int) resultvar; })
#  else
#   define INTERNAL_SYSCALL_MAIN_INLINE(name, err, nr, args...) \
    EXTRAVAR_##nr							      \
    asm volatile (							      \
    LOADARGS_##nr							      \
    "movl %1, %%eax\n\t"						      \
    "call *_dl_sysinfo\n\t"						      \
    RESTOREARGS_##nr							      \
    : "=a" (resultvar)							      \
    : "i" (__NR_##name) ASMFMT_##nr(args) : "memory", "cc")
#   define INTERNAL_SYSCALL_NCS(name, err, nr, args...) \
  ({									      \
    register unsigned int resultvar;					      \
    EXTRAVAR_##nr							      \
    asm volatile (							      \
    LOADARGS_##nr							      \
    "call *_dl_sysinfo\n\t"						      \
    RESTOREARGS_##nr							      \
    : "=a" (resultvar)							      \
    : "0" (name) ASMFMT_##nr(args) : "memory", "cc");			      \
    (int) resultvar; })
#  endif
# endif /* GCC 5  */
#else
# ifdef OPTIMIZE_FOR_GCC_5
#  define INTERNAL_SYSCALL_MAIN_INLINE(name, err, nr, args...) \
    LOADREGS_##nr(args)							\
    asm volatile (							\
    "int $0x80"								\
    : "=a" (resultvar)							\
    : "a" (__NR_##name) ASMARGS_##nr(args) : "memory", "cc")
#  define INTERNAL_SYSCALL_NCS(name, err, nr, args...) \
  ({									\
    register unsigned int resultvar;					\
    LOADREGS_##nr(args)							\
    asm volatile (							\
    "int $0x80"								\
    : "=a" (resultvar)							\
    : "a" (name) ASMARGS_##nr(args) : "memory", "cc");			\
    (int) resultvar; })
# else /* GCC 5  */
#  define INTERNAL_SYSCALL_MAIN_INLINE(name, err, nr, args...) \
    EXTRAVAR_##nr							      \
    asm volatile (							      \
    LOADARGS_##nr							      \
    "movl %1, %%eax\n\t"						      \
    "int $0x80\n\t"							      \
    RESTOREARGS_##nr							      \
    : "=a" (resultvar)							      \
    : "i" (__NR_##name) ASMFMT_##nr(args) : "memory", "cc")
#  define INTERNAL_SYSCALL_NCS(name, err, nr, args...) \
  ({									      \
    register unsigned int resultvar;					      \
    EXTRAVAR_##nr							      \
    asm volatile (							      \
    LOADARGS_##nr							      \
    "int $0x80\n\t"							      \
    RESTOREARGS_##nr							      \
    : "=a" (resultvar)							      \
    : "0" (name) ASMFMT_##nr(args) : "memory", "cc");			      \
    (int) resultvar; })
# endif /* GCC 5  */
#endif

Aquí se puede ver que hay muchos aspectos de esta definición macro
emmmmm no sé cuál debería ser. . .
Así que escribo a usted primero

Pero lo cierto es que la definición de la macro no es más que el código de montaje en la instrucción de interrupción software del núcleo, el uso de SYSENTER ir en el núcleo, el uso de las llamadas al sistema int $ 0x80 en el núcleo, la diferencia entre los dos es que la CPU uso no los mismos recursos, int $ 0x80 es capturado por el núcleo de interrupción puerta, el siguiente blog para explicar (para abrir una nueva fosa)

Este blog es sólo la capa de aplicación de la toma de función de traducción definición de la macro de nuevo, finalmente encontró su sección llamada al sistema de compilación
puede conocer el zócalo de interfaz de capa de aplicación no hace ninguna tareas sustantivas, sólo el sistema llama paquete

continuará

Publicado siete artículos originales · ganado elogios 1 · visitas 703

Supongo que te gusta

Origin blog.csdn.net/qq_41957544/article/details/102528948
Recomendado
Clasificación