Microsoft MVP성태의 닷넷 이야기
VC++: 69. geek스러운 C/C++ 퀴즈 문제 [링크 복사], [링크+제목 복사],
조회: 26649
글쓴 사람
정성태 (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]

... 61  62  [63]  64  65  66  67  68  69  70  71  72  73  74  75  ...
NoWriterDateCnt.TitleFile(s)
12364정성태10/11/202019435.NET Framework: 948. C# 9.0 - (2) localsinit 플래그 내보내기 무시(Suppress emitting localsinit flag)파일 다운로드1
12363정성태10/11/202021129.NET Framework: 947. C# 9.0 - (1) 대상으로 형식화된 new 식(Target-typed new expressions) [2]파일 다운로드1
12362정성태10/11/202017690VS.NET IDE: 151. Visual Studio 2019에 .NET 5 rc/preview 적용하는 방법
12361정성태10/11/202019703.NET Framework: 946. C# 9.0을 위한 개발 환경 구성
12360정성태10/8/202014934오류 유형: 666. The type or namespace name '...' does not exist in the namespace 'Microsoft.VisualStudio.TestTools' (are you missing an assembly reference?)
12359정성태10/7/202017143오류 유형: 665. Windows - 재부팅 후 iSCSI 연결이 끊기는 문제
12358정성태10/7/202018004오류 유형: 664. Web Deploy 설치 시 "A newer version of Microsoft Web Deploy 3.6 was found on this machine." 오류 [3]
12357정성태10/7/202015648오류 유형: 663. 이벤트 로그 - The storage optimizer couldn't complete retrim on New Volume
12356정성태10/7/202031277오류 유형: 662. ASP.NET Core와 500.19, 500.21 오류 (0x8007000d)
12355정성태10/3/202014817오류 유형: 661. Hyper-V Linux VM의 Internal 유형의 가상 Switch에 대한 IP 연결이 되지 않는 경우
12354정성태10/2/202028832오류 유형: 660. Web Deploy (msdeploy.axd) 실행 시 오류 기록 [1]
12353정성태10/2/202018275개발 환경 구성: 518. 비주얼 스튜디오에서 IIS 웹 서버로 "Web Deploy"를 이용해 배포하는 방법
12352정성태10/2/202019527개발 환경 구성: 517. Hyper-V Internal 네트워크에 NAT을 이용한 인터넷 연결 제공
12351정성태10/2/202017973오류 유형: 659. Nox 실행이 안 되는 경우 - Unable to bind to the underlying transport for ...
12350정성태9/25/202022392Windows: 175. 윈도우 환경에서 클라이언트 소켓의 최대 접속 수 [2]파일 다운로드1
12349정성태9/25/202016562Linux: 32. Ubuntu 20.04 - docker를 위한 tcp 바인딩 추가
12348정성태9/25/202017584오류 유형: 658. 리눅스 docker - Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock
12347정성태9/25/202033123Windows: 174. WSL 2의 네트워크 통신 방법 [4]
12346정성태9/25/202016601오류 유형: 657. IIS - http://localhost 방문 시 Service Unavailable 503 오류 발생
12345정성태9/25/202016131오류 유형: 656. iisreset 실행 시 "Restart attempt failed." 오류가 발생하지만 웹 서비스는 정상적인 경우파일 다운로드1
12344정성태9/25/202018050Windows: 173. 서비스 관리자에 "IIS Admin Service"가 등록되어 있지 않다면?
12343정성태9/24/202029114.NET Framework: 945. C# - 닷넷 응용 프로그램에서 메모리 누수가 발생할 수 있는 패턴 [5]
12342정성태9/24/202019137디버깅 기술: 171. windbg - 인스턴스가 살아 있어 메모리 누수가 발생하고 있는지 확인하는 방법
12341정성태9/23/202017170.NET Framework: 944. C# - 인스턴스가 살아 있어 메모리 누수가 발생하고 있는지 확인하는 방법파일 다운로드1
12340정성태9/23/202016828.NET Framework: 943. WPF - WindowsFormsHost를 담은 윈도우 생성 시 메모리 누수
12339정성태9/21/202017010오류 유형: 655. 코어 모드의 윈도우는 GUI 모드의 윈도우로 교체가 안 됩니다.
... 61  62  [63]  64  65  66  67  68  69  70  71  72  73  74  75  ...