C程序立即执行后退出,但它有一个while(1)循环 [英] C program immediatley exits after execution, yet it has a while(1) loop

查看:93
本文介绍了C程序立即执行后退出,但它有一个while(1)循环的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在3KB的限制下将c中的minesweeper程序装入程序,以便它可以装入qr代码,并且在我添加选项 -nostdlib 并对其进行编译,尽管在main中有一个while(1)循环而没有退出的方法,该程序仍立即退出。

I'm trying to fit a minesweeper program in c under a 3KB limit so it can fit in a qr code, and it was working fine until when I added the option -nostdlib and compiled it, the program immediately exited, despite having a while(1) loop in main with no way of exiting.

我在链接器中添加的库为 kernel32 gcc msvcrt (如果要重新生成它)。尽管从技术上讲它确实返回0x0,这意味着它成功,但显然不是。否则就不会那样做。在这里可以看到我的代码:

The libraries I added in linker were kernel32, gcc, and msvcrt (in case you want to re-produce it). And while it did technically return 0x0, which means it was 'successful', it obviously wasn't; or it wouldn't have done that. My code can be seen here:

#include <windows.h>

#define WIDTH 100
#define HEIGHT 100
#define BOMBS 801

int xorshf96(int x, int y, int z)
{
   unsigned long t;
   x ^= x << 16;
   x ^= x >> 5;
   x ^= x << 1;

   t = x;
   x = y;
   y = z;
   z = t ^ x ^ y;

  return z;
}


void ExpandGrid(int fullGrid[WIDTH][HEIGHT], int knownGrid[WIDTH][HEIGHT], int blankPos[2])
{
    int neighbors[8][2] = {{0,1}, {1,0}, {1,1},
                          {0,-1},        {-1,0},
                          {-1,-1},{-1,1},{1,-1}};
    int curTile[2];

    knownGrid[blankPos[0]][blankPos[1]] = 1;
    if(fullGrid[blankPos[0]][blankPos[1]] != 0) return;

    for(int blck = 0; blck < 8; ++blck)
    {
        curTile[0] = abs(blankPos[0]+neighbors[blck][0]);
        curTile[1] = abs(blankPos[1]+neighbors[blck][1]);
        if(curTile[0] > WIDTH-1 || curTile[1] > HEIGHT-1) continue;

        if(fullGrid[curTile[0]][curTile[1]] == 0 && knownGrid[curTile[0]][curTile[1]] == 0)
        {
            knownGrid[curTile[0]][curTile[1]] = 1;
            ExpandGrid(fullGrid, knownGrid, curTile);
        }
        else if(fullGrid[curTile[0]][curTile[1]] > 0) knownGrid[curTile[0]][curTile[1]] = 1;
    }
}


int main(void)
{
    COORD characterBufferSize = { WIDTH, HEIGHT };
    COORD characterPosition = { 0, 0 };
    SMALL_RECT consoleWriteArea = { 0, 0, WIDTH - 1, HEIGHT - 1 };
    CHAR_INFO consoleBuffer[WIDTH][HEIGHT];

    HANDLE wHnd = GetStdHandle(STD_OUTPUT_HANDLE);
    HANDLE rHnd = GetStdHandle(STD_INPUT_HANDLE);

    int num1, num2, num3 = 0;
    SYSTEMTIME systime;

    DWORD numEventsRead = 0;
    DWORD numEvents = 0;
    INPUT_RECORD *eventBuffer;
    int wait = 0;

    SetConsoleTitle("Minesweeper!");

    int startGrid[WIDTH][HEIGHT] = { 0 };
    int knownGrid[WIDTH][HEIGHT] = { 0 };
    int arrowPos[2] = {0, 0};
    int bomb[2] = {0, 0};

    for (int i = 0; i < BOMBS; i++)
    {
        while (startGrid[bomb[0]][bomb[1]] < -1 || bomb[0] <= 0 || bomb[1] <= 0 || bomb[0] >= WIDTH-1 || bomb[1] >= HEIGHT-1)
        {
            GetLocalTime(&systime);
            num1, num2, num3 = (int) systime.wMilliseconds;

            bomb[1] = (xorshf96(num3, num2, num1) % (HEIGHT-1)) + 1;

            GetSystemTime(&systime);
            num1, num2, num3 = (int) systime.wMilliseconds;

            bomb[0] = (xorshf96(num1, num2, num3) % (WIDTH-1)) + 1;
        }

        startGrid[bomb[0]][bomb[1]] = -9;

        startGrid[bomb[0] + 1][bomb[1] + 1]++;
        startGrid[bomb[0] + 1][bomb[1]]++;
        startGrid[bomb[0]][bomb[1] + 1]++;
        startGrid[bomb[0] - 1][bomb[1] + 1]++;
        startGrid[bomb[0]][bomb[1] - 1]++;
        startGrid[bomb[0] + 1][bomb[1] - 1]++;
        startGrid[bomb[0] - 1][bomb[1] - 1]++;
        startGrid[bomb[0] - 1][bomb[1]]++;
    }

    while(1)
    {
        if (arrowPos[0] > WIDTH-1) arrowPos[0] = WIDTH-1;
        if (arrowPos[0] < 0) arrowPos[0] = 0;
        if (arrowPos[1] > HEIGHT-1) arrowPos[1] = HEIGHT-1;
        if (arrowPos[1] < 0) arrowPos[1] = 0;

        for (int x = 0; x < WIDTH; ++x)
        {
            for (int y = 0; y < HEIGHT; ++y)
            {

                if (knownGrid[x][y] == 1)
                {
                    if (startGrid[x][y] > 0)
                    {
                        consoleBuffer[x][y].Char.AsciiChar = '0' + startGrid[x][y];
                        consoleBuffer[x][y].Attributes = FOREGROUND_GREEN | FOREGROUND_INTENSITY;
                    }
                    else
                    {
                        consoleBuffer[x][y].Char.AsciiChar = 'o';
                        consoleBuffer[x][y].Attributes = (startGrid[x][y] < 0 ? FOREGROUND_RED : FOREGROUND_BLUE) | FOREGROUND_INTENSITY;
                    }
                }
                else
                {
                    consoleBuffer[x][y].Char.AsciiChar = 00;
                    consoleBuffer[x][y].Attributes = FOREGROUND_BLUE | FOREGROUND_INTENSITY;
                }

                if(arrowPos[0] == x && arrowPos[1] == y)
                {
                    consoleBuffer[x][y].Attributes = BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_GREEN;
                }
            }
        }

        WriteConsoleOutputA(wHnd, *consoleBuffer, characterBufferSize, characterPosition, &consoleWriteArea);

        numEvents = 0;
        numEventsRead = 0;
        GetNumberOfConsoleInputEvents(rHnd, &numEvents);

        if (numEvents)
        {
            eventBuffer = malloc(sizeof(INPUT_RECORD) * numEvents);
            ReadConsoleInput(rHnd, eventBuffer, numEvents, &numEventsRead);
        }

        if(numEventsRead && wait <= 0)
        {
            wait = 50;
            switch (eventBuffer[0].Event.KeyEvent.wVirtualKeyCode)
            {
                case VK_UP:
                    arrowPos[0]--;
                    break;
                case VK_DOWN:
                    arrowPos[0]++;
                    break;
                case VK_LEFT:
                    arrowPos[1]--;
                    break;
                case VK_RIGHT:
                    arrowPos[1]++;
                    break;
                case VK_RETURN:
                    ExpandGrid(startGrid, knownGrid, arrowPos);
                    break;
            }
        }

        wait--;
    }

}


推荐答案

使用 -nostdlib 两个效果:


  • 它阻止标准库的内容被自动链接;

  • 它会阻止C运行时启动代码 crt0 被链接。

  • it stops the standard library stuff from being automatically linked; and
  • it stops the C runtime start-up code crt0 from being linked.

最后一个很重要,通常在调用 main()之前会发生很多事情,如果不链接 crt0 ,然后是 real 入口点 _start (不是 main )不存在。

That last one is important, there's normally a lot of stuff that happens before main() is called and, if you don't link crt0 then the real entry point _start (not main) does not exist.

因此解决方案是提供您的自有 _start 但没有真正C程序所需的所有凌乱的C环境设置。就像提供 mystart.S 一样简单:

So the solution is to provide your own _start but without all of the messy C environment set-up that's needed for real C programs. That's as simple as providing a mystart.S as follows:

.globl _start
_start:
    call main           # call main without any setup.
    movl %eax, %ebx     # copy return value to pass back.
    movl $1, %eax       # function code for exit.
    int $0x80           # invoke function.

使用非常基本C程序组合如下:

Combine that with a very basic C program as follows:

int main(void) {
    return 42;
}

然后,您可以按照以下成绩单进行编译和测试:

Then you can compile and test it, as per the following transcript:

pax> gcc -nostdlib -o nolibc nolibc.c mystart.S
pax> ./nolibc ; echo $?
42




可以回答您的特定问题 ,为什么不运行?。但是,我仍然得到了相当大的可执行文件大小,甚至加上都从其他地方收集了一些优化:


That answers your specific question, "Why won't it run?". However, I still ended up with a rather chunky executable size, even with some extra optimisations gathered from elsewhere:

gcc -nostdlib -Os -ffunction-sections -fdata-sections -Wl,--gc-sections -o nolibc nolibc.c mystart.S
strip -s -R .comment -R .gnu.version --strip-unneeded nolibc

因此,除此之外,您可能还不得不摆弄链接脚本以使其仅加载什么内容。

So, beyond that, you'll probably have to fiddle with the linker script to have it only load what is absolutely necessary for your executable to run.

由于它是一个相当大的主题,并且与您的特定问题无关,因此在这里我不再赘述。我建议(当然应该在搜索后)问一个有关如何执行此操作的问题。

I won't go into that here since it's a rather large subject and not relevant to your specific question. I'd suggest asking (after searching of course) a different question on how to do that.

并记住 int $ 80 是Linux认为的内存。如果要在Windows上执行类似的操作,则应检查 crt0 代码在该平台上的工作方式。可能会使用 ExitProcess(),因此您需要使用类似的东西(未经测试,因此您需要自己对其进行调试):

And keep in mind that int $80 is a Linux think, from memory. If you want to do something similar for Windows, you should examine how the crt0 code works on that platform. It's likely to use ExitProcess() so you would need something like (untested, so you'll need to debug it yourself):

.globl _start
.extern ExitProcess
_start:
    call main           # call main without any setup.
    push %eax           # push main return code for delivery to OS.
                        # win64 equiv is, I think: mov %eax, %ecx
    call ExitProcess    # And off we go.

,然后找出如何与Windows dll / lib文件链接。

and then work out how to link with the Windows dll/lib files.

这篇关于C程序立即执行后退出,但它有一个while(1)循环的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆