Here's the code:
segment .text
global _start
_start:
mov rcx, [rsp+16]
dec rdx
.L1:
inc rdx
cmp al, byte [rcx+rdx]
jnz .L1
mov rax, 4
mov rbx, 1
int 0x80
mov rax, 1
mov rbx, 0
int 0x80
It moves the address of second argument string (argv[1]) argument into RCX, increments RDX times count characters until '\0' and writes to STDOUT_FILENO.
When I compile it with yasm, link with ld and run the executable as follows:
$ ./a.out somechars
Expected output is:
somechars$
($ stands for terminal prompt, newline is missing)
But instead I see terminal prompt immediately, just as if I hadn't run anything and just hit ENTER on empty command line.
Then I've put some more lines into source:
segment .data ; NEW
; NEW
deb db "somechars", 0 ; NEW
; NEW
segment .text
global _start
_start:
mov rcx, [rsp+16]
mov rcx, deb ; NEW
dec rdx
.L1:
inc rdx
cmp al, byte [rcx+rdx]
jnz .L1
mov rax, 4
mov rbx, 1
int 0x80
mov rax, 1
mov rbx, 0
int 0x80
And it does well:
$ ./a.out somechars
somechars$
(decided to type identical command, although "somechars" could be omitted)
Here's what debugger says:
(gdb) l
1 segment .data
2
3 deb db "somechars", 0
4
5 segment .text
6
7 global _start
8
9 _start:
10 mov rcx, [rsp+16]
(gdb) b 9
Breakpoint 1 at 0x4000b0: file exp.asm, line 9.
(gdb) run somechars
Starting program: /home/polazhinets_a/work/ll/a.out somechars
Breakpoint 1, _start () at exp.asm:10
10 mov rcx, [rsp+16]
(gdb) ni
11 mov rcx, deb
(gdb) x/10cb $rcx
0x7fffffffe1b7: 115 's' 111 'o' 109 'm' 101 'e' 99 'c' 104 'h' 97 'a' 114 'r'
0x7fffffffe1bf: 115 's' 0 '\000'
(gdb) ni
12 dec rdx
(gdb) x/10cb $rcx
0x6000e8: 115 's' 111 'o' 109 'm' 101 'e' 99 'c' 104 'h' 97 'a' 114 'r'
0x6000f0: 115 's' 0 '\000'
(gdb)
There'se clearly no difference between tens of bytes of data data that RCX points at after either MOV, except in first case the address is low (data segment), while in second it is high (stack segment).
I know, that neither READ nor WRITE offers no guarantee and is likely process 0 bytes, if there is a delay somewhere, but I'm not trying to write ten bytes of garbage from, say, 0x7fffff0000f8 (< RSP), so that OS would be allocating some extra pages of memory for my stack, resolving valid but still physically unmaped virtual address, and it's nothing to do with output stream, as it does well when source is 0x6000e8.
What's the real cause?
SOLVED
48-bit stack virtual address doesn't fit 32 bits, so SYSCALL should be used instead of 32-bit INT