• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

FASM - przypisawanie wartości zmiennej z rejestru

VPS Starter Arubacloud
+1 głos
614 wizyt
pytanie zadane 5 listopada 2018 w Assembler przez DeBos123 Nałogowiec (44,950 p.)

Witam, próbuję w fasm'ie przypisać wartoś do zmiennej z jakiegoś rejestru.

Chodzi o to, że definiuje zmienną:

a db ?

I chciałbym ustawić 'a' na wartość rejestru eax.

Próbowałem zrobić to w taki sposób:

mov a,eax

Ale dostaję błąd:

invalid operand

Czy ktoś mógłby mi wytłumaczyć czemu ten kod nie działa i podać lub naprowadzić mnie na rozwiązanie?

1 odpowiedź

0 głosów
odpowiedź 5 listopada 2018 przez Chess Szeryf (76,710 p.)
wybrane 6 listopada 2018 przez DeBos123
 
Najlepsza

https://flatassembler.net/docs.php?article=manual#1.1 

When operand is a data in memory, the address of that data (also any numerical expression, but it may contain registers) should be enclosed in square brackets or preceded by ptr operator. For example instruction mov eax,3 will put the immediate value 3 into the EAX register, instruction mov eax,[7] will put the 32-bit value from the address 7 into EAX and the instruction mov byte [7],3 will put the immediate value 3 into the byte at address 7, it can also be written as mov byte ptr 7,3. To specify which segment register should be used for addressing, segment register name followed by a colon should be put just before the address value (inside the square brackets or after the ptr operator).

To jest chyba dokumentacja FASM.

W NASM składnia też wymaga podania nawiasów kwadratowych do wzięcia efektywnego, czy jak to się nazywa adresu w pamięci, żeby móc się do niego odwołać. 

2.2.2 NASM Requires Square Brackets For Memory References

https://www.nasm.us/doc/nasmdoc2.html#section-2.2.2

https://www.tortall.net/projects/yasm/manual/html/nasm-effaddr.html

Odpowiedzią na Twoje pytanie jest najprawdopodobniej to:

mov eax, [my_var]

lub: 

mov dword [my_var], eax

ewentualnie:

mov [my_var], eax

Ogólnie to staraj się czytać tak równolegle dokumentację np. Intel'a i swojego assembler'a, ponieważ assembler'y mają swoje składnie i pewne specyficzne instrukcje.

https://software.intel.com/sites/default/files/managed/39/c5/325462-sdm-vol-1-2abcd-3abcd.pdf

global _main
extern _printf

section .data

my_var: dw 10, 0, 0
formatter: dw "%d", 0xa, 0

section .text

_main:

mov eax, [my_var]

push eax
push formatter
call _printf
pop eax
pop eax

section .bss
global _main
extern _printf

section .data

my_var: dw 10, 0, 0
formatter: dw "%d", 0xa, 0

section .text

_main:

mov eax, 50

mov dword [my_var], eax

push dword [my_var]
push formatter
call _printf
add esp, 8

section .bss

assembler: NASM, kompilacja pod Windows'em:

nasm -fwin32 name_file.asm && gcc name_file.obj && a

Pod Linux'em lekko zmodyfikowany wyżej kod można by skompilować tak:

nasm -o name_file.obj -felf32 name_file.asm && gcc -m32 name_file.obj -o name_file && ./name_file
komentarz 6 listopada 2018 przez DeBos123 Nałogowiec (44,950 p.)

Dziękuje za pomoc.

Napotkałem kolejny problem, który akurat sam rozwiązałem.

Czemu 'normalnie zdefiniowaną' zmienną mogę przenieść do rejestru w taki sposób:

mov eax,my_var

A przy zmiennej, do której przypisałem wartość z rejestru:

mov dword [my_var2],eax

aby przenieść ją później znowu do rejestru muszę to robić w ten sposób:

mov eax,dword [my_var2]

Czemu nie mogę tego zrobić jak przy 'normalnej' zmiennej?

I czemu jeżeli definiuję zmienną:

my_var db ?

To muszę używać 'dword' a nie 'byte' przy przenoszeniu wartości do rejestru?

1
komentarz 6 listopada 2018 przez Chess Szeryf (76,710 p.)
edycja 6 listopada 2018 przez Chess

I czemu jeżeli definiuję zmienną:

my_var db ?

To muszę używać 'dword' a nie 'byte' przy przenoszeniu wartości do rejestru?

Ponieważ assembler/compilator, nie wie ile bitów ma zarezerwować na poszczególną instrukcję w pamięci, czy coś takiego. Na tym etapie, nie pytaj dlaczego tak jest. Jest bo jest i tyle. Gdy nabierzesz więcej doświadczenia w asm, to już raczej będziesz wiedzieć dlaczego tak, a nie inaczej. Bardziej szczegółowa odpowiedź na te pytanie poniżej.

The data reservation directive should be followed by only one numerical expression, and this value defines how many cells of the specified size should be reserved. All data definition directives also accept the ? value, which means that this cell should not be initialized to any value and the effect is the same as by using the data reservation directive. The uninitialized data may not be included in the output file, so its values should be always considered unknown.

Table 1.3 Data directives

Size (bytes) Define data Reserve data
1
db
file
rb
2
dw
du
rw
4 dd rd
6
dp
df
rp
rf
8 dq rq
10 dt rt

https://flatassembler.net/docs.php?article=manual

https://pl.wikibooks.org/wiki/Asembler_x86/Zmienne/NASM

Czemu 'normalnie zdefiniowaną' zmienną mogę przenieść do rejestru w taki sposób:

mov eax,my_var

"Normalnie" zainicjalizowaną zmienną możesz przypisać do rejestru w standardowy sposób, ponieważ takie coś jest dopuszczalne, ale tam pewnie siedzą "śmieci" (losowe wartości), bo nie podałeś nawiasów kwadratowych dla zmiennej.

Jeśli masz taką deklarację w sekcji danych (section .data):

my_var: dw 25
my_var2: dw ?

, to musisz rozróżniać, są dane zainicjalizowane i niezainicjalizowane, czyli takie, które tak jakby deklarujesz w locie, przynajmniej ja to tak rozumiem. Są one bez nadania wartości.

mov eax, [7]

Nawiasy kwadratowe mówią, żeby wziąć 32-bitową wartość spod adresu 7 do eax. Czyli spod tego adresu 0111 (binarnie). Pod tym adresem jest jakaś wartość np. 200 (liczba) i przypisz tę wartość do rejestru eax.

Natomiast to:

mov eax, 3

wkłada wartość 3 do eax, bez drogi pośredniczącej jak wyżej.

Niektóre assembler'y nie pamiętają deklaracji zmiennych. Czyli jeśli napiszesz, gdzieś np.

var: db "my_var", 0

, to później i tak musisz napisać, gdzieś w kodzie:

mov byte [var], eax

, ponieważ nie wie jakiego rozmiaru jest zmienna var, czy ma 8 bitów, czy 16, itd..

2.2.3 NASM Doesn't Store Variable Types

https://www.nasm.us/doc/nasmdoc2.html#section-2.2.2

W NASM'ie o ile dobrze zrozumiałem zagadnienie, to muszę podać nawiasy kwadratowe, żeby móc odczytać np. wartość ze zmiennej, bo inaczej na wyjściu dostanę jakieś losowe wartości z pamięci.

Jeśli przypisałeś do rejestru eax wartość ze zmiennej w taki sposób:

mov eax, my_var

, to sprawdź teraz jaką wartość wypisze Ci w konsoli, możliwe że jakieś "śmieci", bo nie podałeś nawiasów kwadratowych (tak jak np. w kodzie poniżej), ale to zależy od assemblera, ja testuję na NASM, nie FASM.

mov dword [my_var2], eax

Tak jak pisałem niektóre assemblery "nie chcą pamiętać" typów z zadeklarowanej zmiennej, MASM chyba pamięta, ale nie wiem, musiałbym sprawdzić.

Tak jak pisałem wcześniej musisz napisać typ zmiennej, jakiego jest rozmiaru, żeby assembler wiedział, czego ma się spodziewać. Tak jest i tyle, ktoś tak zaprojektował niektóre assembler'y tak, że jest jak jest. Coś za coś. Niektóre assemblery mają takie zalety i takie wady, a inne inne wady i zalety, itp..

Co do Twojego przykładu:

mov dword [my_var2], eax

Tutaj OK, assembler chyba nie zna wielkości zmiennej, musisz podać.

Dalej:

mov eax, dword [my_var2]

Tutaj w NASM moim zdaniem nie trzeba podawać tego dword, tylko samo [my_var2], ponieważ assembler chyba zna wielkość (size) zmiennej (operandu po prawej stronie).

global _main
extern _printf

section .data

my_var: dw 10, 0, 0
formatter: dw "%d", 0xa, 0

section .text

_main:

xor eax, eax

mov ah, dword [buffer]
push eax
push formatter
call _printf
pop eax
pop eax

section .bss

buffer: resb 1

U mnie te:

buffer: resb 1

jest chyba odpowiednikiem Twojego:

my_var db ?

Nie można chyba przenosić/kopiować wartości z operandu o mniejszej wielkości do większej. Ale już odwrotnie, czyli o większej wielkości do mniejszej się da, o ile dobrze zauważyłem. Możliwe, że istnieją trick'i, żeby to obejść, ale tego trzeba byłoby doszukiwać się w dokumentacjach.

mov ah, dword [buffer]

To powyżej przechodzi w NASM, ale to:

mov eax, byte [buffer]

już nie.

Moim zdaniem dzieje się tak, dlatego, że to co się nie zmieści zostaje "ucięte" i w operandzie pozostaje ta wartość, która nie została "ucięta". W odwrotną stronę to jest niemożliwe, bo tak konstruktorzy assemblerów pomyśleli, żeby jak masz np.:

mov eax, byte [buffer]

, to żeby do rejestru eax nie ładowało się 8 młodszych bitów, a resztę
dopełniona zerami, tylko w ogóle nie dopuszcza takiego czegoś. Są od tego pewnie trick'i, żeby móc coś takiego wykonać, ale na tym poziomie, tym się raczej nie przejmuj, jak chcesz to doczytaj gdzieś.

global _main
extern _printf

section .data

my_var: dw 10, 0, 0
formatter: dw "%d", 0xa, 0

section .text

_main:

xor eax, eax

mov word [buffer], 256

mov al, [buffer]
push eax
push formatter
call _printf
pop eax
pop eax

section .bss

buffer: resb 1

Rezultat 0. A jeśli zamiast 256 będzie 257, to będzie 1. Przy 255 będzie 255.

Dlaczego tak się dzieje? Tutaj dobrze narysować "mantysę" na bity i odpowiedzieć sobie na to pytanie.

Analizuję to (section .text):

xor eax, eax
mov word [buffer], 256
mov al, [buffer]

, w sekcji .bss (section .bss), oczywiście jest to:

buffer: resb 1

Zerujemy rejestr eax xor'em. 

Dalej, do 16-bitowej zmiennej przenosimy wartość 256. To się mieści już w starszych 8 bitach nie młodszych.

Liczba 256 (1 0000 0000), jak widać w al (młodsze 8 bitów) nie zmieści się liczba 256, ponieważ jest w starszych 8 bitach. Rezultatem jest zero, ponieważ w młodszych bitach jest 8 zer. Od bitu 0 do 7. Jeśli napisze się taką liczbę 257, to rezultatem jest 1, ponieważ: 1 0000 0001, w młodszych bitach jest tylko jeden bit "zapalony" na 1.

Podsyłam linka, 89 strona, opisane m.in. starszy bajt i młodszy bajt:

https://software.intel.com/sites/default/files/managed/39/c5/325462-sdm-vol-1-2abcd-3abcd.pdf

komentarz 6 listopada 2018 przez DeBos123 Nałogowiec (44,950 p.)
Dzięki za wyjaśnienie
1
komentarz 6 listopada 2018 przez Chess Szeryf (76,710 p.)
edycja 7 listopada 2018 przez Chess
Najprawdopodobniej wprowadziłem Cię w błąd z tymi nawiasami kwadratowymi, więc skreśliłem w komentarzu powyżej, to co nie jest do końca prawdą.

Wartość podana w nawiasie kwadratowym odwołuje się (pośrednio) do miejsca w pamięci i z tego miejsca np. odczytuje wartość. Zaś wartość bez nawiasów odwołuje się (bezpośrednio) do adresu, gdzie jest wartość.

Zależy, więc co chcesz osiągnąć, czy odwołać się do adresu w pamięci, czy do adresu tej wartości, która ma gdzieś przypisany jakiś adres. W tym powyższym komentarzu masz z tym przykład jak coś.

Ogólnie, to możesz zapoznać się też z instrukcją LEA. 1100 strona w Manuals Intel.

Video do obejrzenia (Gynvael Coldwind): https://www.youtube.com/watch?v=80MJD-kLUW0 https://www.youtube.com/playlist?list=PL7CA8FE35B665D4DD

http://parzych.net/2010/06/assembler-pigulka-najwazniejsze-komendy-rejestry-przyklady/

http://cs.lmu.edu/~ray/notes/nasmtutorial/

Podobne pytania

0 głosów
1 odpowiedź 184 wizyt
pytanie zadane 3 lutego 2018 w Assembler przez KubenQPL Maniak (62,820 p.)
0 głosów
1 odpowiedź 231 wizyt
pytanie zadane 8 maja 2023 w Assembler przez Saskus Nowicjusz (150 p.)
+1 głos
0 odpowiedzi 127 wizyt
pytanie zadane 10 grudnia 2018 w Assembler przez DeBos123 Nałogowiec (44,950 p.)

92,454 zapytań

141,262 odpowiedzi

319,099 komentarzy

61,854 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Akademia Sekuraka 2024 zapewnia dostęp do minimum 15 szkoleń online z bezpieczeństwa IT oraz dostęp także do materiałów z edycji Sekurak Academy z roku 2023!

Przy zakupie możecie skorzystać z kodu: pasja-akademia - użyjcie go w koszyku, a uzyskacie rabat -30% na bilety w wersji "Standard"! Więcej informacji na temat akademii 2024 znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...