Well... you can't read anything from the terminal (or console. or stdin) but text. If the pesky user (you) types "123", we read into the buffer the character '1' (31h), the character '2' (32h), and the character '3' (33h). They're numbers, of course, but they're the ascii codes of the numbers we're looking for, not the numbers we're looking for...
Since you're on Linux, you can do "man ascii" to see an ascii table. As you can see, the lower numbered ones are "control codes" - you already know one of them, 0Ah or 10 decimal, the linefeed character (you call it "nxline" in your code). There are a couple of other interesting control codes, mostly they're not - we want to avoid writing them to stdout, 'cause they'll mess up our display. The "printable characters" start at 20h with the space. Then there's some punctuation, and at 30h we come to the character '0'. The other characters representing decimal digits follow, then there's more punctuation and 'A' at 41h. You may want to allow the user to use either 'A' - 'F' or 'a' - 'f'.
We usually interpret that "123" as decimal (multiply by 10 for each digit), but we can interpret it as hex... We need to remember that each character represents 4 bits - a number beween 0 and 15 (decimal), not a number between 0 and 10! To do decimal, we have to multiply and divide by 10, for hex we have to multiply and divide by 16... but we can do that with shifts and rotates - easier in a way (beginners have a lot of trouble with "div"!).
Now we have to look at how sys_read works. In your macro, you're putting the second parameter in edx - you're using 4. But sys_read won't return until the user hits "enter", and the linefeed generated by that is included in the count! If the pesky user types more than 3 characters and "enter", only 4 go into your buffer and anything more stays in the OS's buffer ("keyboard buffer"?), ready to be read next time. If you type "FFFFFFFF" trying to get a 32-bit number, the first "FFFF" goes into your buffer and is transferred to your array at index 0, then the next loop gets the second "FFFF" - goes to index 1 then the next loop gets the linefeed (0Ah or 10 decimal), and that goes into index 2 (where it isn't going to display anything, when you get to that). You probably want to convert it to the number 0FFFFh, (or 0FFFFFFFFh if you had it all) before you transfer it to your array - 0FFFFFFFFh will fit in eax, the characters "FFFFFFFF" won't!
I think that's the root of your problem. Make your buffer bigger - 9 bytes for 32-bit numbers, 17 bytes fot 64-bit numbers (you sure you want to do that? It'll take two registers... or switch to 64-bit code). Won't hurt if the buffer is too big. Then "read_string buffer 9", then walk down the buffer a character at a time, checking each for the '0'-'9', 'A'-'F', 'a'-'f' range, and subtracting the correct amount to make it a number between 0 and 15 (decimal) - 4 bits. Mask this number off to just the 4 bits we want (and eax, 0Fh). Did I mention that we need to zero out a register for "result so far" before we start? Yeah, and now that we've got a valid number, shift the "result so far" left by 4 (multiply by 16). Then "or" the "result so far" with our new 4 bits. Repeat until done. I like to quit if I encounter anything outside the "valid" ranges - that'll cover a zero-terminated string or a linefeed-terminated "string" like sys_read gives you... or garbage from the pesky user You might want to count characters, in addition, to avoid overflow.
I don't think I have an example at hand, but I could probably come up with one if you need it. Give it a shot first.
Or... we could "just call scanf" (they make me say that
).
Best,
Frank