notas de estudo pilha de rede Linux Kernel (a) - Análise glibc2.30 a chamada de função de soquete

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

Este arquivo define uma função de soquete

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

Primeiro vamos dar um exemplo chamadas de soquete são:

socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

linux pilha de protocolo de rede de BSD Socket Layer início inteiramente parte do kernel, por isso, interface de programação de rede linux quase nada tem sido feito na camada de aplicação, por exemplo, a tomada de função é chamada, apenas a glibc fornece uma interface para uma chamada de sistema, menor siga o passo socketcall definições de macro para analisar o modo de funcionamento (claro no mach o sistema, soquete chamadas e funções do linux grande diferença no sistema funciona, mas apenas se concentrar na análise de pilha linux protocolo de rede)

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

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

Encontrado no bloco de código e chamar outro __SOCKETCALL (SOCKOP _ ## nome, args ) e retorna sc_ret
continuar a acompanhar __SOCKETCALL vai encontrar uma gama de definições seguinte

#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_ nome #, args)可以得到:(按步骤)
1 .__ SOCKETCALL_DISP (__SOCKETCALL, SOCKOP__socket, args)
2 .__ SOCKETCALL_CONCAT (__SOCKETCALL, __ SOCKETCALL_NARGS (SOCKOP__socket, fd, o tipo de domínio)) (nome SOCKOP #, args)
3.翻译__SOCKETCALL_NARGS
__SOCKETCALL_CONCAT (__SOCKETCALL, __ SOCKETCALL_NARGS_X (SOCKOP__socket, fd, o tipo de domínio, 7,6,5,4,3,2,1,0,)) (SOCKOP__socket, fd, o tipo de domínio)
4.翻译__SOCKETCALL_NARGS_X
__SOCKETCALL_CONCAT (__SOCKETCALL, 3) (SOCKOP__socket, fd, o tipo de domínio)
5 .__ SOCKETCALL_CONCAT_X (__SOCKETCALL, 3) (SOCKOP__socket, fd, o tipo de domínio)
6.翻译__SOCKETCALL_CONCAT_X
__SOCKETCALL3 (SOCKOP_socket, fd, o tipo de domínio)

Desta vez nosso caso em nome do
socket (AF_INET, SOCK_STREAM, IPPROTO_TCP) ;
onde:

#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

Essas definições são melhores não fornece o código-fonte para encontrar um local

Finalmente obtida
__SOCKETCALL3 (1,2,1,6)
e substituindo

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

Última tradução é:

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

Não se esqueça este passo é vem, que é socketcall:

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
}

Agora, a tomada de camada de aplicação se tornar como
nós para acompanhar INLINE_SYSCALL, para este passo, é mais quase longe da chamada de 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)
A explicação oficial é esta: para detectar qual componente está sendo compilado

Porque as duas definições não é muita diferença, mas todos emprestado INTERNAL_SYSCALL, e retorna o valor da definição de macro
para que ele esteja em conformidade com o acima macro para analisar

Agora, a camada de aplicativo de soquete um longo caminho:

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álise 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 manter a aparência macro dentro do primeiro INTERNAL_SYSCALL_MAIN tradução _ ## NR (nome, err , args)
a saber:
INTERNAL_SYSCALL_MAIN_2 (socketcall, 1, ((int Long [3]) {(int Long) (2), (int Longo ) (1), (long int ) (6)})
para continuar:
# define INTERNAL_SYSCALL_MAIN_2 (nome, ERR, args ...)
INTERNAL_SYSCALL_MAIN_INLINE (nome, ERR, 2, args)
para dar:
INTERNAL_SYSCALL_MAIN_INLINE (a socketcall, 2 ,. 1, ((long int) {(int longo) ( 2), (a longo int) (1), (a longo int) (6)}) [3]
por isso, neste caso, como bloco de função é:

({									      \
    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; })

Vamos agora olhar para tipo:
agora a camada de aplicação tanto tempo:

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 a analisar 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

Aqui você pode ver, existem muitos lados para esta definição macro
emmmmm que eu não sei qual deles deveria ser. . .
Então eu escrevo para você primeiro

Mas é certo que a definição macro é nada, mas o código de montagem para a instrução de interrupção de software kernel, uso de sysenter ir para o kernel, o uso de chamadas de sistema int $ 0x80 no kernel, a diferença entre os dois é que o cpu uso não os mesmos recursos, int $ 0x80 é pego pelo kernel interrupção portão, o próximo blog para explicar (para abrir um novo poço)

Este blog é apenas a camada de aplicação do soquete macro função de tradução definição de novo, finalmente encontrou sua seção chamada de sistema de compilação
pode saber a tomada de interface de camada de aplicação não faz quaisquer tarefas substantivas, apenas o sistema chama pacote

continua

Lançado sete artigos originais · ganhou elogios 1 · vista 703

Acho que você gosta

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