2

Suppose I have defined a byte in .data called val. Suppose also that I have a number in register r10, let's say it is 12.

I am trying to get a 2s compliment of the number in the r10 and store it for future use in val.

So I do this:

neg r10
mov [val], r10b

But when I try to use the value in val later (or prod around with a debugger), it gets stored and treated as an unsigned value, so if r10 was -12, val is now 244, which is the unsigned equivalent.

How can I move the register to memory while preserving the sign? Alternatively, how do I set the sign after I move that memory back to a different register?

fuz
  • 88,405
  • 25
  • 200
  • 352
Cirno
  • 33
  • 4
  • 4
    As an 8 bit number, 244 unsigned is the same as -12 signed. The sign is preserved. You need to remember whether a number in memory is meant to be interpreted as signed or unsigned. – fuz Oct 22 '20 at 12:37
  • That would make sense, but in that case, if i know that the value is meant to be interpreted as signed, how would I store it back to the register and let the CPU know that? Let's say i move the value to another register later and want to add that negative number to the value of another register, resulting in a subtraction? If i were to do it as is, I'd be adding 244 most likely resulting in 8 bit overflow. – Cirno Oct 22 '20 at 12:42
  • 1
    Are you perhaps related to [this guy](https://stackoverflow.com/questions/64477750/treating-assembly-registers-as-unsigned-vs-signed) who asked a very similar question? – fuz Oct 22 '20 at 12:42
  • Not at all related, but useful to look at answers there too, I couldn't find similar questions when looking around. – Cirno Oct 22 '20 at 12:44
  • 1
    The trick about additions and subtractions is that they work the same way for signed and unsigned numbers, so the instruction doesn't need to know whether the numbers are signed or not. The CPU even tracks unsigned and signed overflow separately in the CF and OF flags. One thing that might be useful is *sign/zero extension,* an operation where a number of a small word size is converted to one of a larger word size while keeping the sign intact (or inserting zero bits). For example, to convert a signed number in `al` into a signed number in `eax`, use `movsx eax, al`. – fuz Oct 22 '20 at 12:44
  • Now that I think about it, you are right. What about testing if the number is negative? When I attempted to use `test` to test the sign bit on the recalled negative number, it would never jump to the label given by `js` – Cirno Oct 22 '20 at 12:46
  • After each ALU operation, the sign flag SF is set to the sign of the result. You can do so manually with `test` if the number in question was not the result of the last ALU operation. Then use `js`/`jns` to jump on the value of the sign flag. – fuz Oct 22 '20 at 12:48
  • 1
    If you have trouble with that, please post the relevant code snippet. I suppose the problem might be you using operations of the wrong data size; as I said, numbers must be extended to a higher data size if you want to add them to numbers of another data size. You make the same mistake with `neg r10` (a 64 bit negation) when your datum is an 8 bit number. `neg r10b` would have been clearer. – fuz Oct 22 '20 at 12:50
  • "it gets stored and treated as an unsigned value" -- by whom? The debugger printing them, perhaps, not necessarily by the program itself. The debugger is not an authority on how the program will interpret the values. The authority is the program and its upcoming instructions. – Erik Eidt Oct 22 '20 at 13:02
  • Makes sense, I was testing the entire register where I should have only tested the lower 8 bytes. Thanks for the help, the picture is clear now. – Cirno Oct 22 '20 at 13:03

1 Answers1

0

A signed 8-bit integer, i.e. -12 is stored as 244. When you try to read the value with a debugger, it will treat the number as an unsigned byte and will show 244. If you tell your debugger to treat the memory as signed bytes, it will work properly.

sb27
  • 382
  • 4
  • 14
  • While this is not directly related to the question, how does one tell gdb to show memory as a signed byte? Right now, to see what's in `val` I am doing `p (int)val`, and that returns an unsigned value back. – Cirno Oct 22 '20 at 12:54
  • 4
    @Cirno That's because your value is not an `int`. An `int` has 4 bytes, but `val` has only one. Try `p (char)val`. – fuz Oct 22 '20 at 12:55