Poke values reside in memory, and their in-memory representation is
not visible from Poke programs. For example, 32
is a 32-bit
signed integer value, and it happens to not be boxed in the Poke
Virtual Machine. Therefore, it occupies exactly 32-bit in the memory
of the machine running poke. Other values, like arrays for example,
are boxed, and they need to store various meta-data.
Regardless of the internal representation, we say these values live
“in memory”. Now, it is also possible to “map” a value to some
area in some underlying IO space. This is done with the map operator
@
, which has two alternate syntax:
type @ offset type @ ios : offset
The ternary version creates a new value using the data located at the offset offset in the specified IO space ios, which shall be an expression evaluating to a signed 32-bit integer.
The binary version uses the current IO space.
If there is no IO space, or the specified IO space doesn’t exist, an
E_no_ios
exception is raised:
(poke) int @ 0#B unhandled no IOS exception
The value created in a map can be either mapped or not mapped. Mapping simple types produces not mapped values, whereas mapping non-simple types create mapped values.
The value attributes mapped
and offset
can be used to
check whether a value is mapped or not, and in that case the offset
where it is mapped:
(poke) var p = Packet @ 0#B (poke) p'mapped 0x1 (poke) p'offset 0x0UL#b
Using the offset
attribute in a not mapped value results in the
E_no_map
exception being raised:
(poke) [1,2,3]'mapped 0x0 (poke) [1,2,3]'offset unhandled no map exception
If the type specified in the map is not a simple type, like an array or a struct, the resulting value is said to be mapped in the IO space:
(poke) type Packet = struct { int i; long l; } (poke) Packet @ 0#B Packet {i=0x464c457f,l=0x10102L} (poke) uint<8>[2] @ 0#B [0x7fUB,0x45UB]
A very important idea on Poke mapping is that it should be possible to manipulate mapped and non-mapped values in a transparent way. For example, consider the quick sort implementation in poke’s standard library. The prototype is:
fun qsort = (any[] array, Comparator cmp_f, long left = 0, long right = array'length - 1) void
qsort
works with both mapped and not-mapped arrays:
(poke) var a = [2,3,1] (poke) var b = int[3] @ 0#B (poke) b [1179403647,65794,0] (poke) qsort (a, IntComparator) (poke) a [1,2,3] (poke) qsort (b, IntComparator) (poke) b [0,33620224,1179403647] (poke) dump :from b'offset :size b'size :ascii 0 76543210 0011 2233 4455 6677 8899 aabb ccdd eeff 00000000: 0000 0000 0001 0102 7f45 4c46
Similarly, you can write functions that operate on abstract entities and data structures such as ELF relocations and sections, DWARF DIEs, etc, and the same code will work with non mapped and mapped values.