Assembly 在不带OUT指令的传统PC扬声器上发声

Assembly 在不带OUT指令的传统PC扬声器上发声,assembly,audio,x86,segmentation-fault,pc,Assembly,Audio,X86,Segmentation Fault,Pc,我目前正在尝试在汇编代码中生成声音。以下是我找到的一些代码: section .text global sound sound: mov al, 182 ; meaning that we're about to load mov ax, 182 out 43h, al ; a new countdown value ret mov ax, 2153 ; count

我目前正在尝试在汇编代码中生成声音。以下是我找到的一些代码:

    section .text
  global sound

sound:
    mov     al, 182         ; meaning that we're about to load
    mov     ax, 182
    out     43h, al         ; a new countdown value
    ret
    mov     ax, 2153        ; countdown value is stored in ax. It is calculated by 
    out     42h, al         ; Output low byte.
    mov     al, ah          ; Output high byte.
    out     42h, al               

    in      al, 61h         
    or      al, 00000011b  
    out     61h, al     ; Send the new value
    ret
根据这段代码的所有者的说法,它应该可以工作,但是当我用C main运行它时,它被一个分段错误杀死了

通过进一步的研究,我发现在现代操作系统中,由于权限的原因,很难访问说话者。如果有人知道如何使用扬声器并播放声音,我很乐意学习


注意:当我以超级用户的身份运行代码时,不会出现分段错误,但不会产生声音。

[在阅读NASM编译器的工作原理之前,我不确定是否有其他编译器]

您的代码很好,但问题是:

  • 它不会在虚拟机中产生声音。 0x43、0x42端口的用途是PIT(可编程间隔计时器)芯片,它处理一些您可以在这里读取的内容。PIT芯片处理的一件事情是车载扬声器,这是您试图访问的。虚拟机没有内置扬声器
  • 长话短说您正在尝试访问主板扬声器,但虚拟机无法使用它,因此您听不到任何声音

    此外,大多数较新的主板也没有板上扬声器

  • 你的密码。 因此,只要看一眼您的代码,我就猜您正在使用nasm,所以我对此有点困惑:
  • 要稍微润色这一部分,您可以移除
    mov ax,182
    ret
    ,因为此处的返回将跳出代码,跳转到您调用的位置,不再运行代码生成:

    mov     ax, 2153        ; countdown value is stored in ax. It is calculated by 
    out     42h, al         ; Output low byte.
    mov     al, ah          ; Output high byte.
    out     42h, al               
    
    in      al, 61h         
    or      al, 00000011b  
    out     61h, al     ; Send the new value
    ret
    
    过时的。对于
    mov-ax,182
    当我使用扬声器时,我的工作原理是没有这个,所以我猜你不需要它,所以如果必要的话,我会说移除它

    因此,修改后的代码版本将是:

    bits 16
    
    start:
    mov ax, 0x07c0   ; Setup the stack past where we are loaded
    add ax, 544
    cli              ; Disable interrupts
    mov ss, ax
    mov sp, 4096
    sti              ; Restore interrupts
    
    mov ax, 0x07c0   ; Set the data segment to where we are
    mov ds, ax
    
    sound:
    mov al, 182         ; Were about to load
    out 0x43, al
    
    mov ax, 15000       ; 15000(Pitch) = 1,193,180 / 79.5453333(Repeating)
    
    out 0x42, al        ; Give the port the lower value
    mov al, ah
    out 0x42, al        ; Now give it the higher
    
    in al, 0x61         
    
    or al, 00000011b    ; Connect the speaker to Timer 2
    out 0x61, al
    jmp $               ; hang
    
    times 510-($-$$) db 0     ; Pad the rest of the file with 0's
    dw 0xaa55                 ; Little Endian MBR Signature
    
    若要运行此操作以查看其是否工作,请确保您的计算机具有车载扬声器。我的看起来像这样:

    如果您没有它,您的可能与我的不一样,如果没有,您可以在代码之后显示或执行某些操作以确保它运行

    我使用这些命令来运行它

    nasm -f bin <YOURFILENAME>.asm -o boot.bin
    dd if=boot.bin of=\\.\<DRIVENUMBER>: bs=512
    
    若要查看是否正在引导,请将其添加到文件顶部的
    位16之后:

    jmp short start
    nop
    
    OEMLabel            db "Contoso"   ; OEM Label
    BytesPerSector      dw 512          ; There are 512b per sector
    SectorsPerCluster   db 1            ; Sectors per cluster
    ReservedForBoot     dw 1            ; # of sectors reserved for boot
    NumberOfFats        db 2            ; # of fats
    RootDirEntries      dw 224          ; # of root directory entries
    LogicalSectors      dw 2880         ; # of sectors
    MediumByte          db 0x0f0        ; Medium descriptor byte
    SectorsPerFat       dw 9            ; # of sectors per fat
    SectorsPerTrack     dw 18           ; # of sectors per track
    Sides               dw 2            ; # of sides
    HiddenSectors       dd 0            ; # of hidden sectors
    LargeSectors        dd 0            ; # of large sectors
    DriveNo             dw 0            ; The drive number
    Signature           db 41           ; The drive signature
    VolumeID            dd 0xdeadbeef   ; The volume id
    VolumeLabel         db "Windows9   "; This can be any 11 characters
    FileSystem          db "FAT12   "   ; File system of the floppy DONT CHANGE
    
    如果出于任何原因,代码无法工作,请检查是否存在任何错误,并确保主板上有内置扬声器

    如需了解更多信息,请参见上文所述。 源代码的基础。 关于汇编的一些技巧,这是一个非常有文档记录的开源操作系统,可以帮助初学者学习汇编

    希望这有帮助


    编辑:Peter Cordes的一些打字错误和帮助(在评论中)

    找到一个在您想要的目标操作系统上工作的库(例如FMOD、BASS),然后在您的程序中使用该库。
    out
    指令具有特权。它还针对不再存在的硬件。您应该在DOSBox中运行这个程序,或者获得一个在Linux下运行的库?对不起,我是个有汇编代码的新手。我将搜索类似的内容,感谢你们两位的回答,因为root允许Linux系统调用成功运行,但如果您不这样做,这仍然会导致root失败。也许你以root用户身份运行的方式隐藏了segfault消息?超级用户仍然独立于内核模式,尽管ioperm/iopl可以允许在用户空间中执行I/O指令(通常具有特权)。准确模拟传统IBM-PC的虚拟机将拥有该虚拟硬件。e、 g.可能是BOCHS或DOSBox。当你说“振荡器”时,我想你实际上是指“PC扬声器”。在您的照片中,它是mobo上的压电元件;在其他情况下,它可以是电路板上的一个标题,您需要连接到线圈扬声器。如果你有一个旧的电脑机箱,你可以把扬声器拿出来,放进一个现代化的机箱里,连接到mobo上。当然,您也可以在模拟器中运行,该模拟器使用常规声音I/O功能通过主机的声卡产生蜂鸣音。顺便说一句,我认为您在512字节引导扇区(例如)的末尾遗漏了
    0xAA55
    MBR引导签名。您的测试之所以成功,可能是因为您写入的字节数少于512字节,因此保留了现有签名?或者,在加载引导扇区之前,BIOS没有检查该签名。顺便说一句,问题是他们试图在Linux或MacOS下的用户空间中运行此代码!!(短语“分段错误”是一个线索)。这是一个showtupper,与早期的
    ret
    (可能是为了查看是否只有第一部分仍然存在故障)等bug分开。如果您进行
    ioperm
    系统调用以启用这些I/O端口以便从用户空间使用,则可能会起作用。或者是的,当然,编写一个引导加载程序可以让你对整个机器进行真正的模式控制。或者这是他的代码中的一个bug。嗯,是的,这个bug很天真地在Linux下的用户空间中运行这个代码,没有使用
    ioperm
    或任何东西,并且惊讶地发现
    out
    出现了故障:P许多初学者没有意识到汇编语言是多么不可移植,他们想知道为什么在复制/粘贴他们找到的一些代码后,
    int 21h
    在Windows(非DOS)可执行文件和类似的东西中不起作用,例如在x86汇编中打印一个数字
    mov ah, 0x0e
    mov al, 'X'
    int 0x10
    
    jmp short start
    nop
    
    OEMLabel            db "Contoso"   ; OEM Label
    BytesPerSector      dw 512          ; There are 512b per sector
    SectorsPerCluster   db 1            ; Sectors per cluster
    ReservedForBoot     dw 1            ; # of sectors reserved for boot
    NumberOfFats        db 2            ; # of fats
    RootDirEntries      dw 224          ; # of root directory entries
    LogicalSectors      dw 2880         ; # of sectors
    MediumByte          db 0x0f0        ; Medium descriptor byte
    SectorsPerFat       dw 9            ; # of sectors per fat
    SectorsPerTrack     dw 18           ; # of sectors per track
    Sides               dw 2            ; # of sides
    HiddenSectors       dd 0            ; # of hidden sectors
    LargeSectors        dd 0            ; # of large sectors
    DriveNo             dw 0            ; The drive number
    Signature           db 41           ; The drive signature
    VolumeID            dd 0xdeadbeef   ; The volume id
    VolumeLabel         db "Windows9   "; This can be any 11 characters
    FileSystem          db "FAT12   "   ; File system of the floppy DONT CHANGE