не мог понять поведение чтения системного вызова - PullRequest
2 голосов
/ 30 января 2011

Вот код, который я пытаюсь запустить:

#include<fcntl.h>
#include<stdio.h>
#include<errno.h>
#include<string.h>
#include<unistd.h>

int main(){

  int ret;

  ret = read(STDIN_FILENO,(int*)2000,3);
  printf("%d--%s\n",ret,strerror(errno));

  return 0;
}

и это вывод, который я получаю на терминале

anirudh@anirudh-Aspire-5920:~/Desktop/testing$ gcc test.c 
anirudh@anirudh-Aspire-5920:~/Desktop/testing$ ./a.out 
lls
-1--Bad address
anirudh@anirudh-Aspire-5920:~/Desktop/testing$ ls
a.out  htmlget_ori.c  mysocket.cpp  Packet Sniffer.c  resolutionfinder.c  test.c
anirudh@anirudh-Aspire-5920:~/Desktop/testing$ 

Вопрос 1: Когда я набираю адрес 2000 в вызове read read(STDIN_FILENO,(int*)2000,3); тогда где находится адрес. Я думаю, что это абсолютный адрес ОЗУ, к которому я пытаюсь получить доступ. Я прав или это смещение и добавляется к базовому адресу сегмента стека. Я не знаю. Программа не дает мне SEGFAULT за нарушение памяти, а дает мне Bad address

Вопрос 2: Хорошо, код вылетает, когда я передаю ввод как lls, и bash выполняет часть "ls" этого "lls". Причина в том, что код вылетает после чтения первой буквы «l», а остальная часть «ls» выполняется bash. но почему bash выполняет левую часть "ls". Почему bash делает это, потому что мой код не работает, и даже если bash был его родительским процессом, он не должен читать из дескриптора файла (STDIN_FILNO), открытого кодом, который я написал. (Я так думаю) ...

Спасибо за ваше время.

Ответы [ 3 ]

4 голосов
/ 30 января 2011

2000, который вы пытаетесь использовать в качестве адреса, является специфичным для процесса виртуальным адресом . Хороши шансы, что в этом диапазоне ничего не отображается; Вы можете добавить этот код, чтобы увидеть, каковы ваши отображения в настоящее время:

char cmd[20];

sprintf(cmd, "pmap -x %i", getpid());
printf("%s\n", cmd);
system(cmd);

Если вам действительно необходимо получить доступ к системе ОЗУ вокруг 2000 (и я не могу себе это представить), используйте системный вызов iopl(2), чтобы отобразить этот диапазон адресов в память процесса. пространство. И остерегайтесь последствий. :)

Что касается остальной части поведения ls, попробуйте добавить \n в строку формата printf(), я обнаружил, что неправильная очистка вывода может привести к путанице, возможно, это просто сбивает с толку , а не просто странно. :)

1 голос
/ 30 января 2011

Вы работаете на процессоре с подкачкой. Ваша ОС поддерживает таблицы страниц, которые переводятся с виртуальных на физические адреса. Таблица страниц для вашего процесса не содержит ничего для виртуального адреса 2000, поэтому read() замечает и возвращает -EFAULT.

stdin подключено к вашему оконечному устройству (/dev/tty). Ваш процесс наследует этот терминал от вашей оболочки, и оболочка возвращает его при выходе из процесса.

0 голосов
/ 30 января 2011

Я отвечу только на вопрос 1. Я не совсем понимаю, что вы подразумеваете под вопросом 2, плюс он может сам позаботиться, как только вы решите свою первую проблему.

Чтобы ответить на ваш вопрос 1, , не будучи на 100% уверенным, я бы поспорил, что (int*)2000 указывает местоположение в сегменте данных вашей программы, то есть, что 2000 является только смещенной частью. Причина, по которой я так думаю, заключается в том, что обычно при любой современной операционной системе вы вряд ли когда-либо будете иметь неограниченный доступ к физической памяти. Компоновщик и загрузчик программ операционной системы обрабатывают все связанные с сегментами вещи для вас - ваша программа только когда-либо увидит смещенную часть (виртуальная & mdash; см. Стр. Ниже) адресов памяти. Все, что связано с данными, обычно происходит в сегменте данных; Связанные с кодом вещи (такие как вызовы функций) обычно связаны с сегментом кода.

На мой взгляд, у вас нет гарантии, что какая-либо конкретная структура данных будет расположена по смещению 2000 вашего сегмента данных. Поэтому ваш read пункт назначения почти всегда недопустим, поскольку в основном это означает, что вы записываете данные в произвольное место в памяти.

P.S. : Под адресом виртуальной памяти я имею в виду, что сегмент вашей программы, возможно, будет загружен ОС по разным адресам физической памяти. Таким образом, смещение 2000 (например) любого сегмента не всегда будет означать один и тот же абсолютный адрес физической памяти; скорее это смещение, то есть относительно базового адреса сегмента, который сам по себе находится по произвольному адресу физической памяти.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...