Great Code - 데이터 타입에 관한 예제

gurugio의 이미지


(우선..도배해서 죄송합니다...)

요즘 64비트 caos 커널에 들어갈 printf 함수를 만들고 있는데
이상한 문제들이 생겼습니다.

32비트용으로 만들어왔던 printf를 64비트용으로 만들기 위해서
int로 사용했던 데이터 타입들을 long으로 바꾸고
va_arg 관련 매크로도 다시 만들었고
어느정도 동작이 잘 되는것 같았습니다.

그런데 아래 코드를 실행시키면 6과 7이 출력되는게 아니라
이상한 쓰레기 값이 출력되는 문제가 생겼습니다.
게다가 이 문제가 들쭉날쭉하게 발생해서 더 알수가 없었습니다.

물론 caos_printf를 32비트 일반 어플리케이션에서 호출해서 사용하면
정상적으로 출력되구요.

48 caos_printf(hello, 1, 2, 3, 4, 5, 6, 7); // variable list

아래과 같이 하면 또 잘되고요.

48 caos_printf(hello, 1, 2, 3, 4, 5, 6, 7, 'a'); // variable list

컴파일 옵션 다음과 같습니다.
gcc -Wall -Winline -I./include -fno-stack-protector -O2 -nostdinc -nostdlib -m64 -c printf.c

Using built-in specs.
Target: i486-linux-gnu
Configured with: ../src/configure -v --enable-languages=c,c++,fortran,objc,obj-c++,treelang --prefix=/usr --enable-shared --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --enable-nls --with-gxx-include-dir=/usr/include/c++/4.1.3 --program-suffix=-4.1 --enable-__cxa_atexit --enable-clocale=gnu --enable-libstdcxx-debug --enable-mpfr --enable-checking=release i486-linux-gnu
Thread model: posix
gcc version 4.1.3 20070929 (prerelease) (Ubuntu 4.1.2-16ubuntu2)

소스를 따로따로 테스트해봤는데도 별 문제가 없어서 혹시나
어셈블리 코드를 확인해봤더니
정말 이상한 것을 발견했습니다.

문제가 뭔지 아시겠지요?
64비트이므로 스택에 데이터를 저장하고 꺼낼때
movq 명령어를 사용해야 하는데 movl을 사용해서
4바이트 데이터만 스택에 저장되고 있었습니다.
그럼 결국 출력에 4바이트 데이터 + 4바이트 쓰레기 값이 출력되는 거였습니다.

80 100122: 41 b9 05 00 00 00 mov $0x5,%r9d
81 100128: 41 b8 04 00 00 00 mov $0x4,%r8d
82 10012e: b9 03 00 00 00 mov $0x3,%ecx
83 100133: ba 02 00 00 00 mov $0x2,%edx
84 100138: be 01 00 00 00 mov $0x1,%esi
85 10013d: bf 00 12 10 00 mov $0x101200,%edi
86 100142: 31 c0 xor %eax,%eax
87 100144: c7 44 24 08 07 00 00 movl $0x7,0x8(%rsp)
88 10014b: 00
89 10014c: c7 04 24 06 00 00 00 movl $0x6,(%rsp)
90 100153: e8 28 06 00 00 callq 100780

그래서 다음과 같이 UL로 데이터 타입을 명확하게 지정하도록 바꿔봤더니 정상적인 값이 출력됩니다.
인자에 상수 값을 쓰지 않고 long타입 변수로 전달하면 당연히 잘 되구요.

47 caos_printf(hello, 1, 2, 3, 4, 5, 6UL, 7UL); // variable list

movq를 사용해서 8바이트 값을 쓰레기값이 없도록 스택에 저장합니다.

68 1000ea: 41 b9 05 00 00 00 mov $0x5,%r9d
69 1000f0: 41 b8 04 00 00 00 mov $0x4,%r8d
70 1000f6: b9 03 00 00 00 mov $0x3,%ecx
71 1000fb: ba 02 00 00 00 mov $0x2,%edx
72 100100: be 01 00 00 00 mov $0x1,%esi
73 100105: bf 00 12 10 00 mov $0x101200,%edi
74 10010a: 31 c0 xor %eax,%eax
75 10010c: 48 c7 44 24 08 07 00 movq $0x7,0x8(%rsp)
76 100113: 00 00
77 100115: 48 c7 04 24 06 00 00 movq $0x6,(%rsp)
78 10011c: 00
79 10011d: e8 5e 06 00 00 callq 100780

일단 지금은 32비트 머신밖에 없어서 gcc에서 m64 옵션으로 사용하고 있는데
gcc가 32비트 기반이라 그런지 모르겠네요.
어쩌면 어플리케이션이 동작할 때는 스택이 0으로 초기화되서 그런건지도 모르겠습니다.
정확한 것은 64비트 머신에서 더 해봐야겠지요.

어쨌든 원인은 정확하게 모르겠습니다만
중요한 것은 상수 데이터를 넘길때는 정확하게 데이터 형을 표시해줘야한다는 것입니다.

하루를 꼬박 고민했는데 어찌보면 기초적일수도 있는 것을 제가 무심하게 생각하고 있었습니다.
기본기가 중요하다는 것을 다시한번 느꼈습니다.

오프라인 스터디때 좀더 자세히 이야기해보겠습니다.

댓글

pynoos의 이미지

hello 대신, "%lld", "%ld", "%d" 등으로..
변수가 아닌, 스트링을 넣어주면, gcc가 친절하게(?) 경고를 주었을텐데요...

---
coolengineer.com

gurugio의 이미지


예 libc에 있는 printf 가 아니라
제가 만든 printf 라서 %d 만 인식하고 %ld는 인식을 못합니다.
그렇지 않아도 %ld를 추가할까 고민을 하고 있습니다.

----
세상을 바꾸는 것은 단 한 사람. 오직 하나님의 사람뿐이다.
개인 홈페이지가 생겼습니다 http://caoskernel.org
어셈러브를 개편중입니다 http://www.asmlove.co.kr

kalstein의 이미지

long이 꼭 8바이트 정수를 의미하지않는걸로 알고있는데요...
C언어적으로는 단순히 크기가 byte <= short <= int <= long 뭐 이런식으로 알고있습니다.

그리고 실질적으로도 8바이트 자료형이 사용되는건 long * 형태던가? 뭐 그럴때만 사용된다고 들은것 같네요. 정확한 답변이 아니라서 죄송합니다 ^^;

------------------------------------------
Let`s Smart Move!!
http://kalstein.tistory.com/


------------------------------------------
Let`s Smart Move!!
http://kalstein.tistory.com/

powerson의 이미지


long이 8byte가 아닌건 아키텍쳐에 따라서 달라지기 때문입니다. 32bit에서는 4, 64bit에서는 8이기 때문이죠. 그리고 64bit machine에서는 long이 8byte를 차지하는게 맞습니다. 물론 pointer들에 대해서도 8byte addressing을 하고요.

그나저나 -m64로 넘기셨다면, 말씀하신대로 8byte로 전달해야 할 거 같은데요 이상하긴 하군요. 말씀하신대로 32bit gcc라서 그런거 같기도 하네요.. ㅎㅎ

------------------------------------------------------
아직은 젊다. 모든 것을 할 수 있는 나이란 말이지.

------------------------------------------------------
아직은 젊다. 모든 것을 할 수 있는 나이란 말이지.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.