Bazı korsanlıktan ve çığlık atmadan sonra, bu çalışmayı başarabiliyordum. Umduğum kadar basit değil, bu yüzden koltuğunuza oturun. Öncelikle, DOS'un tek kullanıcılı, çok işlevli olmayan bir sistem olduğunu farketmeniz gerekir. Bu özel durumda, eşzamanlı olarak çalışan iki sürece sahip olamayacağınız anlamına gelir. , başka bir işleme taşınmadan önce bir işlemin yürütmeyi bitirmesini beklemek için gerekir. Süreç eşzamanlılığı TSR (Terminate ve Stay Resident) süreçleriyle bir şekilde taklit edilebilir, bu da sonlandırılmalarına rağmen bellekte kalır ve kodlarından bazı kesintiler alarak ve daha sonra başka bir koddan çağrılarak yürütme işlemlerine devam edilebilir. Yine de, Windows ve Linux gibi modern işletim sistemlerinde kullanılan aynı türde bir eşzamanlılık değil. Ama konu bu değildi.
NASM'yi seçtiğiniz bir derleyiciniz olarak kullandığınızı söylemiştiniz, bu nedenle kodunuzu, COM komut satırında çalıştırılan COM dosyalarına çıkardığınızı varsaydım. COM dosyaları, 100h
ofsetinde (bu konuma bir atlama yüklendikten sonra) komut istemiyle yüklenir ve başka bir şey içermez, ancak "yalın" kod ve veri içermez - üstbilgiler, bu nedenle üretilmesi en kolay olanıdır.
Montaj kaynağını parçalar halinde açıklayacağım, böylece (belki de) kaputun altında neler olup bittiğini daha iyi anlayabilirsiniz.
programı
org 100h
section .data
exename db "C:\hello.com",0
exename2 db "C:\nasm\nasm.exe",0
cmdline db 0,0dh
aslında belleğe yüklenen dosyanın kaynağını belirtir org
direktifi ile başlar - bizim durumumuzda, bu 100h
olduğunu. Üç etiketin bildirimleri, yürütülecek programların boş sonlandırılmış yolları olan exename
ve exename2
ve yeni oluşturulan işlemin alması gereken komut satırını belirten cmdline
izler. Sadece normal bir dize olmadığını unutmayın: ilk bayt, komut satırındaki karakterlerin sayısı, daha sonra komut satırının kendisi ve bir Carriage Return'dır. Bu durumda, hiçbir komut satırı parametresine sahip değiliz, bu yüzden her şey db 0,0dh
'a kadar kaynar. Paragraf olarak -h -x 3
'u geçmek istediğimizi varsayalım: bu durumda, bu etiketi db 8," -h -x 3",0dh
olarak bildirmeliyiz (başlangıçta fazladan boşluk bırakın!). Etiket dummy
...
dummy times 20 db 0
paramblock dw 0
dw cmdline
dw 0 ; cmdline_seg
dw dummy ; fcb1
dw 0 ; fcb1_seg
dw dummy ; fcb2
dw 0 ; fcb2_seg
Devam ediyoruz sıfır içerecektir sadece 20 bayt. Aşağıda, Daniel Roethlisberger tarafından belirtilen EXEC yapısının bir temsili olan paramblock
etiketi yer almaktadır. İlk öğe sıfırdır, bu da yeni sürecin ebeveyniyle aynı ortama sahip olması gerektiği anlamına gelir. Üç adres takip eder: komut satırına, ilk FCB'ye ve ikinci FCB'ye. Gerçek modda adreslerin iki bölümden oluştuğunu unutmamalısınız: segmentin adresi ve segmente ofset. Her iki adres de 16 bit uzunluğundadır. Ofisinde ilk başta küçük bir endian tarzında yazılıyorlar. Bu nedenle, cmdline
ofseti olarak komut satırını ve FCB'lerin adreslerini dummy
etiketine ofset olarak belirtiriz, çünkü FCB'lerin kendileri kullanılmayacak, ancak adresler her iki durumda da geçerli bir bellek konumuna işaret etmelidir. Yükleyiciler, COM dosyasının yüklü olduğu segmenti seçtiğinden, bölümlerin çalışma zamanında doldurulması gerekir.
section .text
entry:
mov ax, cs
mov [paramblock+4], ax
mov [paramblock+8], ax
mov [paramblock+12],ax
Biz paramblock
yapısında segmenti alanları belirleyerek programı başlayacak. COM dosyaları için, CS = DS = ES = SS
, yani tüm bölümler aynı olduğundan, bu değerleri yalnızca cs
kaydında olanlara ayarladık.
mov ax, 4a00h
mov bx, 50
int 21h
Bu aslında uygulamanın en zor noktalarından biridir. Bir COM dosyası DOS tarafından belleğe yüklendiğinde, varsayılan olarak tüm kullanılabilir bellek atanır (CPU, gerçek modda olduğu için bu konuda hiçbir fikre sahip değildir, ancak DOS internals yine de izler). Bu nedenle, EXEC syscall çağrısı, No memory available
ile başarısız olmasına neden olur. Bu nedenle, DOS'a "RESIZE MEMORY BLOCK" AH=4Ah
numaralı telefonu aratarak gerçekten bu belleğe gerek duymadığımızı söylemeliyiz. bx
kaydının, bellek bloğunun yeni boyutuna 16 baytlık birimlerde ("paragraf") sahip olması gerekiyordu, bu yüzden programımız için 800 bayta sahip olan 50'ye ayarladık. Bu değerin rastgele seçildiğini itiraf etmeliyim, bunu mantıklı bir şeye ayarlamayı denedim (örneğin, gerçek dosya boyutuna dayalı bir değer), ama hiçbir yere ulaşamadım.ES
, "yeniden boyutlandırmak" istediğimiz bölümdür, bizim durumumuzda CS
(veya bir COM dosyası yüklendiğinde hepsi aynı olduğundan, herhangi biri). Bu aramayı tamamladıktan sonra, yeni programımızı belleğe yüklemek ve yürütmek için hazırız.
mov ax, 0100h
int 21h
cmp al, '1'
je .prog1
cmp al, '2'
je .prog2
jmp .end
.prog1:
mov dx, exename
jmp .exec
.prog2:
mov dx, exename2
Bu kod stdin dayalı DX
yerleştirilen programa yolunu seçer, yeterince açıklayıcı olmalıdır. Gerçek EXEC
syscall (AH=4Bh
) olarak adlandırılır burada
.exec:
mov bx, paramblock
mov ax, 4b00h
int 21h
olmasıdır. AL
, 0 içerir, bu da programın yüklenmesi ve çalıştırılması gerektiği anlamına gelir. DS:DX
, yürütülebilir dosyanın yolunun adresini (önceki kod parçası tarafından seçilir) ve ES:BX
, EXEC
yapısını içeren paramblock
etiketinin adresini içerir.
.end:
mov ax, 4c00h
int 21h
exec
tarafından çağrılan program yürütme tamamlandıktan sonra, ana program AH=4Ch
çağrısını yürüterek sıfır olan bir çıkış kodu ile sonlandırılır.
Yardım için Freenode üzerindeki ## asm adresinden vulture-
aracılığıyla. Bunu DOSBox ve MS-DOS 6.22 ile test ettim, bu yüzden umarım sizin için de çalışır.
Gerçekten bir yardıma ihtiyacım var. –
DOS ('int 21h') API'si artık kullanılmaması gereken bir mutlak, etkisiz, oldukça fazla kullanılmayan ve istenmeyen bir yazılım parçasıdır. ** Kesinlikle kullanmanız gerektiğinden emin misiniz? –
@DanielKozar Evet, kesinlikle. Aksine itibarımı vermezdim. Bunun için yardıma ihtiyacım var. –