Building up on @Jesbus comment, here is a commented example achieving what you want :
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract TestAssembly {
function test(uint8 _count) public pure returns (bytes memory) {
// Declares the array in memory
bytes memory bytesTest = new bytes(10);
// Protect against buffer overflow
require(_count <= 10, "not enough bytes in the array");
assembly {
// Skip the first 32 bytes reserved for the length of the memory array
let offset := add(bytesTest, 0x20)
// Loop _count times over the array
for { let i := 0} lt(i, _count) { i := add(i, 1) } {
// Make use of mstore8 (1 byte) instead of mstore (32 bytes)
mstore8(add(offset, i), 0x33)
}
}
return bytesTest;
}
}
EDIT :
I'm adding an example relying on array literals where there is no length prefix and using bytes32.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract TestAssembly {
function test(uint8 _count) public pure returns (bytes32) {
// Declares the byte32 array in memory : this is an array literal -> there is no length prefix
bytes32[1] memory bytesTest = [bytes32(0)];
// Protect against buffer overflow
require(_count <= 32, "not enough bytes in the array");
assembly {
// Loop _count times over the array
for { let i := 0} lt(i, _count) { i := add(i, 1) } {
// Make use of mstore8 (1 byte) instead of mstore (32 bytes)
mstore8(add(bytesTest, i), 0x33)
}
}
return bytesTest[0];
}
}
Plus a third example not relying on solidity arrays but directly allocating / computing in memory through assembly.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract TestAssembly {
function test(uint8 _count) public pure returns (bytes32) {
bytes32 result;
// Protect against buffer overflow
require(_count <= 32, "not enough bytes in the array");
assembly {
// Allocate 32 bytes from the free memory pointer
let buffer := mload(0x40)
// Increase the free memory pointer to account for our buffer
mstore(0x40, add(buffer, 0x20))
// Loop _count times over the array
for { let i := 0} lt(i, _count) { i := add(i, 1) } {
// Make use of mstore8 (1 byte) instead of mstore (32 bytes)
mstore8(add(buffer, i), 0x33)
}
result := mload(buffer)
// Decrease the free memory pointer to account for our buffer
mstore(0x40, sub(buffer, 0x20))
}
return result;
}
}
bytes1throughbytes32local variables are stored on the stack, not in memory, so they cannot be manipulated withmstore.bytes memory bytesTest;is stored in memory. – Jesbus Feb 03 '22 at 19:37SHL,SHR,OR,AND,BYTEto manipulate a value on the stack byte by byte. You don't need assembly to do that. Nota bene:mstorewrites 32 bytes of data to memory.mstore8can be used to only write a single byte. – Jesbus Feb 04 '22 at 10:02