Как запустить программу в одиночку без операционной системы? Можно ли создавать ассемблерные программы, которые компьютер может загружать и запускать при запуске, например, загружать компьютер с флешки, а он запускает программу, которая находится на процессоре?
227 2014-02-26T22:13:38+00:00 3
simhumileco
Редактировал вопрос 12-го июля 2019 в 4:37
Комментарии к вопросу (4)
Ciro Santilli 新疆改造中心法轮功六四事件
Ответ на вопрос
9-го сентября 2015 в 3:23
2015-09-09T15:23:54+00:00
Дополнительно
Запускаемые примеры Давайте создадим и запустим несколько мизерных программ «hello world», работающих без ОС:
- ноутбуке x86 Lenovo Thinkpad T430 с прошивкой UEFI BIOS 1.16
- на базе ARM Raspberry Pi 3. Мы также будем тестировать их на эмуляторе QEMU, так как это безопаснее и удобнее для разработки. Тесты QEMU проводились на хосте Ubuntu 18.04 с предустановленным пакетом QEMU 2.11.1. Код всех приведенных ниже примеров для x86 и других присутствует на этом репозитории GitHub. Как запустить примеры на реальном оборудовании x86. Помните, что выполнение примеров на реальном оборудовании может быть опасным, например, вы можете по ошибке стереть диск или сломать оборудование: делайте это только на старых машинах, не содержащих критических данных! Или еще лучше использовать дешевые полуразборные платы, такие как Raspberry Pi, см. пример ARM ниже. Для типичного ноутбука x86 вам придется сделать примерно следующее:
- Запишите образ на USB-накопитель (это уничтожит ваши данные!): sudo dd if=main.img of=/dev/sdX
- подключите USB к компьютеру
- включите его
- скажите ему загрузиться с USB. Это означает, что прошивка выбирает USB перед жестким диском. Если это не является поведением вашей машины по умолчанию, продолжайте нажимать Enter, F12, ESC или другие подобные странные клавиши после включения, пока не появится меню загрузки, в котором можно выбрать загрузку с USB. Часто в этих меню можно настроить порядок поиска. Например, на моем T430 я вижу следующее. После включения мне нужно нажать Enter, чтобы войти в меню загрузки: Затем, здесь я должен нажать F12, чтобы выбрать USB в качестве загрузочного устройства: Отсюда я могу выбрать USB в качестве загрузочного устройства следующим образом: В качестве альтернативы, чтобы изменить порядок загрузки и выбрать USB с более высоким приоритетом, чтобы не выбирать его вручную каждый раз, я нажму F1 на экране «Startup Interrupt Menu», а затем перейду к: Загрузочный сектор. На x86, самое простое и низкоуровневое, что можно сделать, это создать Master Boot Sector (MBR), который является разновидностью boot sector, а затем установить его на диск. Здесь мы создаем его с помощью одного вызова printf :
printf ‘364%509s125252’ > main.img sudo apt-get install qemu-system-x86 qemu-system-x86_64 -hda main.img
Результат: Обратите внимание, что даже ничего не делая, несколько символов уже напечатаны на экране. Они напечатаны микропрограммой и служат для идентификации системы. А на T430 мы получаем просто пустой экран с мигающим курсором: main.img содержит следующее:
Как запустить программу без прав администратора?
- 364 в восьмеричном формате == 0xf4 в шестнадцатеричном: кодировка для инструкции hlt , которая говорит процессору прекратить работу. Поэтому наша программа не будет ничего делать: только запускаться и останавливаться. Мы используем восьмеричную кодировку, потому что шестнадцатеричные числа x не определены POSIX. Мы можем легко получить эту кодировку с помощью: echo hlt > a.S as -o a.o a.S objdump -S a.o который выводит: a.o: формат файла elf64-x86-64 Разборка секции .text: 0000000000000000 : 0: f4 hlt но это также документировано в руководстве Intel, конечно.
- %509s производят 509 пробелов. Требуется заполнить файл до байта 510.
- 125252 в восьмеричном исчислении == 0x55 , за которым следует 0xaa . Это 2 необходимых магических байта, которые должны быть байтами 511 и 512. BIOS просматривает все наши диски в поисках загрузочных, и считает загрузочными только те, на которых есть эти два волшебных байта. Если их нет, оборудование не будет считать диск загрузочным. Если вы не мастер printf , вы можете подтвердить содержимое main.img с помощью:
hd main.img
который покажет ожидаемое:
00000000 f4 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 |. | 00000010 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 | | * 000001f0 20 20 20 20 20 20 20 20 20 20 20 20 20 20 55 aa | U.| 00000200
где 20 — пробел в ASCII. Микропрограмма BIOS считывает эти 512 байт с диска, помещает их в память и устанавливает ПК на первый байт для начала их выполнения. Здравствуй мир, загрузочный сектор.
Теперь, когда мы сделали минимальную программу, давайте перейдем к hello world. Очевидный вопрос: как сделать IO? Есть несколько вариантов:
- попросить прошивку, например, BIOS или UEFI, сделать это за нас.
- VGA: специальная область памяти, которая при записи выводится на экран. Может использоваться в защищенном режиме.
- написать драйвер и общаться напрямую с аппаратным обеспечением дисплея. Это «правильный» способ сделать это: более мощный, но более сложный.
- [последовательный порт] (https://en.wikipedia.org/wiki/Serial_port). Это очень простой стандартизированный протокол, который отправляет и принимает символы от хост-терминала. На настольных компьютерах он выглядит следующим образом: Источник. К сожалению, он не реализован на большинстве современных ноутбуков, но является обычным способом для плат разработки, см. примеры ARM ниже. Это очень жаль, поскольку такие интерфейсы действительно полезны например, для отладки ядра Linux.
- использовать отладочные возможности чипов. ARM, например, называет их semihosting. На реальном оборудовании это требует дополнительной аппаратной и программной поддержки, но на эмуляторах это может быть бесплатной удобной опцией. Пример. Здесь мы рассмотрим пример с BIOS, так как на x86 это проще. Но учтите, что это не самый надежный метод. main.S
.code16 mov $msg, %si mov $0x0e, %ah loop: lodsb or %al, %al jz halt int $0x10 jmp loop halt: hlt msg: .asciz «hello world»
SECTIONS < /* The BIOS loads the code from the disk to this location. * We must tell that to the linker so that it can properly * calculate the addresses of symbols we might jump to. */ . = 0x7c00; .text : < __start = .; *(.text) /* Place the magic boot bytes at the end of the first 512 sector. */ . = 0x1FE; SHORT(0xAA55) >>
Соберите и соедините с:
as -g -o main.o main.S ld —oformat binary -o main.img -T link.ld main.o qemu-system-x86_64 -hda main.img
Результат: И на T430: Проверено на: Lenovo Thinkpad T430, UEFI BIOS 1.16. Диск сгенерирован на хосте Ubuntu 18.04. Помимо стандартных инструкций пользовательского ассемблера, мы имеем:
- .code16 : указывает GAS на вывод 16-битного кода
- cli : отключить программные прерывания. Они могут заставить процессор снова начать работать после hlt .
- int $0x10 : выполняет вызов BIOS. Это то, что печатает символы один за другим. Важными флагами соединения являются:
- —oformat binary : выводить необработанный двоичный ассемблерный код, не заворачивать его в ELF-файл, как это делается для обычных пользовательских исполняемых файлов. Чтобы лучше понять часть скрипта компоновщика, ознакомьтесь с этапом компоновки с перемещением: https://stackoverflow.com/questions/3322911/what-do-linkers-do/33690144#33690144. Программы для «голого металла» x86 Вот несколько более сложных bare metal установок, которых мне удалось добиться:
- многоядерность: https://stackoverflow.com/questions/980999/what-does-multicore-assembly-language-look-like/33651438#33651438
- paging: https://stackoverflow.com/questions/18431261/how-does-x86-paging-work/18431262#18431262Используйте C вместо ассемблера Резюме: используйте мультизагрузку GRUB, которая решит множество раздражающих проблем, о которых вы никогда не думали. См. раздел ниже. Основная трудность на x86 заключается в том, что BIOS загружает с диска в память только 512 байт, и при использовании C вы, скорее всего, испортите эти 512 байт! Чтобы решить эту проблему, мы можем использовать двухэтапный загрузчик. При этом выполняются дополнительные вызовы BIOS, которые загружают больше байт с диска в память. Вот минимальный пример сборки 2-го этапа с нуля с использованием int 0x13 вызовов BIOS: Альтернативный вариант:
- если вам нужно, чтобы он работал только в QEMU, а не на реальном оборудовании, используйте опцию -kernel , которая загружает в память весь ELF-файл. Вот пример ARM, который я создал с помощью этого метода.
- Для Raspberry Pi прошивка по умолчанию заботится о загрузке образа из ELF-файла с именем kernel7.img , подобно тому, как это делает -kernel в QEMU. Только в учебных целях, вот [одноэтапный минимальный пример на C] (https://github.com/cirosantilli/x86-bare-metal-examples/tree/b4e4c124a3c3c329dcf09a5697237ed3b216a318#c-hello-world): main.c
void main(void) < int i; char s[] = ; for (i = 0; i < sizeof(s); ++i) < __asm__ ( «int $0x10» : : «a» ((0x0e while (1) < __asm__ («hlt»); >; >
.code16 .text .global mystart mystart: ljmp $0, $.setcs .setcs: xor %ax, %ax mov %ax, %ds mov %ax, %es mov %ax, %ss mov $__stack_top, %esp cld call main
ENTRY(mystart) SECTIONS < . = 0x7c00; .text : < entry.o(.text) *(.text) *(.data) *(.rodata) __bss_start = .; /* COMMON vs BSS: https://stackoverflow.com/questions/16835716/bss-vs-common-what-goes-where */ *(.bss) *(COMMON) __bss_end = .; >/* https://stackoverflow.com/questions/53584666/why-does-gnu-ld-include-a-section-that-does-not-appear-in-the-linker-script */ .sig : AT(ADDR(.text) + 512 — 2) < SHORT(0xaa55); >/DISCARD/ : < *(.eh_frame) >__stack_bottom = .; . = . + 0x1000; __stack_top = .; >
set -eux as -ggdb3 —32 -o entry.o entry.S gcc -c -ggdb3 -m16 -ffreestanding -fno-PIE -nostartfiles -nostdlib -o main.o -std=c99 main.c ld -m elf_i386 -o main.elf -T linker.ld entry.o main.o objcopy -O binary main.elf main.img qemu-system-x86_64 -drive file=main.img,format=raw
Стандартная библиотека Си Однако, если вы хотите использовать стандартную библиотеку C, все становится еще интереснее, поскольку у нас нет ядра Linux, в котором реализована большая часть функций стандартной библиотеки C через POSIX. Несколько возможностей, не переходя на полноценную ОС типа Linux, включают:
- Написать свою собственную. В конце концов, это просто куча заголовков и файлов на C, верно? Верно.
- Newlib Подробный пример на: https://electronics.stackexchange.com/questions/223929/c-standard-libraries-on-bare-metal/223931 Newlib реализует для вас все скучные вещи, не связанные с ОС, например, memcmp , memcpy и т.д. Затем, он предоставляет некоторые заглушки для реализации системных вызовов, которые вам нужны самостоятельно. Например, мы можем реализовать exit() на ARM с помощью полухостинга: void _exit(int status) < asmvolatile («mov r0, #0x18; ldr r1, =#0x20026; svc 0x00123456»); > как показано на в этом примере. Например, можно перенаправить printf на UART или ARM системы, или реализовать exit() с помощью semihosting.
- встроенные операционные системы, такие как FreeRTOS и Zephyr. Такие операционные системы обычно позволяют отключить вытесняющее планирование, что дает полный контроль над временем выполнения программы. Их можно рассматривать как своего рода предварительно реализованный Newlib. GNU GRUB Multiboot. Загрузочные сектора просты, но не очень удобны:
- вы можете иметь только одну ОС на диске
- загрузочный код должен быть очень маленьким и умещаться в 512 байт
- многое при запуске приходится делать самому, например, переходить в защищенный режим. Именно по этим причинам GNU GRUB создал более удобный формат файлов под названием multiboot. Минимальный рабочий пример: https://github.com/cirosantilli/x86-bare-metal-examples/tree/d217b180be4220a0b4a453f31275d38e697a99e0/multiboot/hello-world Я также использую его в своем GitHub examples repo, чтобы иметь возможность легко запускать все примеры на реальном оборудовании, не прожигая USB миллион раз. Результат работы QEMU: T430: Если вы подготовите свою ОС как мультизагрузочный файл, GRUB сможет найти его в обычной файловой системе. Так поступает большинство дистрибутивов, помещая образы ОС в /boot . Мультизагрузочные файлы — это, по сути, ELF-файл со специальным заголовком. Они указываются GRUB по адресу: https://www.gnu.org/software/grub/manual/multiboot/multiboot.html. Вы можете превратить мультизагрузочный файл в загрузочный диск с помощью grub-mkrescue . Прошивка. На самом деле, ваш загрузочный сектор не является первым программным обеспечением, которое запускается на процессоре системы. На самом деле первой запускается так называемая прошивка, которая представляет собой программное обеспечение:
- созданное производителями аппаратного обеспечения
- обычно с закрытым исходным кодом, но, скорее всего, на языке C
- хранится в памяти только для чтения, и поэтому его сложнее или невозможно изменить без согласия производителя. Хорошо известные прошивки включают:
- BIOS: старая универсальная прошивка для x86. SeaBIOS — это реализация с открытым исходным кодом по умолчанию, используемая QEMU.
- UEFI: преемник BIOS, лучше стандартизированный, но с большими возможностями и невероятно раздутый.
- Coreboot: благородная попытка создания арки с открытым исходным кодом. Прошивка делает такие вещи, как:
- перебирает каждый жесткий диск, USB, сеть и т.д., пока не найдет что-то загрузочное. Когда мы запускаем QEMU, -hda говорит, что main.img — это жесткий диск, подключенный к оборудованию, и hda — первый, который будет опробован, и он используется.
- загрузить первые 512 байт в RAM память по адресу 0x7c00 , поместить туда CPU’s RIP, и дать ему запуститься
- показать на дисплее такие вещи, как меню загрузки или вызовы печати BIOS. Прошивка предлагает функциональность, подобную ОС, от которой зависит большинство ОС. Например, подмножество Python было перенесено для работы с BIOS / UEFI:
Источник: kzen.dev
Как запустить программу без операционной системы: часть 2
В первой части нашей статьи мы рассказали о том, каким образом можно получить простую программу “Hello World”, которая запускается без операционной системы и печатает сообщение на экран.
В этой части статьи, хочется развить получившийся в первой части код таким образом, чтобы он мог быть отлажен через GDB, компилировался через оболочку Visual Studio и печатал на экран список PCI устройств.
! ВАЖНО!: Все дальнейшие действия могут успешно осуществляться только после успешного прохождения всех 6-ти шагов описанных в первой части статьи).
Учимся отлаживать программу
Как отладить код kernel.bin? Для этого нужно добавить в kernel.bin симовлы для отладки и запустить отладчик:
1. Добавим опцию компилятора в файле makefile, чтобы он генерировал отладочные символы:
CFLAGS = -Wall -fno-builtin -nostdinc -nostdlib -ggdb3
2. Добавим пару строк на этапе сборки, чтобы на диск записывался kernel.bin без символов (такой файл можно сделать при помощи утилиты strip). Для этого нужно исправить цель kernel.bin в makefile:
тогда:
kernel.bin – не содержит символы – его можно запускать;
kernel.bin.dbg – содержит и символы и код – его можно скормить отладчику.
3. Установим отладчик:
sudo apt-get install cgdb
4. Перекомпилируем программу:
make clean make all sudo make image
5. Запустим qemu с опцией ожидания отладчика:
sudo qemu-system-i386 -s -S -hda hdd.img sudo qemu-system-i386 -hda hdd.img 192.168.1.8 user 123456 ~/Desktop/_habr -pw $(RbPassword) $(RbUser)%40$(RbHost) cd $(RbRoot); cd $(RblFolder); $(SolutionDir)toolsplink -batch $(RbToolArgs) $(RbToolExe) make all $(RbToolExe) make rebuild $(RbToolExe) make cleanall $(RbToolArgs) $(RblExecute) $(RblIncludePath) $(RbBuildCmd) $(RbRebuildAllCmd) $(RbCleanCmd) $(RbIncludePath) $(SolutionDir) toolsplink $(RbExecuteCmd) $(RbBuildCmd) $(RbRebuildAllCmd) $(RbCleanCmd) $(RbIncludePath) $(SolutionDir)toolsplink $(RbExecuteCmd)
6. Меняем файл ”projkernelvskernel.vcxproj ” так же по инструкции:
7. В итоге должно получиться примерно следующее:
8. Проверяем, что все работает:
Таким образом, для дельнейшей разработки нашей программы можно использовать оболочку Visual Studio, хоть и компилятор GCC на Linux.
Сканирование устройств PCI
Как теперь просканировать системную шину PCI на наличие устройств? Следуя инструкциям в статье выполняем следующие действия (загрузочный образ уже готов, поэтому только добавляем код сканирования PCI):
1. Добавляем в файл includetypes.h, следующее определение типа:
typedef unsigned long u32; typedef unsigned short u16; typedef unsigned char u8;
2. Добавляем файл includeio.h, который без изменений можно взять из проекта bitvisor из каталога (includeio.h).
3. Добавляем файл includepci.h, который содержит основные определения для функций работы с PCI. Он имеет следующее содержимое:
#ifndef _PCI_H #define _PCI_H #include «types.h» #define PCI_CONFIG_PORT 0x0CF8 #define PCI_DATA_PORT 0x0CFC #define PCI_MAX_BUSES 255 #define PCI_MAX_DEVICES 32 #define PCI_MAX_FUNCTIONS 8 #define PCI_HEADERTYPE_NORMAL 0 #define PCI_HEADERTYPE_BRIDGE 1 #define PCI_HEADERTYPE_CARDBUS 2 #define PCI_HEADERTYPE_MULTIFUNC 0x80 typedef union < struct < u16 vendorID; u16 deviceID; u16 commandReg; u16 statusReg; u8 revisionID; u8 progIF; u8 subClassCode; u8 classCode; u8 cachelineSize; u8 latency; u8 headerType; u8 BIST; >__attribute__((packed)) option; u32 header[4]; > __attribute__((packed)) PCIDevHeader; void ReadConfig32(u32 bus, u32 dev, u32 func, u32 reg, u32 *data); char *GetPCIDevClassName(u32 class_code); void PCIScan(); #endif
4. Добавляем файл pci.c в корень проекта, со следующим содержимым (мы немного улучшили этот код по сравнению с основной статьей):
#include «types.h» #include «printf.h» #include «io.h» #include «pci.h» typedef struct < u32 class_code; char name[32]; >PCIClassName; static PCIClassName g_PCIClassNames[] = < < 0x00, «before PCI 2.0»>, < 0x01, «disk controller»>, < 0x02, «network interface»>, < 0x03, «graphics adapter»>, < 0x04, «multimedia controller»>, < 0x05, «memory controller»>, < 0x06, «bridge device»>, < 0x07, «communication controller»>, < 0x08, «system device»>, < 0x09, «input device»>, < 0x0a, «docking station»>, < 0x0b, «CPU»>, < 0x0c, «serial bus»>, < 0x0d, «wireless controller»>, < 0x0e, «intelligent I/O controller»>, < 0x0f, «satellite controller»>, < 0x10, «encryption controller»>, < 0x11, «signal processing controller»>, < 0xFF, «proprietary device»>>; typedef union < struct < u32 zero : 2; u32 reg_num : 6; u32 func_num : 3; u32 dev_num : 5; u32 bus_num : 8; u32 reserved : 7; u32 enable_bit : 1; >; u32 val; > PCIConfigAddres; void ReadConfig32(u32 bus, u32 dev, u32 func, u32 reg, u32 *data) < PCIConfigAddres addr; addr.val = 0; addr.enable_bit = 1; addr.reg_num = reg; addr.func_num = func; addr.dev_num = dev; addr.bus_num = bus; out32(PCI_CONFIG_PORT, addr.val); in32(PCI_DATA_PORT, data); return; >char *GetPCIDevClassName(u32 class_code) < int i; for (i = 0; i < sizeof(g_PCIClassNames)/sizeof(g_PCIClassNames[0]); i++) < if (g_PCIClassNames[i].class_code == class_code) return g_PCIClassNames[i].name; >return NULL; > int ReadPCIDevHeader(u32 bus, u32 dev, u32 func, PCIDevHeader *p_pciDevice) < int i; if (p_pciDevice == 0) return 1; for (i = 0; i < sizeof(p_pciDevice->header)/sizeof(p_pciDevice->header[0]); i++) ReadConfig32(bus, dev, func, i, header[i]); if (p_pciDevice->option.vendorID == 0x0000 || p_pciDevice->option.vendorID == 0xffff || p_pciDevice->option.deviceID == 0xffff) return 1; return 0; > void PrintPCIDevHeader(u32 bus, u32 dev, u32 func, PCIDevHeader *p_pciDevice) < char *class_name; printf(«bus=0x%x dev=0x%x func=0x%x venID=0x%x devID=0x%x», bus, dev, func, p_pciDevice->option.vendorID, p_pciDevice->option.deviceID); class_name = GetPCIDevClassName(p_pciDevice->option.classCode); if (class_name) printf(» class_name=%s», class_name); printf(«n»); > void PCIScan(void) < int bus; int dev; for (bus = 0; bus < PCI_MAX_BUSES; bus++) for (dev = 0; dev < PCI_MAX_DEVICES; dev++) < u32 func = 0; PCIDevHeader pci_device; if (ReadPCIDevHeader(bus, dev, func, PrintPCIDevHeader(bus, dev, func, if (pci_device.option.headerType for (func = 1; func < PCI_MAX_FUNCTIONS; func++) < if (ReadPCIDevHeader(bus, dev, func, PrintPCIDevHeader(bus, dev, func, >> > >
5. Добавляем запуск сканирования PCI устройств в kernel.c:
#include «printf.h» #include «screen.h» #include «types.h» #include «pci.h» void main() < clear_screen(); printf(«n>>> Hello World!n»); PCIScan(); >
6. Вносим необходимые изменения в makefile:
OBJFILES = loader.o common/printf.o common/screen.o pci.o kernel.o
7. Теперь можно пересобрать проект:
make rebuild sudo make image
8. Запускаем проект, чтобы убедиться, что все работает:
sudo qemu-system-i386 -hda hdd.img
Так мы получили список PCI устройств на компьютере. Это так же будет работать и на обычном компьютере, загрузившись с флешки.
Пройдя все шаги в этой статье вы можете собственноручно разобраться во всем и увидеть работающую программу, которую можно полноценно отлаживать.
Источник: savepearlharbor.com
Можно ли запустить компьютерную программу без операционной системы? [закрытый]
Мне интересно, можно ли запустить компьютерную программу без операционной системы. Есть ли способ сделать это?
задан Anderson Green
01.01.2023 9:11 3158
1 ответ
«Нормальные» Компьютеры
без операционной системы невозможно запустить программу, которая была написана для работы в операционной системе. Большинство программ такого рода.
вы могли бы написать программу, которая работает без операционной системы, но это было бы очень сложной задачей, главным образом потому, что операционная система предоставляет драйверы для всего оборудования. Без ОС ваша программа должна была бы напрямую управлять конкретным оборудованием. Не все производители оборудования выпускают детали как это сделать (например, nVidia), но предоставлять драйверы только для определенных операционных систем.
У вас также будет проблема с тем, как заставить компьютер загрузить и запустить вашу программу. В большинстве настольных компьютеров нужно поместить в программу где в BIOS найти загрузчик ОС.
вероятно, вам придется написать программу на языке ассемблера низкого уровня или, возможно, что-то вроде C без каких-либо стандартных библиотек, которые являются ОС зависимый.
микроконтроллеры
Вы можете писать программы для таких вещей, как Arduino, без какой-либо ОС на Arduino. существуют наборы для разработки, которые позволяют писать код на относительно высокоуровневых языках, наборы для разработки обычно предоставляют эквивалент драйверов для конкретного оборудования.
Операционные Системы
можно переопределить «операционная система» способом, который делает все вышеперечисленное. Я предполагаю, что вы имеете в виду программное обеспечение, сопоставимое для операционных систем Windows или Linux.
отвечен RedGrittyBrick 2023-01-02 16:59
Постоянная ссылка на данную страницу: [ Скопировать ссылку | Сгенерировать QR-код ]
Ваш ответ
Опубликуйте как Гость или авторизуйтесь
Опубликовать ответ
Похожие вопросы про тегам:
operating-systems
- Почему операционные системы (обычно?) не удается получить доступ к настройкам BIOS?
- Как отобразить «Comic Sans MS» в Linux?
- Как решить сломанный dnf в Fedora 26, когда я получаю «ImportError: bad magic number in ‘six'»
Недавние вопросы
- 7 Какое максимальное количество разделов можно создать на жестком диске?
- 3 Таблица прилипает к верхней части страницы, как ее удалить?
- 6 При двусторонней печати как исправить, что задняя страница печатается вверх ногами?
- 4 Как превратить оглавление в простой форматированный текст?
- 5 Что значит 1Rx8 и 2Rx8 для оперативной памяти и совместимы ли они?
- 10 Копирование и вставка в Windows PowerShell
- 13 Сочетание клавиш для сворачивания удаленного рабочего стола
- 1 Как включить фон рабочего стола на удаленном компьютере?
- 5 Как сделать ярлык на рабочем столе доступным для всех пользователей в Windows 10
- 1 Зачем Windows 10 нужна служба очереди сообщений и почему она установлена по умолчанию?
Недавние публикации
Наушники Wireless и True Wireless: чем они отличаются?
Не включается iPad: причины и решения проблемы
Как ускорить передачу данных по Bluetooth
Как правильно приобрести подержанный iPhone?
Каковы преимущества фотоэлектрической системы?
5 лучших USB–пылесосов для клавиатуры
Как выбрать чехол-аккумулятор для смартфона
Мобильный телефон Razr: новая складная раскладушка от Motorola стоит 1200 евро
Компания Nothing: смартфон Phone 2 должен быть «более премиальным» и выйти в этом году
UMTS — История технологии сотовой связи
Выбор домена
3D-печать: будущее массового производства
Искусственный интеллект в малом бизнесе: как улучшить эффективность и конкурентоспособность
Ошибки, которых стоит избегать при продвижении сайта
Высокие технологии в Windows: что это такое и как их использовать в своих приложениях
- Конструктор автоворонок для мессенджеров: упрощение коммуникации и автоматизация бизнес-процессов
- Осознанные воспоминания – технология «живых» фото
Акции IT-компаний [17.06]
Apple | $173,24 | +0,81% | ![]() |
Amazon | $114,49 | -1,94% | ![]() |
Microsoft | $325,19 | +3,61% | ![]() |
$123,44 | +2,11% | ![]() |
|
Netflix | $364,74 | -0,03% | ![]() |
Intel | $27,45 | -5,34% | ![]() |
$254,49 | +2,11% | ![]() |
|
Tesla | $185,54 | +1,44% | ![]() |
Tencent | $322,40 | -3,01% | ![]() |
Цитата дня
Надеюсь, что в конце своих дней, когда я предстану перед Богом, у меня не останется ни капли таланта, чтобы я могла сказать ему: Я использовала все, что ты дал мне.
- Какое максимальное количество разделов можно создать на жестком диске?
- Таблица прилипает к верхней части страницы, как ее удалить?
- При двусторонней печати как исправить, что задняя страница печатается вверх ногами?
- Как превратить оглавление в простой форматированный текст?
Источник: kompsekret.ru