flat assembler
Message board for the users of flat assembler.

Index > Main > Signed integers?

Author
Thread Post new topic Reply to topic
Tabaci



Joined: 26 Apr 2018
Posts: 6
Location: Sweden
Tabaci 15 May 2018, 07:48
As far as I've understood it, integers are unsigned by default; I haven't managed to get around that yet. What I remember from an x86 Assembly class, is that a signed integer is the "two's complement?" of any given unsigned integer. Then, once you have that signed integer, you would use the `imul` and `idiv` instructions to multiply and divide it, howbeit `add` and `sub` would work like they normally do.

After doing some research on the web, I've seen some people stating that no conversion is necessary at all. But when I attempt to write a number preceded by a `-` and then print it out with the C interface's `printf` function utilizing the `%d`, `-1` turns into `255`. Frankly, for an unsigned integer that would make impeccable sense.

Code:
; I'm making a very basic compiler; that's why it's pushed onto the stack first
; the `-12` might need to be treated in the form of an equation
push -12
pop eax
    


Is there an instruction to convert an unsigned integer into a signed integer? Is it already a signed integer; do I need to treat it differently in the code if I'm to use it as a signed integer?

Best regards,

_________________
My sandwich: it was reduced to dust, I tell you. It was pulverized!
Post 15 May 2018, 07:48
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20459
Location: In your JS exploiting you and your system
revolution 15 May 2018, 08:20
In assembly all register values are just numbers. There is no notion of signed or unsigned. It is up to the program to determine how that number is treated. Some instructions can treat a number as signed (like imul and idiv) and others treat it as unsigned (mul & div). And other instructions are agnostic (add & sub).

When you want to convert a number to decimal as a string, then you have to tell printf how to treat the number. Something like %d/%u/%i will tell printf how you want the number printed.
Post 15 May 2018, 08:20
View user's profile Send private message Visit poster's website Reply with quote
Furs



Joined: 04 Mar 2016
Posts: 2572
Furs 15 May 2018, 12:20
Tabaci wrote:
Is there an instruction to convert an unsigned integer into a signed integer? Is it already a signed integer; do I need to treat it differently in the code if I'm to use it as a signed integer?
255 is a signed 8-bit integer, but printf expects a 32-bit arg (or 64-bit if x64).

-1 as 32-bit is not 0x000000FF -- that's 255, as you got. You need to "propagate" the sign bit of the 8-bit int over all the higher bits, this is called "sign extension", and there is an instruction to do it:
Code:
movsx eax, al    
Converts 0x000000FF to 0xFFFFFFFF, which is -1.

There's also zero extension (for unsigned numbers) where the higher bits are simply set to zeros, not the former sign bit's value. That's movzx.

Of course, nothing stops you from using movzx on a "signed" integer, you just won't get what you expect, but it's perfectly valid, there's no such thing as "signed" integer type for the CPU, just instructions performing sign-extension, zero-extension, or whatever.
Post 15 May 2018, 12:20
View user's profile Send private message Reply with quote
DimonSoft



Joined: 03 Mar 2010
Posts: 1228
Location: Belarus
DimonSoft 15 May 2018, 19:01
revolution wrote:
In assembly all register values are just numbers.

A tiny correction: any values are not even numbers but just sets of bits grouped/accessed together. Signed/unsigned, number/character/handle/color/float — all of these are just ways to interpret values formed by such bits.
Post 15 May 2018, 19:01
View user's profile Send private message Visit poster's website Reply with quote
rugxulo



Joined: 09 Aug 2005
Posts: 2341
Location: Usono (aka, USA)
rugxulo 15 May 2018, 21:07
Tabaci wrote:
As far as I've understood it, integers are unsigned by default;


Sometimes the term "integer" is misused.

Wikipedia wrote:

An integer (from the Latin integer meaning "whole") is a number that can be written without a fractional component. For example, 21, 4, 0, and −2048 are integers, while 9.75, ​5 1⁄2, and √2 are not.


Old K&R C didn't barely have unsigned (except for int?), but eventually that was allowed for various ordinal types. J&W Pascal was only integer and subranges thereof. Modula-2 added CARDINAL (unsigned) because it was originally a 16-bit implementation, and that was needed for addressing. But it complicated type compatibility, so when Oberon was introduced, since it was 32-bit, they went back to INTEGER (also SHORTINT, LONGINT) "type inclusion" to simplify things again. I think newer Oberon-07 might sometimes have some unsigned stuff in SYSTEM pseudo-module.

Tabaci wrote:

After doing some research on the web, I've seen some people stating that no conversion is necessary at all. But when I attempt to write a number preceded by a `-` and then print it out with the C interface's `printf` function utilizing the `%d`, `-1` turns into `255`. Frankly, for an unsigned integer that would make impeccable sense.


Probably some b.s. regarding unary operator or such. Make sure you're using the right format string syntax (see here).

(Frankly, this is one of several things that Pascal and derivatives don't have a problem with, their data typing is stricter.)

Tabaci wrote:

Is there an instruction to convert an unsigned integer into a signed integer? Is it already a signed integer; do I need to treat it differently in the code if I'm to use it as a signed integer?


old NASM 0.98.39 doc wrote:

B.4.181 `MOVSX', `MOVZX': Move Data with Sign or Zero Extend

MOVSX reg16,r/m8 ; o16 0F BE /r [386]
MOVSX reg32,r/m8 ; o32 0F BE /r [386]
MOVSX reg32,r/m16 ; o32 0F BF /r [386]

MOVZX reg16,r/m8 ; o16 0F B6 /r [386]
MOVZX reg32,r/m8 ; o32 0F B6 /r [386]
MOVZX reg32,r/m16 ; o32 0F B7 /r [386]

`MOVSX' sign-extends its source (second) operand to the length of
its destination (first) operand, and copies the result into the
destination operand. `MOVZX' does the same, but zero-extends rather
than sign-extending.
Post 15 May 2018, 21:07
View user's profile Send private message Visit poster's website Reply with quote
Furs



Joined: 04 Mar 2016
Posts: 2572
Furs 16 May 2018, 20:21
Ok, my previous post is a bit confusing when you think about C's "types", so here's a more detailed explanation.

When you use an unsigned char type (8-bit unsigned integer), the compiler assumes that the value stored in there is unsigned. So 0xFF means 255, not -1.

When you pass it to printf, it needs to convert it to 32-bit because that's what printf expects. So it converts it with movzx because it assumes 0xFF means 255, since you told it it's unsigned. Even if you place -1 in that variable, it is 0xFF, but the compiler will assume it's unsigned so 0xFF = 255, therefore convert it with movzx (i.e. 0x000000FF, zero extended).

It's all about what the compiler does with the type you gave it. The type is just information to the compiler about the uses for that variable.

The only difference if you make it signed, in this case, is the compiler will use movsx instead. You can also cast it on the spot, i.e. printf("%d", (signed char)x); will print -1 if x was 0xFF, because compiler will now generate movsx instead.

BTW, same with comparisons where sign matters: a < b converts to signed comparison only if a's type is signed.
Post 16 May 2018, 20:21
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.