Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/70.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/macos/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用main和scanf/printf的Mac OS X 32位nasm汇编程序?_C_Macos_Gcc_Assembly_Nasm - Fatal编程技术网

使用main和scanf/printf的Mac OS X 32位nasm汇编程序?

使用main和scanf/printf的Mac OS X 32位nasm汇编程序?,c,macos,gcc,assembly,nasm,C,Macos,Gcc,Assembly,Nasm,我花了一整天的时间试图编译一些简单的程序,但到目前为止运气很差。我想做的是编译和运行用nasm汇编编写的程序 我已升级到最新的nasm(v2.10.09)。所以让我跳进代码,因为我还不太了解这些东西。下面是一段在linux上运行的汇编代码,使用elf格式和链接的witch gcc(注释是我对发生的事情的理解): 没什么太大的。然而,我该如何在OSX上实现这一点呢?我甚至无法以任何方式编译/链接它。如果它编译了,我就不能链接它(关于i386和x86的一些东西不能链接在一起(我知道,但如何修复它?)

我花了一整天的时间试图编译一些简单的程序,但到目前为止运气很差。我想做的是编译和运行用nasm汇编编写的程序

我已升级到最新的nasm(v2.10.09)。所以让我跳进代码,因为我还不太了解这些东西。下面是一段在linux上运行的汇编代码,使用
elf
格式和链接的witch gcc(注释是我对发生的事情的理解):

没什么太大的。然而,我该如何在OSX上实现这一点呢?我甚至无法以任何方式编译/链接它。如果它编译了,我就不能链接它(关于i386和x86的一些东西不能链接在一起(我知道,但如何修复它?)。我试过十几种方法,但都没有成功

进一步了解如何在OS X组件上
printf
scanf

下面是另一个徒劳的
scanf
printf
返回值的尝试(这一个实际编译和链接,甚至运行!):

使用:
nasm-f macho-o test.o test.asm编译它,并将它与
d-lc-o test-arch i386 test.o-macosx\u version\u min 10.7
链接。工作不正常。在linux上,非常容易访问这个scanf和printf内容。上面是什么?能做得简单些吗

我不想在这个问题上添加更多的内容,因为人们有时会看到一个大问题和一件事“嗯,太长了,不会读”。但是如果有人要求更多的信息,我会尽力的

请帮帮我,因为我想不出来

编辑 第一个使用
nasm-f macho-o out.o test.asm
进行编译,但是使用
gcc-o test out.o
或使用
ld-lc-o test-arch i386 out.o-macosx_version\u min 10.7
和附加平面
-arch i386
也不能解决它。如果我可以编写“类似linux”的程序集,我会很高兴,因为我不必担心堆栈对齐之类的问题。 gcc错误表示:

ld: warning: ignoring file out.o, file was built for i386 which is not the architecture being linked (x86_64): out.o
Undefined symbols for architecture x86_64:
  "_main", referenced from:
      start in crt1.10.6.o
ld: symbol(s) not found for architecture x86_64
ld误差如下所示:

Undefined symbols for architecture i386:
  "printf", referenced from:
      main in out.o
  "start", referenced from:
     -u command line option
ld: symbol(s) not found for architecture i386

请帮忙。

你问了很多关于你的代码的问题,你真的不理解那里的汇编代码

首先,由于您编写代码的方式,
main
例程将成为C风格程序的入口点。因为MacOSX连接的工作方式;在生成可执行文件时,当链接器拉入
/usr/lib/crt1.o
时,必须将其命名为
\u main
,以匹配链接器正在查找的作为默认程序入口点的符号名称(如果对文件执行nm操作,您将看到一个条目,如:
U\U main
。类似地,所有库例程都以一个前导下划线开头,因此如果要使用它们,您必须使用该前缀

其次,MAC OS调用约定要求所有
调用的堆栈对齐为16字节,这意味着您必须确保堆栈指针在每个点上都相应对齐。在主例程的入口点,您已经知道,由于堆栈中存储的返回地址用于返回,因此未对齐这意味着,如果你想进行一次调用,你必须将堆栈向下移动至少12个字节才能进行调用

有了这条信息,我们就不必再使用ebp了,只需将esp专门用于代码目的

假设序言为:

bits 32
extern _printf
global _main

section .data
    message db "Hello world!", 10, 0

section .text
_main:
进入
\u main
时,重新对齐堆栈:

sub esp, 12
add esp, 12
mov dword[esp], output_string
接下来,我们将消息的地址存储到esp指向的地址中:

mov dword[esp], message
然后我们称之为printf:

call _printf
然后我们恢复堆栈:

sub esp, 12
add esp, 12
mov dword[esp], output_string
设置
main
的返回代码,然后返回:

mov eax, 0
ret
MAC OS X的ABI使用
eax
作为例程的返回码,只要它适合寄存器。编译并链接代码后:

nasm -f macho -o test.o test.asm 
ld -o test -arch i386 test.o -macosx_version_min 10.7 -lc /usr/lib/crt1.o
它运行并打印消息,以
0
退出

接下来,我们将讨论您的扫描和打印示例

首先,scanf只扫描,你不能在那里有一个提示;它根本不起作用,所以你必须将提示从扫描中分离出来。我们已经向你展示了如何进行打印,现在我们需要展示的是scanf

在数据部分设置变量:

scan_string     db  "%d", 0
limit           dd  0
首先将
scan\u string
的地址存储在
esp
中,然后将limit的地址存储在
esp+4
中,然后调用scanf:

mov dword[esp], scan_string
mov dword[esp + 4], limit
call _scanf
我们现在应该将扫描的值存储在限制内存位置

打印此邮件的旁边:

output_string   db  "Value %d", 10, 0
接下来,我们将输出字符串的地址放在堆栈上:

sub esp, 12
add esp, 12
mov dword[esp], output_string
将限制地址的值读入eax寄存器,并将其放入
esp+4
-即printf的第二个参数:

mov eax, [limit]
mov dword[esp + 4], eax
call _printf
接下来,我们调用exit,因此我们必须将exit代码存储在堆栈中并调用
\u exit
函数-这与简单的print变量不同,因为我们实际上是在调用exit,而不是简单地返回

mov dword[esp], 0
call _exit
至于一些问题:

为什么要对齐

因为Mac OS X就是这样做的

为什么推得不够好

是的,但我们在例程开始时对齐了堆栈,对齐的堆栈是一个正常运行的堆栈,通过按下和弹出您正在扰乱对齐。这是使用
ebp
寄存器而不是
esp
寄存器的目的之一

如果我们使用
ebp
寄存器,函数prolog将如下所示:

push ebp
mov ebp, esp
sub esp, 8 ; in this case to obtain alignment
add esp, 8
pop ebp
epilog的功能如下所示:

push ebp
mov ebp, esp
sub esp, 8 ; in this case to obtain alignment
add esp, 8
pop ebp
您也可以在其中放入对称pusha/popa调用,但是如果您不使用寄存器,为什么要使堆栈复杂化呢

有关32位函数调用机制的更好概述,请参阅,ABI函数调用指南提供了有关参数的更多详细信息