2014-11-12 2 views
2

Привет всем.Linux x86_64 программирование гнезд сборки

Итак, я изучаю сборку.
И в соответствии с моими обычными шагами обучения с любым новым языком, который я забираю, я пришел к созданию сетей с сборкой.

Который, к сожалению, не так уж хорошо, поскольку я очень сильно потерпел неудачу на шаге 0, который будет получать сокет, через который может начаться общение.

Код сборки должен быть примерно равен следующему коду C: (. Давайте игнорировать тот факт, что он не закрывает сокет сейчас)

#include <stdio.h> 
#include <sys/socket.h> 

int main(){ 
     int sock; 
     sock = socket(AF_INET, SOCK_STREAM, 0); 
} 

Так вот что я сделал до сих пор :

  • Проверен the manual. Что означало бы, что мне нужно сделать socketcall(), все это хорошо и хорошо. Проблема начинается с того, что ему понадобится int, который описывает, какой сокет должен делать. Вызовы manpage не помогают много с этим или как он только описывает, что:

Об одном некоторых архитектуры, например, x86-64 и ARM-нет SOCKETCALL() системного вызова; вместо сокета (2), accept (2), bind (2) и , так что действительно реализованы как отдельные системные вызовы.

  • Но нет таких вызовов в первоначальном списке системных вызовов - и, насколько я знаю, socket(), accept(), bind(), listen() и т.д., звонки с libnet и не из ядра. Это меня совершенно смутило, поэтому я решил скомпилировать приведенный выше код C и проверить его с помощью strace. Это дало следующее:

    гнездо (PF_INET, SOCK_STREAM, IPPROTO_IP) = 3

  • Хотя это не заставило меня ближе к знанию, что socket()является она объяснить это аргументы. Для ведьмы я, похоже, не нашел правильной документации (снова). Я думал, что PF_INET, SOCK_STREAM, IPPROTO_IP будет определен в <sys/socket.h>, но мой grep-для них, похоже, не нашел ничего полезного. Поэтому я решил просто закрыть его, используя gdb в тандеме с disass main, чтобы найти значения.Это дало следующие результаты:

    свалки ассемблера для функции главного: 0x00000000004004fd < +0>: нажимной RBP 0x00000000004004fe < +->: мы ПОР RSP 0x0000000000400501 < +4>: Sub RSP, 0x10 0x0000000000400505 < +8>: мы EDX, 0x0 0x000000000040050a < +13>: мы еси, 0x1 0x000000000040050f < +18>: MOV EDI, 0x2 0x0000000000400514 < +23>: вызов 0x400400 0x0000000000400519 < +28>: мы DWORD PTR [rbp-0x4], eax 0x000000000040051c < +31>: оставить
    0x000000000040051d < +32>: ret
    Конец сборщика самосвалов.

  • В моем опыте это означало бы, что socket() получает его параметры из EDX (PF_INET), ESI (SOCK_STREAM) и EDI (IPPROTO_IP). Что было бы странно для syscall (поскольку соглашение с системами linux syscalls было бы использовать EAX/RAX для номера вызова и других регистров для параметров в порядке возрастания, например RBX, , RDX ...). Тот факт, что это beaing CALL -ed, а не INT 0x80 'd также подразумевает, что это на самом деле не системный вызов, а нечто, вызываемое из общего объекта. Или что-то.

  • Но с другой стороны. Передача аргументов в регистрах очень странная для чего-то, что CALL -ed. Обычно, насколько я знаю, аргумент для вызываемых вещей должен быть PUSH -ed на стек, поскольку компилятор не может знать, какие регистры они будут пытаться использовать.

  • Такое поведение становится еще более интересно, при проверке полученного двоичного файла с ldd:

    Linux-vdso.so.1 (0x00007fff4a7fc000) libc.so.6 =>/Библиотека/x86_64-Linux-ГНУ/libc.so.6 (0x00007f56b0c61000) /lib64/ld-linux-x86-64.so.2 (0x00007f56b1037000)

  • Там, как представляется, нет сетевой библиотеки не связаны между собой.

И это тот момент, когда у меня кончились идеи.

Так я прошу следующее:

  • документация, которая описывает фактические системные вызовы в x86-64 Linux Kernel и их связанные с ними номера. (Предпочтительно в качестве файла заголовка для C.)
  • Заголовочные файлы, которые определяют PF_INET, SOCK_STREAM, IPPROTO_IP, поскольку это действительно меня беспокоит, что я не смог найти их в своей собственной системе.
  • Возможно, учебник для создания сетей в сборке на x86-64 linux. (Для x86-32 это легко найти материал, но по какой-то причине я подошел пустым с 64-битным материалом.)

Спасибо!

+0

Вы не найдете определения в заголовке, который вы включаете в grep, потому что он, в свою очередь, включает менее портативный заголовочный файл, который обеспечивает фактическое значение (возможно, несколько таких слоев). Большинство процессоров с умеренным или большим числом регистров традиционно программируются через ABI, которые используют первые несколько аргументов в указанных регистрах для повышения эффективности, прежде чем прибегать к стеку для остатка. –

+0

'networking with assembly' - вы действительно выбрали это как учебное упражнение? Кто-то держит вас под прицелом? –

ответ

1

В 64-битном соглашении о вызове используются регистры для передачи аргументов как в пространстве пользователя, так и в системных вызовах. Как вы видели, соглашение об использовании пользовательского пространства: rdi, rsi, rdx, rcx, r8, r9. Для системных вызовов используется r10 вместо rcx, который скроен инструкцией syscall. См. wikipedia или документацию ABI для получения более подробной информации.

Определения различных констант скрыты в заголовочных файлах, которые, тем не менее, легко обнаруживаются при поиске в файловой системе, если у вас установлены необходимые пакеты разработки. Вы должны посмотреть в /usr/include/x86_64-linux-gnu/bits/socket.h и /usr/include/linux/in.h.

Что касается списка системных вызовов, тривиальным является один из них, например this. Конечно, вы также можете всегда смотреть в исходный код ядра.

Смежные вопросы