When objdump -S my_program, usually I can see the following indirect jmp instruction, which is typically used for switch/case jump table:
ffffffff802e04d3: ff 24 d5 38 2e 10 81 jmpq *-0x7eefd1c8(,%rdx,8)
How to understand the address -0x7eefd1c8? It means the table's base address is 0xffffffff802e04d3 - 0x7eefd1c8?
Also, how can I get -0x7eefd1c8 from ff 24 d5 38 2e 10 81?
decoding issue
Than you have to look at Intel Development Manuals
ff is JMP opcode (Jump near, absolute indirect) [1]
24 is a ModR/M byte [2] which means that SIB byte goes after it (JMP opcode has only one operand, so register field is ignored)
d5 is a SIB byte [2] which means that disp32 goes after that, Scale = 8 and Index = %rdx (in 32-bit mode, Index should be %edx) with no base.
38 2e 10 81 is a 4-byte disp32 operand. If you encode it as double word, you will get 0x81102e38 note that highest bit is set to 1. It is a sign bit meaning that value is encoded in Two’s Complement Encoding [3].
Converting from two's complement gives us expected number:
>>> print hex(0x81102e38 - (1 << 32))
-0x7eefd1c8
When processor executes that instruction in 64-bit mode, it reads 8 bytes from 0xffffffff81102e38 + (%rdx * 8) (original number is sign-extended) and puts that quad word into %rip [4].
References to manuals:
Vol.2A, section 3.2 INSTRUCTIONS (A-M), page 3-440
Vol 2, section 2.1.5 Addressing-Mode Encoding of ModR/M and SIB Bytes, pages 2-6..2-7
Vol 1, section 4.2.1.2 Signed Integers, page 4-4
Vol 2, section 2.2.1.3 Displacement, page 2-11
Related
Code to convert from Fahrenheit to Celsius.
Input 100.0f Stored in the x8 integer register.
Output in the f0 register.
What is the error in the code?
Trying to implement the formula: Output = (100.0-32.0)*(5.0/9.0)
_start:
li x5,0x40a00000 # floating point representation of 5 in hex as per IEEE 754 notation. Storing in x5.
li x6, 0x41100000 # floating point representation of 9 in hex as per IEEE 754 notation. Storing in x6.
li x7, 0x42000000 # floating point representation of 32 in hex as per IEEE 754 notation. Storing in x7.
li x8, 0x42c80000 # floating point representation of 100 in hex as per IEEE 754 notation. Storing in x8. This is the input.
flw f0,0(x5) # Storing the value 5.0 in the floating point register f0
flw f1,0(x6) # Storing the value 9.0 in the floating point register f1
flw f2,0(x8) # Storing the value 100.0 in the floating point register f2
fdiv.s f0, f0, f1 # storing the value 5.0/9.0 in the register f0
flw f1, 0(x7) # storing the value 32.0 in the register f1.
fsub.s f2, f2, f1 # f2 = 100.0f – 32.0f = 68.0f
fmul.s f0, f0, f2 # f0 = 68.0f*(5.0f/9.0f) This is the output.
Compile Command:
~/spiking$ riscv64-unknown-elf-gcc -nostdlib -nostartfiles -T spike.lds faren.S -o faren.elf**
The flw instruction is used to load a floating-point value from memory. In your case, you use x5 as a pointer (which isn't what you intended).
To move the bits untouched from an X register to a floating-point register you can use fmv.w.x.
The following code is from BPF filters (Berkley Packet Filters). in the first line, ldh [12], it loads [12] something of a packet but documentation of BPF filter says ldh is used to load a half word of a packet and in third line it loads [23] something of a packet but documentation says ldb is used to a load byte . I like to know what is 12 and 23 along with ldh and ldb respectively.
ldh [12]
jne #0x800, drop
ldb [23]
jneq #6, drop
ret #-1
drop: ret #0
the above code only allow tcp packets to enter into the tcp-ip stack(socket).
Explanation of BPF filters https://www.kernel.org/doc/Documentation/networking/filter.txt
In addition to pchaigno's answer, here is an explanation on the concrete values that your program loads.
In your case the program processes the packet starting from the Layer 2 (Ethernet) (other socket families/types can start at layer 3 or 4 headers). It goes like this:
ldh [12] # Load two bytes at offset 12
# Offset 12 is the 2-byte long Ethertype field of the
# Ethernet header
jne #0x800, drop # If those two bytes are not 0x800
# (i.e. packet is not IPv4), go to “drop”
ldb [23] # Load one byte at offset 23
# Offset 23 is offset 9 in the IPv4 header
# (23 minus 14 bytes for the Ethernet header)
# This is the 1-byte long Protocol field
jneq #6, drop # Load Protocol number, if different from 6
# (IANA number for TCP), go to “drop”
ret #-1 # Keep packet
drop: ret #0 # Drop packet (“truncate to 0 length”)
12 and 23 are offsets into the packet. So ldh [12] loads a half word at offset 12 in the packet.
This is referred to as the "Addressing mode" in the documentation and, in this case, the bytecode is using the "Addressing mode 1".
I have been working on string encoding schemes and while I examine how UTF-16 works, I have a question. Why using complex surrogate pairs to represent 21 bits code point? Why not to simply store the bits in the first code unit and the remaining bits in the second code unit? Am I missing something! Is there a problem to store the bits directly like we did in UTF-8?
Example of what I am thinking of:
The character '🙃'
Corresponding code point: 128579 (Decimal)
The binary form: 1 1111 0110 0100 0011 (17 bits)
It's 17-bit code point.
Based on UTF-8 schemes, it will be represented as:
240 : 11110 000
159 : 10 011111
153 : 10 011001
131 : 10 000011
In UTF-16, why not do something looks like that rather than using surrogate pairs:
49159 : 110 0 0000 0000 0111
30275 : 01 11 0110 0100 0011
Proposed alternative to UTF-16
I think you're proposing an alternative format using 16-bit code units analogous to the UTF-8 code scheme — let's designate it UTF-EMF-16.
In your UTF-EMF-16 scheme, code points from U+0000 to U+7FFF would be encoded as a single 16-bit unit with the MSB (most significant bit) always zero. Then, you'd reserve 16-bit units with the 2 most significant bits set to 10 as 'continuation units', with 14 bits of payload data. And then you'd encode code points from U+8000 to U+10FFFF (the current maximum Unicode code point) in 16-bit units with the three most significant bits set to 110 and up to 13 bits of payload data. With Unicode as currently defined (U+0000 .. U+10FFFF), you'd never need more than 7 of the 13 bits set.
U+0000 .. U+7FFF — One 16-bit unit: values 0x0000 .. 0x7FFF
U+8000 .. U+10FFF — Two 16-bit units:
1. First unit 0xC000 .. 0xC043
2. Second unit 0x8000 .. 0xBFFF
For your example code point, U+1F683 (binary: 1 1111 0110 0100 0011):
First unit: 1100 0000 0000 0111 = 0xC007
Second unit: 1011 0110 0100 0011 = 0xB643
The second unit differs from your example in reversing the two most significant bits, from 01 in your example to 10 in mine.
Why wasn't such a scheme used in UTF-16
Such a scheme could be made to work. It is unambiguous. It could accommodate many more characters than Unicode currently allows. UTF-8 could be modified to become UTF-EMF-8 so that it could handle the same extended range, with some characters needing 5 bytes instead of the current maximum of 4 bytes. UTF-EMF-8 with 5 bytes would encode up to 26 bits; UTF-EMF-16 could encode 27 bits, but should be limited to 26 bits (roughly 64 million code points, instead of just over 1 million). So, why wasn't it, or something very similar, adopted?
The answer is the very common one – history (plus backwards compatibility).
When Unicode was first defined, it was hoped or believed that a 16-bit code set would be sufficient. The UCS2 encoding was developed using 16-bit values, and many values in the range 0x8000 .. 0xFFFF were given meanings. For example, U+FEFF is the byte order mark.
When the Unicode scheme had to be extended to make Unicode into a bigger code set, there were many defined characters with the 10 and 110 bit patterns in the most significant bits, so backwards compatibility meant that the UTF-EMF-16 scheme outlined above could not be used for UTF-16 without breaking compatibility with UCS2, which would have been a serious problem.
Consequently, the standardizers chose an alternative scheme, where there are high surrogates and low surrogates.
0xD800 .. 0xDBFF High surrogates (most signicant bits of 21-bit value)
0xDC00 .. 0xDFFF Low surrogates (less significant bits of 21-bit value)
The low surrogates range provides storage for 10 bits of data — the prefix 1101 11 uses 6 of 16 bits. The high surrogates range also provides storage for 10 bits of data — the prefix 1101 10 also uses 6 of 16 bits. But because the BMP (Basic Multilingual Plane — U+0000 .. U+FFFF) doesn't need to be encoded with two 16-bit units, the UTF-16 encoding subtracts 1 from the high order data, and can therefore be used to encode U+10000 .. U+10FFFF. (Note that although Unicode is a 21-bit encoding, not all 21-bit (unsigned) numbers are valid Unicode code points. Values from 0x110000 .. 0x1FFFFF are 21-bit numbers but are not a part of Unicode.)
From the Unicode FAQ — UTF-8, UTF-16, UTF-32 & BOM:
Q: What’s the algorithm to convert from UTF-16 to character codes?
A: The Unicode Standard used to contain a short algorithm, now there is just a bit distribution table. Here are three short code snippets that translate the information from the bit distribution table into C code that will convert to and from UTF-16.
Using the following type definitions
typedef unsigned int16 UTF16;
typedef unsigned int32 UTF32;
the first snippet calculates the high (or leading) surrogate from a character code C.
const UTF16 HI_SURROGATE_START = 0xD800
UTF16 X = (UTF16) C;
UTF32 U = (C >> 16) & ((1 << 5) - 1);
UTF16 W = (UTF16) U - 1;
UTF16 HiSurrogate = HI_SURROGATE_START | (W << 6) | X >> 10;
where X, U and W correspond to the labels used in Table 3-5 UTF-16 Bit Distribution. The next snippet does the same for the low surrogate.
const UTF16 LO_SURROGATE_START = 0xDC00
UTF16 X = (UTF16) C;
UTF16 LoSurrogate = (UTF16) (LO_SURROGATE_START | X & ((1 << 10) - 1));
Finally, the reverse, where hi and lo are the high and low surrogate, and C the resulting character
UTF32 X = (hi & ((1 << 6) -1)) << 10 | lo & ((1 << 10) -1);
UTF32 W = (hi >> 6) & ((1 << 5) - 1);
UTF32 U = W + 1;
UTF32 C = U << 16 | X;
A caller would need to ensure that C, hi, and lo are in the appropriate ranges. [
so this book "assembly language step by step" is really awesome, but it was sort of cryptic about how two's complement works when working on actual memory and register data. along with that, i'm not sure how signed values are represented in memory either, which i feel might be what's keeping me confused. anywho...
it says: "-1 = $FF, -2 = $FE and so on". now i understand that the two's complement of a number is itself multiplied by -1 and when added to the original will give you 0. so, FF is the hex equivalent of 11111111 in binary, and 255 in decimal. so my question is: what's the book saying when it says "-1 = $FF"? does it mean that -255 + -1 will give you 0 but also, which it didn't explicitly, set the OF flag?
so in practice... let's say we have 11h, which is 17 in decimal, and 00100001 in binary. and this value is in AL.
so then we NEG AL, and this will set the CF and SF, and change the value in AL to... 239 in decimal, 11101111 in binary, or EFh? i just don't see how that would be 17 * -1? or is that just a poorly worded explanation by the book, where it really means that it gives you the value you would need to cause an overflow?
thanks!
In two's complement, for bytes, (-x) == (256 - x) == (~x + 1). (~ is C'ish for the NOT operator, which flips all the bits in its operand.)
Let's say we have 11h.
100h - 11h == EFh
(256 - 17 == 239)
Note, the 256 works with bytes, cause they're 8 bits in size. For 16-bit words you'd use 2^16 (65536), for dwords 2^32. Also note that all math is mod 256 for bytes, 65536 for shorts, etc.
Or, using not/+1,
~11h = EEh
+1... EFh
This method works for words of all sizes.
what's the book saying when it says "-1 = $FF"?
If considering a byte only, the two's complement of 1 is 0xff (or $FF if using that format for hex numbers).
To break it down, the complement (or one's complement) of 1 is 0xfe, then you add 1 to get the two's complement: 0xff
Similarly for 2: the complement is 0xfd, add 1 to get the two's complement: 0xfe
Now let's look at 17 decimal. As you say, that's 0x11. The complement is 0xee, and the two's complement is 0xef - all that agrees with what you stated in your question.
Now, experiment with what happens when you add the numbers together. First in decimal:
17 + (-17) == 0
Now in hex:
0x11 + 0xef == 0x100
Since we're dealing with numeric objects that are only a byte in size, the 1 in 0x100 is discarded (some hand waving here...), and we result in:
0x11 + 0xef == 0x00
To deal with the 'hand waving' (I probably won't do this in an understandable manner, unfortunately): since the overflow flag (OF or sometimes called V for reasons that I don't know) is the same as the carry flag (C) the carry can be ignored (it's an indication that signed arithmetic occurred correctly). One way to think of it that's probably not very precise, but I find useful, is that leading ones in a negative two's complement number are 'the same as' leading zeros in a non-negative two's complement number.
If a server received a base64 string and wanted to check it's length before converting,, say it wanted to always permit the final byte array to be 16KB. How big could a 16KB byte array possibly become when converted to a Base64 string (assuming one byte per character)?
Base64 encodes each set of three bytes into four bytes. In addition the output is padded to always be a multiple of four.
This means that the size of the base-64 representation of a string of size n is:
ceil(n / 3) * 4
So, for a 16kB array, the base-64 representation will be ceil(16*1024/3)*4 = 21848 bytes long ~= 21.8kB.
A rough approximation would be that the size of the data is increased to 4/3 of the original.
From Wikipedia
Note that given an input of n bytes,
the output will be (n + 2 - ((n + 2) %
3)) / 3 * 4 bytes long, so that the
number of output bytes per input byte
converges to 4 / 3 or 1.33333 for
large n.
So 16kb * 4 / 3 gives very little over 21.3' kb, or 21848 bytes, to be exact.
Hope this helps
16kb is 131,072 bits. Base64 packs 24-bit buffers into four 6-bit characters apiece, so you would have 5,462 * 4 = 21,848 bytes.
Since the question was about the worst possible increase, I must add that there are usually line breaks at around each 80 characters. This means that if you are saving base64 encoded data into a text file on Windows it will add 2 bytes, on Linux 1 byte for each line.
The increase from the actual encoding has been described above.
This is a future reference for myself. Since the question is on worst case, we should take line breaks into account. While RFC 1421 defines maximum line length to be 64 char, RFC 2045 (MIME) states there'd be 76 char in one line at most.
The latter is what C# library has implemented. So in Windows environment where a line break is 2 chars (\r\n), we get this: Length = Floor(Ceiling(N/3) * 4 * 78 / 76)
Note: Flooring is because during my test with C#, if the last line ends at exactly 76 chars, no line-break follows.
I can prove it by running the following code:
byte[] bytes = new byte[16 * 1024];
Console.WriteLine(Convert.ToBase64String(bytes, Base64FormattingOptions.InsertLineBreaks).Length);
The answer for 16 kBytes encoded to base64 with 76-char lines: 22422 chars
Assume in Linux it'd be Length = Floor(Ceiling(N/3) * 4 * 77 / 76) but I didn't get around to test it on my .NET core yet.
Also it would depend on actual character encoding, i.e. if we encode to UTF-32 string, each base64 character would consume 3 additional bytes (4 byte per char).