0

i am compiling this program in cygwin 64 bit windows, no output, compiles correctly

#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;
}
Michael Petch
  • 46,082
  • 8
  • 107
  • 198

1 Answers1

3

Michael's comment does correctly define the problem. But as an explanation, it is a little thin. So...

While syscall is the way for a user-mode application (user-mode: if you are not writing a device driver or changing the operating system's kernel, you are writing user-mode) to ask an x64 operating system to do something for you, every x64 OS has slightly different format for making the request.

For example, in the code you posted, you move the value 1 into the eax register. Why do you do that? Why 1 instead of (say) 23? The answer is that on Linux, eax is used to hold a number that tells what operation you want the OS to do. 1 means output string. Then you have to put specific values in other specific registers to say what you want to print and where you want to print it.

But which values you need to set and where they need to go is defined by the people who wrote Linux. Windows can (and does) do things entirely differently: different values, different registers, etc.

So the reason this code doesn't work is that it was designed specifically for Linux and you are trying to run it on Windows. And while cygwin can make things look more linux-like (for example making a command prompt that handles rm commands), it can't change what happens when you directly invoke the operating system via syscall. You are still running Windows, and that's who is going to handle the syscall. There's nothing cygwin can do about that.

So, with all this in mind, how do you make this code work under Windows? The short answer is that you can't. Microsoft doesn't publish the syscall numbers and what values go in which registers.

If you want to print something under Windows, you are going to need to call a system dll which does all that for you. You can either call ntdll.dll, or some other dll (like msvcrt.dll) which in turn ends up calling ntdll.dll.

There's some good examples at How to write hello world in assembler under Windows?

PS If you find the guy who originally wrote that asm, tell him that while it works on Linux, it is horribly inefficient.

Community
  • 1
  • 1
David Wohlferd
  • 7,110
  • 2
  • 29
  • 56
  • 1
    I kept my comment deliberately thin ;-), I wasn't going to write an answer that basically ends up being a non-answer, or at least not what the OP wanted to hear. lol. Not sure why the OP couldn't just use the _C_ library to print. – Michael Petch Jan 12 '17 at 22:39
  • 1
    It appears the OPs code made a debut on SO [in this answer](http://stackoverflow.com/a/23020467/3857942) although a similar code snippet appears on a blog as well. A foot note is that answer actually has a link to a better implementation and explanation in this [other SO answer](http://stackoverflow.com/a/9508738/3857942) – Michael Petch Jan 12 '17 at 22:53
  • I'm not sure what the OP's goal is. While some people like to program to the "bare metal," in this case it looks like he is just copying something he saw somewhere else. People get confused about what cygwin can and can't do. Explaining why it works in linux, but not in the linux 'emulator' seemed like the least I could do to make up for the bad news. – David Wohlferd Jan 12 '17 at 23:41
  • Just a nitpick, but you rarely if ever call functions directly from ntdll.dll. That's the native API, not designed to be used by user-mode applications. You will usually call a wrapper function provided by the Win32 API, primarily from the kernel32 and/or user32 DLLs (though there are a number of others). The CRT (msvcrt.dll and other specific versions) is also commonly used, as noted in your answer. – Cody Gray - on strike Jan 13 '17 at 14:13
  • @CodyGray I don't disagree about ntdll, but it's about as close as you can get to the "bare metal" in Windows. The OP was vague about his actual goal, but I can't think of another good reason to use inline asm to do syscall. You are correct that using msvcrt.dll and company provides a bunch of benefits, and should be the preferred course (especially since OP is already programming in C). But generally speaking, avoiding inline asm should also be the preferred course. – David Wohlferd Jan 13 '17 at 19:56
  • It is a bit below "bare metal". The ntdll functions are explicitly undocumented for applications, so it's not just an issue of losing the added value of higher-level functions. You will have to reverse engineer them yourself, and then commit to fixing your code each time Windows gets updated. Of course I can't disagree with anything else you said! – Cody Gray - on strike Jan 15 '17 at 10:42