Microsoft MVP성태의 닷넷 이야기
VC++: 69. geek스러운 C/C++ 퀴즈 문제 [링크 복사], [링크+제목 복사],
조회: 26693
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 

geek스러운 C/C++ 퀴즈 문제

아래의 문제를 보게 되었는데요. ^^

진짜 어려운 프로그래밍 퀴즈 문제
; https://www.okjsp.net/seq/215850

문제를 여기다 복사해 보면 다음과 같습니다.

typedef int (*f)();
int variable = 1;

int function()
{
    if (variable == 1)
        return /* INPUT */    <------ put your solution here!

    5;
    victory();
}

int main()
{
    function();
    return 0;
}

// your main objective is to call the victory function.
// you must put one line of your code:
// - max 11 chars.
// - you can't use: "main", "victory", "asm", "%", "*", "_", "#", "/", """, "'".
// - you have only one semicolon.

어렵군요. ^^ 저도 풀기는 했지만 11자 제한은 넘어버려서 16자로 맞췄습니다. 게다가 좀 일반적이지도 않고!

제가 한 방법은 다음과 같습니다.

int function()
{
    if (variable == 1)
        return (function+25)();

    5;
    victory();
}

이 코드는 Visual C++에서는 함수 포인터 연산이 자유롭지 않아서 컴파일이 안되고 대신 gcc에서 해야 합니다. 그런데, 왜 25바이트를 더했냐고요? ^^

일단, 숫자 25대신 아무 거나 대입시켜서 위의 코드를 컴파일 해야 하는데요. 이 때 어셈블리 코드를 출력시켜 주어야 합니다.

How to get GCC to generate assembly code
; http://www.delorie.com/djgpp/v2faq/faq8_20.html

gcc -c -g -Wa,-a,-ad  ConsoleApplication1.c > foo.lst

출력된 어셈블리 코드에서 _function 부분만 발췌해 보면 다음과 같은 코드를 볼 수 있는데,

  40 0000 01000000      .long   1
  41                    .text
  42                    .globl  _function
  44                _function:
  45                LFB7:
  13:ConsoleApplication1.c **** 
  14:ConsoleApplication1.c **** typedef int (*f)();
  15:ConsoleApplication1.c **** int variable = 1;
  16:ConsoleApplication1.c **** 
  17:ConsoleApplication1.c **** int function()
  18:ConsoleApplication1.c **** {
  46                    .loc 1 18 0
  47                    .cfi_startproc
  48 0019 55            pushl   %ebp
  49                LCFI3:
  50                    .cfi_def_cfa_offset 8
  51                    .cfi_offset 5, -8
  52 001a 89E5          movl    %esp, %ebp
  53                LCFI4:
  54                    .cfi_def_cfa_register 5
  55 001c 83EC08        subl    $8, %esp
  19:ConsoleApplication1.c ****     if (variable == 1)
  56                    .loc 1 19 0
  57 001f A1000000      movl    _variable, %eax
  57      00
  58 0024 83F801        cmpl    $1, %eax
  59 0027 7509          jne L3
  20:ConsoleApplication1.c ****         return (function+25)();
  60                    .loc 1 20 0
  61 0029 B8320000      movl    $_function+25, %eax
  61      00
  62 002e FFD0          call    *%eax
  63 0030 EB05          jmp L2
  64                L3:
  21:ConsoleApplication1.c **** 
  22:ConsoleApplication1.c ****     5;
  23:ConsoleApplication1.c ****     victory();
  65                    .loc 1 23 0
  66 0032 E8C9FFFF      call    _victory
  66      FF
  67                L2:
  24:ConsoleApplication1.c **** }

이 중에서, function 함수 포인터의 진입점에서 call _victory 기계어 코드까지 출력된 바이트 수를 합산해 보면,

  55        (1 byte)
  89E5      (2 bytes)
  83EC08    (3 bytes)
  A1000000  (4 bytes)
  00        (1 byte)
  83F801    (3 bytes)
  7509      (2 bytes)
  B8320000  (4 bytes)
  00        (1 byte)
  FFD0      (2 bytes)
  EB05      (2 bytes)
  ====================
            25 bytes

정확히 25바이트가 나옵니다. 따라서, return (function+25)();는 25바이트 옵셋 후의 코드를 진입점으로 하는 함수를 호출하는 것과 같은 효과를 가지는 것입니다.

테스트를 위해 코드를 다음과 같이 바꿔 볼까요?

#include <stdio.h>

void victory()
{
    printf("victory2 called!!!");
}

typedef int (*f)();
int variable = 1;

int function()
{
    if (variable == 1)
        return (function+25)();

    5;
    victory();
}

int main()
{
    function();
    return 0;
}

이제 gcc로 컴파일하고 실행하면 "victory2 called!!!" 문자열이 출력되는 것을 확인할 수 있습니다.

$ gcc ConsoleApplication1.c
$ a
victory2 called!!!

물론, 이 방법을 사용하면 Debug/Release 빌드마다 옵셋이 바뀐다는 문제점이 있긴 합니다. 어쨌든, 저는 최소한의 문자열로 축소하기 위해 써 먹은 방법이 여기까지입니다.

어떻게 하면 5자를 더 줄일 수 있을까요? ^^ 함수 포인터 타입 f와 "5;" 로 끝나는 코드를 잘 이용하는 것이 문제 출제자의 의도 같은데...




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]







[최초 등록일: ]
[최종 수정일: 3/26/2021]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 



2013-07-08 03시52분
[ryujh] 안녕하세요.

피시에 컴파일러가 없어서 해보지 않았는데

if (variable==1)
return
variable++;
5;

이 문법이 컴파일과 런타임에 각각 오류가 없다면 가능하지 않을까요?

이상입니다.
[guest]
2013-07-08 03시55분
[ryujh] 써넣고 보니 function() 을 두번실행할 수 없으니 무효. 다시 생각해봐야 하겠습니다.
[guest]

... 121  122  123  124  125  126  127  128  129  130  131  [132]  133  134  135  ...
NoWriterDateCnt.TitleFile(s)
1755정성태9/22/201434174오류 유형: 241. Unity Web Player를 설치해도 여전히 설치하라는 화면이 나오는 경우 [4]
1754정성태9/22/201424519VC++: 80. 내 컴퓨터에서 C++ AMP 코드가 실행이 될까요? [1]
1753정성태9/22/201420506오류 유형: 240. Lync로 세미나 참여 시 소리만 들리지 않는 경우 [1]
1752정성태9/21/201440974Windows: 100. 윈도우 8 - RDP 연결을 이용해 VNC처럼 사용자 로그온 화면을 공유하는 방법 [5]
1751정성태9/20/201438842.NET Framework: 464. 프로세스 간 통신 시 소켓 필요 없이 간단하게 Pipe를 열어 통신하는 방법 [1]파일 다운로드1
1750정성태9/20/201423771.NET Framework: 463. PInvoke 호출을 이용한 비동기 파일 작업파일 다운로드1
1749정성태9/20/201423705.NET Framework: 462. 커널 객체를 위한 null DACL 생성 방법파일 다운로드1
1748정성태9/19/201425315개발 환경 구성: 238. [Synergy] 여러 컴퓨터에서 키보드, 마우스 공유
1747정성태9/19/201428347오류 유형: 239. psexec 실행 오류 - The system cannot find the file specified.
1746정성태9/18/201425982.NET Framework: 461. .NET EXE 파일을 닷넷 프레임워크 버전에 상관없이 실행할 수 있을까요? - 두 번째 이야기 [6]파일 다운로드1
1745정성태9/17/201422936개발 환경 구성: 237. 리눅스 Integration Services 버전 업그레이드 하는 방법 [1]
1744정성태9/17/201430962.NET Framework: 460. GetTickCount / GetTickCount64와 0x7FFE0000 주솟값 [4]파일 다운로드1
1743정성태9/16/201420912오류 유형: 238. 설치 오류 - Failed to get size of pseudo bundle
1742정성태8/27/201426892개발 환경 구성: 236. Hyper-V에 설치한 리눅스 VM의 VHD 크기 늘리는 방법 [2]
1741정성태8/26/201421275.NET Framework: 459. GetModuleHandleEx로 알아보는 .NET 메서드의 DLL 모듈 관계파일 다운로드1
1740정성태8/25/201432439.NET Framework: 458. 닷넷 GC가 순환 참조를 해제할 수 있을까요? [2]파일 다운로드1
1739정성태8/24/201426452.NET Framework: 457. 교착상태(Dead-lock) 해결 방법 - Lock Leveling [2]파일 다운로드1
1738정성태8/23/201421993.NET Framework: 456. C# - CAS를 이용한 Lock 래퍼 클래스파일 다운로드1
1737정성태8/20/201419678VS.NET IDE: 93. Visual Studio 2013 동기화 문제
1736정성태8/19/201425532VC++: 79. [부연] CAS Lock 알고리즘은 과연 빠른가? [2]파일 다운로드1
1735정성태8/19/201418121.NET Framework: 455. 닷넷 사용자 정의 예외 클래스의 최소 구현 코드 - 두 번째 이야기
1734정성태8/13/201419774오류 유형: 237. Windows Media Player cannot access the file. The file might be in use, you might not have access to the computer where the file is stored, or your proxy settings might not be correct.
1733정성태8/13/201426239.NET Framework: 454. EmptyWorkingSet Win32 API를 사용하는 C# 예제파일 다운로드1
1732정성태8/13/201434365Windows: 99. INetCache 폴더가 다르게 보이는 이유
1731정성태8/11/201426954개발 환경 구성: 235. 점(.)으로 시작하는 파일명을 탐색기에서 만드는 방법
1730정성태8/11/201422060개발 환경 구성: 234. Royal TS의 터미널(Terminal) 연결에서 한글이 깨지는 현상 해결 방법
... 121  122  123  124  125  126  127  128  129  130  131  [132]  133  134  135  ...