[완료] io.h의 __raw_readl을 어떻게 이해할지 알려주시면 감사하겠습니다.

snowavalanch의 이미지

매크로 해석이 어렵네요...
아래와 같이 사용되는데, 해석이 안되네요.
__raw_readl(mcpdm->io_base + reg);

#define __raw_readl(a) (__chk_io_ptr(a), *(volatile unsigned int __force *)(a))

# define __chk_io_ptr(x) (void)0

어떻게 이해할지 알려주시면 감사하겠습니다.

wariua의 이미지

__chk_io_ptr()이 항상 "(void)0"으로 확장되는 매크로인 건 아닙니다. 헤더 파일을 보면 __CHECKER__ 심볼 정의 여부에 따라 extern 함수 선언이거나 (void)0이 되는데, __CHECKER__ 심볼은 sparse라는 커널 소스 분석 툴과 관련돼 있습니다. 즉, sparse를 사용하지 않는다면

#define __raw_readl(a) ((void)0, *(volatile unsigned int __force *)(a))

즉,

#define __raw_readl(a) (*(volatile unsigned int __force *)(a))

입니다.

__force 역시도 __CHECKER__ 심볼이 정의돼 있을 때만 뭔가로 확장됩니다. 따라서 또 생략~

#define __raw_readl(a) (*(volatile unsigned int *)(a))

volatile은 이미 알고 계시겠죠. "최적화 하겠다고 깝치지 말고 시킨 대로 그 위치에서 꼭 읽으셈" 정도의 의미...

즉, 핵심은 주어진 주소에서 unsigned int 값을 읽는 것입니다. memory-mapped I/O일 테니까 컴파일러 최적화에 영향 받지 않게 하기 위해 volatile 키워드를 추가한 것이고, sparse를 이용한 정적/동적 분석을 위해 검사 함수 __chk_io_ptr()과 지시자 __force를 추가한 것입니다.

$PWD `date`

snowavalanch의 이미지

#define __raw_readl(a) ((void)0, *(volatile unsigned int __force *)(a))에서
#define __raw_readl(a) (*(volatile unsigned int __force *)(a))로

(void)0이 생략되는데,
그냥 무시하는 건가요?
무시하는 것을 어떻게 이해하면 될지?
(우매한 질문일지 모른다는 불안감이...)

wariua의 이미지

앞서 답변 드린 내용과 마찬가지로 "(void)0"의 정체 역시 검색 엔진을 통해 어렵지 않게 정보를 얻으실 수 있습니다. :-)

요약하자면 place-holder입니다.

자... __chk_io_ptr() 함수를 호출한 후 주어진 주소를 dereference 하는 함수 형태 매크로를 만들고 싶다고 해보겠습니다.

#define __raw_readl(a) (__chk_io_ptr(a), *(unsigned int *)(a))

정도면 무난하겠지요. 그런데 __CHECKER__ 심볼이 없을 때는 __chk_io_ptr() 함수 호출을 하지 않게 하고 싶습니다. 어떻게 해야 할까요? 간단하게 생각하면 다음처럼 할 수 있을 겁니다.

#ifdef __CHECKER__
#define __raw_readl(a) (__chk_io_ptr(a), *(unsigned int *)(a))
#else
#define __raw_readl(a) (*(unsigned int *)(a))
#endif

하지만 이런 종류의 매크로가 많다면 좀 귀찮은 작업이 됩니다. 게다가 dereference 코드가 중복돼 있는 것도 아름답지 않아 보입니다.

그렇다면... __CHECKER__ 심볼이 정의돼 있지 않을 때에는 __chk_io_ptr()이 아무 것도 하지 않는 expression이 되도록 하면 어떨까요?

#ifdef __CHECKER__
extern void __chk_io_ptr(void *ptr);
#else
#define __chk_io_ptr(x) (0)
#endif
 
#define __raw_readl(a) (__chk_io_ptr(a), *(unsigned int *)(a))

(0이라는 값 자체는 중요하지 않습니다. __chk_io_ptr(x)을 (0) 대신 (42) 등으로 정의해도 다르지 않습니다.)

근데 이렇게 하면 __CHECKER__가 정의돼 있지 않을 때, 즉 __raw_readl(a)이 다음과 같이 확장될 때:

((0), *(unsigned int *)(a))

-Wall 옵션을 써서 (더 정확히는 -Wunused-value 옵션을 써서) 컴파일 하면 "left-hand operand of comma expression has no effect"라는 경고가 나옵니다. 분명 의도한 대로 작성한 적법한 코드이긴 한데 컴파일러는 뭐라뭐라 그러고... 그런데 앞에다 "(void)"를 붙이면? 와~ 컴파일러 경고가 사라졌습니다.

왜 컴파일러가 "0, ..."에 대해선 쫑알대면서 "(void)0, ..."에는 조용한지에 대해선 제가 아는 게 얕아 말씀을 못 드립니다~

$PWD `date`

snowavalanch의 이미지

이해가 쏙쏙 되네요. 감사합니다.

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.