"일꾼이 일을 잘하려면 먼저 도구를 갈고 닦아야 한다." - 공자, 『논어』.
첫 장 > 프로그램 작성 > 런타임 이해: C에서 현대 언어까지

런타임 이해: C에서 현대 언어까지

2024-11-08에 게시됨
검색:340

Understanding Runtimes: From C to Modern Languages

현대 소프트웨어 개발 및 프로그래밍 시대에 "런타임"이라는 용어는 논의되는 언어와 상황에 따라 다른 의미를 가질 수 있습니다. 저는 Java나 Python과 같은 최신 언어와 비교하여 C에서 런타임이 작동하는 방식에 중점을 두고 이러한 차이점을 명확히 하기 위해 왔습니다. 이 글은 초보 프로그래머를 대상으로 하므로 복잡한 개념을 깊이 파고드는 것은 피하겠습니다.

런타임이란 무엇입니까?

기본적으로 런타임은 개발자가 작성한 코드를 읽고 실행하는 프로그램 자체입니다. 하지만 일부 개발자가 C 언어로 런타임을 사용하면 혼란스러워집니다.

최신 언어 런타임

Java 또는 Python과 같은 언어에서 런타임은 myfile.js 파일을 읽는 프로그램 자체이므로 다음과 같은 nodejs 프로그램을 실행합니다. node myfile.js 및 v8 엔진(은 JavaScript 엔진이며 JavaScript를 구문 분석하고 실행합니다. code.)는 새 파일 생성, 하위 프로세스 실행 등 모든 것을 관리하며 가장 중요한 것은 v8에서 허용하지 않는 작업을 수행할 수 없다는 것입니다.
하지만 c 프로그램을 실행할 때 c myfile.c를 수행하지 않고 한 번만 컴파일하면 되며 이제 더 이상 gcc가 필요하지 않으며 직접 실행하면 됩니다.

C "런타임"

C에서는 Java나 Python과 같은 방식으로 코드와 함께 실행되는 별도의 프로그램이 없습니다. 대신, 종종 C "런타임"이라고 불리는 것은 실제로 컴파일 중에 추가된 정적으로 삽입된 코드와 명령 세트입니다. 이는 CPU/OS 수준에서 필요한 특정 작업을 처리하기 위해 최종 바이너리에 포함된 최소한의 명령 집합입니다. 함수 호출에 대한 스택 프레임 생성 및 해제를 처리합니다(어셈블리에서 PUSH, POP, CALL, RET와 같은 명령어 사용). 인라인 어셈블리를 사용하여 자체 __start 함수를 제공함으로써 이를 재정의할 수 있으므로 개발자가 프로그램의 진입점과 초기화를 완벽하게 제어할 수 있습니다.


void __start() {
// Custom entry point, no standard library initialization
// You have no access to argc and argv here unless you access them manually from registers
// you can create you own custom stack setup, initialization and etc here.

// Exit directly using a syscall
asm("mov $60, %rax; mov $0, %rdi; syscall"); // exit(0) syscall
}


이것은 전혀 런타임처럼 보이지 않으며 개발자가 그럴 필요가 없도록 컴파일러에 의해 추가된 일부 어셈블리 언어 코드일 뿐입니다.

C의 힘과 책임

C에서는 인라인 어셈블리를 사용하여 시스템 호출을 직접 호출하여 OS에서 일반적으로 허용하지 않는 방식으로 커널과 상호 작용할 수 있습니다. 이것이 바로 맬웨어가 생성되는 방식입니다. 인라인 어셈블리를 사용하면 개발자가 C 코드 내에서 어셈블리 언어 지침을 작성할 수 있습니다. 이는 성능이 중요한 코드에 사용되거나 특정 하드웨어 기능에 액세스하는 데 자주 사용됩니다.

C의 인라인 어셈블리

  • 인라인 어셈블리를 사용하면 개발자가 C 코드 내에서 어셈블리 언어 지침을 작성할 수 있습니다. 이는 성능이 중요한 코드에 사용되거나 특정 하드웨어 기능에 액세스하는 데 자주 사용됩니다.
  • CPU 명령어를 직접 실행하는 방법을 제공합니다.

커널과의 직접적인 상호작용

  • 인라인 어셈블리를 사용하면 프로그래머는 상위 수준 라이브러리를 거치지 않고도 시스템 호출을 직접 호출할 수 있습니다.
  • 예를 들어 인라인 어셈블리를 사용하여 시스템 호출에 적합한 매개변수로 레지스터를 설정한 다음 이를 트리거할 수 있습니다.
  • 인라인 어셈블리를 사용하면 시스템 리소스에 대한 낮은 수준의 제어가 가능하므로 보안 메커니즘을 우회하거나 커널을 직접 조작하는 데 사용할 수 있습니다. 이는 악성코드가 보호된 메모리에 액세스하거나, 시스템 호출을 가로채거나, 프로세스 및 해당 메모리를 조작하는 등의 무단 작업을 수행할 수 있는 방법입니다.
  • 맬웨어는 OS의 취약점을 악용하거나 이러한 낮은 수준의 상호 작용을 사용하여 키 로깅, 권한 상승 또는 스텔스 작업과 같은 작업을 수행할 수 있습니다.

리눅스 C에는 커널의 캐싱 메커니즘 중 일부를 우회하여 파일 데이터를 저장 장치에 직접 쓸 수 있는 FLAG가 있는데, 이를 O_DIRECT 플래그라고 하며 이는 열기 및 쓰기 시스템 호출과 함께 사용됩니다. 이 플래그는 데이터가 RAM에 버퍼링되지 않거나 커널 공간에서 커널에 의해 관리되지 않도록 보장합니다. 이는 데이터를 하드 드라이브에 직접 기록하지만 JVM에서는 이를 허용하지 않으며 이는 단지 하나의 간단한 예일 뿐입니다.
다음은 간단한 예입니다:


asm volatile (
"syscall"
: "=a" (written)
: "0" (1),
"D" (fd),
"S" (buffer),
"d" (BLOCK_SIZE)
: "rcx", "r11", "memory"
);


*참고: *(작성)는 main() 내부에서 생성된 변수이고, (1)은 쓰기를 위한 시스템 호출 번호이고, (fd)는 파일이 기록되는 위치입니다. 즉 int fs = open("path .log",O_WRONLY; (BLOCK_SIZE)는 또 다른 변수 이름입니다. 그보다 더 복잡합니다.

런타임의 진화

런타임의 개념이 수년에 걸쳐 발전해 왔다는 점을 이해하는 것이 중요합니다. 70년대의 C "런타임"은 2000년대의 언어에서 볼 수 있는 강력한 런타임 환경과 매우 다릅니다. 이러한 발전은 특히 다양한 프로그래밍 시대에 익숙한 개발자들 사이에서 런타임을 논의할 때 혼란을 야기할 수 있습니다.

결론

지금 사람들이 1970년대 런타임과 2000년대 런타임을 비교하고 있는 것 같은데, 이로 인해 신규 개발자와 기존 개발자가 혼동되고 있습니다.
특정 문제를 해결하는 것은 프로그래밍 언어의 주요 작업입니다. C로 API를 생성하기 위해 전체 프레임워크를 작성하고 싶지는 않습니다. 우리는 nodejs를 가지고 있고 그것에 능숙하며 자바스크립트로 베어 메탈 코드를 작성할 필요가 없습니다. 이미 C가 있고 정말 훌륭합니다. 바퀴를 재발명해야 하는 이유, 화성에서 운전하고 싶지 않다면 바퀴를 사용하여 멋진 자동차를 만들어 보세요.

릴리스 선언문 이 기사는 https://dev.to/bossysmaxx/understanding-runtimes-from-c-to-modern-언어s-3fkj?1에 복제되어 있습니다. ​​침해 내용이 있는 경우에는 [email protected]으로 연락하여 삭제하시기 바랍니다. 그것
최신 튜토리얼 더>

부인 성명: 제공된 모든 리소스는 부분적으로 인터넷에서 가져온 것입니다. 귀하의 저작권이나 기타 권리 및 이익이 침해된 경우 자세한 이유를 설명하고 저작권 또는 권리 및 이익에 대한 증거를 제공한 후 이메일([email protected])로 보내주십시오. 최대한 빨리 처리해 드리겠습니다.

Copyright© 2022 湘ICP备2022001581号-3