C 프로그램은 실행 후 즉시 종료되지만 while (1) 루프가 있습니다.
나는 qr 코드에 맞출 수 있도록 3KB 제한 아래에서 c에 지뢰 찾기 프로그램을 맞추려고 노력하고 있으며 옵션을 추가 -nostdlib
하고 컴파일 할 때까지 잘 작동 했으며 잠시 동안에도 프로그램이 즉시 종료되었습니다. (1 ) 종료 할 방법이없는 메인 루프.
링커에 추가 한 라이브러리는 kernel32
,, gcc
및 msvcrt
( 재생산 하려는 경우)입니다. 기술적으로는 0x0을 반환했는데, 이는 '성공'을 의미하지만 분명히 그렇지 않았습니다. 아니면 그렇게하지 않았을 것입니다. 내 코드는 여기에서 볼 수 있습니다.
#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
가 링크되는 것을 중지합니다 .
마지막이 중요하다,이 미연에 물건을 많이 일반적이다 main()
당신이 연결하지 않는 경우, 호출됩니다 및 crt0
다음 실제 진입 점 _start
(하지 main
존재하지 않음).
따라서 해결책은 실제 C 프로그램에 필요한 모든 복잡한 C 환경 설정없이 직접 제공하는 것 _start
입니다. mystart.S
다음과 같이 제공하는 것만 큼 간단 합니다.
.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 프로그램 :
int main(void) {
return 42;
}
그런 다음 다음 스크립트에 따라 컴파일하고 테스트 할 수 있습니다.
pax> gcc -nostdlib -o nolibc nolibc.c mystart.S
pax> ./nolibc ; echo $?
42
그러면 "왜 실행되지 않습니까?"라는 특정 질문에 대한 답 이됩니다. 그러나 다른 곳에서 수집 한 추가 최적화 에도 불구 하고 여전히 실행 파일 크기가 다소 뭉툭했습니다 .
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
따라서 그 이상으로 실행 파일을 실행하는 데 절대적으로 필요한 것만로드하려면 링커 스크립트를 조작해야 할 것입니다.
그것은 다소 큰 주제이고 귀하의 특정 질문과 관련이 없기 때문에 여기서는 다루지 않을 것입니다. 나는 그것을하는 방법에 대해 (물론 검색 후) 다른 질문을하는 것이 좋습니다.
그리고 그것은 기억 int $80
에서 리눅스가 생각 한다는 것을 명심하십시오 . Windows에서 유사한 작업을 수행하려면 crt0
해당 플랫폼 에서 코드가 어떻게 작동 하는지 조사해야 합니다. 사용할 가능성이 높 ExitProcess()
으므로 다음과 같은 것이 필요할 것입니다. ( 예상 되지 않았으므로 직접 디버깅해야합니다.)
.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 파일과 연결하는 방법을 알아 봅니다.