0

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

0 Answers0