Can anyone explain how to typecast this datatype in nasm

Programming, for all ages and all languages.
Post Reply
Darkpony
Posts: 7
Joined: Sun Sep 24, 2017 8:21 am
Libera.chat IRC: Darkpony

Can anyone explain how to typecast this datatype in nasm

Post by Darkpony »

I want to typecast a time_t to an unsigned long. I know how to do it in c and c++. I also know how to extern it into my nasm. However, for a project I need to do it in nasm or gnu only. Is this even possible?
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: Can anyone explain how to typecast this datatype in nasm

Post by Brendan »

Hi,
Darkpony wrote:I want to typecast a time_t to an unsigned long. I know how to do it in c and c++. I also know how to extern it into my nasm. However, for a project I need to do it in nasm or gnu only. Is this even possible?
Assembly language (and the CPU itself) has no types, so type casts aren't possible.


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
User avatar
iansjack
Member
Member
Posts: 4688
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Can anyone explain how to typecast this datatype in nasm

Post by iansjack »

... or necessary.
User avatar
Schol-R-LEA
Member
Member
Posts: 1925
Joined: Fri Oct 27, 2006 9:42 am
Location: Athens, GA, USA

Re: Can anyone explain how to typecast this datatype in nasm

Post by Schol-R-LEA »

To expand on this answer: at the machine level, data in memory is just a value represented as a group of high or low electrical signals - just a byte (that is, 8 bits) or group of bytes with nothing inherent to them to indicate what those bits mean.

Pick a byte in memory. Try to guess, just based on the data alone, if the byte is...
  • an ASCII character?
  • A UTF-8 character (which often is the same thing... but not always)?
  • An EBCDIC character (not likely, but definitely different from the previous two)?
  • The first byte of a UTF-16 Unicode character?
  • The first character of a string?
  • The last character of a string?
  • A character in the middle of a string?
  • An unsigned 8-bit integer?
  • A signed 8-bit integer?
  • One byte of a larger integer?
  • One byte of a float?
  • Eight boolean flags?
  • A bitset variable, where each bit represents the present or absence of a possible member of an eight-member set domain in this particular set?
  • something else, which may well be entirely specific to what the program is doing?
In most CPUs and memory systems, there is nothing about the way that byte exists in memory that tells you (there have been some historically, but tagged memory architectures never became common, more's the pity), and nothing about it that prevents the program from trying to add, e.g., half of an IPv6 address to the last two bytes of a character string plus a zero-delimiter and five more bytes from an adjacent string, as if they were two 64-bit values - it is a meaningless action, but one the hardware will do nothing to stop the program from doing.

There are implicit types to many ALU operations, but that just means that it expects the bytes it is being applied to are ones which the it makes sense to apply them to - the instruction doesn't care if it actually is or not, it will treat it as such even if doing so is nonsensical.

I'll add some more about this in a bit, but the important part is that this was something done by the translator - the compiler or interpreter - not something done in the machine code. Different languages do it differently, but it is all in the language itself, and with compiled code in particular, often (especially in C) doesn't involve any runtime representation of the type in the generated code.

One of the things languages differ on are type casts and type compatibility. Most languages have ways to coerce or cast the type of one value to another; for this post, I'll call something that just copies the bits into a variable while ignoring the type constraints a 'coercion', and one which actually juggles the value to change its representation a 'cast'. The important thing to get here is that a cast requires runtime code inserted into the program, while a coercion, in most cases, doesn't.

OK, now that we've got that: assembly language.

The usual idea of an assembly language is to represent machine code as a series of instructions - mnemonics for the operation, plus one or more optional arguments - that are pretty close to a one-to-one match to the machine code. They generally give you a few tools for doing the grunt work of machine code programming - specifically, computing label offsets - let you give symbolic names to constants and blocks of memory (for holding the variables), handle basic things like the ORGin point of the program in memory, and maybe a macro facility to avoid repeating the same code over and over again, but usually not much else. There are exceptions to this such as 'High Level Assemblers', but the usual idea is that the assembly language be a straightforward human-readable representation of machine code.

It is possible to write an assembler that has type declarations to let you say what you have in mind explicitly, or even a type checking facility that will give you a warning if you have a mismatch, and some actually do (including Microsoft Macro Assembler, if I am not mistaken) but those are rare, and when they do have them, it is just for programmer convenience as a way to avoid mistakes. Even when they are there, there is no requirement for using them - that sort of being against the spirit of the thing - and as a rule, no one does unless they have some very specific requirement that they happen to solve.

And no assembler I am aware of does type checking on external references. Again, it could be done, but it really wouldn't make sense.

The TL;DR of this is: you don't need a type cast. You only need to know how big a time_t is for your system and compiler. From your question, I would assume you've already determined it to be an unsigned long, though I would recommend double-checking (and maybe using an explicitly-size type such as uint64_t or uint32_t instead if you have a choice - unsigned long isn't an exactly-sized type.)

IIRC, the older POSIX requirement was that time_t had to be at least 32 bits, but people noticed how bad an idea this was when the Y2K bug panic occurred in the late 1990s and they changed it to... well, I don't think it is required to be 64-bit, per se, but I am pretty sure it usually is now.

younger forum-goers asking "what's the Y2K bug?" in 3...2...1...

OK, here's some history if you want to read it - your call, but trust me, it will help explain a lot about some programming languages.

Two of the first high-level languages - FORTRAN and LISP - had no explicit types, and even today, Lisp dialects generally don't require declarations. They did actually have types, but they weren't stated as such - they were used by the compiler or interpreter to keep track of things as they were processing the code, but that was mostly to make sure that they had a big enough block of memory to hold the type and wouldn't try to add a symbol to a pointer or something.

The original FORTRAN had a pretty weaksauce method of treating variables as either integers or floats depending on the first letter of the variable's name (not chars, and originally, no complexes as well - they added complexes pretty soon, but for characters they had a bizarre system for using integer arrays as character strings, which would drive Fortran programmers (note the case) insane for over twenty years.

The original LISP had hidden type tags as part of each datum (not, take note, the variable - variables were just references, to the data, or rather, pairs of references to the variable name and the and you could still use the SET special form to change them to any data regardless of type). The type was dependent on what the literal form it read in (or was part of the program) was - if it read in a string that the READ form parsed as type xyz, it got turned into a value of that type. Since there were only three literal types at first - lists, integers, and symbols - this wasn't too hard to cope with.

Starting with IAL (a sort of Pre-Alpha Early Access version of Algol-60, with the name later retconned to Algol-58) and, in its own messed-up way, COBOL, most later high-level languages added the concept of type declarations - and type checking, and type casts - primarily to make writing the compilers easier, but also as a safety net to make it a lot less likely that a programmer would make a typo that implicitly declared a new variable with an undetermined value rather than using the one they originally meant to use.

Not every language used them the same ways as other languages - in particular, many didn't require them and only had them to make it clear what the programmer wanted it to be, often assuming that an undeclared variable was of some default type - but the idea did spread and got expanded as a way to check the validity of operations, to check that a procedure call had the right number and types of arguments, and even determine which of a group of overloaded or generic procedures to use based on the arguments (what is called 'polymorphic dispatch').

Of course, there are times when you have data in one type which you need to use as another, which is where type coercions and casts come in.

Some languages let you choose which one you want (C++ specifically), but usually the compiler picks which one to do based on which types it is going to and from. Many even have default rules for handling an implicit cast as a matter of convenience; for numbers in particular, most languages will automatically (and silently) change an integer value into a corresponding floating-point value as part of an assignment or an arithmetic operation, despite the two representations usually being dramatically different.
Rev. First Speaker Schol-R-LEA;2 LCF ELF JAM POEE KoR KCO PPWMTF
Ordo OS Project
Lisp programmers tend to seem very odd to outsiders, just like anyone else who has had a religious experience they can't quite explain to others.
Post Reply