Assembly Language & x86 Low-Level Systems Programming · レッスン

プロシージャの定義と呼び出し

CALLとRET命令を使って独自のプロシージャ(関数)を定義・呼び出し、スタックフレームの設定方法を理解します。

レッスン 2/412 ステップ

「プロシージャの定義と呼び出し」はCoddyKit上の無料Assembly Language & x86 Low-Level Systems Programmingレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはAssembly Language & x86 Low-Level Systems Programming学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Assembly Language & x86 Low-Level Systems Programmingコースには全4レッスンが含まれています。

このレッスンの一部はまだ翻訳されておらず、英語で表示されています。

What are Procedures?

In assembly, a procedure (often called a function or subroutine) is a block of code designed to perform a specific task. They help organize your program and avoid repeating code.

Think of them like functions in high-level languages like C++ or Python. They allow you to break down complex problems into smaller, manageable parts, making your code modular and easier to read.

Calling a Procedure with CALL

To execute a procedure, we use the CALL instruction. When CALL is executed, two important things happen:

  • The address of the instruction immediately after CALL is pushed onto the stack. This is known as the return address.
  • The CPU then jumps to the starting address of the procedure you specified.

This mechanism ensures that the program knows exactly where to resume execution once the procedure has completed its work.

Returning from a Procedure with RET

Once a procedure has finished its assigned task, it needs to return control to the code that called it. This is achieved using the RET instruction.

When RET is executed:

  • The CPU pops the return address from the top of the stack.
  • The CPU then jumps to this popped address, effectively resuming execution at the instruction immediately following the original CALL.

Together, CALL and RET form the fundamental pair for managing program flow between different procedures.

Your First Procedure Call

Let's look at a simple assembly program that demonstrates a basic procedure call and return. We'll define a procedure named print_hello and call it from our program's entry point, _start.

This example uses Linux system calls for output and program exit.

section .data
    msg db "Hello from proc!", 0xA
    len equ $ - msg

section .text
    global _start

_start:
    call print_hello

    ; Exit program (sys_exit)
    mov eax, 1    ; System call number for sys_exit
    xor ebx, ebx  ; Exit code 0
    int 0x80

print_hello:
    ; Print "Hello from proc!" (sys_write)
    mov eax, 4    ; System call number for sys_write
    mov ebx, 1    ; File descriptor for stdout
    mov ecx, msg  ; Address of string to write
    mov edx, len  ; Length of string
    int 0x80
    ret

Understanding the Output

When you run the previous code, it will print "Hello from proc!" to your console. Here's a step-by-step breakdown of what happened:

  • The _start routine executed call print_hello.
  • The address of the instruction mov eax, 1 (which is right after call print_hello) was pushed onto the stack.
  • The CPU jumped to the print_hello procedure.
  • print_hello executed its instructions to print the message.
  • ret popped the saved return address from the stack and jumped back to the _start routine.
  • _start then executed the system call to exit the program.

What are Stack Frames?

When a procedure is called, it often needs its own private workspace on the stack to manage its data. This dedicated region on the stack is called a stack frame.

A stack frame typically holds several key pieces of information for a procedure:

  • The return address (pushed by the CALL instruction).
  • Saved register values (e.g., the caller's base pointer).
  • Local variables specific to that procedure.
  • Arguments passed to the procedure (we'll cover this in the next lesson!).

Setting Up the Base Pointer (EBP)

The base pointer register (`EBP` in 32-bit, `RBP` in 64-bit) is a crucial tool for managing stack frames. It provides a stable reference point within the current stack frame, making it easy to access local variables and arguments.

A common setup sequence at the very beginning of a procedure is:

  • push ebp: This saves the caller's current `EBP` value onto the stack, so it can be restored later.
  • mov ebp, esp: This sets `EBP` to the current value of the stack pointer (`ESP`), establishing the base of the new stack frame.

Allocating Local Variables

After setting up `EBP`, a procedure can allocate space for its own local variables on the stack. This is typically done by simply decrementing the stack pointer (`ESP`).

sub esp, N

Here, `N` represents the total number of bytes required for all local variables. For example, sub esp, 4 allocates enough space for one 32-bit integer.

These local variables can then be accessed efficiently relative to `EBP` (e.g., [ebp-4], [ebp-8], etc.).

Tearing Down the Stack Frame

Before a procedure returns, its stack frame must be properly dismantled to restore the stack to its original state. This involves deallocating local variables and restoring the caller's base pointer.

The LEAVE instruction is a convenient way to perform these two actions in one step:

  • mov esp, ebp: This deallocates any local variables by moving `ESP` back to where `EBP` points (the base of the frame).
  • pop ebp: This restores the caller's `EBP` value, which was saved at the beginning of the procedure.

After LEAVE, the stack is correctly positioned for the RET instruction to pop the return address.

Procedure with a Stack Frame

This example demonstrates a complete procedure that sets up a proper stack frame, allocates space for a hypothetical local variable, and then correctly tears down the frame before returning.

Notice how `push ebp`, `mov ebp, esp`, `sub esp, 4`, `leave`, and `ret` work together.

section .data
    msg db "Procedure with frame!", 0xA
    len equ $ - msg

section .text
    global _start

_start:
    call my_framed_proc

    ; Exit program
    mov eax, 1
    xor ebx, ebx
    int 0x80

my_framed_proc:
    push ebp            ; 1. Save caller's EBP
    mov ebp, esp        ; 2. Set EBP for new frame

    sub esp, 4          ; 3. Allocate 4 bytes for a local variable
    ; mov dword [ebp-4], 123 ; Example: store a local value

    ; Print message (for demonstration)
    mov eax, 4
    mov ebx, 1
    mov ecx, msg
    mov edx, len
    int 0x80

    leave               ; 4. Deallocate locals, restore EBP
    ret                 ; 5. Return to caller

Procedure Call Flow Check

Consider the following x86 assembly snippet:

  call my_function
  mov eax, 1
my_function:
  ret

What specific address is pushed onto the stack by the call my_function instruction?

Defining & Calling Procedures Recap

We've covered the essential concepts of defining and calling procedures in x86 assembly. Here are the key takeaways from this lesson:

  • The CALL instruction pushes the return address onto the stack and transfers control to a procedure.
  • The RET instruction pops the return address from the stack and transfers control back to the caller.
  • Stack frames, managed primarily with the EBP/RBP register, provide a dedicated and organized workspace on the stack for a procedure's local variables and saved registers.
  • A typical stack frame setup involves push ebp, mov ebp, esp, and allocating local variables with sub esp, N.
  • Tearing down the stack frame is done using the LEAVE instruction (or manually with mov esp, ebp and pop ebp) before RET.

Next, we'll build on this by learning how to pass arguments to procedures and retrieve return values.

無料で開始

AI チューターと学ぶ Assembly — 無料

ブラウザでリアルコードを書いて実行し、24/7 の AI チューターから瞬時にサポートを受け、ウェブまたはアプリで続きから学習できます。

コース
12
レッスン
48

よくある質問

「プロシージャの定義と呼び出し」レッスンは無料ですか?

はい。「プロシージャの定義と呼び出し」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Assembly Language & x86 Low-Level Systems Programmingコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Assembly Language & x86 Low-Level Systems Programmingコースには全4レッスンが含まれています。

「プロシージャの定義と呼び出し」で何を学びますか?

CALLとRET命令を使って独自のプロシージャ(関数)を定義・呼び出し、スタックフレームの設定方法を理解します。 ブラウザで直接実行するハンズオンコードでAssembly Language & x86 Low-Level Systems Programmingを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Assembly Language & x86 Low-Level Systems Programmingを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのAssembly Language & x86 Low-Level Systems Programmingは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。

「プロシージャの定義と呼び出し」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このAssembly Language & x86 Low-Level Systems Programmingレッスンでコードを書いて実行できますか?

はい。すべてのAssembly Language & x86 Low-Level Systems Programmingレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. コールスタックの基礎
  2. プロシージャの定義と呼び出し
  3. 引数と戻り値の受け渡し
  4. スタックフレームとローカル変数
← Assembly Language & x86 Low-Level Systems Programmingに戻る