Skip to content

Instantly share code, notes, and snippets.

@YangSiJun528
Last active October 16, 2025 07:11
Show Gist options
  • Select an option

  • Save YangSiJun528/309fe1a139f818284558822277b8ca70 to your computer and use it in GitHub Desktop.

Select an option

Save YangSiJun528/309fe1a139f818284558822277b8ca70 to your computer and use it in GitHub Desktop.
Reflections on Trusting Trust 한국어 AI 번역

Ken Thompson의 Reflections on Trusting Trust라는 글이 PDF로 되어있어서 보기 어려움. 이를 마크다운으로 변환 -> 한국어 변환을 수행해서 보기 좋게 바꿈.

원본 자료 링크

결론

시스템은 완전히 안전하지 않다. 기술적으로 완전한 신뢰는 불가능하다. 그렇다고 해서 우리가 개인/사회의 책임을 저버려서는 안 된다.

내용 해석 추가

2단계 코드가 이해가 잘 안갔어서 설명을 보완하자면,

컴파일러에 새로운 이스케이프 시퀀스를 추가하는 과정임.

문제 상황

  • \v(수직 탭)이라는 새로운 토큰을 예시 언어에 추가하려 함
  • 하지만 기존 컴파일러(그림 2.1.)는 \v를 알지 못함 → return('\v');에서 파싱 에러 발생

해결 과정

  1. 임시 구현: \v 대신 \v의 ASCII 값(11)을 사용하는 소스코드 작성(그림 2.3.) (return(11);)
  2. 중간 컴파일러 생성: 이 소스 코드로 기존 컴파일러를 컴파일 → \v를 이해하는 중간 컴파일러 생성
  3. 최종 구현: 이 중간 컴파일러로 원래 의도한 return('\v'); 코드(그림 2.2.)를 컴파일 → 완전한 기능의 컴파일러 완성

핵심 통찰

이 과정은 키워드, 연산자 등 어떤 새 기능을 추가하는 과정과 본질적으로 동일함.

더 나아가 부트스트랩에서도 이런 과정이 발생함:

  1. 다른 언어로 기본 컴파일러 구현
  2. 이를 통해 자체 언어의 최소 컴파일러 빌드
  3. 이 컴파일러로 반복적 자기개선 → 완전한 컴파일러로 진화

그림 3.1, 3.2, 3.3 설명

그림 3.1: 정상 컴파일러

compile(s)
char *s;
{
    ... // 정상 컴파일
}

깨끗한 컴파일러.


그림 3.2: 1단계 트로이 목마

compile(char *s)
{
    if(match(s, "if(strcmp(password, encrypted))")) {
        compile("if(strcmp(password, encrypted) || strcmp(password, \"backdoor\"))");
        return;
    }
    // 정상 컴파일
}

login 프로그램 컴파일 시 백도어 삽입.


그림 3.3: 자기복제 트로이 목마

compile(char *s)
{
    // login 프로그램 감지
    if(match(s, "login 패턴")) {
        compile("백도어 코드");
        return;
    }
    
    // 컴파일러 소스 감지
    if(match(s, "compile 함수 패턴")) {
        compile("위 악성 코드 포함된 컴파일러");
        return;
    }
}

자기복제 메커니즘:

  1. 악성 컴파일러로 login 컴파일 → 백도어 삽입
  2. 악성 컴파일러로 컴파일러 컴파일 → 악성 코드 복제
  3. 소스에서 악성 코드 제거해도 바이너리는 영구 악성

결과

소스: [깨끗] → 검사 통과
  ↓
악성 컴파일러 → 바이너리: [백도어 포함]
  ↓
컴파일러 재컴파일 → 새 컴파일러도 악성

Turing Award Lecture

Reflections on Trusting Trust

To what extent should one trust a statement that a program is free of Trojan horses? Perhaps it is more important to trust the people who wrote the software.

KEN THOMPSON

INTRODUCTION

I thank the ACM for this award. I can't help but feel that I am receiving this honor for timing and serendipity as much as technical merit. UNIX(^1) swept into popularity with an industry-wide change from central mainframes to autonomous minis. I suspect that Daniel Bobrow [1] would be here instead of me if he could not afford a PDP-10 and had to "settle" for a PDP-11. Moreover, the current state of UNIX is the result of the labors of a large number of people.

There is an old adage, "Dance with the one that brought you," which means that I should talk about UNIX. I have not worked on mainstream UNIX in many years, yet I continue to get undeserved credit for the work of others. Therefore, I am not going to talk about UNIX, but I want to thank everyone who has contributed.

That brings me to Dennis Ritchie. Our collaboration has been a thing of beauty. In the ten years that we have worked together, I can recall only one case of miscoordination of work. On that occasion, I discovered that we both had written the same 20-line assembly language program. I compared the sources and was astounded to find that they matched character-for-character. The result of our work together has been far greater than the work that we each contributed.

I am a programmer. On my 1040 form, that is what I put down as my occupation. As a programmer, I write programs. I would like to present to you the cutest program I ever wrote. I will do this in three stages and try to bring it together at the end.

STAGE I

In college, before video games, we would amuse ourselves by posing programming exercises. One of the favorites was to write the shortest self-reproducing program. Since this is an exercise divorced from reality, the usual vehicle was FORTRAN. Actually, FORTRAN was the language of choice for the same reason that three-legged races are popular.

More precisely stated, the problem is to write a source program that, when compiled and executed, will produce as output an exact copy of its source. If you have never done this, I urge you to try it on your own. The discovery of how to do it is a revelation that far surpasses any benefit obtained by being told how to do it. The part about "shortest" was just an incentive to demonstrate skill and determine a winner.

Figure 1 shows a self-reproducing program in the C(^3) programming language. (The purist will note that the program is not precisely a self-reproducing program, but will produce a self-reproducing program.) This entry is much too large to win a prize, but it demonstrates the technique and has two important properties that I need to complete my story: 1) This program can be easily written by another program. 2) This program can contain an arbitrary amount of excess baggage that will be reproduced along with the main algorithm. In the example, even the comment is reproduced.

char s[ ] = {
    '\n',
    '0',
    '\n',
    '!',
    ':',
    '\n',
    '\n',
    '/',
    '.',
    '\n',
    (213 lines deleted)
    0
};

/* The string s is a representation of the body of this program from '0' to the end.
*/
main( )
{
    int i;
    printf("char\ts[ ] = {\n");
    for(i=0; s[i]; i++)
    printf("\t%d, \n", s[i]);
    printf("%s", s);
}

Here are some simple transliterations to allow a non-C programmer to read this code:

  • = assignment
  • == equal to .EQ.
  • != not equal to .NE.
  • ++ increment
  • 'x' single character constant
  • "xxx" multiple character string
  • %d format to convert to decimal
  • %s format to convert to string
  • \t tab character
  • \n newline character

then allows it to recompile itself, thus perpetuating the knowledge.

STAGE II

Suppose we wish to alter the C compiler to include the sequence "\v" to represent the vertical tab character. The extension to Figure 2.1 is obvious and is presented in Figure 2.2. We then recompile the C compiler, but we get a diagnostic. Obviously, since the binary version of the compiler does not know about "\v," the source is not legal C. We must "train" the compiler. After it "knows" what "\v" means, then our new change will become legal C. We look up on an ASCII chart that a vertical tab is decimal 11. We alter our source to look like Figure 2.3. Now the old compiler accepts the new source. We install the resulting binary as the new official C compiler and now we can write the portable version the way we had it in Figure 2.2.

This is a deep concept. It is as close to a "learning" program as I have seen. You simply tell it once, then you can use this self-referencing definition.

FIGURE 2.1.

c = next( );
if(c != '\\')
    return(c);
c = next( );
if(c == '\\')
    return('\\');
if(c == 'n')
    return('\n');
...

FIGURE 2.2.

c = next( );
if(c != '\\')
    return(c);
c = next( );
if(c == '\\')
    return('\\');
if(c == 'n')
    return('\n');
if(c == 'v')
    return('\v');
...

FIGURE 2.3.

c = next( );
if(c != '\\')
    return(c);
c = next( );
if(c == '\\')
    return('\\');
if(c == 'n')
    return('\n');
if(c == 'v')
    return(11);
...

STAGE III

Again, in the C compiler, Figure 3.1 represents the high level control of the C compiler where the routine "compile" is called to compile the next line of source. Figure 3.2 shows a simple modification to the compiler that will deliberately miscompile source whenever a particular pattern is matched. If this were not deliberate, it would be called a compiler "bug." Since it is deliberate, it should be called a "Trojan horse."

The actual bug I planted in the compiler would match code in the UNIX "login" command. The replacement code would miscompile the login command so that it would accept either the intended encrypted password or a particular known password. Thus if this code were installed in binary and the binary were used to compile the login command, I could log into that system as any user.

Such blatant code would not go undetected for long. Even the most casual perusal of the source of the C compiler would raise suspicions.

The final step is represented in Figure 3.3. This simply adds a second Trojan horse to the one that already exists. The second pattern is aimed at the C compiler. The replacement code is a Stage I self-reproducing program that inserts both Trojan horses into the compiler. This requires a learning phase as in the Stage II example. First we compile the modified source with the normal C compiler to produce a bugged binary. We install this binary as the official C. We can now remove the bugs from the source of the compiler and the new binary will reinsert the bugs whenever it is compiled. Of course, the login command will remain bugged with no trace in source anywhere.

FIGURE 3.1.

compile(s)
char *s;
{
    ...
}

FIGURE 3.2.

compile(s)
char *s;
{
    if(match(s, "pattern")) 
        compile("bug");
    return;
}

FIGURE 3.3.

compile(s)
char *s;
{
    if(match(s, "pattern1")) 
        compile("bug1");
    return;
    if(match(s, "pattern2")) 
        compile("bug2");
    return;
}

MORAL

The moral is obvious. You can't trust code that you did not totally create yourself. (Especially code from companies that employ people like me.) No amount of source-level verification or scrutiny will protect you from using untrusted code. In demonstrating the possibility of this kind of attack, I picked on the C compiler. I could have picked on any program-handling program such as an assembler, a loader, or even hardware microcode. As the level of program gets lower, these bugs will be harder and harder to detect. A well-installed microcode bug will be almost impossible to detect.

After trying to convince you that I cannot be trusted, I wish to moralize. I would like to criticize the press in its handling of the "hackers," the 414 gang, the Dalton gang, etc. The acts performed by these kids are vandalism at best and probably trespass and theft at worst. It is only the inadequacy of the criminal code that saves the hackers from very serious prosecution. The companies that are vulnerable to this activity, (and most large companies are very vulnerable) are pressing hard to update the criminal code. Unauthorized access to computer systems is already a serious crime in a few states and is currently being addressed in many more state legislatures as well as Congress.

There is an explosive situation brewing. On the one hand, the press, television, and movies make herds of vandals by calling them whiz kids. On the other hand, the acts performed by these kids will soon be punishable by years in prison.

I have watched kids testifying before Congress. It is clear that they are completely unaware of the seriousness of their acts. There is obviously a cultural gap. The act of breaking into a computer system has to have the same social stigma as breaking into a neighbor's house. It should not matter that the neighbor's door is unlocked. The press must learn that misguided use of a computer is no more amazing than drunk driving of an automobile.

Acknowledgment

I first read of the possibility of such a Trojan horse in an Air Force critique [4] of the security of an early implementation of Multics. I cannot find a more specific reference to this document. I would appreciate it if anyone who can supply this reference would let me know.

REFERENCES

  1. Bobrow, D.C., Burchfiel, J.D., Murphy, D.L., and Tomlinson, R.S. TENEX, a paged time-sharing system for the PDP-10. Commun. ACM 15, 3 (Mar. 1972), 135-144.
  2. Kernighan, B.W., and Ritchie, D.M. The C Programming Language. Prentice-Hall, Englewood Cliffs, N.J., 1978.
  3. Ritchie, D.M., and Thompson, K. The UNIX time-sharing system. Commun. ACM 17, (July 1974), 365-375.
  4. Unknown Air Force Document.

Author's Present Address: Ken Thompson, AT&T Bell Laboratories, Room ZC-519, 600 Mountain Ave., Murray Hill, NJ 07974.


Permission to copy without fee all or part of this material is granted provided that the copies are not made or distributed for direct commercial advantage, the ACM copyright notice and the title of the publication and its date appear, and notice is given that copying is by permission of the Association for Computing Machinery. To copy otherwise, or to republish, requires a fee and/or specific permission.

© 1984 0001-0782/84/0800-0761 75¢
August 1984 Volume 27 Number 8 Communications of the ACM 761-783

(^1) UNIX is a trademark of AT&T Bell Laboratories.

튜링상 강연

신뢰에 대한 성찰

프로그램에 트로이 목마가 없다는 주장을 어디까지 믿어야 할까? 어쩌면 소프트웨어를 만든 사람들을 신뢰하는 것이 더 중요할지도 모른다.

켄 톰슨

서론

ACM에서 이 상을 주셔서 감사합니다. 이 영예를 받는 데 있어 기술적 공로만큼이나 타이밍과 우연이 큰 역할을 했다고 느낍니다. UNIX(^1)는 산업 전반이 중앙 메인프레임에서 독립적인 미니 컴퓨터로 전환되면서 큰 인기를 끌었습니다. 만약 대니얼 보브로우(Daniel Bobrow)[1]가 PDP-10을 살 여유가 없어서 PDP-11을 "만족"해야 했다면, 제가 아니라 그가 여기 서 있었을지도 모릅니다. 게다가 UNIX의 현재 모습은 수많은 사람들의 노력의 결과입니다.

"당신을 성공으로 이끈 사람과 춤을 춰라"라는 옛 속담이 있죠. 이는 제가 UNIX에 대해 이야기해야 한다는 뜻일 겁니다. 하지만 저는 오랫동안 주류 UNIX 작업에 참여하지 않았고, 다른 이들의 공로를 과분하게 인정받고 있습니다. 그래서 UNIX에 대한 이야기는 하지 않겠습니다. 다만, 기여한 모든 분께 감사 인사를 전하고 싶습니다.

이제 데니스 리치(Dennis Ritchie)에 대해 이야기하고 싶습니다. 우리 둘의 협업은 정말 아름다운 경험이었습니다. 10년간 함께 일하며 작업이 꼬인 경우는 단 한 번뿐이었습니다. 그때 우리는 둘 다 같은 20줄짜리 어셈블리 언어 프로그램을 작성했었죠. 소스 코드를 비교했을 때, 문자 하나까지 완벽히 일치하는 걸 보고 깜짝 놀랐습니다. 우리가 함께 만든 결과물은 각자가 기여한 것보다 훨씬 더 큰 가치를 지닙니다.

저는 프로그래머입니다. 세금 신고서에 직업란에 "프로그래머"라고 적습니다. 프로그래머로서 저는 프로그램을 작성합니다. 오늘 여러분께 제가 쓴 가장 멋진 프로그램을 소개하고 싶습니다. 이를 세 단계로 나누어 설명하고, 마지막에 전체를 아우르는 이야기를 해보려 합니다.

1단계

대학 시절, 비디오 게임이 없던 시절에 우리는 프로그래밍 연습문제로 시간을 보냈습니다. 가장 인기 있던 문제 중 하나는 가장 짧은 자기 복제 프로그램을 만드는 것이었습니다. 이건 현실과 동떨어진 연습이었기 때문에 보통 FORTRAN을 사용했죠. 사실 FORTRAN이 선택된 이유는 마치 삼각 달리기 경주가 인기 있는 것과 비슷한 이유였습니다.

좀 더 정확히 말하자면, 문제는 컴파일하고 실행했을 때 자신의 소스 코드와 똑같은 출력을 내는 소스 프로그램을 작성하는 것이었습니다. 이걸 해보지 않았다면 꼭 한번 시도해보시길 권합니다. 어떻게 하는지 알아내는 과정은 누가 가르쳐주는 것보다 훨씬 더 큰 깨달음을 줍니다. "가장 짧게"라는 조건은 기술을 뽐내고 승자를 가리기 위한 동기부여였습니다.

그림 1은 C(^3) 프로그래밍 언어로 작성된 자기 복제 프로그램입니다. (정확히 말하자면 이 프로그램 자체는 자기 복제가 아니라 자기 복제 프로그램을 생성하는 프로그램입니다.) 이 코드는 상을 받을 정도로 짧지는 않지만, 기법을 보여주며 제 이야기에 필요한 두 가지 중요한 특성을 가지고 있습니다: 1) 이 프로그램은 다른 프로그램에 의해 쉽게 작성될 수 있습니다. 2) 이 프로그램은 주요 알고리즘과 함께 불필요한 여분의 데이터를 포함할 수 있고, 이 데이터도 함께 복제됩니다. 예시에서는 주석까지 복제됩니다.

char s[ ] = {
    '\n',
    '0',
    '\n',
    '!',
    ':',
    '\n',
    '\n',
    '/',
    '.',
    '\n',
    (213 삭제됨)
    0
};

/* 문자열 s는 이 프로그램의 본문('0'부터 끝까지)을 나타냅니다.
*/
main( )
{
    int i;
    printf("char\ts[ ] = {\n");
    for(i=0; s[i]; i++)
    printf("\t%d, \n", s[i]);
    printf("%s", s);
}

C를 모르는 분들을 위해 간단한 변환 표를 제공합니다:

  • = 대입
  • == 같음 (.EQ.)
  • != 같지 않음 (.NE.)
  • ++ 증가
  • 'x' 단일 문자 상수
  • "xxx" 다중 문자 문자열
  • %d 10진수로 변환하는 형식
  • %s 문자열로 변환하는 형식
  • \t 탭 문자
  • \n 줄바꿈 문자

이렇게 하면 프로그램이 스스로를 재컴파일할 수 있어 지식을 영속화합니다.

2단계

C 컴파일러에 수직 탭 문자를 나타내는 "\v" 시퀀스를 추가하고 싶다고 가정해봅시다. 그림 2.1에서 그림 2.2로의 확장은 명확하며, 그림 2.2에 제시되어 있습니다. 하지만 C 컴파일러를 재컴파일하려고 하면 진단 메시지가 나타납니다. 바이너리 버전의 컴파일러가 "\v"를 모르기 때문에 소스 코드가 올바른 C가 아닌 겁니다. 우리는 컴파일러를 "훈련"시켜야 합니다. "\v"가 무엇인지 알게 되면 새로운 변경이 올바른 C가 됩니다. ASCII 표를 확인해보니 수직 탭은 10진수 11입니다. 그래서 소스를 그림 2.3처럼 수정합니다. 이제 기존 컴파일러가 새 소스를 받아들입니다. 결과 바이너리를 새로운 공식 C 컴파일러로 설치하면, 그림 2.2처럼 이식 가능한 버전을 작성할 수 있습니다.

이건 꽤 깊은 개념입니다. 제가 본 것 중 가장 "학습" 프로그램에 가까운 사례입니다. 한 번만 알려주면, 이 자기 참조 정의를 사용할 수 있습니다.

그림 2.1.

c = next( );
if(c != '\\')
    return(c);
c = next( );
if(c == '\\')
    return('\\');
if(c == 'n')
    return('\n');
...

그림 2.2.

c = next( );
if(c != '\\')
    return(c);
c = next( );
if(c == '\\')
    return('\\');
if(c == 'n')
    return('\n');
if(c == 'v')
    return('\v');
...

그림 2.3.

c = next( );
if(c != '\\')
    return(c);
c = next( );
if(c == '\\')
    return('\\');
if(c == 'n')
    return('\n');
if(c == 'v')
    return(11);
...

3단계

다시 C 컴파일러에서, 그림 3.1은 컴파일러의 상위 수준 제어를 나타내며, 여기서 compile 루틴이 다음 소스 줄을 컴파일하기 위해 호출됩니다. 그림 3.2는 특정 패턴이 일치할 때 소스를 의도적으로 잘못 컴파일하도록 수정한 간단한 예입니다. 만약 이게 의도적이지 않았다면 컴파일러 "버그"라고 불렸을 겁니다. 하지만 의도적이라면 "트로이 목마"라고 해야겠죠.

제가 컴파일러에 심은 실제 버그는 UNIX의 "login" 명령어에서 특정 코드를 찾아냈습니다. 대체 코드는 로그인 명령어가 원래의 암호화된 비밀번호나 특정한 알려진 비밀번호를 모두 받아들이도록 잘못 컴파일하게 했습니다. 따라서 이 코드가 바이너리에 설치되고 그 바이너리로 로그인 명령어를 컴파일하면, 저는 원하는 사용자로 시스템에 로그인할 수 있었습니다.

이런 노골적인 코드는 오래 가지 못하고 발각되었을 겁니다. C 컴파일러 소스를 대충 훑어봐도 의심을 불러일으켰을 테니까요.

마지막 단계는 그림 3.3에 나타나 있습니다. 여기서는 이미 존재하는 트로이 목마에 두 번째 트로이 목마를 추가합니다. 두 번째 패턴은 C 컴파일러를 겨냥합니다. 대체 코드는 1단계의 자기 복제 프로그램으로, 두 트로이 목마를 모두 컴파일러에 삽입합니다. 이는 2단계의 학습 단계가 필요합니다. 먼저 수정된 소스를 정상 C 컴파일러로 컴파일하여 버그가 포함된 바이너리를 만듭니다. 이 바이너리를 공식 C 컴파일러로 설치합니다. 이제 컴파일러 소스에서 버그를 제거해도, 새 바이너리는 컴파일될 때마다 버그를 다시 삽입합니다. 물론 로그인 명령어는 소스에 흔적 없이 계속 버그 상태로 남습니다.

그림 3.1.

compile(s)
char *s;
{
    ...
}

그림 3.2.

compile(s)
char *s;
{
    if(match(s, "pattern")) 
        compile("bug");
    return;
}

그림 3.3.

compile(s)
char *s;
{
    if(match(s, "pattern1")) 
        compile("bug1");
    return;
    if(match(s, "pattern2")) 
        compile("bug2");
    return;
}

교훈

교훈은 명확합니다. 당신이 직접 만들지 않은 코드는 절대 신뢰할 수 없습니다. (특히 저 같은 사람을 고용한 회사에서 나온 코드라면 더더욱요.) 소스 수준의 검증이나 면밀한 검토도 신뢰할 수 없는 코드를 사용하는 위험에서 당신을 보호하지 못합니다. 이런 공격 가능성을 보여주기 위해 저는 C 컴파일러를 예로 들었습니다. 하지만 어셈블러, 로더, 심지어 하드웨어 마이크로코드 같은 프로그램 처리 프로그램이라면 무엇이든 대상이 될 수 있었습니다. 프로그램의 수준이 낮아질수록 이런 버그는 탐지하기 점점 더 어려워집니다. 잘 심어진 마이크로코드 버그는 거의 탐지 불가능할 겁니다.

저를 신뢰할 수 없다고 설득한 뒤, 이제 도덕적 이야기를 하고 싶습니다. 언론이 "해커", 414 갱, 달튼 갱 등을 다루는 방식에 대해 비판하고 싶습니다. 이 아이들이 한 행동은 기껏해야 기물 파손이고, 최악의 경우 무단 침입이나 절도일 뿐입니다. 형사법의 미비함 덕분에 해커들이 심각한 기소에서 벗어나고 있습니다. 이런 활동에 취약한 회사들(대부분의 대기업이 매우 취약합니다)은 형사법을 강화하려고 강하게 압박하고 있습니다. 컴퓨터 시스템에 대한 무단 접근은 이미 몇몇 주에서 심각한 범죄로 간주되며, 현재 많은 주 의회와 의회에서도 이 문제를 다루고 있습니다.

폭발적인 상황이 조성되고 있습니다. 한편으로는 언론, TV, 영화가 이들을 "천재 아이들"이라 부르며 기물 파손을 부추기고 있습니다. 다른 한편으로는 이 아이들의 행동이 곧 수년의 징역으로 처벌받을 수 있습니다.

저는 아이들이 의회에서 증언하는 모습을 보았습니다. 그들은 자신들의 행동이 얼마나 심각한지 전혀 모르고 있었습니다. 분명히 문화적 간극이 존재합니다. 컴퓨터 시스템에 침입하는 행위는 이웃집에 몰래 들어가는 것과 같은 사회적 낙인을 받아야 합니다. 이웃집 문이 잠겨 있지 않다고 해서 문제가 없는 게 아닙니다. 언론은 컴퓨터의 오용이 자동차 음주 운전보다 더 대단한 일이 아니라는 점을 배워야 합니다.

감사의 글

이런 트로이 목마의 가능성을 처음 알게 된 건 Multics의 초기 구현 보안에 대한 공군의 비평[4]에서였습니다. 이 문서에 대한 더 구체적인 참조를 찾지 못했습니다. 참조를 제공해 줄 수 있는 분이 있다면 알려주시면 감사하겠습니다.

참고 문헌

  1. Bobrow, D.C., Burchfiel, J.D., Murphy, D.L., and Tomlinson, R.S. TENEX, a paged time-sharing system for the PDP-10. Commun. ACM 15, 3 (Mar. 1972), 135-144.
  2. Kernighan, B.W., and Ritchie, D.M. The C Programming Language. Prentice-Hall, Englewood Cliffs, N.J., 1978.
  3. Ritchie, D.M., and Thompson, K. The UNIX time-sharing system. Commun. ACM 17, (July 1974), 365-375.
  4. Unknown Air Force Document.

저자 현 주소: Ken Thompson, AT&T Bell Laboratories, Room ZC-519, 600 Mountain Ave., Murray Hill, NJ 07974.


이 자료의 전체 또는 일부를 수수료 없이 복사할 수 있는 권한은 상업적 이익을 위해 복사하거나 배포하지 않고, ACM 저작권 고지와 출판 제목 및 날짜가 포함되며, Association for Computing Machinery의 허가로 복사되었다는 고지가 포함된 경우에 허용됩니다. 그 외의 복사나 재출판에는 수수료 및/또는 특정 허가가 필요합니다.

© 1984 0001-0782/84/0800-0761 75¢
1984년 8월, Communications of the ACM 제27권 8호, 761-783페이지

(^1) UNIX는 AT&T Bell Laboratories의 상표입니다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment