2017-01-12 18 views
0

я компиляции этой программы в Cygwin 64-битных Windows, не выход, не компилирует правильновстроенный ассемблер не показывает вывод

#include <unistd.h> 

int main(void) 
{ 
    const char hello[] = "Hello World!\n"; 
    const size_t hello_size = sizeof(hello); 
    ssize_t ret; 
    asm volatile 
    (
     "movl $1, %%eax\n\t" 
     "movl $1, %%edi\n\t" 
     "movq %1, %%rsi\n\t" 
     "movl %2, %%edx\n\t" 
     "syscall" 
     : "=a"(ret) 
     : "g"(hello), "g"(hello_size) 
     : "%rdi", "%rsi", "%rdx", "%rcx", "%r11" 
    ); 
    return 0; 
} 
+3

Используемый вами 'syscall' применяется к 64-разрядному Linux, а не к Windows/Cygwin. –

+0

@MichaelPetch. Вы должны ответить на этот вопрос. – yugr

ответ

3

комментарий Майкла делает правильно определить проблему. Но, как объяснение, он немного худой. Итак ...

В то время как syscall является способом применения пользовательского режима (пользовательский режим: если вы не пишете драйвер устройства или не меняете ядро ​​операционной системы, вы пишете пользовательский режим), чтобы задать x64 операционная система, чтобы что-то сделать для вас, каждая операционная система x64 имеет немного другой формат для запроса.

Например, в коде, который вы отправили, вы перемещаете значение 1 в регистр eax. Зачем ты это делаешь? Почему 1 вместо (скажем) 23? Ответ заключается в том, что в Linux eax используется для хранения номера, который сообщает, какую операцию вы хотите выполнить ОС. 1 означает выходную строку. Затем вам нужно указать конкретные значения в других конкретных регистрах, чтобы сказать, что вы хотите распечатать, и где вы хотите его распечатать.

Но какие значения вы должны установить, и куда им нужно идти, определяются люди, которые написали Linux. Windows может (и делает) делать что-то совершенно по-другому: разные значения, разные регистры и т. Д.

Поэтому причина, по которой этот код не работает, заключается в том, что он был разработан специально для Linux, и вы пытаетесь запустить его в Windows. И в то время как cygwin может сделать вещи более похожими на linux (например, создавая командную строку, которая обрабатывает команды rm), она не может изменить то, что происходит, когда вы напрямую вызываете операционную систему через syscall. Вы все еще работаете с Windows, и это тот, кто будет работать с syscall. Ничего, что может сделать cygwin.

Итак, имея в виду все это, как заставить этот код работать под Windows? Короткий ответ заключается в том, что вы не можете. Microsoft не публикует номера системных вызовов и значения, в которые входят регистры.

Если вы хотите напечатать что-то под Windows, вам нужно будет вызвать системную dll, которая сделает все, что для вас. Вы можете либо вызвать файл ntdll.dll, либо другую dll (например, msvcrt.dll), которая, в свою очередь, вызывает вызов ntdll.dll.

Там некоторые хорошие примеры в How to write hello world in assembler under Windows?

PS Если вы нашли парень, который первоначально написал, что ассемблер, скажите ему, что в то время как он работает на Linux, это ужасно неэффективен.

+1

Я сохранил свой комментарий намеренно тонким ;-), я не собирался писать ответ, который в основном заканчивается тем, что он не отвечает, или, по крайней мере, не то, что ОР хотел услышать. лол. Не знаю, почему OP не мог просто использовать библиотеку _C_ для печати. –

+1

Похоже, что код OPs дебютировал на SO [в этом ответе] (http://stackoverflow.com/a/23020467/3857942), хотя подобный фрагмент кода также появляется в блоге. Нотная записка заключается в том, что на самом деле у ответа есть ссылка на лучшую реализацию и объяснение в этом [другом SO-ответе] (http://stackoverflow.com/a/9508738/3857942) –

+0

Я не уверен, что цель OP. Хотя некоторым людям нравится программировать «голый металл», в этом случае похоже, что он просто копирует то, что он видел где-то в другом месте. Люди путаются о том, что cygwin может и не может сделать. Объяснение, почему это работает в Linux, но не в эмуляторе Linux, показалось мне наименьшим, что я мог сделать, чтобы восполнить плохие новости. –