我写了一个简单的NASM程序:
printtest.asm
section .data
str_out db "val = %d",10,0
section .text
global main
extern printf
main:
PUSH 5
PUSH DWORD str_out
CALL printf
ADD ESP, 8
MOV EAX, 1
INT 80h
Run Code Online (Sandbox Code Playgroud)
我使用以下命令链接并创建可执行文件:
nasm -f elf -l printtest.lst printtest.asm
gcc -o printtest printtest.o
Run Code Online (Sandbox Code Playgroud)
链接和执行时,这将打印"val = 5"没有问题.据我所知,printf默认情况下调用会写入stdout.那么为什么当我尝试将其传输到另一个程序时,其他程序似乎没有收到任何输入?
例如
./printtest | cat
Run Code Online (Sandbox Code Playgroud)
似乎什么都不做
我相信我从根本上误解了一些问题.
在移动的垃圾收集器中,必须有一种精确的方法来区分堆栈和堆上的哪些值是引用,哪些是立即值.这个细节似乎在我读过的关于垃圾收集的大部分文献中都被掩盖了.
我已经研究过为每个堆栈帧分配一些前导码是否有效,例如,在调用之前描述每个参数.但肯定所有这一切都将问题推向了间接的上层.然后,当在GC循环期间遍历它以获得立即值或引用时,如何区分前导码和堆栈帧?
有人可以解释一下这是如何在现实世界中实现的吗?
下面是这个问题的示例程序,它使用第一个类函数词法闭包及其堆栈框架图和位于堆上的父代环境:
一个示例程序
def foo(x) = {
def bar(y,z) = {
return x + y + z
}
return bar
}
def main() = {
let makeBar = foo(1)
makeBar(2,3)
}
Run Code Online (Sandbox Code Playgroud)
调用时Bar的堆栈框架:
在此示例中,bar的堆栈帧具有局部变量x,它是指向堆上的值的指针,其中参数y和z是直接整数值.
我读到,Objective CAML对堆栈上的每个值使用一个标记位,该值为每个值添加前缀.允许在GC循环期间对每个值进行二进制ref-or-imm检查.但这可能会产生一些不必要的副作用.整数限制为31位,并且需要调整原始计算的动态代码生成以补偿这一点.简而言之 - 感觉有点太脏了.必须有一个更优雅的解决方案.
是否有可能知道并静态访问此信息?比如以某种方式将类型信息传递给垃圾收集器?
我写了一个简单的汇编程序:
section .data
str_out db "%d ",10,0
section .text
extern printf
extern exit
global main
main:
MOV EDX, ESP
MOV EAX, EDX
PUSH EAX
PUSH str_out
CALL printf
SUB ESP, 8 ; cleanup stack
MOV EAX, EDX
PUSH EAX
PUSH str_out
CALL printf
SUB ESP, 8 ; cleanup stack
CALL exit
Run Code Online (Sandbox Code Playgroud)
我是NASM汇编程序和GCC,用于将目标文件链接到linux上的可执行文件.
本质上,该程序首先将堆栈指针的值放入寄存器EDX,然后将该寄存器的内容打印两次.但是,在第二次printf调用之后,打印到stdout的值与第一个不匹配.
这种行为似乎很奇怪.当我用EBX替换该程序中每次使用EDX时,输出的整数与预期的完全相同.我只能推断在printf函数调用期间某些时候EDX会被覆盖.
为什么会这样?如何确保我将来使用的寄存器与C lib函数不冲突?