1

In x86, I understand multi-byte objects are stored in memory little endian style.

Now generally speaking, when it comes to CPU instructions, the OPCODE determines the purpose of the instruction and data/memory addresses may follow the opcode in it's encoded format. My understanding is the Opcode portion of the instruction should be the most significant byte and thus appear at the highest address of any given instruction encoding representation.

Can someone explain the memory layout on this x86 linux gdb example? I would imagine that the opcode 0xb8 would appear at a higher address due to it being the most significant byte.

(gdb) disassemble _start

Dump of assembler code for function _start:
0x08048080 <+0>:    mov    eax,0x11223344

(gdb) x/1xb _start+0
0x8048080 <_start>:     0xb8
(gdb) x/1xb _start+1
0x8048081 <_start+1>:   0x44
(gdb) x/1xb _start+2
0x8048082 <_start+2>:   0x33
(gdb) x/1xb _start+3
0x8048083 <_start+3>:   0x22
(gdb) x/1xb _start+4
0x8048084 <_start+4>:   0x11

It appears the instruction mov eax, 0x11223344 is encoding as 0x11 0x22 0x33 0x44 0xb8.

Questions.

1.) How does the CPU know how many bytes the instruction will take up if the first byte it see's is not an opcode?

2.) I'm wondering if perhaps x86 cpu instructions do not even have endian-ness and are considering some type of string? (probably way off here)

htederson
  • 11
  • 1
  • 1
    #2 is correct. Instructions don't have endianness, although constants embedded in them do. As you can see in your gdb dump, the opcode **is** the first byte (but it may be preceded by prefix bytes). See also _Intel® 64 and IA-32 Architectures Software Developer's Manual Volume 2: Instruction Set Reference, A-Z, CHAPTER 2 INSTRUCTION FORMAT_ – Jester Jul 20 '16 at 00:30
  • I may be confusing multi-byte integers with a CPU instruction comprising more than one byte when it comes to the memory representation – htederson Jul 20 '16 at 00:31
  • Thanks Jester for pointing out that the opcode *is* the first byte of the encoded instruction, that one slipped by me. – htederson Jul 20 '16 at 00:34
  • `How does the CPU know how many bytes the instruction will take up` there were tons of answers for that on this site already – phuclv Jul 22 '16 at 07:44
  • Near duplicate: [How does the CPU know how many bytes it should read for the next instruction, considering instructions have different lenghts?](https://stackoverflow.com/q/56385995), and re: endianness: [How to interpret objdump disassembly output columns?](https://stackoverflow.com/q/60905135) – Peter Cordes Mar 06 '21 at 03:17

1 Answers1

5

x86 is a variable length instruction set, you start with a single byte which has no endianness, it is wherever it is.

Then depending on the opcode there may be more bytes and those might for example be a 32 bit immediate, and (if that group of bytes is an immediate or address of some sort) THOSE bytes will be little endian. Say you have the five bytes ABCDE (no endianess, think array or string). The A byte is the opcode, the B byte would then be the lower 8 bits of the immediate and the E the upper 8 bits of the immediate.

Opcode is a hard to use term, in these older 8/16 bit CISC processors like x86 the entire byte was an opcode that you basically looked up in a table to see what it meant (and inside the processor they did use a table to figure out how to execute it). When you look at MIPS or ARM or other (certainly RISC) instruction sets like those, only a portion of the 32 bits are the "opcode" and in neither of those cases is it the same set of bits from one instruction to another, you have to look at various places in the instruction (yes there is overlap to make the decoding sane), MIPS is a lot more consistent you have one blob in one place you look at but one of those patterns requires you to look at another blob of bits to fully decode. ARM you start at a common bit and as you work your way across you are further decoding the instruction, then you may have to grab some random looking spots to fully decode. The rest of the bits are operands, what register to use or immediate or whatever the kind of thing that in a CISC you needed a look up table for (are implied by the opcode but not defined by bits in the opcode).

1) the next byte after the prior instruction will be interpreted as an opcode even if not intended to be one (if execution continues to that byte and doesnt branch). I dont remember my x86 table off hand to know if there are any undefined instructions or not, if undefined then it will hit a handler, otherwise it will decode what it finds as machine code and if it is not properly formed instructions will likely crash, sometimes you get lucky and it just messes something up and keeps going, or even more lucky and you cant tell that it almost crashed.

2) you are right for these 8/16 bit CISC or similar instruction sets they are treated more like strings that you parse through linearly.

old_timer
  • 69,149
  • 8
  • 89
  • 168
  • Yes I am well aware that ARM and MIPS have 16 bit alternate instruction sets within some of their cores, and ARM even worse with a variable length 16 bit instruction set (thumb2 extensions to thumb). Plus all the floating point stuff, maybe a JAVA thing, etc. For explanation purposes above just talking about a fixed 32 bit instruction is fine. If you do some googling you should find the encodings for mips and arm and perhaps you can "see" how they decode, they both have different approaches to their design. – old_timer Jul 20 '16 at 01:48
  • Thank you dwelch, I appreciate your insight. – htederson Jul 20 '16 at 22:47
  • I guess I may not have answered question 1). How the cpu knows is the opcode it reads does tell it. it knows from the opcode and/or additional bytes that follow how many total bytes it will need for that instruction. It is variable length so some instructions are as short as one byte and others can be relatively long. I think the question of what is the longest intel instruction has been asked multiple times, not that interesting IMO but some folks played along. – old_timer Jul 20 '16 at 22:53
  • you are IMO basically right on track. The opcode tells the story, things like immediates and addresses and offsets that follow are little endian. but they are treated like little strings of bytes they are not aligned on any boundaries as they vary in length depending on the instruction and the options for that instruction. The intel documentation lays this out, the docs are easy to come by online or in print. – old_timer Jul 20 '16 at 22:55
  • So when we transfer a word of data from memory into register EAX, the LSB of that word (lowest address) is transferred into the low 8 bits of EAX.. simply AL. Is the CPU's instruction register similiar in that it transfers an instruction into it and the "most significant byte" of the Instruction Register refers to the Opcode of the instruction transferred in? – htederson Jul 21 '16 at 02:22
  • sure that is what your example demonstrated yes? You wanted the 32 bit value 0x11223344 in EAX or 0x44 in al 0x33 in ah, 0x3344 in AX. And the encoding was an opcode then the four immediate bytes in little endian order. right? – old_timer Jul 21 '16 at 02:27
  • there isnt an instruction register nor does it have most significant bytes. instructions are just bytes in memory just like a string, visualize them being pulled into the processor one byte at a time in order. examine the opcode which tells you what the next thing you need to do is, in this case one byte tells you to suck in the next four from memory and feed them to EAX, then examine the next byte after those five and see what that opcode says to do. I see your confusion, there isnt necessarily an instruction register. – old_timer Jul 21 '16 at 02:29
  • If/when you google for the information you are after, you will see that some instructions it may take more than just one byte to describe what action you want the processor to do, and then as needed after that there may be some what I am calling immediate values. In your example 0x11223344 is an immediate value. – old_timer Jul 21 '16 at 02:32