2 votes

Pourquoi `write()` est-il exécuté via une instruction `call` au lieu d'une interruption?

J'essayais de jouer un peu en assembleur. Ma compréhension est que les appels systèmes sont réalisés via une interruption générée par l'instruction syscall.

Cependant, après avoir compilé un programme simple sur mon ordinateur en utilisant clang -S:

int main() {
  write(0, "HI", 2);
  return 0;
}

L'assembleur pertinent généré est le suivant :

    movl    $0, -4(%rbp)
    leaq    L_.str(%rip), %rsi
    movl    $2, %edx
    movb    $0, %al
    callq   _write

Pourquoi est-ce ainsi ?

Existe-t-il un moyen de voir l'appel de système réellement effectué sur OS X ?

3voto

Masklinn Points 1749

Parce que vous appelez une fonction de la bibliothèque standard C. Cette fonction peut ou non englober un appel système, pourrait utiliser un appel système inattendu (par exemple un appel plus moderne que l'original) et doit généralement effectuer diverses opérations de configuration et de nettoyage pour s'adapter entre les conventions d'appel en C et en appel système.

L'enveloppe est généralement assez mince, mais c'est quand même une enveloppe (par exemple, sur linux, les appels système renvoient généralement soit un succès, soit -errno en cas d'échec, la libc doit ensuite vérifier l'échec, stocker le errno dans le threadlocal correspondant et renvoyer la valeur "correcte" définie par la norme ou POSIX à la place).

0voto

Kamil.S Points 1151

Comme l'a mentionné @user207421 dans le commentaire write en tant que fonction de bibliothèque standard C doit finalement envelopper un appel système spécifique à la plate-forme. Sur MacOS, la couche de façade est définie dans libsystem_kernel.dylib qui est utilisée par l'implémentation de la bibliothèque standard C de MacOS libSystem.B.dylib. Les numéros des appels système ne sont pas une interface publique et sont sujets à modification selon les versions de MacOS. De plus, comme l'a souligné @fuz, certains d'entre eux pourraient même devenir obsolètes et ne pas avoir d'entrée/numéro syscall directement mais resteront pris en charge par la couche d'enrobage.

Lorsque vous lancez votre programme, vous pouvez vérifier l'action réelle du syscall dans l'interface de ligne de commande lldb avec :

lldb ./a.out
b write
run
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
    frame #0: 0x00007fff63e0f040 libsystem_kernel.dylib`write
libsystem_kernel.dylib`write:
->  0x7fff63e0f040 <+0>:  mov    eax, 0x2000004
    0x7fff63e0f045 <+5>:  mov    r10, rcx
    0x7fff63e0f048 <+8>:  syscall 
    0x7fff63e0f04a <+10>: jae    0x7fff63e0f054            ; <+20>
Target 0: (a.out) stopped.
(lldb)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X