Learning Dark Arts of Yul Part II

Learning Dark Arts of Yul Part II

Reading a Slot in Yul

Lets start with a Coding Example

contract offsetAndShifting{
    uint128 public a = 22;
    uint96 public b =15;
    uint16 public c = 8;
    uint8 public d = 1;

    function readValueBySlot(uint256 slot) external view return(bytes32 uint){
        assembly{
            value := sload(slot)
        }
    }

    function getOffsetOfC() external pure returns(uint256 slot, uint256 offset){
        assembly{
            slot := c.slot // get the Slot
            offset := c.offset // get the exact position of c
        }
    }

    function readValueOfC() external view returns(uint256 e){
        assembly{
            let value := sload(c.slot) // slot 0
            let shifted ;= shr(mul(c.offset,8),value)

            e := and(0xffff,shifted) // Masking 
        }
    }
}

  • We use the .slot function to get the Exact slot of our value

  • To find the exact position of our variable in a slot we use .offset function

In the above code in the readValueOfC() function we first read the slot of c and then we shift the Pointer to the exact position of C by utilizing the shr built-in function and Finally we use the masking technique by applying the AND gate to retrieve the Value of C .

Writing to a Slot (Bit Shifting)

 function writeToC(uint16 newC) external {
        assembly {
            // newC = 0x000000000000000000000000000000000000000000000000000000000000000a
            let slotValue := sload(C.slot)
            // slotValue =  0x0001000800000000000000000000000f00000000000000000000000000000016
            let clearedC := and(
                slotValue,
                0xffff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff
            )
            // mask      =  0xffff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff
            // slotValue =  0x0001000800000000000000000000000f00000000000000000000000000000016
            // clearedC =   0x0001000000000000000000000000000f00000000000000000000000000000016
            let shiftedNewC := shl(mul(C.offset, 8), newC)
            // shiftedNewC = 0x0000000a00000000000000000000000000000000000000000000000000000000
            let newSlotValue := or(shiftedNewC, clearedC)
            // shiftedNewC = 0x0000000a00000000000000000000000000000000000000000000000000000000
            // clearedC    = 0x0001000000000000000000000000000f00000000000000000000000000000016
            // newVal      = 0x0001000a00000000000000000000000f00000000000000000000000000000016
            sstore(C.slot, newSlotValue)
        }
    }

Okay writing a Slot in Yul is a bit complex , but lets break it into a step by step process

In the previous example we want to edit/write to the variable C , which is packed in the same slot with a,b and d . So how to edit it without changing or affecting a,b and d

Step 1 :

  • Load the Slot value of the whole Slot of C

Step 2 :

  • Perform an AND gate operation with the Slot Value with a 64-size length-ed hex-decimal string where only the number of bits utilized by the variable along with its offset position must be kept ‘0’ and all other bits shall be ‘f’ or ‘1’ , As a result the whole byte occupied by old value of c are now nullified.

Step 3

  • Shift the new value on the exact offset place of c

Step 4

  • Perform the OR operation between value obtained from Step 2 & 3

Step 5

  • Store the value of Step 4 in the Slot C