I've come across this sequence of bytes: 2e 88 38.

Hopper disassembles this as:

mov    byte [cs:rax], bh

This online disassembler gives slightly different output:

mov    BYTE PTR cs:[rax],bh 

Either way, I can't make heads nor tails of what the intended result of this instruction is.

  • 1
    I think it's the same meaning with slightly different syntax. Commented Jul 1, 2021 at 12:50
  • @macro_controller That was my assumption, but given I couldn't tell what either meant I didn't want to jump to that conclusion and leave something potentially important out of the question
    – MTCoster
    Commented Jul 1, 2021 at 13:08
  • It might not even be a valid instruction -- that is to say, does it make sense in the context of the surrounding instructions, or are they nonsensical? Commented Jul 2, 2021 at 7:23

2 Answers 2


In 16- and 32-bit modes the memory accesses used the ds or ss registers, but by using segment override, you could force usage of another segment (selector in protected mode). For example, in 16-bit real mode

 mov bx, [si]

Would access the address ds*16 + si


 mov bx, cs:[si]

Would access cs*16+si

The distinction was less useful in most 32-but OSes, which usually set up memory so that cs, ds, es, ss all pointed to the same flat 32-bit memory space although in theory they could be different (and often they did have different permissions). In 64-bit mode the segment registers are even less useful - in it the segment overrides are officially ignored except for fs and gs.

So in your example the cs prefix (2e) is completely redundant and serves no useful purpose: the instruction has the same effect as

mov  byte [rax], bh

However the disassembler still prints cs: to show that the prefix is present in the instruction.


char * rax; = bh
or byte* rax = bh or simply mov the [8..16] bit component of rbx register into the address pointed by 64 bit register rax at [0..7] bit place and zero out the remaining bits

or in other words if address 12345678`9abcdef contains 0x0

and register rbx contains 0x00000000`0000ffff

then after this operation address 12345678`9abcdef will contain 0xff

see below a simulation of operation with windbg

0:000> ? @rip
Evaluate expression: 140705686294668 = 00007ff8`9873108c
0:000> dq @rip l1
00007ff8`9873108c  c338c483`4800ebcc
0:000> r @rax = @rip
0:000> r @rbx = 0xffff
0:000> r @bh
0:000> eq @rax
00007ff8`9873108c c338c483`4800ebcc @bh
00007ff8`98731094 cccccccc`cccccccc
0:000> dq @rip l1
00007ff8`9873108c  00000000`000000ff

and cs, ds, es , ss segment registers do not matter much in flat memory model.

only fs and gs segment registers matters

a sample code that demonstrates the write using various segment prefixes in x64
ml64 wont encode the instruction so need to emit raw bytes using define byte

c code with inline assembly usage follows

cpp file

:\>type inline_cpp.cpp

#include <windows.h>
extern "C" void segregtest(ULONG64 *addr ,BYTE value);
ULONG64 myaddr = 0x77;
int main (void)
        return 0;


:\>type inline_asm.asm
PUBLIC segregtest
segregtest PROC
mov rax,rcx
mov bh,dl
db 2Eh
mov byte ptr [rax] ,    bh
add bh,11h
db 3Eh
mov byte ptr [rax] ,    bh
add bh,11h
db 36h
mov byte ptr [rax] ,    bh
add bh,11h
db 26h
mov byte ptr [rax] ,    bh
add bh,11h
db 64h
mov byte ptr [rax] ,    bh
add bh,11h
db 65h
mov byte ptr [rax] ,    bh
segregtest ENDP

compile link with

:\>type assemble_compile_link.bat
ml64 /c /Zi /nologo %1_asm.asm

cl /Zi /W4 /Od /analyze /nologo /GS- /EHsc %1_cpp.cpp /link /release /subsystem:windows /fixed /entry:main %1_asm.obj

execution and tracing

:\>assemble_compile_link.bat inline

:\>cdb -c "g inline_cpp!segregtest;t 10;q" inline_cpp.exe | awk /Reading/,/quit/
0:000> cdb: Reading initial command 'g inline_cpp!segregtest;t 10;q'
00000001`40001003 8afa            mov     bh,dl
00000001`40001005 2e8838          mov     byte ptr cs:[rax],bh cs:00000001`40003000=77
00000001`40001008 80c711          add     bh,11h
00000001`4000100b 3e8838          mov     byte ptr ds:[rax],bh ds:00000001`40003000=88
00000001`4000100e 80c711          add     bh,11h
00000001`40001011 368838          mov     byte ptr ss:[rax],bh ss:00000001`40003000=99
00000001`40001014 80c711          add     bh,11h
00000001`40001017 268838          mov     byte ptr es:[rax],bh es:00000001`40003000=aa
00000001`4000101a 80c711          add     bh,11h
00000001`4000101d 648838          mov     byte ptr fs:[rax],bh fs:00000001`40003000=bb
00000001`40001020 80c711          add     bh,11h
00000001`40001023 658838          mov     byte ptr gs:[rax],bh gs:00000001`40003000=cc
(1b44.cf8): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
  • "and cs ds es segemtn registers do not matter much in flat memory model" - This is the part my question was about - I understand the mov instruction works usually, what I can't figure out (or search for apparently) is what [cs:rax] (or cs:[rax]) means
    – MTCoster
    Commented Jul 1, 2021 at 21:06
  • added a snippet that shows usage
    – blabb
    Commented Jul 2, 2021 at 18:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.