Assembler wyświetlanie napisu

Odpowiedz Nowy wątek
2019-04-11 11:53
0

Witam!
Potrzebuję wyświetlić na konsoli pierwszą literkę z ciągu znaków. Mam następujący kod, który nie działa:

.intel_syntax noprefix
.global main
.text
    main:
        mov eax, offset mesg 
                mov bl, [eax]
        push ebx 
        call printf 
        pop ebx
        mov ebx, 0
                mov eax, 0
        ret 

.data
mesg:
.asciz "Hello, world\n"

Całość przy gcc dodaje -m32.
Nie mam pojęcia jak wyswietlic ta literkę.
Liczę na pomoc, Pozdrawiam :)

Pozostało 580 znaków

2019-04-11 12:11
0

NASM avoids this undesirable situation by having a much simpler syntax for memory references. The rule is simply that any access to the contents of a memory location requires square brackets around the address, and any access to the address of a variable doesn't. So an instruction of the form mov ax,foo will always refer to a compile-time constant, whether it's an EQU or the address of a variable; and to access the contents of the variable bar, you must code mov ax,[bar].

This also means that NASM has no need for MASM's OFFSET keyword, since the MASM code mov ax,offset bar means exactly the same thing as NASM's mov ax,bar. If you're trying to get large amounts of MASM code to assemble sensibly under NASM, you can always code %idefine offset to make the preprocessor treat the OFFSET keyword as a no-op.

https://nasm.us/doc/nasmdoc2.html

NASM nie posiada w swojej składni słowa kluczowego OFFSET. To nie MASM. Nie wspiera również takich instrukcji:

For this reason, NASM doesn't support the LODS, MOVS, STOS, SCAS, CMPS, INS, or OUTS instructions, but only supports the forms such as LODSB, MOVSW, and SCASD, which explicitly specify the size of the components of the strings being manipulated.

global _main
extern _printf

section .data

txt: db "Hello World", 0
format: db "%c", 0

section .text

_main:
xor eax, eax

mov eax, [txt]
push eax
push format
call _printf
add esp, 8

section .bss

Edit: //

global _main
extern _printf

section .data

txt: db "Hello World", 0

section .text

_main:
xor eax, eax

push ebp 
mov ebp, esp
sub esp, 0x28

mov eax, txt
push eax
mov word[esp+0x4], 0x420
call _printf

pop eax
ret

section .bss

Część kodu zaczępnąłem z: http://www.ccis.northeastern.[...]/unix-xv6-source/forktest.asm i wspierałem się: https://www.imada.sdu.dk/~kslarsen/dm546/Material/IntelnATT.htm

Powyższy kod wypisuje cały napis, dostosuj tak, jak chcesz, aby wypisywał jeden znak.

global _main
extern _printf

section .data

txt: db "Hello World", 0

section .text

_main:
xor eax, eax

push ebp 
mov ebp, esp
sub esp, 0x28

mov eax, txt
mov dword[eax+1], 0

push eax
;mov word[esp+0x4], 0x420

call _printf

pop eax
ret

Może dałoby się ten kod lepiej napisać, no ale jest napisany jak jest.
Korzystałem między innymi z tego źródła: https://forum.nasm.us/index.php?topic=2152.0


global _main
extern _printf

section .data
; 0xA
txt: db "Hello,World!", 10, 0
txt_len: equ $-txt

section .text

_main:

mov ecx, txt_len

l22:
    push ecx

    lea esi, [txt]

    add esi, ecx

    mov byte[esi+1], 0xA
    mov byte[esi+2], 0x00

    cmp ecx, 4
    je label_here

    pop ecx
    dec ecx
    cmp ecx, -1
jne l22

ret

label_here:

push esi
call _printf
add esp, 4

pop ecx

ret

section .bss

Wypisuje odpowiednią literę zależnie od liczby, którą jest przy tym cmp ecx, 4. Zamiast 4 można wpisać inną liczbę i wypisze inną literę.

global _main
extern _printf

section .data
; 0xA
txt: db "Hello,World!", 10, 0
txt_len: equ $-txt

section .text

_main:

mov ecx, txt_len

l22:
    push ecx

    lea esi, [txt]

    add esi, ecx

    mov byte[esi+1], 0xA
    mov byte[esi+2], 0x00

    push esi
    call _printf
    add esp, 4

    pop ecx
    dec ecx
    cmp ecx, -1
jne l22

ret

section .bss

Wypisuje wszystko odwrotnie.
//

mov eax, [txt+1], wyrzuci "e". Pamiętaj, że istnieje takie coś jak konwencja wywołania parametrów w funkcji. Dla printf to jest "od prawej do lewej", czyli najpierw tekst do wypisania, a później format. Popatrz na składnię instrukcji printf. http://www.cplusplus.com/reference/cstdio/printf/ Char ma 8 bitów, więc musisz napisać db, czyli 1 bajt. int printf ( const char * format, ... );

http://issc.uj.ac.za/assembler/NASM.pdf
http://www.student.chemia.uj.[...]okumentacja/asm_pdf_linux.pdf
https://gynvael.coldwind.pl/?id=445
https://ww2.ii.uj.edu.pl/~kap[...]print-lecture-and-sources.php
http://fulmanski.pl/zajecia/x86/zajecia_20142015/book.pdf

<-- Konwencje wywołań.

edytowany 12x, ostatnio: Neutral, 2019-04-12 18:47
Okej, zrozumiałem, fajnie że podesłałeś kod, ja nie ogarniam assemblera, po prostu w ramach zajęć muszę przez to przejść. Powyższe rozwiązanie raczej nie przejdzie, czy da rade używając mojego powyższego szkieletu to zrobić? Też ciężko mi wyszukać jakiś tutorial pod to co mam wyżej - sors21 2019-04-11 12:39
Gdybyś napisał jaki to jest Assembler to byłoby każdemu łatwiej Ci pomóc - Shizzer 2019-04-11 12:50
No dobre pytanie :D. Mój powyższy kod odpalam zwyczajnie przez '''gcc -m32 a.s'' i ta składnia intelowska, jaką widać powyżej. - sors21 2019-04-11 13:04
Masz wydrukować literę 'H' tylko? - Shizzer 2019-04-11 13:28

Pozostało 580 znaków

2019-04-11 13:37
0

W zasadzie to nadal nie wiem co to jest za składnia. Niby przypomina trochę MASM, trochę GNU Assembly, w każdym razie stworzyłem taki kod co drukuje literę H - nie wiem czy o to chodziło, ale podejrzewam, że chodziło Ci o wydrukowanie którejś z liter. Tak czy inaczej będziesz mógł sobie ten kod przebudować zgodnie z zadaniem, które masz do wykonania.

.intel_syntax noprefix
.global main
.text
    main:
        mov eax, offset mesg 
        mov bl, byte [eax-1]
        mov eax, offset format_char
        push ebx
        push eax
        call printf 
        pop eax
        pop ebx
        mov ebx, 0
        mov eax, 0
        ret 

.data
mesg:
.asciz "Hello, world\n"
format_char:
.asciz "%c\n"

Btw. polecam zapoznać się z debuggerem gdb, bo daje ogromne możliwości. ;) Możesz sobie chociażby wypróbować komendy z tego linku -> https://www.tutorialspoint.com/gnu_debugger/index.htm


Pozostało 580 znaków

2019-04-11 20:36
1
Shizzer napisał(a):

W zasadzie to nadal nie wiem co to jest za składnia. Niby przypomina trochę MASM, trochę GNU Assembly

NASM ma swoją składnię. Moim zdaniem lepszą od MASM/TASM (bo bardziej spójną) i od GNU as (bo ta to w ogóle jakieś dziwactwo).

Ale to wyżej to GNU z .intel_syntax, czyli taka jakaś hybryda.

edytowany 1x, ostatnio: Azarien, 2019-04-11 20:38

Pozostało 580 znaków

2019-04-12 12:13
0

Tak w sumie to potrzebuję wypisać wszystko po kolei ale nadal nie mogę tutaj licznika ogarnąć co by mi iterował po ciągu znaków

Pozostało 580 znaków

2019-04-12 13:06
0

Po co Ci tutaj jakikolwiek licznik? Przecież funkcje ze standardowej biblioteki C typu puts lub printf (chociaż nawiasem mówiąc kompilator przy wypisywaniu ciągu znaków bez podanego formatu i tak zamieni printf na puts) wypiszą ten ciąg znaków za Ciebie - wystarczy, że przekażesz do nich jego adres.

Nie wiem czy wiesz, ale ta dyrektywa .asciz jest po to, żeby z literału utworzyć C-String, czyli dany literał dzięki tej dyrektywie jest z automatu uzupełniany na końcu NULL-bytem -> http://bravegnu.org/gnu-eprog/asm-directives.html


Pozostało 580 znaków

2019-04-12 13:31
0

Pierwszą literkę można wyświetlić korzystając z ciągu formatującego, jeśli musi być printf. Alternatywnie za pomocą write.
Przerobiony przykład podany przez ciebie:

.intel_syntax noprefix
.global main
.text
main:
  push ebp    /*tworzysz ramkę stosu*/
  mov ebp,esp

  push offset mesg    /*odłożenie argumentu na stosie*/
  push offset format    /*format na stos*/
  call printf
  add esp, 8   /*zdjęcie argumentów ze stosu*/

  mov esp,ebp    /*przywracasz poprzednią ramkę stosu*/
  pop ebp

  xor eax,eax    /*zwrócenie bez błedu (zerowanie eax)*/

  ret    /*wracasz z funkcji*/

.data
mesg:
.asciz "Hello, world\n"
format:
.asciz "%.1s\n"
edytowany 2x, ostatnio: woki, 2019-04-12 13:35

Pozostało 580 znaków

2019-04-12 15:04
0

Okej, troszkę skłamałem. Ostateczny cel to zamiana literek duże na małe a małe na duże, wypisując je kolejno jedna po drugiej, nie jako ciąg w jednej linii. Tak, wiem można by wpisać napis tak:

.intel_syntax noprefix
.global main
.text
    main:
        mov eax, offset mesg 
        push eax 
        call printf 
        add esp, 4 
        xor eax, eax 
        ret 

.data
mesg:
.asciz "Hello, world\n"

Ale to się mija z moim celem. Stąd mowa o liczniku i iterowaniu :P.

edytowany 1x, ostatnio: sors21, 2019-04-12 15:05
zapoznaj się z http://xyproblem.info/ następnym razem wątek poleci do kosza a ty dostaniesz bana :) - Shalom 2019-04-12 15:55

Pozostało 580 znaków

2019-04-12 16:25
0

Tu masz kod zamieniający małe litery na duże i duże na małe. Napisałem go w NASM, bo tego Twojego Assemblera nie znam. Możesz sobie zamienić kod z NASM na swój Assembler. Skoro w jednym z komentarzy pisałeś, że masz to zrobić w ramach zajęć to powinieneś po prostu wiedzieć jakiego tam Assemblera używacie. Gdybyś mi napisał, o którego chodzi byłoby mi łatwiej się dostosować i może czegoś nowego nauczyć, a tak to musisz się męczyć samemu.

global main
extern printf
section .text
    main:
        push ebp
        mov ebp, esp
        mov eax, mesg
        mov ecx, 0

        .loop_through_str:
            cmp byte [eax+ecx], 0           ; check if our pointer points to the null-byte
            je .output
            cmp byte [eax+ecx], 65          ; if ( *(mesg+idx) >= 'A' )
            jae .to_lower_check
            jmp .not_a_letter

        .to_lower_check:
            cmp byte [eax+ecx], 90          ; if ( *(mesg+idx) <= 'Z' )
            jbe .to_lower
            cmp byte [eax+ecx], 97          ; if ( *(mesg+idx) >= 'a' )
            jae .to_upper_check

        .to_upper_check:
            cmp byte [eax+ecx], 122         ; if ( *(mesg+idx) <= 'z' )
            jbe .to_upper
            jmp .not_a_letter               ; else { continue; }

        .to_lower:
            xor edx, edx
            mov dl, byte [eax+ecx]
            add dl, 32
            mov byte [eax+ecx], dl
            inc ecx
            jmp .loop_through_str

        .to_upper:
            xor edx, edx
            mov dl, byte [eax+ecx]
            sub dl, 32
            mov byte [eax+ecx], dl
            inc ecx
            jmp .loop_through_str

        .not_a_letter:
            inc ecx                     ; continue
            jmp .loop_through_str

        .output:
            push eax
            call printf
        xor eax, eax 
        leave
        ret 

section .data
mesg: db "Hello, world", 0xa, 0

edytowany 1x, ostatnio: Shizzer, 2019-04-12 16:29

Pozostało 580 znaków

2019-04-12 23:11
0

Sama pętla wypisywania może wyglądać następująco (litery będą oddzielone spacjami - patrz "format"):

print:
  mov esi, offset mesg
  xor ebx,ebx
  print_loop:
    mov bl,[esi]
    cmp bl,0
    jz finish

    push ebx
    push offset format
    call printf
    add esp, 8    /*zdjęcie argumentu ze stosu*/
    inc esi

    jmp print_loop
finish:

...
.data
format:
.asciz "%c "

Natomiast zamiana liter z małych na duże i na odwrót możesz zrobić za pomocą czegoś takiego:

        cld
        mov esi, offset mesg
        mov edi,esi

loop:
        lodsb
        cmp al,0
        jz print
small:  
/*Twój kod sprawdzający i zmieniający z małej na dużą (może mieć 6 linii)
big:
/* Twój kod sprawdzający i zamieniający z dużej na małą (może mieć 5 linii)*/
next:
        stosb
        jmp loop

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0