Solidity의 mload()add()EVM 어셈블리(Assembly)에서 메모리를 다룰 때 사용되는 저수준 함수(low-level functions)이다.
이 두 함수는 일반적인 Solidity 코드에서는 잘 사용되지 않지만, 저수준 메모리 조작이 필요한 경우(예: call, delegatecall, staticcall 등의 실행)에는 필수적이다.


📌 1. mload() 함수: 메모리에서 데이터 읽기

📝 함수 정의

mload(uint256 p) -> value
  • p: 메모리 주소(메모리에서 읽을 위치, 바이트 단위)
  • value: p 주소에 저장된 32바이트(256비트) 크기의 값을 반환

🔹 mload()의 역할

  • EVM의 메모리에서 32바이트(256비트) 데이터를 읽는 역할을 한다.
  • Solidity에서는 bytes memory 배열을 다룰 때, 첫 32바이트는 배열의 길이를 저장한다.
  • 따라서, mload(data)를 호출하면 data의 길이를 읽을 수 있다.

📌 예제 코드: mload()를 사용한 메모리 읽기

pragma solidity ^0.8.0;

contract TestMload {
    function getMemoryData(bytes memory data) public pure returns (uint256) {
        assembly {
            let length := mload(data) // data의 길이를 가져옴
            return(length, 0x20) // 길이를 반환 (첫 32바이트에 저장됨)
        }
    }
}

📌 설명

  1. data는 동적 배열(bytes memory)이므로, 첫 32바이트는 데이터 길이를 저장하고 있음.
  2. mload(data)첫 32바이트 값을 읽어length에 저장.
  3. return(length, 0x20)을 사용해 길이를 반환.

📌 실행 예제

bytes memory data = abi.encode("Hello, world!"); // "Hello, world!"를 바이너리로 변환
uint256 length = getMemoryData(data);

🔹 data첫 32바이트에는 "Hello, world!"의 길이(13)가 저장되어 있음 → mload(data) == 13


🔎 mload()가 메모리를 읽는 방식

메모리는 32바이트(256비트) 단위로 정렬되어 있음. mload()메모리의 특정 주소(p)부터 32바이트를 읽음.

예제: 메모리 상태

메모리 주소 데이터
0x00 0x000000000000000000000000000000000000000000000000000000000000000D (13 in decimal)
0x20 0x48656c6c6f2c20776f726c642100000000000000000000000000000000000000 ("Hello, world!" in bytes)

📌 mload(data) 실행 결과는 0x000000000000000000000000000000000000000000000000000000000000000D (13)
📌 mload(add(data, 0x20)) 실행 결과는 "Hello, world!"의 첫 32바이트 값


📌 2. add() 함수: 주소 또는 숫자 더하기

📝 함수 정의

add(uint256 a, uint256 b) -> result
  • a: 첫 번째 숫자 또는 메모리 주소
  • b: 두 번째 숫자 또는 오프셋(offset)
  • result: a + b 결과 값

🔹 add()의 역할

  • 두 개의 숫자를 더하는 역할을 한다.
  • 일반적인 연산 뿐만 아니라, 메모리 주소 계산에 사용된다.

📌 예제 코드: add()를 사용한 주소 계산

pragma solidity ^0.8.0;

contract TestAdd {
    function addNumbers(uint256 a, uint256 b) public pure returns (uint256 sum) {
        assembly {
            sum := add(a, b)
        }
    }
}

📌 설명

  1. add(a, b)는 단순히 두 숫자를 더한 값(a + b)을 반환.
  2. Solidity에서는 안전한 연산을 위해 기본적으로 오버플로우 방지가 적용되지만, EVM 어셈블리에서는 오버플로우가 발생할 수 있음.

📌 실행 예제

uint256 result = addNumbers(5, 10); // 결과: 15

add(5, 10)15


📌 add()를 사용하여 메모리 주소 이동

배열에서 특정 데이터 위치를 찾을 때 활용됨

function getSecondItem(bytes memory data) public pure returns (uint256 secondItem) {
    assembly {
        secondItem := mload(add(data, 0x20)) // data의 두 번째 값 읽기
    }
}

📌 설명

  • data의 첫 32바이트는 배열의 길이가 저장됨.
  • add(data, 0x20)data실제 데이터 시작 위치.
  • mload(add(data, 0x20)) → 두 번째 항목을 읽음.

📌 add()mload()를 함께 사용하는 이유

Solidity에서 bytes memory는 첫 32바이트가 길이를 저장하고, 그 이후부터 실제 데이터가 저장됨.
따라서 데이터를 읽을 때, mload()add()를 조합하여 정확한 위치를 찾아야 함.

📌 실제 사용 예

success := call(txGas, to, value, add(data, 0x20), mload(data), 0, 0)
  1. mload(data)data 배열의 길이를 가져옴.
  2. add(data, 0x20)data의 첫 32바이트(길이 정보)를 건너뛰고, 실제 데이터 시작 위치를 찾음.
  3. call()을 실행하여 해당 데이터를 전송.

📌 정리

함수 역할 사용 예
mload(uint256 p) 메모리 주소 p에서 32바이트 데이터 읽기 mload(data)data의 길이 읽기
add(uint256 a, uint256 b) a + b 연산 수행 add(data, 0x20)data에서 실제 데이터 시작 위치 찾기

mload()는 32바이트(256비트) 단위로 데이터를 읽는다.
add()는 숫자 연산 또는 메모리 주소 이동에 사용된다.
Solidity에서 ABI 인코딩된 데이터를 처리할 때 필수적인 연산이다. 🚀🔥

+ Recent posts