LINUX.ORG.RU

Бесконечный цикл в TASM (8086)

 , , ,


0

2

Задача более сложная, но в приведенном коде я даже не справился по какой-то причине с подсчетом длины строки. При чем я в принципе не понимаю где моя ошибка. Прошу пожалуйста указать на ошибку, а не скинуть ее решение.

DATA SEGMENT
    STRING DB "ABCDE", 0    
DATA ENDS

SSEG SEGMENT STACK
    DW 100 DUP(?)
SSEG ENDS

CODE SEGMENT
    ASSUME CS:CODE, DS: DATA, SS:SSEG
    
START:
    XOR AX, AX
    MOV SI, 0

    MOV SI, OFFSET STRING ; SI ---> FIRST STRING MEMBER. USED TO COUNT STRING'S LENGTH

    ;COUNTING STRING'S LENGTH
    WHILE:CMP STRING[SI], 0 
   
          INC SI
          JNZ WHILE
    MOV AX, SI ;AX => 5H
        
        
        
    
EXIT:MOV AH, 4CH
     INT 21H
CODE ENDS
END START

Программа уходит в бесконечный луп не выходя из «тела» «цикла».



Последнее исправление: durambes (всего исправлений: 1)
Ответ на: комментарий от anonymous

Ну правильно. Сперва сравниваю равняется ли значение на позиции STRING[SI] нулю. Потом, если не равняется, прибавляю 1 к SI и если ZF не 0 -> опять прыгаю на лейбл WHILE. А как только SI будет равен 5, значение по этому адресу памяти будет 0, ZF = 0 -> в лейбл WHILE я больше не перепрыгну и продолжу дальше помещая значение в AX

durambes
() автор топика
Ответ на: комментарий от durambes

Проще учитывать какие команды не трогают флаги. Например, mov. А всё незнакомое по умолчанию считать трогающим флаги и стараться делать условный переход как можно ближе к сравнению. Потому что практически вся математика флаги обязательно трогает.

KivApple ★★★★★
()
Последнее исправление: KivApple (всего исправлений: 1)
Ответ на: комментарий от durambes

Буду знать, что INC сбрасывает ZF.

Он его устанавливает. Если результатом INC будет ноль, то ZF будет установлен в 1.

i-rinat ★★★★★
()
    MOV SI, OFFSET STRING
WHILE:
    CMP STRING[SI], 0 

Этот MOV удалить бы. А то там может не ноль быть и фигня выйдет.

xaizek ★★★★★
()
Ответ на: комментарий от durambes

Вот только SI потом используется как смещение от начала STRING и поэтому SI должно быть сначала нулём.

xaizek ★★★★★
()
Ответ на: комментарий от xaizek

А как иначе я узнаю начало строки? Узнаю начало строки, допустим оно лежит в ячейке 0EAH и дальше иду по ней инкрементируя SI (0EBH, 0ECH и т.д)

durambes
() автор топика
Ответ на: комментарий от xaizek

Вот и ответ онанимусу из первого коммента. Учить ассемблеру надо. Иначе появляются такие вот специалисты… Похапешники без страха и укропа.

aalst
()
Ответ на: комментарий от unstable-case

ZF устанавливается, если в результате операции получился ноль.
Например, xor eax,eax тоже выставит ZF.

bigbit ★★★★★
()
Ответ на: комментарий от durambes

xaizek верно говорит: к строке можно обращаться как DS:SI, тогда в SI должно быть смещение строки (OFFSET STRING), а можно как STRING[SI], тогда STRING - это и есть смещение строки, а SI должно быть равно 0,1,2,...
Вообще для подобного поиска есть готовые команды, например, scasb, которые можно выполнять в цикле (repne).
Вот примеры:
https://ravesli.com/assembler-stroki/#toc-6
https://www.cyberforum.ru/asm-beginners/thread1580673.html

spirit ★★★★★
()
Ответ на: комментарий от spirit

В таком случае я не могу понять почему плохо находить тем способом, которым воспользовался я, начало строки. Если можешь - объясни пожалуйста.

durambes
() автор топика
Ответ на: комментарий от durambes

Ну или я тебя не так понял, или ты меня. Я нахожу начало строки только единожды командой OFFSET, чтобы понимать где она в логической памяти начинается.

durambes
() автор топика
Ответ на: комментарий от durambes

Покажу на примере, когда оно перестанет работать.

DATA SEGMENT
    OTHERSTRING DB "BLABLA", 0
    STRING DB "ABCDE", 0    
DATA ENDS
...
    MOV SI, OFFSET STRING ; SI = OFFSET STRING == 7,

    WHILE:CMP STRING[SI], 0 ; STRING[SI] == STRING[7] == ??? (где-то после строки)

SI надо использовать либо как индекс относительно STRING и инициализировать нулём, либо как указатель и инициализировать смещением STRING. В текущем коде он используется как индекс (в выражении STRING[SI], которое эквивалентно [OFFSET STRING + SI], т.е. уже на первой итерации имеем [OFFSET STRING + OFFSET STRING]), но инициализируется смещением. А работает оно только потому что смещение равно нулю.

xaizek ★★★★★
()

я понимаю учить асму на тасме в 2000 годах, да еще и с int 21h. Но блять в 2020? Когда 64-битная архитектура уже имеет не сегментированную память?

возьми хоть nasm уже.

anonymous
()
Ответ на: комментарий от anonymous

очевидно что это ему задал препод

anonymous
()
Ответ на: комментарий от spirit

Вообще для подобного поиска есть готовые команды, например, scasb, которые можно выполнять в цикле (repne).

К слову, в интеловских мануалах по ассемблеру официально говорится, что циклы эффективнее специализированных команд.

kawaii_neko ★★★★
()
Ответ на: комментарий от xaizek

Бля, вот я урод. Наконец-то понял о чем речь. Спасибо большое.

durambes
() автор топика
Ответ на: комментарий от kawaii_neko

это считай что просто унаследованный способ получить халявный регистр для tls. наделай обычных переменных, посмотрим, сколько сегментов ты насчитаешь

anonymous
()
Ответ на: комментарий от anonymous

Что за «халявный регистр для tls»? Что за чепуху ты несешь?

В x86_64 сегментные регистры никуда не делись, они по-прежнему участвуют в процессе вычисления отображения виртуального адреса на физический, судя по приведенному коду. Просто нет legacy в виде «80286 protected mode» и когда говорят «x86_64», всегда подразумевают «flat memory model».

Ничто не мешает тебе написать свой «эмулятор терминала», в котором линейные адреса в cs, ss и ds не будут создавать. Только вот умучаешься с абстракцией «указателя» в популярны ЯП такую модель памяти дружить.

kawaii_neko ★★★★
()
Ответ на: комментарий от kawaii_neko

В x86_64 сегментные регистры никуда не делись, они по-прежнему участвуют в процессе вычисления отображения виртуального адреса на физический, судя по приведенному коду.

в котором линейные адреса в cs, ss и ds не будут создавать.

У Intel’а в мануалах написано:

64-bit mode — Segmentation is generally (but not completely) disabled, creating a flat 64-bit linear-address space. Specifically, the processor treats the segment base of CS, DS, ES, and SS as zero in 64-bit mode (this makes a linear address equal an effective address). Segmented and real address modes are not available in 64- bit mode.

If an instruction uses base registers RSP/RBP and uses a segment override prefix to specify a non-SS segment, a canonical fault generates a #GP (instead of an #SS). In 64-bit mode, only FS and GS segment-overrides are appli- cable in this situation. Other segment override prefixes (CS, DS, ES and SS) are ignored. Note that this also means that an SS segment-override applied to a “non-stack” register reference is ignored. Such a sequence still produces a #GP for a canonical fault (and not an #SS).

In 64-bit mode: CS, DS, ES, SS are treated as if each segment base is 0, regardless of the value of the associated segment descriptor base. This creates a flat address space for code, data, and stack. FS and GS are exceptions. Both segment registers may be used as additional base registers in linear address calculations (in the addressing of local data and certain operating system data structures).

i-rinat ★★★★★
()

Даже если я SI ставлю в 0 (mov si, 0), то на string[2] у меня все равно zf = 1 и из цикла выходит.

durambes
() автор топика
Ответ на: комментарий от durambes

Наверно, в CMP STRING[SI], 0 надо добавить byte ptr?

anonymous
()
    STRING DB "ABCDE"
    LENGTH DB ?  
DATA ENDS

SSEG SEGMENT STACK
    DW 100 DUP(?)
SSEG ENDS

CODE SEGMENT
    ASSUME CS:CODE, DS:DATA, SS:SSEG
    
START: 
    MOV AX,DATA 
    MOV DS,AX
    
    XOR CX, CX
    XOR SI, SI
    XOR BX, BX
    
    MOV CL, OFFSET LENGTH ;LENGTH'S ADRESS    
    SUB CL, OFFSET STRING ;LENGTH'S ADRESS - STRING'S ADRESS = 05H 
    MOV SI, 0H
    
    WHILE:CMP BYTE PTR SI, CL
         JZ DONE
         
         MOV AH, BYTE PTR DS:[SI] ;LEFT
         MOV BL, BYTE PTR DS:[CL] ;RIGHT
         XCHG AH, AL
         MOV DS:[SI], AH
         MOV DS:[CL], AL
         
         INC SI          
         LOOP WHILE
         
    DONE: ;CODE DONE
        
    
EXIT:MOV AH, 4CH
     INT 21H
CODE ENDS
END START

Я уже все перепробовал, но перевернуть строку не могу. Помогите пожалуйста. Умоляю ткните пальцем где именно я туплю и почему, а дальше я сам постораюсь догадаться.

durambes
() автор топика
Ответ на: комментарий от durambes

MOV AH, BYTE PTR DS:[SI] ;LEFT
MOV AL, BYTE PTR DS:[CL] ;RIGHT
XCHG AH, AL
MOV DS:[SI], AH
MOV DS:[CL], AL

На волосок от лока шины данных. И да, xchg тебе здесь не нужен, поменяй AH и AL в двух последних инструкциях.

cppsektant
()
Ответ на: комментарий от durambes

И решения своей проблемы ты конечно же не опубликуешь, оставив на форуме очередную бесполезную тему для тех, кто попадёт сюда из поисковых систем.

EXL ★★★★★
()
Ответ на: комментарий от anonymous

какая жесть. это как бы в 2020 учили бы алхимии на курсах физики…

Когда исторической реконструкцией занимаются, одеваются в средневековые костюмы и доспехи и машут мечами, ты тоже возмущаешься?

Harald ★★★★★
()
Ответ на: комментарий от anonymous

Реконструкцией не только гуманитарии могут заниматься, историю развития техники знать не помешает

Harald ★★★★★
()
Ответ на: комментарий от kawaii_neko

Кстати говоря, вот тут это демонстрируется на примере 95й винды: http://www.os2museum.com/wp/those-win9x-crashes-on-fast-machines/

According to the Pentium Processor Family Developer’s Manual Volume 3: Architecture and Programming Manual (Intel order no. 241430), the LOOP instruction. The absolute best case when the branch is taken is 6 clock cycles. The Intel manual notes that “[t]he unconditional LOOP instruction takes longer to execute than a two-instruction sequence which decrements the count register and jumps if the count does not equal zero”.

И далее по тексту

Unlike Intel, the AMD-K6 Processor Code Optimization Application Note (AMD publication 21924 Rev. D, January 2000) actually recommends using the LOOP instruction where applicable and on page 89 says: JCXZ takes 2 cycles when taken and 7 cycles when not taken. LOOP takes 1 cycle.

What that means is that the K6-2 executed the LOOP instruction six times faster than contemporary Intel CPUs at the same clock speed. That’s quite a big difference.

Так что все эти рекомендации могут ехать от процессора к процессору.

luke ★★★★★
()

Давно сюда не заходил. Вот решение, если что:

START: 
    MOV AX,DATA 
    MOV DS,AX
    
    XOR CX, CX
    XOR SI, SI
    XOR BX, BX
    XOR AX, AX
    
    
    MOV CL, OFFSET LENGTH ;LENGTH'S ADRESS    
    SUB CL, OFFSET STRING ;LENGTH'S ADRESS - STRING'S ADRESS = 05H
    DEC CL
    
    WHILE:CMP SI, CX
         JZ DONE
            
         MOV AL, [STRING+SI]
         MOV DI, CX
         
         MOV AH, BYTE PTR [STRING+DI]
         
         XCHG AL, AH
         
         MOV BYTE PTR DS:[SI], AL
         MOV BYTE PTR DS:[DI], AH
         
         
         
         INC SI          
         LOOP WHILE
         
    DONE: ;CODE DONE
        
    
EXIT:MOV AH, 4CH
     INT 21H
CODE ENDS
END START```
durambes
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.