How to print the length of a string in assembly
...
mov edx,len ;message length
This loads edx
with some kind of numeric value, like 14 in this case. len
is "equ" constant symbol, something like #define
in C.
mov ecx,msg ;message to write
This loads ecx
with address of first character (msg
is label, pointing into memory).
mov ebx,1 ;file descriptor (stdout)
mov eax,4 ;system call number (sys_write)
int 0x80 ;call kernel
...
msg db 'Hello, world!', 0xa ;our string
This defines 14 bytes of memory, with values 72 ('H'), 101 ('e'), ... . The first byte is pointed at by msg
label (memory address of it).
len equ $ - msg ;length of our string
This defines constant len
visible during compile time. It doesn't define any memory content, so you can't find it in the executable or during runtime (unless used, like by that mov edx,len
, then it is compiled into that particular instruction of course).
The definition is $ - msg
, the $
in this context works as "current address", where the next defined machine code byte will be compiled, so at this place it is equal to msg + 14
(I hope I did count the number of characters correctly :) ). And ((msg+14) - msg) = 14
= number of bytes defined in the memory between the definition of len
and label msg
.
Notice how I avoid words as variable or chars, the ASM is more low level, so labels into memory and bytes is more accurate wording and I hope it will help you to recognize the subtle differences.
Your len2 equ $ - len
after the len
did thus define value len2
as (msg+14)
(still there in the memory, no new byte added by len
definition) minus len
which is 14
, so you effectively defined len2
equal to msg
.
Then:
mov edx,len2 ;message length
mov ecx,len ;message to write
...
Does call sys_write
with pointer to string equal to 14
(invalid memory reference, that area of memory is off limits to ordinary user code), and length equal to address msg
, which will be on 32b linux very likely some value like 0x80004000
, i.e. over 2G of characters to output.
The sys_write
naturally doesn't like that, fails, and returns error code in eax
.
To output anything to console with sys_write
you have to first write it into memory as ASCII (I think UTF8 is supported by default in Ubuntu shell, but too lazy to verify) encoded string, and give the sys_write
address of that memory, and length in bytes (with UTF8 string the difference between bytes and chars is important, sys_write
is not aware of characters, it works with binary files and bytes, so the length is amount of bytes).
I'm not going to write code to output numbers, as that's several lines long (simplified printf
implementation) and SO has several Q+A over this, but I hope my explanation will help you to understand what happened and how it works.
If you are just learning ASM, consider either linking against clib
to have printf
available, or even better, use debugger, and verify the values straight in registers in debugger, don't bother with string output yet, that's a bit more advanced topic then the initial arithmetic, and basic flow control and operating stack. After you will be more comfortable with how basic instruction works, and how to debug the code, it will be more easier to try to output numbers then.
FASM: String store and console output
Your length calculations are incorrect. For instance the value of msg_more_size
would be:
msg_more_size = msg_equal-msg_more
$ is actually denotes where your current code location is. So $-msg_more
means almost the whole string.
NASM assembler : How to align values using EQU, to get the next alignment boundary after a label without actually padding
As Nate explained, NASM won't do arbitrary math on addresses, even when making a flat binary instead of just writing relocations into an ELF or COFF .o
/ .obj
.
NASM concatenates sections when making a flat binary, but doesn't emit any bytes for .bss
.
This program assembles to the 5 bytes of machine code you want:
bits 32
mov eax, label
end: ; here is the end of program
section .bss
align 4 ; in the BSS where they don't end up in the file
label:
$ nasm -fbin foo.asm
$ ll foo
-rwxr-xr-x 1 peter peter 5 Dec 30 15:16 foo
$ ndisasm -b32 foo
00000000 B808000000 mov eax,0x8
I'm somewhat surprised that worked; IDK if it's officially supported or if I got lucky.
It does also work with YASM.
In FASM, even without a section .bss
directive, it seems to just skip writing alignment padding at the end of the file. (So I got a 6-byte file because I didn't look up the right FASM directive for a 32-bit flat binary output, so it used a 66
operand-size prefix to encode mov eax, 8
for 16-bit mode.)
Related Topics
Problem in Restoring Floating Toolbar for Qmainwindow
Put Graphics on The Screen Without /Dev/Fb0
Find Command Search Only Non Hidden Directories
Linux Clipboard Read/Write in C
Vfs: File-Max Limit 1231582 Reached
Vim Pauses If Echo in .Vimrc File
Phony Targets for Parallel Execution of Make
How to Switch Between Different Versions of Julia (Specifically Between V0.3 and V0.4 on Ubuntu)
How to Set Just Year with Linux Date Command
Can't Untar a Complete Directory Using Tar -Cvpzf
Linux Allocates Memory at Specific Physical Address
How to Use Multiple Threads for Zlib Compression (Same Input Source)
Why Is This Int $0X10 Bios Int Not Working on Linux
Arch/X86/Include/Asm/Unistd.H VS. Include/Asm-Generic/Unistd.H
Sublimetext3 Build on The Server Over Ssh
How to Enable Spell Checker in Google Colab (Colab Operates on Linux Os)